BuddyPress - Version 2.7.0-beta1

Version Description

= 2.6.2 = See: https://codex.buddypress.org/releases/version-2-6-2/

= 2.6.1.1 = See: https://codex.buddypress.org/releases/version-2-6-1-1/

= 2.6.1 = See: https://codex.buddypress.org/releases/version-2-6-1/

= 2.6.0 = See: https://codex.buddypress.org/releases/version-2-6-0/

Download this release

Release Info

Developer mercime
Plugin Icon 128x128 BuddyPress
Version 2.7.0-beta1
Comparing to
See all releases

Code changes from version 2.6.2 to 2.7.0-beta1

Files changed (216) hide show
  1. bp-activity/bp-activity-actions.php +1 -40
  2. bp-activity/bp-activity-akismet.php +23 -0
  3. bp-activity/bp-activity-cache.php +21 -0
  4. bp-activity/bp-activity-filters.php +15 -11
  5. bp-activity/bp-activity-functions.php +226 -49
  6. bp-activity/bp-activity-loader.php +1 -1
  7. bp-activity/bp-activity-notifications.php +23 -225
  8. bp-activity/bp-activity-screens.php +1 -1
  9. bp-activity/bp-activity-template.php +11 -11
  10. bp-activity/classes/class-bp-activity-activity.php +24 -2
  11. bp-activity/classes/class-bp-activity-component.php +11 -16
  12. bp-activity/classes/class-bp-activity-list-table.php +20 -2
  13. bp-activity/js/mentions.min.js +1 -1
  14. bp-blogs/bp-blogs-activity.php +1 -1
  15. bp-blogs/bp-blogs-filters.php +14 -0
  16. bp-blogs/bp-blogs-functions.php +20 -0
  17. bp-blogs/bp-blogs-loader.php +2 -0
  18. bp-blogs/bp-blogs-template.php +94 -18
  19. bp-blogs/classes/class-bp-blogs-blog.php +33 -10
  20. bp-blogs/classes/class-bp-blogs-component.php +6 -1
  21. bp-core/admin/bp-core-admin-components.php +1 -0
  22. bp-core/admin/bp-core-admin-functions.php +22 -0
  23. bp-core/admin/bp-core-admin-schema.php +13 -26
  24. bp-core/admin/bp-core-admin-slugs.php +11 -3
  25. bp-core/admin/bp-core-admin-tools.php +20 -29
  26. bp-core/admin/css/common-rtl.css +45 -0
  27. bp-core/admin/css/common-rtl.min.css +1 -1
  28. bp-core/admin/css/common.css +45 -0
  29. bp-core/admin/css/common.min.css +1 -1
  30. bp-core/admin/images/activity-embeds.png +0 -0
  31. bp-core/bp-core-actions.php +11 -4
  32. bp-core/bp-core-admin.php +27 -19
  33. bp-core/bp-core-attachments.php +8 -6
  34. bp-core/bp-core-avatars.php +21 -30
  35. bp-core/bp-core-buddybar.php +11 -11
  36. bp-core/bp-core-cache.php +107 -0
  37. bp-core/bp-core-caps.php +65 -20
  38. bp-core/bp-core-catchuri.php +71 -20
  39. bp-core/bp-core-classes.php +1 -0
  40. bp-core/bp-core-cssjs.php +104 -14
  41. bp-core/bp-core-customizer-email.php +3 -5
  42. bp-core/bp-core-dependency.php +0 -12
  43. bp-core/bp-core-filters.php +53 -43
  44. bp-core/bp-core-functions.php +405 -52
  45. bp-core/bp-core-loader.php +1 -3
  46. bp-core/bp-core-options.php +19 -59
  47. bp-core/bp-core-taxonomy.php +113 -5
  48. bp-core/bp-core-template-loader.php +5 -1
  49. bp-core/bp-core-template.php +73 -8
  50. bp-core/bp-core-theme-compatibility.php +11 -9
  51. bp-core/bp-core-update.php +109 -24
  52. bp-core/bp-core-wpabstraction.php +0 -7
  53. bp-core/classes/class-bp-admin.php +6 -6
  54. bp-core/classes/class-bp-attachment-avatar.php +1 -4
  55. bp-core/classes/class-bp-attachment-cover-image.php +291 -291
  56. bp-core/classes/class-bp-attachment.php +12 -12
  57. bp-core/classes/class-bp-button.php +232 -77
  58. bp-core/classes/class-bp-core-html-element.php +127 -0
  59. bp-core/classes/class-bp-core-nav.php +15 -15
  60. bp-core/classes/class-bp-core-oembed-extension.php +21 -15
  61. bp-core/classes/class-bp-core-user.php +17 -0
  62. bp-core/classes/class-bp-theme-compat.php +1 -1
  63. bp-core/classes/class-bp-user-query.php +11 -4
  64. bp-core/css/avatar-rtl.css +1 -1
  65. bp-core/css/avatar-rtl.min.css +1 -1
  66. bp-core/css/avatar.css +1 -1
  67. bp-core/css/avatar.min.css +1 -1
  68. bp-core/deprecated/2.7.php +26 -0
  69. bp-core/js/bp-plupload.min.js +1 -1
  70. bp-core/js/confirm.min.js +1 -1
  71. bp-core/js/cover-image.js +277 -277
  72. bp-core/js/jquery.atwho.min.js +0 -1
  73. bp-core/js/{jquery-cookie.js → vendor/jquery-cookie.js} +0 -0
  74. bp-core/js/{jquery-cookie.min.js → vendor/jquery-cookie.min.js} +1 -1
  75. bp-core/js/{jquery-scroll-to.js → vendor/jquery-scroll-to.js} +0 -0
  76. bp-core/js/{jquery-scroll-to.min.js → vendor/jquery-scroll-to.min.js} +1 -1
  77. bp-core/js/{jquery.atwho.js → vendor/jquery.atwho.js} +0 -0
  78. bp-core/js/vendor/jquery.atwho.min.js +1 -0
  79. bp-core/js/{jquery.atwho.txt → vendor/jquery.atwho.txt} +0 -0
  80. bp-core/js/{jquery.caret.js → vendor/jquery.caret.js} +0 -0
  81. bp-core/js/{jquery.caret.min.js → vendor/jquery.caret.min.js} +1 -1
  82. bp-core/js/{jquery.caret.txt → vendor/jquery.caret.txt} +0 -0
  83. bp-core/js/vendor/livestamp.js +129 -0
  84. bp-core/js/vendor/livestamp.min.js +1 -0
  85. bp-core/js/vendor/moment.js +4040 -0
  86. bp-core/js/vendor/moment.min.js +2 -0
  87. bp-forums/bp-forums-bbpress-sa.php +8 -11
  88. bp-forums/bp-forums-template.php +9 -14
  89. bp-friends/bp-friends-actions.php +2 -2
  90. bp-friends/bp-friends-cache.php +41 -0
  91. bp-friends/bp-friends-filters.php +7 -34
  92. bp-friends/bp-friends-functions.php +75 -0
  93. bp-friends/bp-friends-loader.php +1 -1
  94. bp-friends/bp-friends-notifications.php +15 -96
  95. bp-friends/bp-friends-template.php +0 -4
  96. bp-friends/bp-friends-widgets.php +2 -2
  97. bp-friends/classes/class-bp-core-friends-widget.php +7 -10
  98. bp-friends/classes/class-bp-friends-component.php +8 -2
  99. bp-friends/classes/class-bp-friends-friendship.php +296 -49
  100. bp-groups/admin/css/admin-rtl.css +17 -7
  101. bp-groups/admin/css/admin-rtl.min.css +1 -1
  102. bp-groups/admin/css/admin.css +17 -7
  103. bp-groups/admin/css/admin.min.css +1 -1
  104. bp-groups/admin/js/admin.min.js +1 -1
  105. bp-groups/bp-groups-actions.php +33 -2
  106. bp-groups/bp-groups-activity.php +5 -14
  107. bp-groups/bp-groups-admin.php +107 -13
  108. bp-groups/bp-groups-cache.php +73 -3
  109. bp-groups/bp-groups-filters.php +1 -1
  110. bp-groups/bp-groups-forums.php +1 -1
  111. bp-groups/bp-groups-functions.php +150 -68
  112. bp-groups/bp-groups-loader.php +1 -1
  113. bp-groups/bp-groups-notifications.php +53 -11
  114. bp-groups/bp-groups-screens.php +43 -1
  115. bp-groups/bp-groups-template.php +338 -79
  116. bp-groups/bp-groups-widgets.php +7 -11
  117. bp-groups/classes/class-bp-group-extension.php +4 -10
  118. bp-groups/classes/class-bp-groups-component.php +16 -16
  119. bp-groups/classes/class-bp-groups-group-members-template.php +5 -3
  120. bp-groups/classes/class-bp-groups-group.php +361 -178
  121. bp-groups/classes/class-bp-groups-invite-template.php +4 -2
  122. bp-groups/classes/class-bp-groups-list-table.php +132 -3
  123. bp-groups/classes/class-bp-groups-member-suggestions.php +1 -6
  124. bp-groups/classes/class-bp-groups-member.php +90 -27
  125. bp-groups/classes/class-bp-groups-template.php +5 -6
  126. bp-groups/classes/class-bp-groups-theme-compat.php +8 -4
  127. bp-groups/classes/class-bp-groups-widget.php +1 -1
  128. bp-loader.php +9 -7
  129. bp-members/bp-members-cache.php +13 -1
  130. bp-members/bp-members-functions.php +40 -5
  131. bp-members/bp-members-screens.php +2 -2
  132. bp-members/bp-members-template.php +60 -34
  133. bp-members/classes/class-bp-core-members-widget.php +9 -13
  134. bp-members/classes/class-bp-core-recently-active-widget.php +1 -3
  135. bp-members/classes/class-bp-core-whos-online-widget.php +1 -4
  136. bp-members/classes/class-bp-members-admin.php +277 -0
  137. bp-members/classes/class-bp-members-component.php +5 -1
  138. bp-messages/bp-messages-functions.php +106 -8
  139. bp-messages/bp-messages-loader.php +3 -1
  140. bp-messages/bp-messages-notifications.php +21 -104
  141. bp-messages/bp-messages-template.php +0 -1
  142. bp-messages/classes/class-bp-messages-component.php +3 -1
  143. bp-messages/classes/class-bp-messages-message.php +12 -6
  144. bp-messages/classes/class-bp-messages-notice.php +8 -2
  145. bp-messages/classes/class-bp-messages-thread.php +30 -7
  146. bp-messages/js/autocomplete/jquery.autocomplete.min.js +1 -1
  147. bp-messages/js/autocomplete/jquery.dimensions.min.js +1 -1
  148. bp-notifications/bp-notifications-loader.php +1 -1
  149. bp-notifications/classes/class-bp-notifications-notification.php +26 -20
  150. bp-settings/bp-settings-actions.php +1 -1
  151. bp-settings/bp-settings-loader.php +1 -1
  152. bp-templates/bp-legacy/buddypress-functions.php +44 -12
  153. bp-templates/bp-legacy/buddypress/activity/comment.php +2 -2
  154. bp-templates/bp-legacy/buddypress/activity/entry.php +2 -2
  155. bp-templates/bp-legacy/buddypress/activity/index.php +8 -8
  156. bp-templates/bp-legacy/buddypress/assets/_attachments/avatars/index.php +2 -2
  157. bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php +36 -36
  158. bp-templates/bp-legacy/buddypress/blogs/index.php +16 -5
  159. bp-templates/bp-legacy/buddypress/common/search/dir-search-form.php +16 -0
  160. bp-templates/bp-legacy/buddypress/forums/index.php +13 -5
  161. bp-templates/bp-legacy/buddypress/groups/create.php +70 -29
  162. bp-templates/bp-legacy/buddypress/groups/groups-loop.php +5 -1
  163. bp-templates/bp-legacy/buddypress/groups/index.php +16 -5
  164. bp-templates/bp-legacy/buddypress/groups/single/activity.php +2 -2
  165. bp-templates/bp-legacy/buddypress/groups/single/admin.php +19 -456
  166. bp-templates/bp-legacy/buddypress/groups/single/admin/delete-group.php +41 -0
  167. bp-templates/bp-legacy/buddypress/groups/single/admin/edit-details.php +53 -0
  168. bp-templates/bp-legacy/buddypress/groups/single/admin/group-avatar.php +67 -0
  169. bp-templates/bp-legacy/buddypress/groups/single/admin/group-cover-image.php +33 -0
  170. bp-templates/bp-legacy/buddypress/groups/single/admin/group-settings.php +124 -0
  171. bp-templates/bp-legacy/buddypress/groups/single/admin/manage-members.php +332 -0
  172. bp-templates/bp-legacy/buddypress/groups/single/admin/membership-requests.php +35 -0
  173. bp-templates/bp-legacy/buddypress/groups/single/cover-image-header.php +124 -123
  174. bp-templates/bp-legacy/buddypress/groups/single/forum.php +1 -1
  175. bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php +1 -1
  176. bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php +1 -1
  177. bp-templates/bp-legacy/buddypress/groups/single/group-header.php +5 -3
  178. bp-templates/bp-legacy/buddypress/groups/single/home.php +1 -1
  179. bp-templates/bp-legacy/buddypress/groups/single/invites-loop.php +1 -1
  180. bp-templates/bp-legacy/buddypress/groups/single/members.php +1 -1
  181. bp-templates/bp-legacy/buddypress/groups/single/request-membership.php +2 -0
  182. bp-templates/bp-legacy/buddypress/groups/single/requests-loop.php +2 -2
  183. bp-templates/bp-legacy/buddypress/groups/single/send-invites.php +3 -1
  184. bp-templates/bp-legacy/buddypress/members/index.php +17 -7
  185. bp-templates/bp-legacy/buddypress/members/members-loop.php +1 -1
  186. bp-templates/bp-legacy/buddypress/members/register.php +3 -3
  187. bp-templates/bp-legacy/buddypress/members/single/activity.php +2 -2
  188. bp-templates/bp-legacy/buddypress/members/single/blogs.php +1 -1
  189. bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php +103 -103
  190. bp-templates/bp-legacy/buddypress/members/single/forums.php +1 -1
  191. bp-templates/bp-legacy/buddypress/members/single/friends.php +7 -1
  192. bp-templates/bp-legacy/buddypress/members/single/friends/requests.php +2 -0
  193. bp-templates/bp-legacy/buddypress/members/single/groups.php +7 -1
  194. bp-templates/bp-legacy/buddypress/members/single/groups/invites.php +2 -0
  195. bp-templates/bp-legacy/buddypress/members/single/home.php +1 -1
  196. bp-templates/bp-legacy/buddypress/members/single/member-header.php +1 -1
  197. bp-templates/bp-legacy/buddypress/members/single/messages.php +9 -1
  198. bp-templates/bp-legacy/buddypress/members/single/messages/compose.php +2 -0
  199. bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php +2 -0
  200. bp-templates/bp-legacy/buddypress/members/single/messages/single.php +1 -1
  201. bp-templates/bp-legacy/buddypress/members/single/notifications.php +1 -1
  202. bp-templates/bp-legacy/buddypress/members/single/notifications/read.php +2 -0
  203. bp-templates/bp-legacy/buddypress/members/single/notifications/unread.php +2 -0
  204. bp-templates/bp-legacy/buddypress/members/single/plugins.php +1 -1
  205. bp-templates/bp-legacy/buddypress/members/single/profile.php +1 -1
  206. bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php +2 -2
  207. bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php +33 -33
  208. bp-templates/bp-legacy/buddypress/members/single/profile/edit.php +1 -1
  209. bp-templates/bp-legacy/buddypress/members/single/profile/profile-loop.php +1 -1
  210. bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php +1 -1
  211. bp-templates/bp-legacy/buddypress/members/single/settings.php +1 -1
  212. bp-templates/bp-legacy/buddypress/members/single/settings/general.php +2 -0
  213. bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php +2 -0
  214. bp-templates/bp-legacy/buddypress/members/single/settings/profile.php +2 -0
  215. bp-templates/bp-legacy/css/buddypress-rtl.css +19 -8
  216. bp-templates/bp-legacy/css/buddypress-rtl.min.css +1 -1
bp-activity/bp-activity-actions.php CHANGED
@@ -71,7 +71,7 @@ function bp_activity_action_permalink_router() {
71
  } else {
72
 
73
  // Set redirect to group activity stream.
74
- if ( $group = groups_get_group( array( 'group_id' => $activity->item_id ) ) ) {
75
  $redirect = bp_get_group_permalink( $group ) . bp_get_activity_slug() . '/' . $activity->id . '/';
76
  }
77
  }
@@ -604,45 +604,6 @@ function bp_activity_action_favorites_feed() {
604
  }
605
  add_action( 'bp_actions', 'bp_activity_action_favorites_feed' );
606
 
607
- /**
608
- * Loads Akismet filtering for activity.
609
- *
610
- * @since 1.6.0
611
- * @since 2.3.0 We only support Akismet 3+.
612
- */
613
- function bp_activity_setup_akismet() {
614
- $bp = buddypress();
615
-
616
- // Bail if Akismet is not active.
617
- if ( ! defined( 'AKISMET_VERSION' ) ) {
618
- return;
619
- }
620
-
621
- // Bail if older version of Akismet.
622
- if ( ! class_exists( 'Akismet' ) ) {
623
- return;
624
- }
625
-
626
- // Bail if no Akismet key is set.
627
- if ( ! bp_get_option( 'wordpress_api_key' ) && ! defined( 'WPCOM_API_KEY' ) ) {
628
- return;
629
- }
630
-
631
- /**
632
- * Filters if BuddyPress Activity Akismet support has been disabled by another plugin.
633
- *
634
- * @since 1.6.0
635
- *
636
- * @param bool $value Return value of bp_is_akismet_active boolean function.
637
- */
638
- if ( ! apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
639
- return;
640
- }
641
-
642
- // Instantiate Akismet for BuddyPress.
643
- $bp->activity->akismet = new BP_Akismet();
644
- }
645
-
646
  /**
647
  * AJAX endpoint for Suggestions API lookups.
648
  *
71
  } else {
72
 
73
  // Set redirect to group activity stream.
74
+ if ( $group = groups_get_group( $activity->item_id ) ) {
75
  $redirect = bp_get_group_permalink( $group ) . bp_get_activity_slug() . '/' . $activity->id . '/';
76
  }
77
  }
604
  }
605
  add_action( 'bp_actions', 'bp_activity_action_favorites_feed' );
606
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  /**
608
  * AJAX endpoint for Suggestions API lookups.
609
  *
bp-activity/bp-activity-akismet.php CHANGED
@@ -14,6 +14,29 @@ if ( ! buddypress()->do_autoload ) {
14
  require dirname( __FILE__ ) . '/classes/class-bp-akismet.php';
15
  }
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  /**
18
  * Delete old spam activity meta data.
19
  *
14
  require dirname( __FILE__ ) . '/classes/class-bp-akismet.php';
15
  }
16
 
17
+ /**
18
+ * Loads Akismet filtering for activity.
19
+ *
20
+ * @since 1.6.0
21
+ * @since 2.3.0 We only support Akismet 3+.
22
+ */
23
+ function bp_activity_setup_akismet() {
24
+ /**
25
+ * Filters if BuddyPress Activity Akismet support has been disabled by another plugin.
26
+ *
27
+ * @since 1.6.0
28
+ *
29
+ * @param bool $value Return value of bp_is_akismet_active boolean function.
30
+ */
31
+ if ( ! apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
32
+ return;
33
+ }
34
+
35
+ // Instantiate Akismet for BuddyPress.
36
+ buddypress()->activity->akismet = new BP_Akismet();
37
+ }
38
+ add_action( 'bp_activity_setup_globals', 'bp_activity_setup_akismet' );
39
+
40
  /**
41
  * Delete old spam activity meta data.
42
  *
bp-activity/bp-activity-cache.php CHANGED
@@ -63,3 +63,24 @@ function bp_activity_clear_cache_for_deleted_activity( $deleted_ids ) {
63
  }
64
  }
65
  add_action( 'bp_activity_deleted_activities', 'bp_activity_clear_cache_for_deleted_activity' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
64
  }
65
  add_action( 'bp_activity_deleted_activities', 'bp_activity_clear_cache_for_deleted_activity' );
66
+
67
+ /**
68
+ * Reset cache incrementor for the Activity component.
69
+ *
70
+ * Called whenever an activity item is created, updated, or deleted, this
71
+ * function effectively invalidates all cached results of activity queries.
72
+ *
73
+ * @since 2.7.0
74
+ *
75
+ * @return bool True on success, false on failure.
76
+ */
77
+ function bp_activity_reset_cache_incrementor() {
78
+ $without_last_activity = bp_core_reset_incrementor( 'bp_activity' );
79
+ $with_last_activity = bp_core_reset_incrementor( 'bp_activity_with_last_activity' );
80
+ return $without_last_activity && $with_last_activity;
81
+ }
82
+ add_action( 'bp_activity_delete', 'bp_activity_reset_cache_incrementor' );
83
+ add_action( 'bp_activity_add', 'bp_activity_reset_cache_incrementor' );
84
+ add_action( 'added_activity_meta', 'bp_activity_reset_cache_incrementor' );
85
+ add_action( 'updated_activity_meta', 'bp_activity_reset_cache_incrementor' );
86
+ add_action( 'deleted_activity_meta', 'bp_activity_reset_cache_incrementor' );
bp-activity/bp-activity-filters.php CHANGED
@@ -207,13 +207,15 @@ function bp_activity_filter_kses( $content ) {
207
  global $allowedtags;
208
 
209
  $activity_allowedtags = $allowedtags;
210
- $activity_allowedtags['a']['class'] = array();
211
- $activity_allowedtags['a']['id'] = array();
212
- $activity_allowedtags['a']['rel'] = array();
213
- $activity_allowedtags['a']['title'] = array();
214
- $activity_allowedtags['b'] = array();
215
- $activity_allowedtags['code'] = array();
216
- $activity_allowedtags['i'] = array();
 
 
217
  $activity_allowedtags['img'] = array();
218
  $activity_allowedtags['img']['src'] = array();
219
  $activity_allowedtags['img']['alt'] = array();
@@ -222,8 +224,10 @@ function bp_activity_filter_kses( $content ) {
222
  $activity_allowedtags['img']['class'] = array();
223
  $activity_allowedtags['img']['id'] = array();
224
  $activity_allowedtags['img']['title'] = array();
225
- $activity_allowedtags['span'] = array();
226
- $activity_allowedtags['span']['class'] = array();
 
 
227
 
228
 
229
  /**
@@ -278,7 +282,7 @@ function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
278
 
279
  // Linkify the mentions with the username.
280
  foreach ( (array) $usernames as $user_id => $username ) {
281
- $content = preg_replace( '/(@' . $username . '\b)/', "<a href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $content );
282
  }
283
 
284
  // Put everything back.
@@ -319,7 +323,7 @@ function bp_activity_at_name_filter_updates( $activity ) {
319
  if ( ! empty( $usernames ) ) {
320
  // Replace @mention text with userlinks.
321
  foreach( (array) $usernames as $user_id => $username ) {
322
- $activity->content = preg_replace( '/(@' . $username . '\b)/', "<a href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $activity->content );
323
  }
324
 
325
  // Add our hook to send @mention emails after the activity item is saved.
207
  global $allowedtags;
208
 
209
  $activity_allowedtags = $allowedtags;
210
+ $activity_allowedtags['a']['class'] = array();
211
+ $activity_allowedtags['a']['id'] = array();
212
+ $activity_allowedtags['a']['rel'] = array();
213
+ $activity_allowedtags['a']['title'] = array();
214
+
215
+ $activity_allowedtags['b'] = array();
216
+ $activity_allowedtags['code'] = array();
217
+ $activity_allowedtags['i'] = array();
218
+
219
  $activity_allowedtags['img'] = array();
220
  $activity_allowedtags['img']['src'] = array();
221
  $activity_allowedtags['img']['alt'] = array();
224
  $activity_allowedtags['img']['class'] = array();
225
  $activity_allowedtags['img']['id'] = array();
226
  $activity_allowedtags['img']['title'] = array();
227
+
228
+ $activity_allowedtags['span'] = array();
229
+ $activity_allowedtags['span']['class'] = array();
230
+ $activity_allowedtags['span']['data-livestamp'] = array();
231
 
232
 
233
  /**
282
 
283
  // Linkify the mentions with the username.
284
  foreach ( (array) $usernames as $user_id => $username ) {
285
+ $content = preg_replace( '/(@' . $username . '\b)/', "<a class='bp-suggestions-mention' href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $content );
286
  }
287
 
288
  // Put everything back.
323
  if ( ! empty( $usernames ) ) {
324
  // Replace @mention text with userlinks.
325
  foreach( (array) $usernames as $user_id => $username ) {
326
+ $activity->content = preg_replace( '/(@' . $username . '\b)/', "<a class='bp-suggestions-mention' href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $activity->content );
327
  }
328
 
329
  // Add our hook to send @mention emails after the activity item is saved.
bp-activity/bp-activity-functions.php CHANGED
@@ -1663,56 +1663,28 @@ function bp_activity_get( $args = '' ) {
1663
  * );
1664
  */
1665
  'filter' => array()
1666
- ) );
1667
-
1668
- // Attempt to return a cached copy of the first page of sitewide activity.
1669
- if ( ( 1 === (int) $r['page'] ) && empty( $r['max'] ) && ( 'all' === $r['fields'] ) && empty( $r['search_terms'] ) && empty( $r['meta_query'] ) && empty( $r['date_query'] ) && empty( $r['filter_query'] ) && empty( $r['filter'] ) && empty( $r['scope'] )&& empty( $r['exclude'] ) && empty( $r['in'] ) && ( 'DESC' === $r['sort'] ) && empty( $r['exclude'] ) && ( 'ham_only' === $r['spam'] ) ) {
1670
-
1671
- $activity = wp_cache_get( 'bp_activity_sitewide_front', 'bp' );
1672
- if ( false === $activity ) {
1673
-
1674
- $activity = BP_Activity_Activity::get( array(
1675
- 'page' => $r['page'],
1676
- 'per_page' => $r['per_page'],
1677
- 'max' => $r['max'],
1678
- 'fields' => $r['fields'],
1679
- 'sort' => $r['sort'],
1680
- 'search_terms' => $r['search_terms'],
1681
- 'meta_query' => $r['meta_query'],
1682
- 'date_query' => $r['date_query'],
1683
- 'filter_query' => $r['filter_query'],
1684
- 'filter' => $r['filter'],
1685
- 'scope' => $r['scope'],
1686
- 'display_comments' => $r['display_comments'],
1687
- 'show_hidden' => $r['show_hidden'],
1688
- 'spam' => $r['spam'],
1689
- 'update_meta_cache' => $r['update_meta_cache'],
1690
- 'count_total' => $r['count_total'],
1691
- ) );
1692
-
1693
- wp_cache_set( 'bp_activity_sitewide_front', $activity, 'bp' );
1694
- }
1695
 
1696
- } else {
1697
- $activity = BP_Activity_Activity::get( array(
1698
- 'page' => $r['page'],
1699
- 'per_page' => $r['per_page'],
1700
- 'max' => $r['max'],
1701
- 'sort' => $r['sort'],
1702
- 'search_terms' => $r['search_terms'],
1703
- 'meta_query' => $r['meta_query'],
1704
- 'date_query' => $r['date_query'],
1705
- 'filter_query' => $r['filter_query'],
1706
- 'filter' => $r['filter'],
1707
- 'scope' => $r['scope'],
1708
- 'display_comments' => $r['display_comments'],
1709
- 'show_hidden' => $r['show_hidden'],
1710
- 'exclude' => $r['exclude'],
1711
- 'in' => $r['in'],
1712
- 'spam' => $r['spam'],
1713
- 'count_total' => $r['count_total'],
1714
- ) );
1715
- }
1716
 
1717
  /**
1718
  * Filters the requested activity item(s).
@@ -3417,6 +3389,211 @@ function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
3417
  do_action( 'bp_activity_mark_as_ham', $activity, $source );
3418
  }
3419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3420
 
3421
  /** Embeds *******************************************************************/
3422
 
1663
  * );
1664
  */
1665
  'filter' => array()
1666
+ ), 'activity_get' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1667
 
1668
+ $activity = BP_Activity_Activity::get( array(
1669
+ 'page' => $r['page'],
1670
+ 'per_page' => $r['per_page'],
1671
+ 'max' => $r['max'],
1672
+ 'sort' => $r['sort'],
1673
+ 'search_terms' => $r['search_terms'],
1674
+ 'meta_query' => $r['meta_query'],
1675
+ 'date_query' => $r['date_query'],
1676
+ 'filter_query' => $r['filter_query'],
1677
+ 'filter' => $r['filter'],
1678
+ 'scope' => $r['scope'],
1679
+ 'display_comments' => $r['display_comments'],
1680
+ 'show_hidden' => $r['show_hidden'],
1681
+ 'exclude' => $r['exclude'],
1682
+ 'in' => $r['in'],
1683
+ 'spam' => $r['spam'],
1684
+ 'update_meta_cache' => $r['update_meta_cache'],
1685
+ 'count_total' => $r['count_total'],
1686
+ 'fields' => $r['fields'],
1687
+ ) );
1688
 
1689
  /**
1690
  * Filters the requested activity item(s).
3389
  do_action( 'bp_activity_mark_as_ham', $activity, $source );
3390
  }
3391
 
3392
+ /* Emails *********************************************************************/
3393
+
3394
+ /**
3395
+ * Send email and BP notifications when a user is mentioned in an update.
3396
+ *
3397
+ * @since 1.2.0
3398
+ *
3399
+ * @param int $activity_id The ID of the activity update.
3400
+ * @param int $receiver_user_id The ID of the user who is receiving the update.
3401
+ */
3402
+ function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) {
3403
+ $notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' );
3404
+
3405
+ // Don't leave multiple notifications for the same activity item.
3406
+ foreach( $notifications as $notification ) {
3407
+ if ( $activity_id == $notification->item_id ) {
3408
+ return;
3409
+ }
3410
+ }
3411
+
3412
+ $activity = new BP_Activity_Activity( $activity_id );
3413
+ $email_type = 'activity-at-message';
3414
+ $group_name = '';
3415
+ $message_link = bp_activity_get_permalink( $activity_id );
3416
+ $poster_name = bp_core_get_user_displayname( $activity->user_id );
3417
+
3418
+ remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3419
+ remove_filter( 'bp_get_activity_content_body', 'wpautop' );
3420
+ remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3421
+
3422
+ /** This filter is documented in bp-activity/bp-activity-template.php */
3423
+ $content = apply_filters( 'bp_get_activity_content_body', $activity->content );
3424
+
3425
+ add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3426
+ add_filter( 'bp_get_activity_content_body', 'wpautop' );
3427
+ add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3428
+
3429
+ // Now email the user with the contents of the message (if they have enabled email notifications).
3430
+ if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
3431
+ if ( bp_is_active( 'groups' ) && bp_is_group() ) {
3432
+ $email_type = 'groups-at-message';
3433
+ $group_name = bp_get_current_group_name();
3434
+ }
3435
+
3436
+ $unsubscribe_args = array(
3437
+ 'user_id' => $receiver_user_id,
3438
+ 'notification_type' => $email_type,
3439
+ );
3440
+
3441
+ $args = array(
3442
+ 'tokens' => array(
3443
+ 'activity' => $activity,
3444
+ 'usermessage' => wp_strip_all_tags( $content ),
3445
+ 'group.name' => $group_name,
3446
+ 'mentioned.url' => $message_link,
3447
+ 'poster.name' => $poster_name,
3448
+ 'receiver-user.id' => $receiver_user_id,
3449
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
3450
+ ),
3451
+ );
3452
+
3453
+ bp_send_email( $email_type, $receiver_user_id, $args );
3454
+ }
3455
+
3456
+ /**
3457
+ * Fires after the sending of an @mention email notification.
3458
+ *
3459
+ * @since 1.5.0
3460
+ * @since 2.5.0 $subject, $message, $content arguments unset and deprecated.
3461
+ *
3462
+ * @param BP_Activity_Activity $activity Activity Item object.
3463
+ * @param string $deprecated Removed in 2.5; now an empty string.
3464
+ * @param string $deprecated Removed in 2.5; now an empty string.
3465
+ * @param string $deprecated Removed in 2.5; now an empty string.
3466
+ * @param int $receiver_user_id The ID of the user who is receiving the update.
3467
+ */
3468
+ do_action( 'bp_activity_sent_mention_email', $activity, '', '', '', $receiver_user_id );
3469
+ }
3470
+
3471
+ /**
3472
+ * Send email and BP notifications when an activity item receives a comment.
3473
+ *
3474
+ * @since 1.2.0
3475
+ * @since 2.5.0 Updated to use new email APIs.
3476
+ *
3477
+ * @param int $comment_id The comment id.
3478
+ * @param int $commenter_id The ID of the user who posted the comment.
3479
+ * @param array $params {@link bp_activity_new_comment()}.
3480
+ */
3481
+ function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) {
3482
+ $original_activity = new BP_Activity_Activity( $params['activity_id'] );
3483
+ $poster_name = bp_core_get_user_displayname( $commenter_id );
3484
+ $thread_link = bp_activity_get_permalink( $params['activity_id'] );
3485
+
3486
+ remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3487
+ remove_filter( 'bp_get_activity_content_body', 'wpautop' );
3488
+ remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3489
+
3490
+ /** This filter is documented in bp-activity/bp-activity-template.php */
3491
+ $content = apply_filters( 'bp_get_activity_content_body', $params['content'] );
3492
+
3493
+ add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3494
+ add_filter( 'bp_get_activity_content_body', 'wpautop' );
3495
+ add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3496
+
3497
+ if ( $original_activity->user_id != $commenter_id ) {
3498
+
3499
+ // Send an email if the user hasn't opted-out.
3500
+ if ( 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) {
3501
+
3502
+ $unsubscribe_args = array(
3503
+ 'user_id' => $original_activity->user_id,
3504
+ 'notification_type' => 'activity-comment',
3505
+ );
3506
+
3507
+ $args = array(
3508
+ 'tokens' => array(
3509
+ 'comment.id' => $comment_id,
3510
+ 'commenter.id' => $commenter_id,
3511
+ 'usermessage' => wp_strip_all_tags( $content ),
3512
+ 'original_activity.user_id' => $original_activity->user_id,
3513
+ 'poster.name' => $poster_name,
3514
+ 'thread.url' => esc_url( $thread_link ),
3515
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
3516
+ ),
3517
+ );
3518
+
3519
+ bp_send_email( 'activity-comment', $original_activity->user_id, $args );
3520
+ }
3521
+
3522
+ /**
3523
+ * Fires at the point that notifications should be sent for activity comments.
3524
+ *
3525
+ * @since 2.6.0
3526
+ *
3527
+ * @param BP_Activity_Activity $original_activity The original activity.
3528
+ * @param int $comment_id ID for the newly received comment.
3529
+ * @param int $commenter_id ID of the user who made the comment.
3530
+ * @param array $params Arguments used with the original activity comment.
3531
+ */
3532
+ do_action( 'bp_activity_sent_reply_to_update_notification', $original_activity, $comment_id, $commenter_id, $params );
3533
+ }
3534
+
3535
+
3536
+ /*
3537
+ * If this is a reply to another comment, send an email notification to the
3538
+ * author of the immediate parent comment.
3539
+ */
3540
+ if ( empty( $params['parent_id'] ) || ( $params['activity_id'] == $params['parent_id'] ) ) {
3541
+ return;
3542
+ }
3543
+
3544
+ $parent_comment = new BP_Activity_Activity( $params['parent_id'] );
3545
+
3546
+ if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id ) {
3547
+
3548
+ // Send an email if the user hasn't opted-out.
3549
+ if ( 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) {
3550
+
3551
+ $unsubscribe_args = array(
3552
+ 'user_id' => $parent_comment->user_id,
3553
+ 'notification_type' => 'activity-comment-author',
3554
+ );
3555
+
3556
+ $args = array(
3557
+ 'tokens' => array(
3558
+ 'comment.id' => $comment_id,
3559
+ 'commenter.id' => $commenter_id,
3560
+ 'usermessage' => wp_strip_all_tags( $content ),
3561
+ 'parent-comment-user.id' => $parent_comment->user_id,
3562
+ 'poster.name' => $poster_name,
3563
+ 'thread.url' => esc_url( $thread_link ),
3564
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
3565
+ ),
3566
+ );
3567
+
3568
+ bp_send_email( 'activity-comment-author', $parent_comment->user_id, $args );
3569
+ }
3570
+
3571
+ /**
3572
+ * Fires at the point that notifications should be sent for comments on activity replies.
3573
+ *
3574
+ * @since 2.6.0
3575
+ *
3576
+ * @param BP_Activity_Activity $parent_comment The parent activity.
3577
+ * @param int $comment_id ID for the newly received comment.
3578
+ * @param int $commenter_id ID of the user who made the comment.
3579
+ * @param array $params Arguments used with the original activity comment.
3580
+ */
3581
+ do_action( 'bp_activity_sent_reply_to_reply_notification', $parent_comment, $comment_id, $commenter_id, $params );
3582
+ }
3583
+ }
3584
+
3585
+ /**
3586
+ * Helper method to map action arguments to function parameters.
3587
+ *
3588
+ * @since 1.9.0
3589
+ *
3590
+ * @param int $comment_id ID of the comment being notified about.
3591
+ * @param array $params Parameters to use with notification.
3592
+ */
3593
+ function bp_activity_new_comment_notification_helper( $comment_id, $params ) {
3594
+ bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params );
3595
+ }
3596
+ add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 );
3597
 
3598
  /** Embeds *******************************************************************/
3599
 
bp-activity/bp-activity-loader.php CHANGED
@@ -17,7 +17,7 @@ if ( ! buddypress()->do_autoload ) {
17
  }
18
 
19
  /**
20
- * Bootstrap the Activity component.
21
  *
22
  * @since 1.6.0
23
  */
17
  }
18
 
19
  /**
20
+ * Set up the bp-activity component.
21
  *
22
  * @since 1.6.0
23
  */
bp-activity/bp-activity-notifications.php CHANGED
@@ -10,194 +10,6 @@
10
  // Exit if accessed directly.
11
  defined( 'ABSPATH' ) || exit;
12
 
13
- /* Emails *********************************************************************/
14
-
15
- /**
16
- * Send email and BP notifications when a user is mentioned in an update.
17
- *
18
- * @since 1.2.0
19
- *
20
- * @param int $activity_id The ID of the activity update.
21
- * @param int $receiver_user_id The ID of the user who is receiving the update.
22
- */
23
- function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) {
24
- $notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' );
25
-
26
- // Don't leave multiple notifications for the same activity item.
27
- foreach( $notifications as $notification ) {
28
- if ( $activity_id == $notification->item_id ) {
29
- return;
30
- }
31
- }
32
-
33
- $activity = new BP_Activity_Activity( $activity_id );
34
- $email_type = 'activity-at-message';
35
- $group_name = '';
36
- $message_link = bp_activity_get_permalink( $activity_id );
37
- $poster_name = bp_core_get_user_displayname( $activity->user_id );
38
-
39
- remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
40
- remove_filter( 'bp_get_activity_content_body', 'wpautop' );
41
- remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
42
-
43
- /** This filter is documented in bp-activity/bp-activity-template.php */
44
- $content = apply_filters( 'bp_get_activity_content_body', $activity->content );
45
-
46
- add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
47
- add_filter( 'bp_get_activity_content_body', 'wpautop' );
48
- add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
49
-
50
- // Now email the user with the contents of the message (if they have enabled email notifications).
51
- if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
52
- if ( bp_is_active( 'groups' ) && bp_is_group() ) {
53
- $email_type = 'groups-at-message';
54
- $group_name = bp_get_current_group_name();
55
- }
56
-
57
- $args = array(
58
- 'tokens' => array(
59
- 'activity' => $activity,
60
- 'usermessage' => wp_strip_all_tags( $content ),
61
- 'group.name' => $group_name,
62
- 'mentioned.url' => $message_link,
63
- 'poster.name' => $poster_name,
64
- 'receiver-user.id' => $receiver_user_id,
65
- ),
66
- );
67
-
68
- bp_send_email( $email_type, $receiver_user_id, $args );
69
- }
70
-
71
- /**
72
- * Fires after the sending of an @mention email notification.
73
- *
74
- * @since 1.5.0
75
- * @since 2.5.0 $subject, $message, $content arguments unset and deprecated.
76
- *
77
- * @param BP_Activity_Activity $activity Activity Item object.
78
- * @param string $deprecated Removed in 2.5; now an empty string.
79
- * @param string $deprecated Removed in 2.5; now an empty string.
80
- * @param string $deprecated Removed in 2.5; now an empty string.
81
- * @param int $receiver_user_id The ID of the user who is receiving the update.
82
- */
83
- do_action( 'bp_activity_sent_mention_email', $activity, '', '', '', $receiver_user_id );
84
- }
85
-
86
- /**
87
- * Send email and BP notifications when an activity item receives a comment.
88
- *
89
- * @since 1.2.0
90
- * @since 2.5.0 Updated to use new email APIs.
91
- *
92
- * @param int $comment_id The comment id.
93
- * @param int $commenter_id The ID of the user who posted the comment.
94
- * @param array $params {@link bp_activity_new_comment()}.
95
- */
96
- function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) {
97
- $original_activity = new BP_Activity_Activity( $params['activity_id'] );
98
- $poster_name = bp_core_get_user_displayname( $commenter_id );
99
- $thread_link = bp_activity_get_permalink( $params['activity_id'] );
100
-
101
- remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
102
- remove_filter( 'bp_get_activity_content_body', 'wpautop' );
103
- remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
104
-
105
- /** This filter is documented in bp-activity/bp-activity-template.php */
106
- $content = apply_filters( 'bp_get_activity_content_body', $params['content'] );
107
-
108
- add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
109
- add_filter( 'bp_get_activity_content_body', 'wpautop' );
110
- add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
111
-
112
- if ( $original_activity->user_id != $commenter_id ) {
113
-
114
- // Send an email if the user hasn't opted-out.
115
- if ( 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) {
116
- $args = array(
117
- 'tokens' => array(
118
- 'comment.id' => $comment_id,
119
- 'commenter.id' => $commenter_id,
120
- 'usermessage' => wp_strip_all_tags( $content ),
121
- 'original_activity.user_id' => $original_activity->user_id,
122
- 'poster.name' => $poster_name,
123
- 'thread.url' => esc_url( $thread_link ),
124
- ),
125
- );
126
-
127
- bp_send_email( 'activity-comment', $original_activity->user_id, $args );
128
- }
129
-
130
- /**
131
- * Fires at the point that notifications should be sent for activity comments.
132
- *
133
- * @since 2.6.0
134
- *
135
- * @param BP_Activity_Activity $original_activity The original activity.
136
- * @param int $comment_id ID for the newly received comment.
137
- * @param int $commenter_id ID of the user who made the comment.
138
- * @param array $params Arguments used with the original activity comment.
139
- */
140
- do_action( 'bp_activity_sent_reply_to_update_notification', $original_activity, $comment_id, $commenter_id, $params );
141
- }
142
-
143
-
144
- /*
145
- * If this is a reply to another comment, send an email notification to the
146
- * author of the immediate parent comment.
147
- */
148
- if ( empty( $params['parent_id'] ) || ( $params['activity_id'] == $params['parent_id'] ) ) {
149
- return;
150
- }
151
-
152
- $parent_comment = new BP_Activity_Activity( $params['parent_id'] );
153
-
154
- if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id ) {
155
-
156
- // Send an email if the user hasn't opted-out.
157
- if ( 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) {
158
- $args = array(
159
- 'tokens' => array(
160
- 'comment.id' => $comment_id,
161
- 'commenter.id' => $commenter_id,
162
- 'usermessage' => wp_strip_all_tags( $content ),
163
- 'parent-comment-user.id' => $parent_comment->user_id,
164
- 'poster.name' => $poster_name,
165
- 'thread.url' => esc_url( $thread_link ),
166
- ),
167
- );
168
-
169
- bp_send_email( 'activity-comment-author', $parent_comment->user_id, $args );
170
- }
171
-
172
- /**
173
- * Fires at the point that notifications should be sent for comments on activity replies.
174
- *
175
- * @since 2.6.0
176
- *
177
- * @param BP_Activity_Activity $parent_comment The parent activity.
178
- * @param int $comment_id ID for the newly received comment.
179
- * @param int $commenter_id ID of the user who made the comment.
180
- * @param array $params Arguments used with the original activity comment.
181
- */
182
- do_action( 'bp_activity_sent_reply_to_reply_notification', $parent_comment, $comment_id, $commenter_id, $params );
183
- }
184
- }
185
-
186
- /**
187
- * Helper method to map action arguments to function parameters.
188
- *
189
- * @since 1.9.0
190
- *
191
- * @param int $comment_id ID of the comment being notified about.
192
- * @param array $params Parameters to use with notification.
193
- */
194
- function bp_activity_new_comment_notification_helper( $comment_id, $params ) {
195
- bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params );
196
- }
197
- add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 );
198
-
199
- /** Notifications *************************************************************/
200
-
201
  /**
202
  * Format notifications related to activity.
203
  *
@@ -339,8 +151,7 @@ function bp_activity_format_notifications( $action, $item_id, $secondary_item_id
339
  * @param int $receiver_user_id ID of user receiving notification.
340
  */
341
  function bp_activity_at_mention_add_notification( $activity, $subject, $message, $content, $receiver_user_id ) {
342
- if ( bp_is_active( 'notifications' ) ) {
343
- bp_notifications_add_notification( array(
344
  'user_id' => $receiver_user_id,
345
  'item_id' => $activity->id,
346
  'secondary_item_id' => $activity->user_id,
@@ -348,8 +159,7 @@ function bp_activity_at_mention_add_notification( $activity, $subject, $message,
348
  'component_action' => 'new_at_mention',
349
  'date_notified' => bp_core_current_time(),
350
  'is_new' => 1,
351
- ) );
352
- }
353
  }
354
  add_action( 'bp_activity_sent_mention_email', 'bp_activity_at_mention_add_notification', 10, 5 );
355
 
@@ -363,17 +173,15 @@ add_action( 'bp_activity_sent_mention_email', 'bp_activity_at_mention_add_notifi
363
  * @param int $commenter_id ID of the user who made the comment.
364
  */
365
  function bp_activity_update_reply_add_notification( $activity, $comment_id, $commenter_id ) {
366
- if ( bp_is_active( 'notifications' ) ) {
367
- bp_notifications_add_notification( array(
368
- 'user_id' => $activity->user_id,
369
- 'item_id' => $comment_id,
370
- 'secondary_item_id' => $commenter_id,
371
- 'component_name' => buddypress()->activity->id,
372
- 'component_action' => 'update_reply',
373
- 'date_notified' => bp_core_current_time(),
374
- 'is_new' => 1,
375
- ) );
376
- }
377
  }
378
  add_action( 'bp_activity_sent_reply_to_update_notification', 'bp_activity_update_reply_add_notification', 10, 3 );
379
 
@@ -387,17 +195,15 @@ add_action( 'bp_activity_sent_reply_to_update_notification', 'bp_activity_update
387
  * @param int $commenter_id ID of the user who made the comment.
388
  */
389
  function bp_activity_comment_reply_add_notification( $activity_comment, $comment_id, $commenter_id ) {
390
- if ( bp_is_active( 'notifications' ) ) {
391
- bp_notifications_add_notification( array(
392
- 'user_id' => $activity_comment->user_id,
393
- 'item_id' => $comment_id,
394
- 'secondary_item_id' => $commenter_id,
395
- 'component_name' => buddypress()->activity->id,
396
- 'component_action' => 'comment_reply',
397
- 'date_notified' => bp_core_current_time(),
398
- 'is_new' => 1,
399
- ) );
400
- }
401
  }
402
  add_action( 'bp_activity_sent_reply_to_reply_notification', 'bp_activity_comment_reply_add_notification', 10, 3 );
403
 
@@ -410,10 +216,6 @@ add_action( 'bp_activity_sent_reply_to_reply_notification', 'bp_activity_comment
410
  * @param int $user_id The id of the user whose notifications are marked as read.
411
  */
412
  function bp_activity_remove_screen_notifications( $user_id = 0 ) {
413
- if ( ! bp_is_active( 'notifications' ) ) {
414
- return;
415
- }
416
-
417
  // Only mark read if the current user is looking at his own mentions.
418
  if ( empty( $user_id ) || (int) $user_id !== (int) bp_loggedin_user_id() ) {
419
  return;
@@ -431,10 +233,6 @@ add_action( 'bp_activity_clear_new_mentions', 'bp_activity_remove_screen_notific
431
  * @param BP_Activity_Activity $activity Activity object.
432
  */
433
  function bp_activity_remove_screen_notifications_single_activity_permalink( $activity ) {
434
- if ( ! bp_is_active( 'notifications' ) ) {
435
- return;
436
- }
437
-
438
  if ( ! is_user_logged_in() ) {
439
  return;
440
  }
@@ -453,7 +251,7 @@ add_action( 'bp_activity_screen_single_activity_permalink', 'bp_activity_remove_
453
  * @since 2.6.0
454
  */
455
  function bp_activity_remove_screen_notifications_for_non_mentions() {
456
- if ( false === bp_is_active( 'notifications' ) || false === is_singular() || false === is_user_logged_in() || empty( $_GET['nid'] ) ) {
457
  return;
458
  }
459
 
@@ -480,7 +278,7 @@ add_action( 'bp_screens', 'bp_activity_remove_screen_notifications_for_non_menti
480
  function bp_activity_at_mention_delete_notification( $activity_ids_deleted = array() ) {
481
  // Let's delete all without checking if content contains any mentions
482
  // to avoid a query to get the activity.
483
- if ( bp_is_active( 'notifications' ) && ! empty( $activity_ids_deleted ) ) {
484
  foreach ( $activity_ids_deleted as $activity_id ) {
485
  bp_notifications_delete_all_notifications_by_type( $activity_id, buddypress()->activity->id );
486
  }
@@ -502,7 +300,7 @@ add_action( 'bp_activity_deleted_activities', 'bp_activity_at_mention_delete_not
502
  */
503
  function bp_activity_add_notification_for_synced_blog_comment( $activity_id, $post_type_comment, $activity_args, $activity_post_object ) {
504
  // If activity comments are disabled for WP posts, stop now!
505
- if ( bp_disable_blogforum_comments() || empty( $activity_id ) || false === bp_is_active( 'notifications' ) ) {
506
  return;
507
  }
508
 
10
  // Exit if accessed directly.
11
  defined( 'ABSPATH' ) || exit;
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * Format notifications related to activity.
15
  *
151
  * @param int $receiver_user_id ID of user receiving notification.
152
  */
153
  function bp_activity_at_mention_add_notification( $activity, $subject, $message, $content, $receiver_user_id ) {
154
+ bp_notifications_add_notification( array(
 
155
  'user_id' => $receiver_user_id,
156
  'item_id' => $activity->id,
157
  'secondary_item_id' => $activity->user_id,
159
  'component_action' => 'new_at_mention',
160
  'date_notified' => bp_core_current_time(),
161
  'is_new' => 1,
162
+ ) );
 
163
  }
164
  add_action( 'bp_activity_sent_mention_email', 'bp_activity_at_mention_add_notification', 10, 5 );
165
 
173
  * @param int $commenter_id ID of the user who made the comment.
174
  */
175
  function bp_activity_update_reply_add_notification( $activity, $comment_id, $commenter_id ) {
176
+ bp_notifications_add_notification( array(
177
+ 'user_id' => $activity->user_id,
178
+ 'item_id' => $comment_id,
179
+ 'secondary_item_id' => $commenter_id,
180
+ 'component_name' => buddypress()->activity->id,
181
+ 'component_action' => 'update_reply',
182
+ 'date_notified' => bp_core_current_time(),
183
+ 'is_new' => 1,
184
+ ) );
 
 
185
  }
186
  add_action( 'bp_activity_sent_reply_to_update_notification', 'bp_activity_update_reply_add_notification', 10, 3 );
187
 
195
  * @param int $commenter_id ID of the user who made the comment.
196
  */
197
  function bp_activity_comment_reply_add_notification( $activity_comment, $comment_id, $commenter_id ) {
198
+ bp_notifications_add_notification( array(
199
+ 'user_id' => $activity_comment->user_id,
200
+ 'item_id' => $comment_id,
201
+ 'secondary_item_id' => $commenter_id,
202
+ 'component_name' => buddypress()->activity->id,
203
+ 'component_action' => 'comment_reply',
204
+ 'date_notified' => bp_core_current_time(),
205
+ 'is_new' => 1,
206
+ ) );
 
 
207
  }
208
  add_action( 'bp_activity_sent_reply_to_reply_notification', 'bp_activity_comment_reply_add_notification', 10, 3 );
209
 
216
  * @param int $user_id The id of the user whose notifications are marked as read.
217
  */
218
  function bp_activity_remove_screen_notifications( $user_id = 0 ) {
 
 
 
 
219
  // Only mark read if the current user is looking at his own mentions.
220
  if ( empty( $user_id ) || (int) $user_id !== (int) bp_loggedin_user_id() ) {
221
  return;
233
  * @param BP_Activity_Activity $activity Activity object.
234
  */
235
  function bp_activity_remove_screen_notifications_single_activity_permalink( $activity ) {
 
 
 
 
236
  if ( ! is_user_logged_in() ) {
237
  return;
238
  }
251
  * @since 2.6.0
252
  */
253
  function bp_activity_remove_screen_notifications_for_non_mentions() {
254
+ if ( false === is_singular() || false === is_user_logged_in() || empty( $_GET['nid'] ) ) {
255
  return;
256
  }
257
 
278
  function bp_activity_at_mention_delete_notification( $activity_ids_deleted = array() ) {
279
  // Let's delete all without checking if content contains any mentions
280
  // to avoid a query to get the activity.
281
+ if ( ! empty( $activity_ids_deleted ) ) {
282
  foreach ( $activity_ids_deleted as $activity_id ) {
283
  bp_notifications_delete_all_notifications_by_type( $activity_id, buddypress()->activity->id );
284
  }
300
  */
301
  function bp_activity_add_notification_for_synced_blog_comment( $activity_id, $post_type_comment, $activity_args, $activity_post_object ) {
302
  // If activity comments are disabled for WP posts, stop now!
303
+ if ( bp_disable_blogforum_comments() || empty( $activity_id ) ) {
304
  return;
305
  }
306
 
bp-activity/bp-activity-screens.php CHANGED
@@ -236,7 +236,7 @@ function bp_activity_screen_single_activity_permalink() {
236
 
237
  // Check to see if the group is not public, if so, check the
238
  // user has access to see this activity.
239
- if ( $group = groups_get_group( array( 'group_id' => $activity->item_id ) ) ) {
240
 
241
  // Group is not public.
242
  if ( 'public' != $group->status ) {
236
 
237
  // Check to see if the group is not public, if so, check the
238
  // user has access to see this activity.
239
+ if ( $group = groups_get_group( $activity->item_id ) ) {
240
 
241
  // Group is not public.
242
  if ( 'public' != $group->status ) {
bp-activity/bp-activity-template.php CHANGED
@@ -1177,11 +1177,7 @@ function bp_activity_secondary_avatar( $args = '' ) {
1177
 
1178
  // Only if groups is active.
1179
  if ( bp_is_active( 'groups' ) ) {
1180
- $group = groups_get_group( array(
1181
- 'group_id' => $item_id,
1182
- 'populate_extras' => false,
1183
- 'update_meta_cache' => false,
1184
- ) );
1185
  $link = bp_get_group_permalink( $group );
1186
  $name = $group->name;
1187
  }
@@ -1476,6 +1472,13 @@ function bp_insert_activity_meta( $content = '' ) {
1476
  // Get the time since this activity was recorded.
1477
  $date_recorded = bp_core_time_since( $activities_template->activity->date_recorded );
1478
 
 
 
 
 
 
 
 
1479
  /**
1480
  * Filters the activity item time since markup.
1481
  *
@@ -1484,7 +1487,7 @@ function bp_insert_activity_meta( $content = '' ) {
1484
  * @param array $value Array containing the time since markup and the current activity component.
1485
  */
1486
  $time_since = apply_filters_ref_array( 'bp_activity_time_since', array(
1487
- '<span class="time-since">' . $date_recorded . '</span>',
1488
  &$activities_template->activity
1489
  ) );
1490
 
@@ -1533,7 +1536,7 @@ function bp_insert_activity_meta( $content = '' ) {
1533
  *
1534
  * @global object $activities_template {@link BP_Activity_Template}
1535
  *
1536
- * @param object|bool $activity Optional. Falls back on the current item in the loop.
1537
  * @return bool True if can delete, false otherwise.
1538
  */
1539
  function bp_activity_user_can_delete( $activity = false ) {
@@ -2090,7 +2093,7 @@ function bp_activity_comment_delete_link() {
2090
  * activity comment.
2091
  */
2092
  function bp_get_activity_comment_delete_link() {
2093
- $link = wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/delete/' . bp_get_activity_comment_id() . '?cid=' . bp_get_activity_comment_id(), 'bp_activity_delete_link' );
2094
 
2095
  /**
2096
  * Filters the link used for deleting the activity comment currently being displayed.
@@ -3162,8 +3165,6 @@ function bp_send_public_message_button( $args = '' ) {
3162
  * @type string $wrapper_id Default: 'post-mention'.
3163
  * @type string $link_href Default: the public message link for
3164
  * the current member in the loop.
3165
- * @type string $link_title Default: 'Send a public message on your
3166
- * activity stream.'.
3167
  * @type string $link_text Default: 'Public Message'.
3168
  * @type string $link_class Default: 'activity-button mention'.
3169
  * }
@@ -3178,7 +3179,6 @@ function bp_send_public_message_button( $args = '' ) {
3178
  'block_self' => true,
3179
  'wrapper_id' => 'post-mention',
3180
  'link_href' => bp_get_send_public_message_link(),
3181
- 'link_title' => __( 'Send a public message on your activity stream.', 'buddypress' ),
3182
  'link_text' => __( 'Public Message', 'buddypress' ),
3183
  'link_class' => 'activity-button mention'
3184
  ) );
1177
 
1178
  // Only if groups is active.
1179
  if ( bp_is_active( 'groups' ) ) {
1180
+ $group = groups_get_group( $item_id );
 
 
 
 
1181
  $link = bp_get_group_permalink( $group );
1182
  $name = $group->name;
1183
  }
1472
  // Get the time since this activity was recorded.
1473
  $date_recorded = bp_core_time_since( $activities_template->activity->date_recorded );
1474
 
1475
+ // Set up 'time-since' <span>.
1476
+ $time_since = sprintf(
1477
+ '<span class="time-since" data-livestamp="%1$s">%2$s</span>',
1478
+ bp_core_get_iso8601_date( $activities_template->activity->date_recorded ),
1479
+ $date_recorded
1480
+ );
1481
+
1482
  /**
1483
  * Filters the activity item time since markup.
1484
  *
1487
  * @param array $value Array containing the time since markup and the current activity component.
1488
  */
1489
  $time_since = apply_filters_ref_array( 'bp_activity_time_since', array(
1490
+ $time_since,
1491
  &$activities_template->activity
1492
  ) );
1493
 
1536
  *
1537
  * @global object $activities_template {@link BP_Activity_Template}
1538
  *
1539
+ * @param BP_Activity_Activity $activity Optional. Falls back on the current item in the loop.
1540
  * @return bool True if can delete, false otherwise.
1541
  */
1542
  function bp_activity_user_can_delete( $activity = false ) {
2093
  * activity comment.
2094
  */
2095
  function bp_get_activity_comment_delete_link() {
2096
+ $link = wp_nonce_url( bp_get_activity_directory_permalink() . 'delete/' . bp_get_activity_comment_id() . '?cid=' . bp_get_activity_comment_id(), 'bp_activity_delete_link' );
2097
 
2098
  /**
2099
  * Filters the link used for deleting the activity comment currently being displayed.
3165
  * @type string $wrapper_id Default: 'post-mention'.
3166
  * @type string $link_href Default: the public message link for
3167
  * the current member in the loop.
 
 
3168
  * @type string $link_text Default: 'Public Message'.
3169
  * @type string $link_class Default: 'activity-button mention'.
3170
  * }
3179
  'block_self' => true,
3180
  'wrapper_id' => 'post-mention',
3181
  'link_href' => bp_get_send_public_message_link(),
 
3182
  'link_text' => __( 'Public Message', 'buddypress' ),
3183
  'link_class' => 'activity-button mention'
3184
  ) );
bp-activity/classes/class-bp-activity-activity.php CHANGED
@@ -645,7 +645,23 @@ class BP_Activity_Activity {
645
  */
646
  $activity_ids_sql = apply_filters( 'bp_activity_paged_activities_sql', $activity_ids_sql, $r );
647
 
648
- $activity_ids = $wpdb->get_col( $activity_ids_sql );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
 
650
  $retval['has_more_items'] = ! empty( $per_page ) && count( $activity_ids ) > $per_page;
651
 
@@ -702,7 +718,13 @@ class BP_Activity_Activity {
702
  * @param string $sort Sort direction for query.
703
  */
704
  $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort );
705
- $total_activities = $wpdb->get_var( $total_activities_sql );
 
 
 
 
 
 
706
 
707
  if ( !empty( $r['max'] ) ) {
708
  if ( (int) $total_activities > (int) $r['max'] ) {
645
  */
646
  $activity_ids_sql = apply_filters( 'bp_activity_paged_activities_sql', $activity_ids_sql, $r );
647
 
648
+ /*
649
+ * Queries that include 'last_activity' are cached separately,
650
+ * since they are generally much less long-lived.
651
+ */
652
+ if ( preg_match( '/a\.type NOT IN \([^\)]*\'last_activity\'[^\)]*\)/', $activity_ids_sql ) ) {
653
+ $cache_group = 'bp_activity';
654
+ } else {
655
+ $cache_group = 'bp_activity_with_last_activity';
656
+ }
657
+
658
+ $cached = bp_core_get_incremented_cache( $activity_ids_sql, $cache_group );
659
+ if ( false === $cached ) {
660
+ $activity_ids = $wpdb->get_col( $activity_ids_sql );
661
+ bp_core_set_incremented_cache( $activity_ids_sql, $cache_group, $activity_ids );
662
+ } else {
663
+ $activity_ids = $cached;
664
+ }
665
 
666
  $retval['has_more_items'] = ! empty( $per_page ) && count( $activity_ids ) > $per_page;
667
 
718
  * @param string $sort Sort direction for query.
719
  */
720
  $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort );
721
+ $cached = bp_core_get_incremented_cache( $total_activities_sql, $cache_group );
722
+ if ( false === $cached ) {
723
+ $total_activities = $wpdb->get_var( $total_activities_sql );
724
+ bp_core_set_incremented_cache( $total_activities_sql, $cache_group, $total_activities );
725
+ } else {
726
+ $total_activities = $cached;
727
+ }
728
 
729
  if ( !empty( $r['max'] ) ) {
730
  if ( (int) $total_activities > (int) $r['max'] ) {
bp-activity/classes/class-bp-activity-component.php CHANGED
@@ -57,10 +57,14 @@ class BP_Activity_Component extends BP_Component {
57
  'adminbar',
58
  'template',
59
  'functions',
60
- 'notifications',
61
  'cache'
62
  );
63
 
 
 
 
 
 
64
  if ( ! buddypress()->do_autoload ) {
65
  $includes[] = 'classes';
66
  }
@@ -68,7 +72,7 @@ class BP_Activity_Component extends BP_Component {
68
  // Load Akismet support if Akismet is configured.
69
  $akismet_key = bp_get_option( 'wordpress_api_key' );
70
 
71
- /** This filter is documented in bp-activity/bp-activity-actions.php */
72
  if ( defined( 'AKISMET_VERSION' ) && class_exists( 'Akismet' ) && ( ! empty( $akismet_key ) || defined( 'WPCOM_API_KEY' ) ) && apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
73
  $includes[] = 'akismet';
74
  }
@@ -116,13 +120,17 @@ class BP_Activity_Component extends BP_Component {
116
  'activity' => $bp->table_prefix . 'bp_activity_meta',
117
  );
118
 
 
 
 
 
119
  // All globals for activity component.
120
  // Note that global_tables is included in this array.
121
  $args = array(
122
  'slug' => BP_ACTIVITY_SLUG,
123
  'root_slug' => isset( $bp->pages->activity->slug ) ? $bp->pages->activity->slug : BP_ACTIVITY_SLUG,
124
  'has_directory' => true,
125
- 'directory_title' => _x( 'Site-Wide Activity', 'component directory title', 'buddypress' ),
126
  'notification_callback' => 'bp_activity_format_notifications',
127
  'search_string' => __( 'Search Activity...', 'buddypress' ),
128
  'global_tables' => $global_tables,
@@ -361,19 +369,6 @@ class BP_Activity_Component extends BP_Component {
361
  parent::setup_title();
362
  }
363
 
364
- /**
365
- * Set up actions necessary for the component.
366
- *
367
- * @since 1.6.0
368
- */
369
- public function setup_actions() {
370
-
371
- // Spam prevention.
372
- add_action( 'bp_include', 'bp_activity_setup_akismet' );
373
-
374
- parent::setup_actions();
375
- }
376
-
377
  /**
378
  * Setup cache groups.
379
  *
57
  'adminbar',
58
  'template',
59
  'functions',
 
60
  'cache'
61
  );
62
 
63
+ // Notifications support.
64
+ if ( bp_is_active( 'notifications' ) ) {
65
+ $includes[] = 'notifications';
66
+ }
67
+
68
  if ( ! buddypress()->do_autoload ) {
69
  $includes[] = 'classes';
70
  }
72
  // Load Akismet support if Akismet is configured.
73
  $akismet_key = bp_get_option( 'wordpress_api_key' );
74
 
75
+ /** This filter is documented in bp-activity/bp-activity-akismet.php */
76
  if ( defined( 'AKISMET_VERSION' ) && class_exists( 'Akismet' ) && ( ! empty( $akismet_key ) || defined( 'WPCOM_API_KEY' ) ) && apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
77
  $includes[] = 'akismet';
78
  }
120
  'activity' => $bp->table_prefix . 'bp_activity_meta',
121
  );
122
 
123
+ // Fetch the default directory title.
124
+ $default_directory_titles = bp_core_get_directory_page_default_titles();
125
+ $default_directory_title = $default_directory_titles[$this->id];
126
+
127
  // All globals for activity component.
128
  // Note that global_tables is included in this array.
129
  $args = array(
130
  'slug' => BP_ACTIVITY_SLUG,
131
  'root_slug' => isset( $bp->pages->activity->slug ) ? $bp->pages->activity->slug : BP_ACTIVITY_SLUG,
132
  'has_directory' => true,
133
+ 'directory_title' => isset( $bp->pages->activity->title ) ? $bp->pages->activity->title : $default_directory_title,
134
  'notification_callback' => 'bp_activity_format_notifications',
135
  'search_string' => __( 'Search Activity...', 'buddypress' ),
136
  'global_tables' => $global_tables,
369
  parent::setup_title();
370
  }
371
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  /**
373
  * Setup cache groups.
374
  *
bp-activity/classes/class-bp-activity-list-table.php CHANGED
@@ -428,8 +428,26 @@ class BP_Activity_List_Table extends WP_List_Table {
428
  <option value="" <?php selected( ! $selected ); ?>><?php _e( 'View all actions', 'buddypress' ); ?></option>
429
 
430
  <?php foreach ( $activity_actions as $component => $actions ) : ?>
431
-
432
- <optgroup label="<?php echo ucfirst( $component ); ?>">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
 
434
  <?php foreach ( $actions as $action_key => $action_values ) : ?>
435
 
428
  <option value="" <?php selected( ! $selected ); ?>><?php _e( 'View all actions', 'buddypress' ); ?></option>
429
 
430
  <?php foreach ( $activity_actions as $component => $actions ) : ?>
431
+ <?php
432
+ // Older avatar activity items use 'profile' for component. See r4273.
433
+ if ( $component === 'profile' ) {
434
+ $component = 'xprofile';
435
+ }
436
+
437
+ if ( bp_is_active( $component ) ) {
438
+ if ( $component === 'xprofile' ) {
439
+ $component_name = buddypress()->profile->name;
440
+ } else {
441
+ $component_name = buddypress()->$component->name;
442
+ }
443
+
444
+ } else {
445
+ // Prevent warnings by other plugins if a component is disabled but the activity type has been registered.
446
+ $component_name = ucfirst( $component );
447
+ }
448
+ ?>
449
+
450
+ <optgroup label="<?php echo esc_html( $component_name ); ?>">
451
 
452
  <?php foreach ( $actions as $action_key => $action_values ) : ?>
453
 
bp-activity/js/mentions.min.js CHANGED
@@ -1 +1 @@
1
- window.bp=window.bp||{},function(a,b,c){var d,e=[];a.mentions=a.mentions||{},a.mentions.users=window.bp.mentions.users||[],"object"==typeof window.BP_Suggestions&&(a.mentions.users=window.BP_Suggestions.friends||a.mentions.users),b.fn.bp_mentions=function(a){b.isArray(a)&&(a={data:a});var c={delay:200,hide_without_suffix:!0,insert_tpl:"</>${atwho-data-value}</>",limit:10,start_with_space:!1,suffix:"",callbacks:{filter:function(a,b,c){var d,e,f,g=[],h=new RegExp("^"+a+"| "+a,"ig");for(e=0,f=b.length;f>e;e++)d=b[e],d[c].toLowerCase().match(h)&&g.push(d);return g},highlighter:function(a,b){if(!b)return a;var c=new RegExp(">(\\s*|[\\w\\s]*)("+this.at.replace("+","\\+")+"?"+b.replace("+","\\+")+")([\\w ]*)\\s*<","ig");return a.replace(c,function(a,b,c,d){return">"+b+"<strong>"+c+"</strong>"+d+"<"})},before_reposition:function(a){var c,d,e,f,g=b("#atwho-ground-"+this.id+" .atwho-view"),h=b("body"),i=this.$inputor.data("atwho");"undefined"!==i&&"undefined"!==i.iframe&&null!==i.iframe?(c=this.$inputor.caret("offset",{iframe:i.iframe}),e=b(i.iframe).offset(),"undefined"!==e&&(c.left+=e.left,c.top+=e.top)):c=this.$inputor.caret("offset"),c.left>h.width()/2?(g.addClass("right"),f=c.left-a.left-this.view.$el.width()):(g.removeClass("right"),f=c.left-a.left+1),h.width()<=400&&b(document).scrollTop(c.top-6),d=parseInt(this.$inputor.css("line-height").substr(0,this.$inputor.css("line-height").length-2),10),(!d||5>d)&&(d=19),a.top=c.top+d,a.left+=f},inserting_wrapper:function(a,b,c){return""+b+c}}},f={callbacks:{remote_filter:function(a,c){var f=b(this),g={};return d=e[a],"object"==typeof d?void c(d):(f.xhr&&f.xhr.abort(),g={action:"bp_get_suggestions",term:a,type:"members"},b.isNumeric(this.$inputor.data("suggestions-group-id"))&&(g["group-id"]=parseInt(this.$inputor.data("suggestions-group-id"),10)),void(f.xhr=b.getJSON(ajaxurl,g).done(function(d){if(d.success){var f=b.map(d.data,function(a){return a.search=a.search||a.ID+" "+a.name,a});e[a]=f,c(f)}})))}},data:b.map(a.data,function(a){return a.search=a.search||a.ID+" "+a.name,a}),at:"@",search_key:"search",tpl:'<li data-value="@${ID}"><img src="${image}" /><span class="username">@${ID}</span><small>${name}</small></li>'},g=b.extend(!0,{},c,f,a);return b.fn.atwho.call(this,g)},b(document).ready(function(){b(".bp-suggestions, #comments form textarea, .wp-editor-area").bp_mentions(a.mentions.users)}),a.mentions.tinyMCEinit=function(){"undefined"!=typeof window.tinyMCE&&null!==window.tinyMCE.activeEditor&&"undefined"!=typeof window.tinyMCE.activeEditor&&b(window.tinyMCE.activeEditor.contentDocument.activeElement).atwho("setIframe",b(".wp-editor-wrap iframe")[0]).bp_mentions(a.mentions.users)}}(bp,jQuery);
1
+ window.bp=window.bp||{},function(a,b,c){var d,e=[];a.mentions=a.mentions||{},a.mentions.users=window.bp.mentions.users||[],"object"==typeof window.BP_Suggestions&&(a.mentions.users=window.BP_Suggestions.friends||a.mentions.users),b.fn.bp_mentions=function(a){b.isArray(a)&&(a={data:a});var c={delay:200,hide_without_suffix:!0,insert_tpl:"</>${atwho-data-value}</>",limit:10,start_with_space:!1,suffix:"",callbacks:{filter:function(a,b,c){var d,e,f,g=[],h=new RegExp("^"+a+"| "+a,"ig");for(e=0,f=b.length;e<f;e++)d=b[e],d[c].toLowerCase().match(h)&&g.push(d);return g},highlighter:function(a,b){if(!b)return a;var c=new RegExp(">(\\s*|[\\w\\s]*)("+this.at.replace("+","\\+")+"?"+b.replace("+","\\+")+")([\\w ]*)\\s*<","ig");return a.replace(c,function(a,b,c,d){return">"+b+"<strong>"+c+"</strong>"+d+"<"})},before_reposition:function(a){var c,d,e,f,g=b("#atwho-ground-"+this.id+" .atwho-view"),h=b("body"),i=this.$inputor.data("atwho");"undefined"!==i&&"undefined"!==i.iframe&&null!==i.iframe?(c=this.$inputor.caret("offset",{iframe:i.iframe}),e=b(i.iframe).offset(),"undefined"!==e&&(c.left+=e.left,c.top+=e.top)):c=this.$inputor.caret("offset"),c.left>h.width()/2?(g.addClass("right"),f=c.left-a.left-this.view.$el.width()):(g.removeClass("right"),f=c.left-a.left+1),h.width()<=400&&b(document).scrollTop(c.top-6),d=parseInt(this.$inputor.css("line-height").substr(0,this.$inputor.css("line-height").length-2),10),(!d||d<5)&&(d=19),a.top=c.top+d,a.left+=f},inserting_wrapper:function(a,b,c){return""+b+c}}},f={callbacks:{remote_filter:function(a,c){var f=b(this),g={};return d=e[a],"object"==typeof d?void c(d):(f.xhr&&f.xhr.abort(),g={action:"bp_get_suggestions",term:a,type:"members"},b.isNumeric(this.$inputor.data("suggestions-group-id"))&&(g["group-id"]=parseInt(this.$inputor.data("suggestions-group-id"),10)),void(f.xhr=b.getJSON(ajaxurl,g).done(function(d){if(d.success){var f=b.map(d.data,function(a){return a.search=a.search||a.ID+" "+a.name,a});e[a]=f,c(f)}})))}},data:b.map(a.data,function(a){return a.search=a.search||a.ID+" "+a.name,a}),at:"@",search_key:"search",tpl:'<li data-value="@${ID}"><img src="${image}" /><span class="username">@${ID}</span><small>${name}</small></li>'},g=b.extend(!0,{},c,f,a);return b.fn.atwho.call(this,g)},b(document).ready(function(){b(".bp-suggestions, #comments form textarea, .wp-editor-area").bp_mentions(a.mentions.users)}),a.mentions.tinyMCEinit=function(){"undefined"!=typeof window.tinyMCE&&null!==window.tinyMCE.activeEditor&&"undefined"!=typeof window.tinyMCE.activeEditor&&b(window.tinyMCE.activeEditor.contentDocument.activeElement).atwho("setIframe",b(".wp-editor-wrap iframe")[0]).bp_mentions(a.mentions.users)}}(bp,jQuery);
bp-blogs/bp-blogs-activity.php CHANGED
@@ -1291,7 +1291,7 @@ function bp_blogs_can_comment_reply( $retval, $comment ) {
1291
 
1292
  // Check comment depth and disable if depth is too large.
1293
  if ( isset( buddypress()->blogs->thread_depth[$comment->item_id] ) ){
1294
- if ( $comment->mptt_left > buddypress()->blogs->thread_depth[$comment->item_id] ) {
1295
  $retval = false;
1296
  }
1297
  }
1291
 
1292
  // Check comment depth and disable if depth is too large.
1293
  if ( isset( buddypress()->blogs->thread_depth[$comment->item_id] ) ){
1294
+ if ( bp_activity_get_comment_depth() > buddypress()->blogs->thread_depth[$comment->item_id] ) {
1295
  $retval = false;
1296
  }
1297
  }
bp-blogs/bp-blogs-filters.php CHANGED
@@ -121,3 +121,17 @@ function bp_blogs_post_pre_publish( $return = true, $blog_id = 0, $post_id = 0,
121
  }
122
  add_filter( 'bp_activity_post_pre_publish', 'bp_blogs_post_pre_publish', 10, 4 );
123
  add_filter( 'bp_activity_post_pre_comment', 'bp_blogs_post_pre_publish', 10, 4 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  }
122
  add_filter( 'bp_activity_post_pre_publish', 'bp_blogs_post_pre_publish', 10, 4 );
123
  add_filter( 'bp_activity_post_pre_comment', 'bp_blogs_post_pre_publish', 10, 4 );
124
+
125
+ /**
126
+ * Registers our custom thumb size with WP's Site Icon feature.
127
+ *
128
+ * @since 2.7.0
129
+ *
130
+ * @param array $sizes Current array of custom site icon sizes.
131
+ * @return array
132
+ */
133
+ function bp_blogs_register_custom_site_icon_size( $sizes ) {
134
+ $sizes[] = bp_core_avatar_thumb_width();
135
+ return $sizes;
136
+ }
137
+ add_filter( 'site_icon_image_sizes', 'bp_blogs_register_custom_site_icon_size' );
bp-blogs/bp-blogs-functions.php CHANGED
@@ -475,6 +475,26 @@ function bp_blogs_update_option_thread_comments_depth( $oldvalue, $newvalue ) {
475
  }
476
  add_action( 'update_option_thread_comments_depth', 'bp_blogs_update_option_thread_comments_depth', 10, 2 );
477
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  /**
479
  * Deletes the 'url' blogmeta for a site.
480
  *
475
  }
476
  add_action( 'update_option_thread_comments_depth', 'bp_blogs_update_option_thread_comments_depth', 10, 2 );
477
 
478
+ /**
479
+ * Syncs site icon URLs to blogmeta.
480
+ *
481
+ * @since 2.7.0
482
+ *
483
+ * @param int|string $old_value Old value
484
+ * @param int|string $new_value New value
485
+ */
486
+ function bp_blogs_update_option_site_icon( $old_value, $new_value ) {
487
+ if ( 0 === $new_value ) {
488
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_thumb', 0 );
489
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_full', 0 );
490
+ } else {
491
+ // Save site icon URL as blogmeta.
492
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_thumb', get_site_icon_url( bp_core_avatar_thumb_width() ) );
493
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_full', get_site_icon_url( bp_core_avatar_full_width() ) );
494
+ }
495
+ }
496
+ add_action( 'update_option_site_icon', 'bp_blogs_update_option_site_icon', 10, 2 );
497
+
498
  /**
499
  * Deletes the 'url' blogmeta for a site.
500
  *
bp-blogs/bp-blogs-loader.php CHANGED
@@ -20,6 +20,8 @@ if ( ! buddypress()->do_autoload ) {
20
 
21
  /**
22
  * Set up the bp-blogs component.
 
 
23
  */
24
  function bp_setup_blogs() {
25
  buddypress()->blogs = new BP_Blogs_Component();
20
 
21
  /**
22
  * Set up the bp-blogs component.
23
+ *
24
+ * @since 1.5.0
25
  */
26
  function bp_setup_blogs() {
27
  buddypress()->blogs = new BP_Blogs_Component();
bp-blogs/bp-blogs-template.php CHANGED
@@ -220,9 +220,20 @@ function bp_the_blog() {
220
  /**
221
  * Output the blogs pagination count.
222
  *
223
- * @global object $blogs_template {@link BP_Blogs_Template}
224
  */
225
  function bp_blogs_pagination_count() {
 
 
 
 
 
 
 
 
 
 
 
226
  global $blogs_template;
227
 
228
  $start_num = intval( ( $blogs_template->pag_page - 1 ) * $blogs_template->pag_num ) + 1;
@@ -236,7 +247,17 @@ function bp_blogs_pagination_count() {
236
  $message = sprintf( _n( 'Viewing %1$s - %2$s of %3$s site', 'Viewing %1$s - %2$s of %3$s sites', $blogs_template->total_blog_count, 'buddypress' ), $from_num, $to_num, $total );
237
  }
238
 
239
- echo $message;
 
 
 
 
 
 
 
 
 
 
240
  }
241
 
242
  /**
@@ -324,19 +345,77 @@ function bp_blog_avatar( $args = '' ) {
324
  'no_grav' => true,
325
  ) );
326
 
327
- // Fetch the avatar.
328
- $avatar = bp_core_fetch_avatar( array(
329
- 'item_id' => $blogs_template->blog->admin_user_id,
330
- 'title' => $r['title'],
331
- // 'avatar_dir' => 'blog-avatars',
332
- // 'object' => 'blog',
333
- 'type' => $r['type'],
334
- 'alt' => $r['alt'],
335
- 'css_id' => $r['id'],
336
- 'class' => $r['class'],
337
- 'width' => $r['width'],
338
- 'height' => $r['height']
339
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
  /**
342
  * In future BuddyPress versions you will be able to set the avatar for a blog.
@@ -1280,7 +1359,6 @@ function bp_blog_create_button() {
1280
  'id' => 'create_blog',
1281
  'component' => 'blogs',
1282
  'link_text' => __( 'Create a Site', 'buddypress' ),
1283
- 'link_title' => __( 'Create a Site', 'buddypress' ),
1284
  'link_class' => 'blog-create no-ajax',
1285
  'link_href' => trailingslashit( bp_get_blogs_directory_permalink() . 'create' ),
1286
  'wrapper' => false,
@@ -1377,7 +1455,6 @@ function bp_blogs_visit_blog_button( $args = '' ) {
1377
  * @type string $link_href Permalink of the current blog in the loop.
1378
  * @type string $link_class Default: 'blog-button visit'.
1379
  * @type string $link_text Default: 'Visit Site'.
1380
- * @type string $link_title Default: 'Visit Site'.
1381
  * }
1382
  * @return string The HTML for the Visit button.
1383
  */
@@ -1391,7 +1468,6 @@ function bp_blogs_visit_blog_button( $args = '' ) {
1391
  'link_href' => bp_get_blog_permalink(),
1392
  'link_class' => 'blog-button visit',
1393
  'link_text' => __( 'Visit Site', 'buddypress' ),
1394
- 'link_title' => __( 'Visit Site', 'buddypress' ),
1395
  );
1396
 
1397
  $button = wp_parse_args( $args, $defaults );
220
  /**
221
  * Output the blogs pagination count.
222
  *
223
+ * @since 1.0.0
224
  */
225
  function bp_blogs_pagination_count() {
226
+ echo bp_get_blogs_pagination_count();
227
+ }
228
+
229
+ /**
230
+ * Get the blogs pagination count.
231
+ *
232
+ * @since 2.7.0
233
+ *
234
+ * @global object $blogs_template {@link BP_Blogs_Template}
235
+ */
236
+ function bp_get_blogs_pagination_count() {
237
  global $blogs_template;
238
 
239
  $start_num = intval( ( $blogs_template->pag_page - 1 ) * $blogs_template->pag_num ) + 1;
247
  $message = sprintf( _n( 'Viewing %1$s - %2$s of %3$s site', 'Viewing %1$s - %2$s of %3$s sites', $blogs_template->total_blog_count, 'buddypress' ), $from_num, $to_num, $total );
248
  }
249
 
250
+ /**
251
+ * Filters the "Viewing x-y of z blogs" pagination message.
252
+ *
253
+ * @since 2.7.0
254
+ *
255
+ * @param string $message "Viewing x-y of z blogs" text.
256
+ * @param string $from_num Total amount for the low value in the range.
257
+ * @param string $to_num Total amount for the high value in the range.
258
+ * @param string $total Total amount of blogs found.
259
+ */
260
+ return apply_filters( 'bp_get_blogs_pagination_count', $message, $from_num, $to_num, $total );
261
  }
262
 
263
  /**
345
  'no_grav' => true,
346
  ) );
347
 
348
+ // Use site icon if available.
349
+ $avatar = '';
350
+ if ( bp_is_active( 'blogs', 'site-icon' ) && function_exists( 'has_site_icon' ) ) {
351
+ $site_icon = bp_blogs_get_blogmeta( bp_get_blog_id(), "site_icon_url_{$r['type']}" );
352
+
353
+ // Never attempted to fetch site icon before; do it now!
354
+ if ( '' === $site_icon ) {
355
+ switch_to_blog( bp_get_blog_id() );
356
+
357
+ // Fetch the other size first.
358
+ if ( 'full' === $r['type'] ) {
359
+ $size = bp_core_avatar_thumb_width();
360
+ $save_size = 'thumb';
361
+ } else {
362
+ $size = bp_core_avatar_full_width();
363
+ $save_size = 'full';
364
+ }
365
+
366
+ $site_icon = get_site_icon_url( $size );
367
+ // Empty site icons get saved as integer 0.
368
+ if ( empty( $site_icon ) ) {
369
+ $site_icon = 0;
370
+ }
371
+
372
+ // Sync site icon for other size to blogmeta.
373
+ bp_blogs_update_blogmeta( bp_get_blog_id(), "site_icon_url_{$save_size}", $site_icon );
374
+
375
+ // Now, fetch the size we want.
376
+ if ( 0 !== $site_icon ) {
377
+ $size = 'full' === $r['type'] ? bp_core_avatar_full_width() : bp_core_avatar_thumb_width();
378
+ $site_icon = get_site_icon_url( $size );
379
+ }
380
+
381
+ // Sync site icon to blogmeta.
382
+ bp_blogs_update_blogmeta( bp_get_blog_id(), "site_icon_url_{$r['type']}", $site_icon );
383
+
384
+ restore_current_blog();
385
+ }
386
+
387
+ // We have a site icon.
388
+ if ( ! is_numeric( $site_icon ) ) {
389
+ if ( empty( $r['width'] ) && ! isset( $size ) ) {
390
+ $size = 'full' === $r['type'] ? bp_core_avatar_full_width() : bp_core_avatar_thumb_width();
391
+ } else {
392
+ $size = (int) $r['width'];
393
+ }
394
+
395
+ $avatar = sprintf( '<img src="%1$s" class="%2$s" width="%3$s" height="%3$s" alt="%4$s" title="%4$s" />',
396
+ esc_url( $site_icon ),
397
+ esc_attr( "{$r['class']} avatar-{$size}" ),
398
+ esc_attr( $size ),
399
+ sprintf( esc_attr__( 'Site icon for %s', 'buddypress' ), bp_get_blog_name() )
400
+ );
401
+ }
402
+ }
403
+
404
+ // Fallback to user ID avatar.
405
+ if ( '' === $avatar ) {
406
+ $avatar = bp_core_fetch_avatar( array(
407
+ 'item_id' => $blogs_template->blog->admin_user_id,
408
+ 'title' => $r['title'],
409
+ // 'avatar_dir' => 'blog-avatars',
410
+ // 'object' => 'blog',
411
+ 'type' => $r['type'],
412
+ 'alt' => $r['alt'],
413
+ 'css_id' => $r['id'],
414
+ 'class' => $r['class'],
415
+ 'width' => $r['width'],
416
+ 'height' => $r['height']
417
+ ) );
418
+ }
419
 
420
  /**
421
  * In future BuddyPress versions you will be able to set the avatar for a blog.
1359
  'id' => 'create_blog',
1360
  'component' => 'blogs',
1361
  'link_text' => __( 'Create a Site', 'buddypress' ),
 
1362
  'link_class' => 'blog-create no-ajax',
1363
  'link_href' => trailingslashit( bp_get_blogs_directory_permalink() . 'create' ),
1364
  'wrapper' => false,
1455
  * @type string $link_href Permalink of the current blog in the loop.
1456
  * @type string $link_class Default: 'blog-button visit'.
1457
  * @type string $link_text Default: 'Visit Site'.
 
1458
  * }
1459
  * @return string The HTML for the Visit button.
1460
  */
1468
  'link_href' => bp_get_blog_permalink(),
1469
  'link_class' => 'blog-button visit',
1470
  'link_text' => __( 'Visit Site', 'buddypress' ),
 
1471
  );
1472
 
1473
  $button = wp_parse_args( $args, $defaults );
bp-blogs/classes/class-bp-blogs-blog.php CHANGED
@@ -48,7 +48,7 @@ class BP_Blogs_Blog {
48
  */
49
  public function __construct( $id = null ) {
50
  if ( !empty( $id ) ) {
51
- $this->id = $id;
52
  $this->populate();
53
  }
54
  }
@@ -63,8 +63,8 @@ class BP_Blogs_Blog {
63
 
64
  $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->blogs->table_name} WHERE id = %d", $this->id ) );
65
 
66
- $this->user_id = $blog->user_id;
67
- $this->blog_id = $blog->blog_id;
68
  }
69
 
70
  /**
@@ -243,6 +243,12 @@ class BP_Blogs_Blog {
243
 
244
  $paged_blogs = BP_Blogs_Blog::get_blog_extras( $paged_blogs, $blog_ids, $type );
245
 
 
 
 
 
 
 
246
  if ( $update_meta_cache ) {
247
  bp_blogs_update_meta_cache( $blog_ids );
248
  }
@@ -338,8 +344,8 @@ class BP_Blogs_Blog {
338
  $user_blogs = array();
339
  foreach ( (array) $blogs as $blog ) {
340
  $user_blogs[$blog->blog_id] = new stdClass;
341
- $user_blogs[$blog->blog_id]->id = $blog->id;
342
- $user_blogs[$blog->blog_id]->blog_id = $blog->blog_id;
343
  $user_blogs[$blog->blog_id]->siteurl = ( is_ssl() ) ? 'https://' . $blog->domain . $blog->path : 'http://' . $blog->domain . $blog->path;
344
  $user_blogs[$blog->blog_id]->name = $blog->name;
345
  }
@@ -364,7 +370,7 @@ class BP_Blogs_Blog {
364
  if ( !$user_id )
365
  $user_id = bp_displayed_user_id();
366
 
367
- return $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$bp->blogs->table_name} WHERE user_id = %d", $user_id ) );
368
  }
369
 
370
  /**
@@ -379,7 +385,9 @@ class BP_Blogs_Blog {
379
 
380
  $bp = buddypress();
381
 
382
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->blogs->table_name} WHERE blog_id = %d", $blog_id ) );
 
 
383
  }
384
 
385
  /**
@@ -444,7 +452,12 @@ class BP_Blogs_Blog {
444
  $paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND {$search_terms_sql} ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC{$pag_sql}" );
445
  $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND {$search_terms_sql} ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC" );
446
 
447
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
 
 
 
 
 
448
  }
449
 
450
  /**
@@ -472,7 +485,12 @@ class BP_Blogs_Blog {
472
  $paged_blogs = $wpdb->get_results( "SELECT DISTINCT b.blog_id FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql} {$pag_sql}" );
473
  $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql}" );
474
 
475
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
 
 
 
 
 
476
  }
477
 
478
  /**
@@ -509,7 +527,12 @@ class BP_Blogs_Blog {
509
  $paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND {$letter_sql} {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC{$pag_sql}" );
510
  $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND {$letter_sql} {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC" );
511
 
512
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
 
 
 
 
 
513
  }
514
 
515
  /**
48
  */
49
  public function __construct( $id = null ) {
50
  if ( !empty( $id ) ) {
51
+ $this->id = (int) $id;
52
  $this->populate();
53
  }
54
  }
63
 
64
  $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->blogs->table_name} WHERE id = %d", $this->id ) );
65
 
66
+ $this->user_id = (int) $blog->user_id;
67
+ $this->blog_id = (int) $blog->blog_id;
68
  }
69
 
70
  /**
243
 
244
  $paged_blogs = BP_Blogs_Blog::get_blog_extras( $paged_blogs, $blog_ids, $type );
245
 
246
+ // Integer casting.
247
+ foreach ( (array) $paged_blogs as $key => $data ) {
248
+ $paged_blogs[ $key ]->blog_id = (int) $paged_blogs[ $key ]->blog_id;
249
+ $paged_blogs[ $key ]->admin_user_id = (int) $paged_blogs[ $key ]->admin_user_id;
250
+ }
251
+
252
  if ( $update_meta_cache ) {
253
  bp_blogs_update_meta_cache( $blog_ids );
254
  }
344
  $user_blogs = array();
345
  foreach ( (array) $blogs as $blog ) {
346
  $user_blogs[$blog->blog_id] = new stdClass;
347
+ $user_blogs[$blog->blog_id]->id = (int) $blog->id;
348
+ $user_blogs[$blog->blog_id]->blog_id = (int) $blog->blog_id;
349
  $user_blogs[$blog->blog_id]->siteurl = ( is_ssl() ) ? 'https://' . $blog->domain . $blog->path : 'http://' . $blog->domain . $blog->path;
350
  $user_blogs[$blog->blog_id]->name = $blog->name;
351
  }
370
  if ( !$user_id )
371
  $user_id = bp_displayed_user_id();
372
 
373
+ return array_map( 'intval', $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$bp->blogs->table_name} WHERE user_id = %d", $user_id ) ) );
374
  }
375
 
376
  /**
385
 
386
  $bp = buddypress();
387
 
388
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->blogs->table_name} WHERE blog_id = %d", $blog_id ) );
389
+
390
+ return is_numeric( $query ) ? (int) $query : $query;
391
  }
392
 
393
  /**
452
  $paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND {$search_terms_sql} ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC{$pag_sql}" );
453
  $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND {$search_terms_sql} ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC" );
454
 
455
+ // Integer casting.
456
+ foreach ( (array) $paged_blogs as $key => $data ) {
457
+ $paged_blogs[ $key ]->blog_id = (int) $paged_blogs[ $key ]->blog_id;
458
+ }
459
+
460
+ return array( 'blogs' => $paged_blogs, 'total' => (int) $total_blogs );
461
  }
462
 
463
  /**
485
  $paged_blogs = $wpdb->get_results( "SELECT DISTINCT b.blog_id FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql} {$pag_sql}" );
486
  $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql}" );
487
 
488
+ // Integer casting.
489
+ foreach ( (array) $paged_blogs as $key => $data ) {
490
+ $paged_blogs[ $key ]->blog_id = (int) $paged_blogs[ $key ]->blog_id;
491
+ }
492
+
493
+ return array( 'blogs' => $paged_blogs, 'total' => (int) $total_blogs );
494
  }
495
 
496
  /**
527
  $paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND {$letter_sql} {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC{$pag_sql}" );
528
  $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND {$letter_sql} {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC" );
529
 
530
+ // Integer casting.
531
+ foreach ( (array) $paged_blogs as $key => $data ) {
532
+ $paged_blogs[ $key ]->blog_id = (int) $paged_blogs[ $key ]->blog_id;
533
+ }
534
+
535
+ return array( 'blogs' => $paged_blogs, 'total' => (int) $total_blogs );
536
  }
537
 
538
  /**
bp-blogs/classes/class-bp-blogs-component.php CHANGED
@@ -32,6 +32,7 @@ class BP_Blogs_Component extends BP_Component {
32
  array(
33
  'adminbar_myaccount_order' => 30,
34
  'search_query_arg' => 'sites_search',
 
35
  )
36
  );
37
  }
@@ -65,12 +66,16 @@ class BP_Blogs_Component extends BP_Component {
65
  'blog' => $bp->table_prefix . 'bp_user_blogs_blogmeta',
66
  );
67
 
 
 
 
 
68
  // All globals for blogs component.
69
  $args = array(
70
  'slug' => BP_BLOGS_SLUG,
71
  'root_slug' => isset( $bp->pages->blogs->slug ) ? $bp->pages->blogs->slug : BP_BLOGS_SLUG,
72
  'has_directory' => is_multisite(), // Non-multisite installs don't need a top-level Sites directory, since there's only one site.
73
- 'directory_title' => _x( 'Sites', 'component directory title', 'buddypress' ),
74
  'notification_callback' => 'bp_blogs_format_notifications',
75
  'search_string' => __( 'Search sites...', 'buddypress' ),
76
  'autocomplete_all' => defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' ),
32
  array(
33
  'adminbar_myaccount_order' => 30,
34
  'search_query_arg' => 'sites_search',
35
+ 'features' => array( 'site-icon' )
36
  )
37
  );
38
  }
66
  'blog' => $bp->table_prefix . 'bp_user_blogs_blogmeta',
67
  );
68
 
69
+ // Fetch the default directory title.
70
+ $default_directory_titles = bp_core_get_directory_page_default_titles();
71
+ $default_directory_title = $default_directory_titles[$this->id];
72
+
73
  // All globals for blogs component.
74
  $args = array(
75
  'slug' => BP_BLOGS_SLUG,
76
  'root_slug' => isset( $bp->pages->blogs->slug ) ? $bp->pages->blogs->slug : BP_BLOGS_SLUG,
77
  'has_directory' => is_multisite(), // Non-multisite installs don't need a top-level Sites directory, since there's only one site.
78
+ 'directory_title' => isset( $bp->pages->blogs->title ) ? $bp->pages->blogs->title : $default_directory_title,
79
  'notification_callback' => 'bp_blogs_format_notifications',
80
  'search_string' => __( 'Search sites...', 'buddypress' ),
81
  'autocomplete_all' => defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' ),
bp-core/admin/bp-core-admin-components.php CHANGED
@@ -276,6 +276,7 @@ function bp_core_admin_components_settings_handler() {
276
  $bp = buddypress();
277
 
278
  // Save settings and upgrade schema.
 
279
  require_once( $bp->plugin_dir . '/bp-core/admin/bp-core-admin-schema.php' );
280
 
281
  $submitted = stripslashes_deep( $_POST['bp_components'] );
276
  $bp = buddypress();
277
 
278
  // Save settings and upgrade schema.
279
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
280
  require_once( $bp->plugin_dir . '/bp-core/admin/bp-core-admin-schema.php' );
281
 
282
  $submitted = stripslashes_deep( $_POST['bp_components'] );
bp-core/admin/bp-core-admin-functions.php CHANGED
@@ -804,7 +804,29 @@ function bp_admin_do_wp_nav_menu_meta_box() {
804
  </ul>
805
  </div>
806
 
 
 
 
 
 
 
 
 
 
 
 
807
  <p class="button-controls">
 
 
 
 
 
 
 
 
 
 
 
808
  <span class="add-to-menu">
809
  <input type="submit"<?php if ( function_exists( 'wp_nav_menu_disabled_check' ) ) : wp_nav_menu_disabled_check( $nav_menu_selected_id ); endif; ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu', 'buddypress' ); ?>" name="add-custom-menu-item" id="submit-buddypress-menu" />
810
  <span class="spinner"></span>
804
  </ul>
805
  </div>
806
 
807
+ <?php
808
+ $removed_args = array(
809
+ 'action',
810
+ 'customlink-tab',
811
+ 'edit-menu-item',
812
+ 'menu-item',
813
+ 'page-tab',
814
+ '_wpnonce',
815
+ );
816
+ ?>
817
+
818
  <p class="button-controls">
819
+ <span class="list-controls">
820
+ <a href="<?php
821
+ echo esc_url( add_query_arg(
822
+ array(
823
+ $post_type_name . '-tab' => 'all',
824
+ 'selectall' => 1,
825
+ ),
826
+ remove_query_arg( $removed_args )
827
+ ) );
828
+ ?>#buddypress-menu" class="select-all"><?php _e( 'Select All', 'buddypress' ); ?></a>
829
+ </span>
830
  <span class="add-to-menu">
831
  <input type="submit"<?php if ( function_exists( 'wp_nav_menu_disabled_check' ) ) : wp_nav_menu_disabled_check( $nav_menu_selected_id ); endif; ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu', 'buddypress' ); ?>" name="add-custom-menu-item" id="submit-buddypress-menu" />
832
  <span class="spinner"></span>
bp-core/admin/bp-core-admin-schema.php CHANGED
@@ -10,23 +10,6 @@
10
  // Exit if accessed directly.
11
  defined( 'ABSPATH' ) || exit;
12
 
13
- /**
14
- * Get the DB schema to use for BuddyPress components.
15
- *
16
- * @since 1.1.0
17
- *
18
- * @global $wpdb $wpdb
19
- *
20
- * @return string The default database character-set, if set.
21
- */
22
- function bp_core_set_charset() {
23
- global $wpdb;
24
-
25
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
26
-
27
- return !empty( $wpdb->charset ) ? "DEFAULT CHARACTER SET {$wpdb->charset}" : '';
28
- }
29
-
30
  /**
31
  * Main installer.
32
  *
@@ -93,7 +76,7 @@ function bp_core_install( $active_components = false ) {
93
  */
94
  function bp_core_install_notifications() {
95
  $sql = array();
96
- $charset_collate = bp_core_set_charset();
97
  $bp_prefix = bp_core_get_table_prefix();
98
 
99
  $sql[] = "CREATE TABLE {$bp_prefix}bp_notifications (
@@ -134,7 +117,7 @@ function bp_core_install_notifications() {
134
  */
135
  function bp_core_install_activity_streams() {
136
  $sql = array();
137
- $charset_collate = bp_core_set_charset();
138
  $bp_prefix = bp_core_get_table_prefix();
139
 
140
  $sql[] = "CREATE TABLE {$bp_prefix}bp_activity (
@@ -184,7 +167,7 @@ function bp_core_install_activity_streams() {
184
  */
185
  function bp_core_install_friends() {
186
  $sql = array();
187
- $charset_collate = bp_core_set_charset();
188
  $bp_prefix = bp_core_get_table_prefix();
189
 
190
  $sql[] = "CREATE TABLE {$bp_prefix}bp_friends (
@@ -209,7 +192,7 @@ function bp_core_install_friends() {
209
  */
210
  function bp_core_install_groups() {
211
  $sql = array();
212
- $charset_collate = bp_core_set_charset();
213
  $bp_prefix = bp_core_get_table_prefix();
214
 
215
  $sql[] = "CREATE TABLE {$bp_prefix}bp_groups (
@@ -219,10 +202,12 @@ function bp_core_install_groups() {
219
  slug varchar(200) NOT NULL,
220
  description longtext NOT NULL,
221
  status varchar(10) NOT NULL DEFAULT 'public',
 
222
  enable_forum tinyint(1) NOT NULL DEFAULT '1',
223
  date_created datetime NOT NULL,
224
  KEY creator_id (creator_id),
225
- KEY status (status)
 
226
  ) {$charset_collate};";
227
 
228
  $sql[] = "CREATE TABLE {$bp_prefix}bp_groups_members (
@@ -266,7 +251,7 @@ function bp_core_install_groups() {
266
  */
267
  function bp_core_install_private_messaging() {
268
  $sql = array();
269
- $charset_collate = bp_core_set_charset();
270
  $bp_prefix = bp_core_get_table_prefix();
271
 
272
  $sql[] = "CREATE TABLE {$bp_prefix}bp_messages_messages (
@@ -325,7 +310,7 @@ function bp_core_install_extended_profiles() {
325
  global $wpdb;
326
 
327
  $sql = array();
328
- $charset_collate = bp_core_set_charset();
329
  $bp_prefix = bp_core_get_table_prefix();
330
 
331
  // These values should only be updated if they are not already present.
@@ -410,7 +395,7 @@ function bp_core_install_extended_profiles() {
410
  */
411
  function bp_core_install_blog_tracking() {
412
  $sql = array();
413
- $charset_collate = bp_core_set_charset();
414
  $bp_prefix = bp_core_get_table_prefix();
415
 
416
  $sql[] = "CREATE TABLE {$bp_prefix}bp_user_blogs (
@@ -517,7 +502,7 @@ function bp_core_install_emails() {
517
  );
518
 
519
  $emails = bp_email_get_schema();
520
- $descriptions = bp_email_get_type_schema();
521
 
522
  // Add these emails to the database.
523
  foreach ( $emails as $id => $email ) {
@@ -535,6 +520,8 @@ function bp_core_install_emails() {
535
  }
536
  }
537
 
 
 
538
  /**
539
  * Fires after BuddyPress adds the posts for its emails.
540
  *
10
  // Exit if accessed directly.
11
  defined( 'ABSPATH' ) || exit;
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * Main installer.
15
  *
76
  */
77
  function bp_core_install_notifications() {
78
  $sql = array();
79
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
80
  $bp_prefix = bp_core_get_table_prefix();
81
 
82
  $sql[] = "CREATE TABLE {$bp_prefix}bp_notifications (
117
  */
118
  function bp_core_install_activity_streams() {
119
  $sql = array();
120
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
121
  $bp_prefix = bp_core_get_table_prefix();
122
 
123
  $sql[] = "CREATE TABLE {$bp_prefix}bp_activity (
167
  */
168
  function bp_core_install_friends() {
169
  $sql = array();
170
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
171
  $bp_prefix = bp_core_get_table_prefix();
172
 
173
  $sql[] = "CREATE TABLE {$bp_prefix}bp_friends (
192
  */
193
  function bp_core_install_groups() {
194
  $sql = array();
195
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
196
  $bp_prefix = bp_core_get_table_prefix();
197
 
198
  $sql[] = "CREATE TABLE {$bp_prefix}bp_groups (
202
  slug varchar(200) NOT NULL,
203
  description longtext NOT NULL,
204
  status varchar(10) NOT NULL DEFAULT 'public',
205
+ parent_id bigint(20) NOT NULL DEFAULT 0,
206
  enable_forum tinyint(1) NOT NULL DEFAULT '1',
207
  date_created datetime NOT NULL,
208
  KEY creator_id (creator_id),
209
+ KEY status (status),
210
+ KEY parent_id (parent_id)
211
  ) {$charset_collate};";
212
 
213
  $sql[] = "CREATE TABLE {$bp_prefix}bp_groups_members (
251
  */
252
  function bp_core_install_private_messaging() {
253
  $sql = array();
254
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
255
  $bp_prefix = bp_core_get_table_prefix();
256
 
257
  $sql[] = "CREATE TABLE {$bp_prefix}bp_messages_messages (
310
  global $wpdb;
311
 
312
  $sql = array();
313
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
314
  $bp_prefix = bp_core_get_table_prefix();
315
 
316
  // These values should only be updated if they are not already present.
395
  */
396
  function bp_core_install_blog_tracking() {
397
  $sql = array();
398
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
399
  $bp_prefix = bp_core_get_table_prefix();
400
 
401
  $sql[] = "CREATE TABLE {$bp_prefix}bp_user_blogs (
502
  );
503
 
504
  $emails = bp_email_get_schema();
505
+ $descriptions = bp_email_get_type_schema( 'description' );
506
 
507
  // Add these emails to the database.
508
  foreach ( $emails as $id => $email ) {
520
  }
521
  }
522
 
523
+ bp_update_option( 'bp-emails-unsubscribe-salt', base64_encode( wp_generate_password( 64, true, true ) ) );
524
+
525
  /**
526
  * Fires after BuddyPress adds the posts for its emails.
527
  *
bp-core/admin/bp-core-admin-slugs.php CHANGED
@@ -184,12 +184,20 @@ function bp_core_admin_slugs_options() {
184
 
185
  <h3><?php _e( 'Registration', 'buddypress' ); ?></h3>
186
 
187
- <p><?php _e( 'Associate WordPress Pages with the following BuddyPress Registration pages.', 'buddypress' ); ?></p>
 
 
 
 
 
 
 
 
188
 
189
  <table class="form-table">
190
  <tbody>
191
 
192
- <?php foreach ( $static_pages as $name => $label ) : ?>
193
 
194
  <tr valign="top">
195
  <th scope="row">
@@ -218,7 +226,7 @@ function bp_core_admin_slugs_options() {
218
  </td>
219
  </tr>
220
 
221
- <?php endforeach ?>
222
 
223
  <?php
224
 
184
 
185
  <h3><?php _e( 'Registration', 'buddypress' ); ?></h3>
186
 
187
+ <?php if ( bp_get_signup_allowed() ) : ?>
188
+ <p><?php _e( 'Associate WordPress Pages with the following BuddyPress Registration pages.', 'buddypress' ); ?></p>
189
+ <?php else : ?>
190
+ <?php if ( is_multisite() ) : ?>
191
+ <p><?php printf( __( 'Registration is currently disabled. Before associating a page is allowed, please enable registration by selecting either the "User accounts may be registered" or "Both sites and user accounts can be registered" option on <a href="%s">this page</a>.', 'buddypress' ), network_admin_url( 'settings.php' ) ); ?></p>
192
+ <?php else : ?>
193
+ <p><?php printf( __( 'Registration is currently disabled. Before associating a page is allowed, please enable registration by clicking on the "Anyone can register" checkbox on <a href="%s">this page</a>.', 'buddypress' ), admin_url( 'options-general.php' ) ); ?></p>
194
+ <?php endif; ?>
195
+ <?php endif; ?>
196
 
197
  <table class="form-table">
198
  <tbody>
199
 
200
+ <?php if ( bp_get_signup_allowed() ) : foreach ( $static_pages as $name => $label ) : ?>
201
 
202
  <tr valign="top">
203
  <th scope="row">
226
  </td>
227
  </tr>
228
 
229
+ <?php endforeach; endif; ?>
230
 
231
  <?php
232
 
bp-core/admin/bp-core-admin-tools.php CHANGED
@@ -21,42 +21,33 @@ function bp_core_admin_tools() {
21
 
22
  <h1><?php esc_html_e( 'BuddyPress Tools', 'buddypress' ) ?></h1>
23
 
24
- <p>
25
- <?php esc_html_e( 'BuddyPress keeps track of various relationships between members, groups, and activity items. Occasionally these relationships become out of sync, most often after an import, update, or migration.', 'buddypress' ); ?>
26
- <?php esc_html_e( 'Use the tools below to manually recalculate these relationships.', 'buddypress' ); ?>
27
  </p>
28
  <p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Avoid running more than one repair job at a time.', 'buddypress' ); ?></p>
29
 
30
  <form class="settings" method="post" action="">
31
- <table class="form-table">
32
- <tbody>
33
- <tr valign="top">
34
- <th scope="row"><?php esc_html_e( 'Repair tools', 'buddypress' ) ?></th>
35
- <td>
36
- <fieldset>
37
- <legend class="screen-reader-text"><span><?php
38
- /* translators: accessibility text */
39
- esc_html_e( 'Repair', 'buddypress' );
40
- ?></span></legend>
41
-
42
- <?php foreach ( bp_admin_repair_list() as $item ) : ?>
43
-
44
- <label for="<?php echo esc_attr( str_replace( '_', '-', $item[0] ) ); ?>"><input type="checkbox" class="checkbox" name="<?php echo esc_attr( $item[0] ) . '" id="' . esc_attr( str_replace( '_', '-', $item[0] ) ); ?>" value="1" /> <?php echo esc_html( $item[1] ); ?></label><br />
45
-
46
- <?php endforeach; ?>
47
-
48
- </fieldset>
49
- </td>
50
- </tr>
51
- </tbody>
52
- </table>
53
-
54
- <fieldset class="submit">
55
- <input class="button-primary" type="submit" name="bp-tools-submit" value="<?php esc_attr_e( 'Repair Items', 'buddypress' ); ?>" />
56
- <?php wp_nonce_field( 'bp-do-counts' ); ?>
57
  </fieldset>
 
58
  </form>
 
59
  </div>
 
60
  <?php
61
  }
62
 
21
 
22
  <h1><?php esc_html_e( 'BuddyPress Tools', 'buddypress' ) ?></h1>
23
 
24
+ <p><?php esc_html_e( 'BuddyPress keeps track of various relationships between members, groups, and activity items. Occasionally these relationships become out of sync, most often after an import, update, or migration.', 'buddypress' ); ?></p>
25
+ <p><?php esc_html_e( 'Use the tools below to manually recalculate these relationships.', 'buddypress' ); ?>
 
26
  </p>
27
  <p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Avoid running more than one repair job at a time.', 'buddypress' ); ?></p>
28
 
29
  <form class="settings" method="post" action="">
30
+
31
+ <fieldset>
32
+ <legend><?php esc_html_e( 'Repair tools', 'buddypress' ) ?></legend>
33
+
34
+ <div class="checkbox">
35
+ <?php foreach ( bp_admin_repair_list() as $item ) : ?>
36
+ <label for="<?php echo esc_attr( str_replace( '_', '-', $item[0] ) ); ?>"><input type="checkbox" class="checkbox" name="<?php echo esc_attr( $item[0] ) . '" id="' . esc_attr( str_replace( '_', '-', $item[0] ) ); ?>" value="1" /> <?php echo esc_html( $item[1] ); ?></label>
37
+ <?php endforeach; ?>
38
+ </div>
39
+
40
+ <p class="submit">
41
+ <input class="button-primary" type="submit" name="bp-tools-submit" value="<?php esc_attr_e( 'Repair Items', 'buddypress' ); ?>" />
42
+ <?php wp_nonce_field( 'bp-do-counts' ); ?>
43
+ </p>
44
+
 
 
 
 
 
 
 
 
 
 
 
45
  </fieldset>
46
+
47
  </form>
48
+
49
  </div>
50
+
51
  <?php
52
  }
53
 
bp-core/admin/css/common-rtl.css CHANGED
@@ -20,6 +20,7 @@ TABLE OF CONTENTS:
20
  2.3 Tools
21
  3.0 User's Lists
22
  4.0 Emails - Edit page
 
23
  ------------------------------------------------------------------------------*/
24
 
25
  /*------------------------------------------------------------------------------
@@ -491,3 +492,47 @@ body.post-type-bp-email .categorydiv label {
491
  padding-right: 25px;
492
  text-indent: -25px;
493
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  2.3 Tools
21
  3.0 User's Lists
22
  4.0 Emails - Edit page
23
+ 5.0 Tools - BuddyPress
24
  ------------------------------------------------------------------------------*/
25
 
26
  /*------------------------------------------------------------------------------
492
  padding-right: 25px;
493
  text-indent: -25px;
494
  }
495
+
496
+ /*------------------------------------------------------------------------------
497
+ * 5.0 Tools - BuddyPress
498
+ *----------------------------------------------------------------------------*/
499
+ .tools_page_bp-tools .wrap {
500
+ max-width: 950px;
501
+ }
502
+
503
+ .tools_page_bp-tools p {
504
+ line-height: 2;
505
+ }
506
+
507
+ .tools_page_bp-tools fieldset {
508
+ margin: 2em 0 0;
509
+ }
510
+
511
+ .tools_page_bp-tools legend {
512
+ color: #23282d;
513
+ font-size: 1.3em;
514
+ font-weight: 600px;
515
+ margin: 1em 0;
516
+ }
517
+
518
+ .tools_page_bp-tools label {
519
+ clear: right;
520
+ display: block;
521
+ line-height: 1.5em;
522
+ margin: 0 0 1em;
523
+ vertical-align: middle;
524
+ }
525
+
526
+ @media screen and (max-width: 782px) {
527
+ .tools_page_bp-tools p {
528
+ line-height: 1.5;
529
+ }
530
+ .tools_page_bp-tools label {
531
+ margin-bottom: 1em;
532
+ padding-left: 25px;
533
+ text-indent: -33px;
534
+ }
535
+ .tools_page_bp-tools .checkbox {
536
+ padding: 0 30px 0 0;
537
+ }
538
+ }
bp-core/admin/css/common-rtl.min.css CHANGED
@@ -1 +1 @@
1
- .bp-badge{color:#d84800;display:inline-block;font:400 150px/1 dashicons!important}.bp-badge:before{content:"\f448"}.dashboard_page_bp-about .bp-changelog-section::after,.dashboard_page_bp-about .bp-feature::after,.index_page_bp-about .bp-changelog-section::after,.index_page_bp-about .bp-feature::after{content:''}.about-wrap .bp-badge{position:absolute;top:0;left:0}@media only screen and (max-width:500px){.about-wrap .bp-badge{position:relative;margin:10px auto;top:auto;left:auto}}.dashboard_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature{margin-bottom:3em;text-align:center}.dashboard_page_bp-about .bp-headline-feature .headline-title,.dashboard_page_bp-about .bp-headline-feature h3,.index_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature h3{font-size:2.2em;line-height:1.3;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature p{font-size:1.15em;margin:1.15em auto .6em;max-width:80%}.dashboard_page_bp-about .bp-headline-feature .introduction,.index_page_bp-about .bp-headline-feature .introduction{font-weight:600}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{clear:both;margin-bottom:2em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:400;line-height:1.5em;margin:0 0 .6em;text-align:center}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{clear:both;overflow:hidden;margin-bottom:3em;margin-top:3em}.dashboard_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature h4{color:#23282d;display:inline-block;font-size:1.25em;margin-bottom:.6em;margin-top:0;width:47%}.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature p{float:right;font-size:1.15em;width:47%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:left}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:left;float:left;margin-right:2.5%;width:50%;max-width:50%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:right;float:right;margin-right:0;margin-left:2.5%}.dashboard_page_bp-about .bp-changelog-section,.index_page_bp-about .bp-changelog-section{border-top:1px solid #ccc;clear:both;margin-bottom:3em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-changelog-section .changelog-title{color:#23282d;font-size:1.8em;font-weight:300;line-height:1.5;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{float:right;margin-left:4.799999999%;position:relative;width:47.6%}.dashboard_page_bp-about .bp-changelog-section .two-col>div.last-feature,.index_page_bp-about .bp-changelog-section .two-col>div.last-feature{margin-left:0}.dashboard_page_bp-about .bp-changelog,.index_page_bp-about .bp-changelog{margin-bottom:3em}.dashboard_page_bp-about .bp-changelog h4,.index_page_bp-about .bp-changelog h4{font-size:1.15em;margin-top:1.5em;margin-bottom:.6em}.dashboard_page_bp-about .bp-changelog p,.index_page_bp-about .bp-changelog p{font-size:1.05em;margin-top:.75em}.bp-assets{clear:both;margin-bottom:2em;padding-top:3em}@media screen and (max-width:782px){.dashboard_page_bp-about .bp-headline-feature,.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature p{max-width:100%}.dashboard_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature .headline-title{font-size:1.5em;line-height:1.5}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{margin-bottom:0;margin-top:2em}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:300;line-height:1.5}.dashboard_page_bp-about .bp-changelog-section h4,.dashboard_page_bp-about .bp-features-section h4,.index_page_bp-about .bp-changelog-section h4,.index_page_bp-about .bp-features-section h4{font-size:1.25em;line-height:1.25;margin-top:.6em;text-align:right}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{margin-bottom:1em;margin-top:1em}.dashboard_page_bp-about .bp-feature h4,.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature p{width:100%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:none}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:right;float:none;margin-right:0;width:100%;max-width:100%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:right;float:none;margin-left:0}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{margin-top:0;padding-bottom:.5em;width:100%}}#adminmenu #toplevel_page_bp-activity .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_user .wp-menu-image:before{content:"\f452"}#adminmenu #toplevel_page_bp-groups .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_user .wp-menu-image:before{content:"\f456"}#adminmenu #toplevel_page_bp-notifications .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_user .wp-menu-image:before{content:"\f439"}#adminmenu #toplevel_page_bp-messages .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_user .wp-menu-image:before{content:"\f457"}#adminmenu #toplevel_page_bp-friends .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_user .wp-menu-image:before{content:"\f454"}#adminmenu #toplevel_page_bp-settings .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_user .wp-menu-image:before{content:"\f108"}#adminmenu li.toplevel_page_bp-components .wp-menu-image,#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{content:"\f448"}.settings_page_bp-components td.plugin-title span{float:right;width:18px;height:18px;margin-left:5px}.settings_page_bp-components td.plugin-title span:before{font-family:dashicons;font-size:18px}.settings_page_bp-components tr.activity td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.notifications td.plugin-title span:before{content:"\f339"}.settings_page_bp-components tr.xprofile td.plugin-title span:before{content:"\f336"}.settings_page_bp-components tr.settings td.plugin-title span:before{content:"\f108"}.settings_page_bp-components tr.groups td.plugin-title span:before{content:"\f456"}.settings_page_bp-components tr.messages td.plugin-title span:before{content:"\f457"}.settings_page_bp-components tr.forums td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.blogs td.plugin-title span:before{content:"\f120"}.settings_page_bp-components tr.friends td.plugin-title span:before{content:"\f454"}.settings_page_bp-components tr.core td.plugin-title span:before{content:"\f448"}.settings_page_bp-components tr.members td.plugin-title span:before{content:"\f307"}#bp-admin-component-form .wp-list-table.plugins .plugin-title{width:25%}@media screen and (max-width:782px){.settings_page_bp-components td.plugin-title span{margin-top:5px}#bp-admin-component-form .wp-list-table.plugins .plugin-title{display:block;width:auto}#bp-admin-component-form .subsubsub{margin-bottom:0;padding-bottom:35px}}#adminmenu .toplevel_page_network-tools div.wp-menu-image:before{content:""}body.site-users-php th#role,body.users-php th#role,body.users_page_bp-signups th#count_sent{width:10%}body.site-users-php th#email,body.site-users-php th#name,body.users-php th#email,body.users-php th#name,body.users-php th#registered,body.users_page_bp-signups th#date_sent,body.users_page_bp-signups th#email,body.users_page_bp-signups th#name,body.users_page_bp-signups th#registered{width:15%}body.post-type-bp-email th#situation,body.users-php th#blogs,body.users_page_bp-signups th#blogs{width:20%}body.users_page_bp-signups td.count_sent,body.users_page_bp-signups th.column-count_sent{text-align:center}body.post-type-bp-email #excerpt{height:auto}body.post-type-bp-email td.column-situation ul{margin:0}body.post-type-bp-email .categorydiv label{display:block;float:right;padding-right:25px;text-indent:-25px}
1
+ .bp-badge{color:#d84800;display:inline-block;font:400 150px/1 dashicons!important}.bp-badge:before{content:"\f448"}.dashboard_page_bp-about .bp-changelog-section::after,.dashboard_page_bp-about .bp-feature::after,.index_page_bp-about .bp-changelog-section::after,.index_page_bp-about .bp-feature::after{content:''}.about-wrap .bp-badge{position:absolute;top:0;left:0}@media only screen and (max-width:500px){.about-wrap .bp-badge{position:relative;margin:10px auto;top:auto;left:auto}}.dashboard_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature{margin-bottom:3em;text-align:center}.dashboard_page_bp-about .bp-headline-feature .headline-title,.dashboard_page_bp-about .bp-headline-feature h3,.index_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature h3{font-size:2.2em;line-height:1.3;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature p{font-size:1.15em;margin:1.15em auto .6em;max-width:80%}.dashboard_page_bp-about .bp-headline-feature .introduction,.index_page_bp-about .bp-headline-feature .introduction{font-weight:600}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{clear:both;margin-bottom:2em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:400;line-height:1.5em;margin:0 0 .6em;text-align:center}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{clear:both;overflow:hidden;margin-bottom:3em;margin-top:3em}.dashboard_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature h4{color:#23282d;display:inline-block;font-size:1.25em;margin-bottom:.6em;margin-top:0;width:47%}.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature p{float:right;font-size:1.15em;width:47%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:left}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:left;float:left;margin-right:2.5%;width:50%;max-width:50%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:right;float:right;margin-right:0;margin-left:2.5%}.dashboard_page_bp-about .bp-changelog-section,.index_page_bp-about .bp-changelog-section{border-top:1px solid #ccc;clear:both;margin-bottom:3em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-changelog-section .changelog-title{color:#23282d;font-size:1.8em;font-weight:300;line-height:1.5;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{float:right;margin-left:4.799999999%;position:relative;width:47.6%}.dashboard_page_bp-about .bp-changelog-section .two-col>div.last-feature,.index_page_bp-about .bp-changelog-section .two-col>div.last-feature{margin-left:0}.dashboard_page_bp-about .bp-changelog,.index_page_bp-about .bp-changelog{margin-bottom:3em}.dashboard_page_bp-about .bp-changelog h4,.index_page_bp-about .bp-changelog h4{font-size:1.15em;margin-top:1.5em;margin-bottom:.6em}.dashboard_page_bp-about .bp-changelog p,.index_page_bp-about .bp-changelog p{font-size:1.05em;margin-top:.75em}.bp-assets{clear:both;margin-bottom:2em;padding-top:3em}@media screen and (max-width:782px){.dashboard_page_bp-about .bp-headline-feature,.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature p{max-width:100%}.dashboard_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature .headline-title{font-size:1.5em;line-height:1.5}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{margin-bottom:0;margin-top:2em}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:300;line-height:1.5}.dashboard_page_bp-about .bp-changelog-section h4,.dashboard_page_bp-about .bp-features-section h4,.index_page_bp-about .bp-changelog-section h4,.index_page_bp-about .bp-features-section h4{font-size:1.25em;line-height:1.25;margin-top:.6em;text-align:right}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{margin-bottom:1em;margin-top:1em}.dashboard_page_bp-about .bp-feature h4,.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature p{width:100%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:none}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:right;float:none;margin-right:0;width:100%;max-width:100%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:right;float:none;margin-left:0}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{margin-top:0;padding-bottom:.5em;width:100%}}#adminmenu #toplevel_page_bp-activity .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_user .wp-menu-image:before{content:"\f452"}#adminmenu #toplevel_page_bp-groups .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_user .wp-menu-image:before{content:"\f456"}#adminmenu #toplevel_page_bp-notifications .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_user .wp-menu-image:before{content:"\f439"}#adminmenu #toplevel_page_bp-messages .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_user .wp-menu-image:before{content:"\f457"}#adminmenu #toplevel_page_bp-friends .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_user .wp-menu-image:before{content:"\f454"}#adminmenu #toplevel_page_bp-settings .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_user .wp-menu-image:before{content:"\f108"}#adminmenu li.toplevel_page_bp-components .wp-menu-image,#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{content:"\f448"}.settings_page_bp-components td.plugin-title span{float:right;width:18px;height:18px;margin-left:5px}.settings_page_bp-components td.plugin-title span:before{font-family:dashicons;font-size:18px}.settings_page_bp-components tr.activity td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.notifications td.plugin-title span:before{content:"\f339"}.settings_page_bp-components tr.xprofile td.plugin-title span:before{content:"\f336"}.settings_page_bp-components tr.settings td.plugin-title span:before{content:"\f108"}.settings_page_bp-components tr.groups td.plugin-title span:before{content:"\f456"}.settings_page_bp-components tr.messages td.plugin-title span:before{content:"\f457"}.settings_page_bp-components tr.forums td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.blogs td.plugin-title span:before{content:"\f120"}.settings_page_bp-components tr.friends td.plugin-title span:before{content:"\f454"}.settings_page_bp-components tr.core td.plugin-title span:before{content:"\f448"}.settings_page_bp-components tr.members td.plugin-title span:before{content:"\f307"}#bp-admin-component-form .wp-list-table.plugins .plugin-title{width:25%}@media screen and (max-width:782px){.settings_page_bp-components td.plugin-title span{margin-top:5px}#bp-admin-component-form .wp-list-table.plugins .plugin-title{display:block;width:auto}#bp-admin-component-form .subsubsub{margin-bottom:0;padding-bottom:35px}}#adminmenu .toplevel_page_network-tools div.wp-menu-image:before{content:""}body.site-users-php th#role,body.users-php th#role,body.users_page_bp-signups th#count_sent{width:10%}body.site-users-php th#email,body.site-users-php th#name,body.users-php th#email,body.users-php th#name,body.users-php th#registered,body.users_page_bp-signups th#date_sent,body.users_page_bp-signups th#email,body.users_page_bp-signups th#name,body.users_page_bp-signups th#registered{width:15%}body.post-type-bp-email th#situation,body.users-php th#blogs,body.users_page_bp-signups th#blogs{width:20%}body.users_page_bp-signups td.count_sent,body.users_page_bp-signups th.column-count_sent{text-align:center}body.post-type-bp-email #excerpt{height:auto}body.post-type-bp-email td.column-situation ul{margin:0}body.post-type-bp-email .categorydiv label{display:block;float:right;padding-right:25px;text-indent:-25px}.tools_page_bp-tools .wrap{max-width:950px}.tools_page_bp-tools p{line-height:2}.tools_page_bp-tools fieldset{margin:2em 0 0}.tools_page_bp-tools legend{color:#23282d;font-size:1.3em;font-weight:600px;margin:1em 0}.tools_page_bp-tools label{clear:right;display:block;line-height:1.5em;margin:0 0 1em;vertical-align:middle}@media screen and (max-width:782px){.tools_page_bp-tools p{line-height:1.5}.tools_page_bp-tools label{margin-bottom:1em;padding-left:25px;text-indent:-33px}.tools_page_bp-tools .checkbox{padding:0 30px 0 0}}
bp-core/admin/css/common.css CHANGED
@@ -20,6 +20,7 @@ TABLE OF CONTENTS:
20
  2.3 Tools
21
  3.0 User's Lists
22
  4.0 Emails - Edit page
 
23
  ------------------------------------------------------------------------------*/
24
 
25
  /*------------------------------------------------------------------------------
@@ -491,3 +492,47 @@ body.post-type-bp-email .categorydiv label {
491
  padding-left: 25px;
492
  text-indent: -25px;
493
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  2.3 Tools
21
  3.0 User's Lists
22
  4.0 Emails - Edit page
23
+ 5.0 Tools - BuddyPress
24
  ------------------------------------------------------------------------------*/
25
 
26
  /*------------------------------------------------------------------------------
492
  padding-left: 25px;
493
  text-indent: -25px;
494
  }
495
+
496
+ /*------------------------------------------------------------------------------
497
+ * 5.0 Tools - BuddyPress
498
+ *----------------------------------------------------------------------------*/
499
+ .tools_page_bp-tools .wrap {
500
+ max-width: 950px;
501
+ }
502
+
503
+ .tools_page_bp-tools p {
504
+ line-height: 2;
505
+ }
506
+
507
+ .tools_page_bp-tools fieldset {
508
+ margin: 2em 0 0;
509
+ }
510
+
511
+ .tools_page_bp-tools legend {
512
+ color: #23282d;
513
+ font-size: 1.3em;
514
+ font-weight: 600px;
515
+ margin: 1em 0;
516
+ }
517
+
518
+ .tools_page_bp-tools label {
519
+ clear: left;
520
+ display: block;
521
+ line-height: 1.5em;
522
+ margin: 0 0 1em;
523
+ vertical-align: middle;
524
+ }
525
+
526
+ @media screen and (max-width: 782px) {
527
+ .tools_page_bp-tools p {
528
+ line-height: 1.5;
529
+ }
530
+ .tools_page_bp-tools label {
531
+ margin-bottom: 1em;
532
+ padding-right: 25px;
533
+ text-indent: -33px;
534
+ }
535
+ .tools_page_bp-tools .checkbox {
536
+ padding: 0 0 0 30px;
537
+ }
538
+ }
bp-core/admin/css/common.min.css CHANGED
@@ -1 +1 @@
1
- .bp-badge{color:#d84800;display:inline-block;font:400 150px/1 dashicons!important}.bp-badge:before{content:"\f448"}.dashboard_page_bp-about .bp-changelog-section::after,.dashboard_page_bp-about .bp-feature::after,.index_page_bp-about .bp-changelog-section::after,.index_page_bp-about .bp-feature::after{content:''}.about-wrap .bp-badge{position:absolute;top:0;right:0}@media only screen and (max-width:500px){.about-wrap .bp-badge{position:relative;margin:10px auto;top:auto;right:auto}}.dashboard_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature{margin-bottom:3em;text-align:center}.dashboard_page_bp-about .bp-headline-feature .headline-title,.dashboard_page_bp-about .bp-headline-feature h3,.index_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature h3{font-size:2.2em;line-height:1.3;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature p{font-size:1.15em;margin:1.15em auto .6em;max-width:80%}.dashboard_page_bp-about .bp-headline-feature .introduction,.index_page_bp-about .bp-headline-feature .introduction{font-weight:600}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{clear:both;margin-bottom:2em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:400;line-height:1.5em;margin:0 0 .6em;text-align:center}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{clear:both;overflow:hidden;margin-bottom:3em;margin-top:3em}.dashboard_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature h4{color:#23282d;display:inline-block;font-size:1.25em;margin-bottom:.6em;margin-top:0;width:47%}.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature p{float:left;font-size:1.15em;width:47%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:right}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:right;float:right;margin-left:2.5%;width:50%;max-width:50%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:left;float:left;margin-left:0;margin-right:2.5%}.dashboard_page_bp-about .bp-changelog-section,.index_page_bp-about .bp-changelog-section{border-top:1px solid #ccc;clear:both;margin-bottom:3em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-changelog-section .changelog-title{color:#23282d;font-size:1.8em;font-weight:300;line-height:1.5;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{float:left;margin-right:4.799999999%;position:relative;width:47.6%}.dashboard_page_bp-about .bp-changelog-section .two-col>div.last-feature,.index_page_bp-about .bp-changelog-section .two-col>div.last-feature{margin-right:0}.dashboard_page_bp-about .bp-changelog,.index_page_bp-about .bp-changelog{margin-bottom:3em}.dashboard_page_bp-about .bp-changelog h4,.index_page_bp-about .bp-changelog h4{font-size:1.15em;margin-top:1.5em;margin-bottom:.6em}.dashboard_page_bp-about .bp-changelog p,.index_page_bp-about .bp-changelog p{font-size:1.05em;margin-top:.75em}.bp-assets{clear:both;margin-bottom:2em;padding-top:3em}@media screen and (max-width:782px){.dashboard_page_bp-about .bp-headline-feature,.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature p{max-width:100%}.dashboard_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature .headline-title{font-size:1.5em;line-height:1.5}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{margin-bottom:0;margin-top:2em}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:300;line-height:1.5}.dashboard_page_bp-about .bp-changelog-section h4,.dashboard_page_bp-about .bp-features-section h4,.index_page_bp-about .bp-changelog-section h4,.index_page_bp-about .bp-features-section h4{font-size:1.25em;line-height:1.25;margin-top:.6em;text-align:left}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{margin-bottom:1em;margin-top:1em}.dashboard_page_bp-about .bp-feature h4,.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature p{width:100%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:none}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:left;float:none;margin-left:0;width:100%;max-width:100%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:left;float:none;margin-right:0}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{margin-top:0;padding-bottom:.5em;width:100%}}#adminmenu #toplevel_page_bp-activity .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_user .wp-menu-image:before{content:"\f452"}#adminmenu #toplevel_page_bp-groups .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_user .wp-menu-image:before{content:"\f456"}#adminmenu #toplevel_page_bp-notifications .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_user .wp-menu-image:before{content:"\f439"}#adminmenu #toplevel_page_bp-messages .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_user .wp-menu-image:before{content:"\f457"}#adminmenu #toplevel_page_bp-friends .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_user .wp-menu-image:before{content:"\f454"}#adminmenu #toplevel_page_bp-settings .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_user .wp-menu-image:before{content:"\f108"}#adminmenu li.toplevel_page_bp-components .wp-menu-image,#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{content:"\f448"}.settings_page_bp-components td.plugin-title span{float:left;width:18px;height:18px;margin-right:5px}.settings_page_bp-components td.plugin-title span:before{font-family:dashicons;font-size:18px}.settings_page_bp-components tr.activity td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.notifications td.plugin-title span:before{content:"\f339"}.settings_page_bp-components tr.xprofile td.plugin-title span:before{content:"\f336"}.settings_page_bp-components tr.settings td.plugin-title span:before{content:"\f108"}.settings_page_bp-components tr.groups td.plugin-title span:before{content:"\f456"}.settings_page_bp-components tr.messages td.plugin-title span:before{content:"\f457"}.settings_page_bp-components tr.forums td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.blogs td.plugin-title span:before{content:"\f120"}.settings_page_bp-components tr.friends td.plugin-title span:before{content:"\f454"}.settings_page_bp-components tr.core td.plugin-title span:before{content:"\f448"}.settings_page_bp-components tr.members td.plugin-title span:before{content:"\f307"}#bp-admin-component-form .wp-list-table.plugins .plugin-title{width:25%}@media screen and (max-width:782px){.settings_page_bp-components td.plugin-title span{margin-top:5px}#bp-admin-component-form .wp-list-table.plugins .plugin-title{display:block;width:auto}#bp-admin-component-form .subsubsub{margin-bottom:0;padding-bottom:35px}}#adminmenu .toplevel_page_network-tools div.wp-menu-image:before{content:""}body.site-users-php th#role,body.users-php th#role,body.users_page_bp-signups th#count_sent{width:10%}body.site-users-php th#email,body.site-users-php th#name,body.users-php th#email,body.users-php th#name,body.users-php th#registered,body.users_page_bp-signups th#date_sent,body.users_page_bp-signups th#email,body.users_page_bp-signups th#name,body.users_page_bp-signups th#registered{width:15%}body.post-type-bp-email th#situation,body.users-php th#blogs,body.users_page_bp-signups th#blogs{width:20%}body.users_page_bp-signups td.count_sent,body.users_page_bp-signups th.column-count_sent{text-align:center}body.post-type-bp-email #excerpt{height:auto}body.post-type-bp-email td.column-situation ul{margin:0}body.post-type-bp-email .categorydiv label{display:block;float:left;padding-left:25px;text-indent:-25px}
1
+ .bp-badge{color:#d84800;display:inline-block;font:400 150px/1 dashicons!important}.bp-badge:before{content:"\f448"}.dashboard_page_bp-about .bp-changelog-section::after,.dashboard_page_bp-about .bp-feature::after,.index_page_bp-about .bp-changelog-section::after,.index_page_bp-about .bp-feature::after{content:''}.about-wrap .bp-badge{position:absolute;top:0;right:0}@media only screen and (max-width:500px){.about-wrap .bp-badge{position:relative;margin:10px auto;top:auto;right:auto}}.dashboard_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature{margin-bottom:3em;text-align:center}.dashboard_page_bp-about .bp-headline-feature .headline-title,.dashboard_page_bp-about .bp-headline-feature h3,.index_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature h3{font-size:2.2em;line-height:1.3;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature p{font-size:1.15em;margin:1.15em auto .6em;max-width:80%}.dashboard_page_bp-about .bp-headline-feature .introduction,.index_page_bp-about .bp-headline-feature .introduction{font-weight:600}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{clear:both;margin-bottom:2em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:400;line-height:1.5em;margin:0 0 .6em;text-align:center}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{clear:both;overflow:hidden;margin-bottom:3em;margin-top:3em}.dashboard_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature h4{color:#23282d;display:inline-block;font-size:1.25em;margin-bottom:.6em;margin-top:0;width:47%}.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature p{float:left;font-size:1.15em;width:47%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:right}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:right;float:right;margin-left:2.5%;width:50%;max-width:50%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:left;float:left;margin-left:0;margin-right:2.5%}.dashboard_page_bp-about .bp-changelog-section,.index_page_bp-about .bp-changelog-section{border-top:1px solid #ccc;clear:both;margin-bottom:3em;margin-top:2em;padding-bottom:0}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-changelog-section .changelog-title{color:#23282d;font-size:1.8em;font-weight:300;line-height:1.5;margin:1.25em 0 .6em;text-align:center}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{float:left;margin-right:4.799999999%;position:relative;width:47.6%}.dashboard_page_bp-about .bp-changelog-section .two-col>div.last-feature,.index_page_bp-about .bp-changelog-section .two-col>div.last-feature{margin-right:0}.dashboard_page_bp-about .bp-changelog,.index_page_bp-about .bp-changelog{margin-bottom:3em}.dashboard_page_bp-about .bp-changelog h4,.index_page_bp-about .bp-changelog h4{font-size:1.15em;margin-top:1.5em;margin-bottom:.6em}.dashboard_page_bp-about .bp-changelog p,.index_page_bp-about .bp-changelog p{font-size:1.05em;margin-top:.75em}.bp-assets{clear:both;margin-bottom:2em;padding-top:3em}@media screen and (max-width:782px){.dashboard_page_bp-about .bp-headline-feature,.dashboard_page_bp-about .bp-headline-feature p,.index_page_bp-about .bp-headline-feature,.index_page_bp-about .bp-headline-feature p{max-width:100%}.dashboard_page_bp-about .bp-headline-feature .headline-title,.index_page_bp-about .bp-headline-feature .headline-title{font-size:1.5em;line-height:1.5}.dashboard_page_bp-about .bp-features-section,.index_page_bp-about .bp-features-section{margin-bottom:0;margin-top:2em}.dashboard_page_bp-about .bp-changelog-section .changelog-title,.dashboard_page_bp-about .bp-features-section h3,.index_page_bp-about .bp-changelog-section .changelog-title,.index_page_bp-about .bp-features-section h3{font-size:1.8em;font-weight:300;line-height:1.5}.dashboard_page_bp-about .bp-changelog-section h4,.dashboard_page_bp-about .bp-features-section h4,.index_page_bp-about .bp-changelog-section h4,.index_page_bp-about .bp-features-section h4{font-size:1.25em;line-height:1.25;margin-top:.6em;text-align:left}.dashboard_page_bp-about .bp-feature,.index_page_bp-about .bp-feature{margin-bottom:1em;margin-top:1em}.dashboard_page_bp-about .bp-feature h4,.dashboard_page_bp-about .bp-feature p,.index_page_bp-about .bp-feature h4,.index_page_bp-about .bp-feature p{width:100%}.dashboard_page_bp-about .bp-feature.opposite h4,.dashboard_page_bp-about .bp-feature.opposite p,.index_page_bp-about .bp-feature.opposite h4,.index_page_bp-about .bp-feature.opposite p{float:none}.dashboard_page_bp-about .bp-feature img,.index_page_bp-about .bp-feature img{clear:left;float:none;margin-left:0;width:100%;max-width:100%}.dashboard_page_bp-about .bp-feature.opposite img,.index_page_bp-about .bp-feature.opposite img{clear:left;float:none;margin-right:0}.dashboard_page_bp-about .bp-changelog-section .two-col>div,.index_page_bp-about .bp-changelog-section .two-col>div{margin-top:0;padding-bottom:.5em;width:100%}}#adminmenu #toplevel_page_bp-activity .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_user .wp-menu-image:before{content:"\f452"}#adminmenu #toplevel_page_bp-groups .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_user .wp-menu-image:before{content:"\f456"}#adminmenu #toplevel_page_bp-notifications .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_user .wp-menu-image:before{content:"\f439"}#adminmenu #toplevel_page_bp-messages .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_user .wp-menu-image:before{content:"\f457"}#adminmenu #toplevel_page_bp-friends .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_user .wp-menu-image:before{content:"\f454"}#adminmenu #toplevel_page_bp-settings .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_network .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_user .wp-menu-image:before{content:"\f108"}#adminmenu li.toplevel_page_bp-components .wp-menu-image,#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{content:"\f448"}.settings_page_bp-components td.plugin-title span{float:left;width:18px;height:18px;margin-right:5px}.settings_page_bp-components td.plugin-title span:before{font-family:dashicons;font-size:18px}.settings_page_bp-components tr.activity td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.notifications td.plugin-title span:before{content:"\f339"}.settings_page_bp-components tr.xprofile td.plugin-title span:before{content:"\f336"}.settings_page_bp-components tr.settings td.plugin-title span:before{content:"\f108"}.settings_page_bp-components tr.groups td.plugin-title span:before{content:"\f456"}.settings_page_bp-components tr.messages td.plugin-title span:before{content:"\f457"}.settings_page_bp-components tr.forums td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.blogs td.plugin-title span:before{content:"\f120"}.settings_page_bp-components tr.friends td.plugin-title span:before{content:"\f454"}.settings_page_bp-components tr.core td.plugin-title span:before{content:"\f448"}.settings_page_bp-components tr.members td.plugin-title span:before{content:"\f307"}#bp-admin-component-form .wp-list-table.plugins .plugin-title{width:25%}@media screen and (max-width:782px){.settings_page_bp-components td.plugin-title span{margin-top:5px}#bp-admin-component-form .wp-list-table.plugins .plugin-title{display:block;width:auto}#bp-admin-component-form .subsubsub{margin-bottom:0;padding-bottom:35px}}#adminmenu .toplevel_page_network-tools div.wp-menu-image:before{content:""}body.site-users-php th#role,body.users-php th#role,body.users_page_bp-signups th#count_sent{width:10%}body.site-users-php th#email,body.site-users-php th#name,body.users-php th#email,body.users-php th#name,body.users-php th#registered,body.users_page_bp-signups th#date_sent,body.users_page_bp-signups th#email,body.users_page_bp-signups th#name,body.users_page_bp-signups th#registered{width:15%}body.post-type-bp-email th#situation,body.users-php th#blogs,body.users_page_bp-signups th#blogs{width:20%}body.users_page_bp-signups td.count_sent,body.users_page_bp-signups th.column-count_sent{text-align:center}body.post-type-bp-email #excerpt{height:auto}body.post-type-bp-email td.column-situation ul{margin:0}body.post-type-bp-email .categorydiv label{display:block;float:left;padding-left:25px;text-indent:-25px}.tools_page_bp-tools .wrap{max-width:950px}.tools_page_bp-tools p{line-height:2}.tools_page_bp-tools fieldset{margin:2em 0 0}.tools_page_bp-tools legend{color:#23282d;font-size:1.3em;font-weight:600px;margin:1em 0}.tools_page_bp-tools label{clear:left;display:block;line-height:1.5em;margin:0 0 1em;vertical-align:middle}@media screen and (max-width:782px){.tools_page_bp-tools p{line-height:1.5}.tools_page_bp-tools label{margin-bottom:1em;padding-right:25px;text-indent:-33px}.tools_page_bp-tools .checkbox{padding:0 0 0 30px}}
bp-core/admin/images/activity-embeds.png CHANGED
Binary file
bp-core/bp-core-actions.php CHANGED
@@ -29,7 +29,7 @@ defined( 'ABSPATH' ) || exit;
29
  * near the bottom of this file.
30
  *
31
  * v--WordPress Actions v--BuddyPress Sub-actions
32
- */
33
  add_action( 'plugins_loaded', 'bp_loaded', 10 );
34
  add_action( 'init', 'bp_init', 10 );
35
  add_action( 'rest_api_init', 'bp_rest_api_init', 20 ); // After WP core.
@@ -57,7 +57,6 @@ add_action( 'bp_loaded', 'bp_setup_components', 2 );
57
  add_action( 'bp_loaded', 'bp_include', 4 );
58
  add_action( 'bp_loaded', 'bp_setup_cache_groups', 5 );
59
  add_action( 'bp_loaded', 'bp_setup_widgets', 6 );
60
- add_action( 'bp_loaded', 'bp_register_member_types', 8 );
61
  add_action( 'bp_loaded', 'bp_register_theme_packages', 12 );
62
  add_action( 'bp_loaded', 'bp_register_theme_directory', 14 );
63
 
@@ -68,9 +67,9 @@ add_action( 'bp_loaded', 'bp_register_theme_directory', 14 );
68
  * The load order helps to execute code at the correct time.
69
  * v---Load order
70
  */
 
 
71
  add_action( 'bp_init', 'bp_core_set_uri_globals', 2 );
72
- add_action( 'bp_init', 'bp_register_post_types', 3 );
73
- add_action( 'bp_init', 'bp_register_taxonomies', 3 );
74
  add_action( 'bp_init', 'bp_setup_globals', 4 );
75
  add_action( 'bp_init', 'bp_setup_canonical_stack', 5 );
76
  add_action( 'bp_init', 'bp_setup_nav', 6 );
@@ -80,6 +79,11 @@ add_action( 'bp_init', 'bp_add_rewrite_tags', 20 );
80
  add_action( 'bp_init', 'bp_add_rewrite_rules', 30 );
81
  add_action( 'bp_init', 'bp_add_permastructs', 40 );
82
 
 
 
 
 
 
83
  /**
84
  * The bp_template_redirect hook - Attached to 'template_redirect' above.
85
  *
@@ -110,3 +114,6 @@ if ( is_admin() ) {
110
 
111
  // Activation redirect.
112
  add_action( 'bp_activation', 'bp_add_activation_redirect' );
 
 
 
29
  * near the bottom of this file.
30
  *
31
  * v--WordPress Actions v--BuddyPress Sub-actions
32
+ */
33
  add_action( 'plugins_loaded', 'bp_loaded', 10 );
34
  add_action( 'init', 'bp_init', 10 );
35
  add_action( 'rest_api_init', 'bp_rest_api_init', 20 ); // After WP core.
57
  add_action( 'bp_loaded', 'bp_include', 4 );
58
  add_action( 'bp_loaded', 'bp_setup_cache_groups', 5 );
59
  add_action( 'bp_loaded', 'bp_setup_widgets', 6 );
 
60
  add_action( 'bp_loaded', 'bp_register_theme_packages', 12 );
61
  add_action( 'bp_loaded', 'bp_register_theme_directory', 14 );
62
 
67
  * The load order helps to execute code at the correct time.
68
  * v---Load order
69
  */
70
+ add_action( 'bp_init', 'bp_register_post_types', 2 );
71
+ add_action( 'bp_init', 'bp_register_taxonomies', 2 );
72
  add_action( 'bp_init', 'bp_core_set_uri_globals', 2 );
 
 
73
  add_action( 'bp_init', 'bp_setup_globals', 4 );
74
  add_action( 'bp_init', 'bp_setup_canonical_stack', 5 );
75
  add_action( 'bp_init', 'bp_setup_nav', 6 );
79
  add_action( 'bp_init', 'bp_add_rewrite_rules', 30 );
80
  add_action( 'bp_init', 'bp_add_permastructs', 40 );
81
 
82
+ /**
83
+ * The bp_register_taxonomies hook - Attached to 'bp_init' @ priority 2 above.
84
+ */
85
+ add_action( 'bp_register_taxonomies', 'bp_register_member_types' );
86
+
87
  /**
88
  * The bp_template_redirect hook - Attached to 'template_redirect' above.
89
  *
114
 
115
  // Activation redirect.
116
  add_action( 'bp_activation', 'bp_add_activation_redirect' );
117
+
118
+ // Email unsubscribe.
119
+ add_action( 'bp_get_request_unsubscribe', 'bp_email_unsubscribe_handler' );
bp-core/bp-core-admin.php CHANGED
@@ -30,25 +30,33 @@ function bp_admin() {
30
  _n_noop( 'Security Release', 'Security Releases', 'buddypress' );
31
  _n_noop( 'Maintenance and Security Release', 'Maintenance and Security Releases', 'buddypress' );
32
 
33
- /* translators: 1: WordPress version number. */
34
- _n_noop( '<strong>Version %1$s</strong> addressed a security issue.',
35
- '<strong>Version %1$s</strong> addressed some security issues.',
36
- 'buddypress' );
37
-
38
- /* translators: 1: WordPress version number, 2: plural number of bugs. */
39
- _n_noop( '<strong>Version %1$s</strong> addressed %2$s bug.',
40
- '<strong>Version %1$s</strong> addressed %2$s bugs.',
41
- 'buddypress' );
42
-
43
- /* translators: 1: WordPress version number, 2: plural number of bugs. Singular security issue. */
44
- _n_noop( '<strong>Version %1$s</strong> addressed a security issue and fixed %2$s bug.',
45
- '<strong>Version %1$s</strong> addressed a security issue and fixed %2$s bugs.',
46
- 'buddypress' );
47
-
48
- /* translators: 1: WordPress version number, 2: plural number of bugs. More than one security issue. */
49
- _n_noop( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
50
- '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.',
51
- 'buddypress' );
 
 
 
 
 
 
 
 
52
 
53
  __( 'For more information, see <a href="%s">the release notes</a>.', 'buddypress' );
54
  }
30
  _n_noop( 'Security Release', 'Security Releases', 'buddypress' );
31
  _n_noop( 'Maintenance and Security Release', 'Maintenance and Security Releases', 'buddypress' );
32
 
33
+ /* translators: 1: BuddyPress version number. */
34
+ _n_noop(
35
+ '<strong>Version %1$s</strong> addressed a security issue.',
36
+ '<strong>Version %1$s</strong> addressed some security issues.',
37
+ 'buddypress'
38
+ );
39
+
40
+ /* translators: 1: BuddyPress version number, 2: plural number of bugs. */
41
+ _n_noop(
42
+ '<strong>Version %1$s</strong> addressed %2$s bug.',
43
+ '<strong>Version %1$s</strong> addressed %2$s bugs.',
44
+ 'buddypress'
45
+ );
46
+
47
+ /* translators: 1: BuddyPress version number, 2: plural number of bugs. Singular security issue. */
48
+ _n_noop(
49
+ '<strong>Version %1$s</strong> addressed a security issue and fixed %2$s bug.',
50
+ '<strong>Version %1$s</strong> addressed a security issue and fixed %2$s bugs.',
51
+ 'buddypress'
52
+ );
53
+
54
+ /* translators: 1: BuddyPress version number, 2: plural number of bugs. More than one security issue. */
55
+ _n_noop(
56
+ '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
57
+ '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.',
58
+ 'buddypress'
59
+ );
60
 
61
  __( 'For more information, see <a href="%s">the release notes</a>.', 'buddypress' );
62
  }
bp-core/bp-core-attachments.php CHANGED
@@ -52,6 +52,11 @@ function bp_attachments_uploads_dir_get( $data = '' ) {
52
  foreach ( $upload_data as $key => $value ) {
53
  if ( 'basedir' === $key || 'baseurl' === $key ) {
54
  $upload_data[ $key ] = trailingslashit( $value ) . $attachments_dir;
 
 
 
 
 
55
  } else {
56
  unset( $upload_data[ $key ] );
57
  }
@@ -963,7 +968,7 @@ function bp_attachments_get_cover_image_settings( $component = 'xprofile' ) {
963
  * Eg: for the user's profile cover image use:
964
  * add_filter( 'bp_before_xprofile_cover_image_settings_parse_args', 'your_filter', 10, 1 );
965
  *
966
- * @since 2.4.0
967
  *
968
  * @param array $settings The cover image settings
969
  */
@@ -990,7 +995,7 @@ function bp_attachments_get_cover_image_settings( $component = 'xprofile' ) {
990
  }
991
 
992
  /**
993
- * Get cover image Width and Height
994
  *
995
  * @since 2.4.0
996
  *
@@ -1242,10 +1247,7 @@ function bp_attachments_cover_image_ajax_upload() {
1242
 
1243
  if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) {
1244
  $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group );
1245
- $bp->groups->current_group = groups_get_group( array(
1246
- 'group_id' => $bp_params['item_id'],
1247
- 'populate_extras' => false,
1248
- ) );
1249
  }
1250
 
1251
  // Other object's cover image.
52
  foreach ( $upload_data as $key => $value ) {
53
  if ( 'basedir' === $key || 'baseurl' === $key ) {
54
  $upload_data[ $key ] = trailingslashit( $value ) . $attachments_dir;
55
+
56
+ // Fix for HTTPS.
57
+ if ( 'baseurl' === $key && is_ssl() ) {
58
+ $upload_data[ $key ] = str_replace( 'http://', 'https://', $upload_data[ $key ] );
59
+ }
60
  } else {
61
  unset( $upload_data[ $key ] );
62
  }
968
  * Eg: for the user's profile cover image use:
969
  * add_filter( 'bp_before_xprofile_cover_image_settings_parse_args', 'your_filter', 10, 1 );
970
  *
971
+ * @since 2.4.0
972
  *
973
  * @param array $settings The cover image settings
974
  */
995
  }
996
 
997
  /**
998
+ * Get cover image Width and Height.
999
  *
1000
  * @since 2.4.0
1001
  *
1247
 
1248
  if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) {
1249
  $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group );
1250
+ $bp->groups->current_group = groups_get_group( $bp_params['item_id'] );
 
 
 
1251
  }
1252
 
1253
  // Other object's cover image.
bp-core/bp-core-avatars.php CHANGED
@@ -313,7 +313,7 @@ function bp_core_fetch_avatar( $args = '' ) {
313
  break;
314
 
315
  case 'group' :
316
- $item_name = bp_get_group_name( groups_get_group( array( 'group_id' => $params['item_id'] ) ) );
317
  break;
318
 
319
  case 'user' :
@@ -648,7 +648,7 @@ function bp_core_fetch_avatar( $args = '' ) {
648
  * @since 2.6.0
649
  *
650
  * @param string $default_grav The avatar default.
651
- * @param array $params The avatar's data.
652
  */
653
  $default_grav = apply_filters( 'bp_core_avatar_default', $default_grav, $params );
654
 
@@ -726,7 +726,7 @@ function bp_core_delete_existing_avatar( $args = '' ) {
726
  *
727
  * @since 2.5.1
728
  *
729
- * @param bool $value Whether or not to delete the avatar.
730
  * @param array $args {
731
  * Array of function parameters.
732
  *
@@ -805,7 +805,7 @@ function bp_core_delete_existing_avatar( $args = '' ) {
805
  *
806
  * @since 2.3.0
807
  *
808
- * @return string|null A json object containing success data if the avatar was deleted
809
  * error message otherwise.
810
  */
811
  function bp_avatar_ajax_delete() {
@@ -948,8 +948,8 @@ function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) {
948
  *
949
  * @since 2.3.0
950
  *
951
- * @return string|null A json object containing success data if the upload succeeded
952
- * error message otherwise.
953
  */
954
  function bp_avatar_ajax_upload() {
955
  // Bail if not a POST action.
@@ -959,7 +959,7 @@ function bp_avatar_ajax_upload() {
959
 
960
  /**
961
  * Sending the json response will be different if
962
- * the current Plupload runtime is html4
963
  */
964
  $is_html4 = false;
965
  if ( ! empty( $_POST['html4' ] ) ) {
@@ -1005,10 +1005,7 @@ function bp_avatar_ajax_upload() {
1005
 
1006
  if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) {
1007
  $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group );
1008
- $bp->groups->current_group = groups_get_group( array(
1009
- 'group_id' => $bp_params['item_id'],
1010
- 'populate_extras' => false,
1011
- ) );
1012
  }
1013
  } else {
1014
  /**
@@ -1171,16 +1168,6 @@ function bp_avatar_handle_capture( $data = '', $item_id = 0 ) {
1171
  /**
1172
  * Crop an uploaded avatar.
1173
  *
1174
- * $args has the following parameters:
1175
- * object - What component the avatar is for, e.g. "user"
1176
- * avatar_dir The absolute path to the avatar
1177
- * item_id - Item ID
1178
- * original_file - The absolute path to the original avatar file
1179
- * crop_w - Crop width
1180
- * crop_h - Crop height
1181
- * crop_x - The horizontal starting point of the crop
1182
- * crop_y - The vertical starting point of the crop
1183
- *
1184
  * @since 1.1.0
1185
  *
1186
  * @param array|string $args {
@@ -1246,8 +1233,8 @@ function bp_core_avatar_handle_crop( $args = '' ) {
1246
  *
1247
  * @since 2.3.0
1248
  *
1249
- * @return string|null A json object containing success data if the crop/capture succeeded
1250
- * error message otherwise.
1251
  */
1252
  function bp_avatar_ajax_set() {
1253
  // Bail if not a POST action.
@@ -1511,6 +1498,8 @@ function bp_core_check_avatar_size( $file ) {
1511
  * Get allowed avatar types.
1512
  *
1513
  * @since 2.3.0
 
 
1514
  */
1515
  function bp_core_get_allowed_avatar_types() {
1516
  $allowed_types = bp_attachments_get_allowed_types( 'avatar' );
@@ -1537,6 +1526,8 @@ function bp_core_get_allowed_avatar_types() {
1537
  * Get allowed avatar mime types.
1538
  *
1539
  * @since 2.3.0
 
 
1540
  */
1541
  function bp_core_get_allowed_avatar_mimes() {
1542
  $allowed_types = bp_core_get_allowed_avatar_types();
@@ -1943,7 +1934,7 @@ function bp_core_avatar_default_thumb( $type = 'gravatar', $params = array() ) {
1943
  * parameter of the WordPress main query to this posted var. To avoid
1944
  * notices, we need to make sure this 'week' query var is reset to 0.
1945
  *
1946
- * @since 2.2.0
1947
  *
1948
  * @param WP_Query|null $posts_query The main query object.
1949
  */
@@ -1977,7 +1968,7 @@ add_action( 'bp_parse_query', 'bp_core_avatar_reset_query', 10, 1 );
1977
  /**
1978
  * Checks whether Avatar UI should be loaded.
1979
  *
1980
- * @since 2.3.0
1981
  *
1982
  * @return bool True if Avatar UI should load, false otherwise.
1983
  */
@@ -2009,7 +2000,7 @@ function bp_avatar_is_front_edit() {
2009
  * - Load the avatar UI for a component that is !groups or !user (return true regarding your conditions)
2010
  * - Completely disable the avatar UI introduced in 2.3 (eg: __return_false())
2011
  *
2012
- * @since 2.3.0
2013
  *
2014
  * @param bool $retval Whether or not to load the Avatar UI.
2015
  */
@@ -2019,7 +2010,7 @@ function bp_avatar_is_front_edit() {
2019
  /**
2020
  * Checks whether the Webcam Avatar UI part should be loaded.
2021
  *
2022
- * @since 2.3.0
2023
  *
2024
  * @global $is_safari
2025
  * @global $is_IE
@@ -2040,7 +2031,7 @@ function bp_avatar_use_webcam() {
2040
  /**
2041
  * Bail when the browser does not support getUserMedia.
2042
  *
2043
- * @see http://caniuse.com/#feat=stream
2044
  */
2045
  if ( $is_safari || $is_IE || ( $is_chrome && ! is_ssl() ) ) {
2046
  return false;
@@ -2060,7 +2051,7 @@ function bp_avatar_use_webcam() {
2060
  /**
2061
  * Template function to load the Avatar UI javascript templates.
2062
  *
2063
- * @since 2.3.0
2064
  */
2065
  function bp_avatar_get_templates() {
2066
  if ( ! bp_avatar_is_front_edit() ) {
@@ -2076,7 +2067,7 @@ function bp_avatar_get_templates() {
2076
  * If the "avatar templates" are not including the new template tag, this will
2077
  * help users to get the avatar UI.
2078
  *
2079
- * @since 2.3.0
2080
  */
2081
  function bp_avatar_template_check() {
2082
  if ( ! bp_avatar_is_front_edit() ) {
313
  break;
314
 
315
  case 'group' :
316
+ $item_name = bp_get_group_name( groups_get_group( $params['item_id'] ) );
317
  break;
318
 
319
  case 'user' :
648
  * @since 2.6.0
649
  *
650
  * @param string $default_grav The avatar default.
651
+ * @param array $params The avatar's data.
652
  */
653
  $default_grav = apply_filters( 'bp_core_avatar_default', $default_grav, $params );
654
 
726
  *
727
  * @since 2.5.1
728
  *
729
+ * @param bool $value Whether or not to delete the avatar.
730
  * @param array $args {
731
  * Array of function parameters.
732
  *
805
  *
806
  * @since 2.3.0
807
  *
808
+ * @return string|null A JSON object containing success data if the avatar was deleted,
809
  * error message otherwise.
810
  */
811
  function bp_avatar_ajax_delete() {
948
  *
949
  * @since 2.3.0
950
  *
951
+ * @return string|null A JSON object containing success data if the upload succeeded
952
+ * error message otherwise.
953
  */
954
  function bp_avatar_ajax_upload() {
955
  // Bail if not a POST action.
959
 
960
  /**
961
  * Sending the json response will be different if
962
+ * the current Plupload runtime is html4.
963
  */
964
  $is_html4 = false;
965
  if ( ! empty( $_POST['html4' ] ) ) {
1005
 
1006
  if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) {
1007
  $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group );
1008
+ $bp->groups->current_group = groups_get_group( $bp_params['item_id'] );
 
 
 
1009
  }
1010
  } else {
1011
  /**
1168
  /**
1169
  * Crop an uploaded avatar.
1170
  *
 
 
 
 
 
 
 
 
 
 
1171
  * @since 1.1.0
1172
  *
1173
  * @param array|string $args {
1233
  *
1234
  * @since 2.3.0
1235
  *
1236
+ * @return string|null A JSON object containing success data if the crop/capture succeeded
1237
+ * error message otherwise.
1238
  */
1239
  function bp_avatar_ajax_set() {
1240
  // Bail if not a POST action.
1498
  * Get allowed avatar types.
1499
  *
1500
  * @since 2.3.0
1501
+ *
1502
+ * @return array
1503
  */
1504
  function bp_core_get_allowed_avatar_types() {
1505
  $allowed_types = bp_attachments_get_allowed_types( 'avatar' );
1526
  * Get allowed avatar mime types.
1527
  *
1528
  * @since 2.3.0
1529
+ *
1530
+ * @return array
1531
  */
1532
  function bp_core_get_allowed_avatar_mimes() {
1533
  $allowed_types = bp_core_get_allowed_avatar_types();
1934
  * parameter of the WordPress main query to this posted var. To avoid
1935
  * notices, we need to make sure this 'week' query var is reset to 0.
1936
  *
1937
+ * @since 2.2.0
1938
  *
1939
  * @param WP_Query|null $posts_query The main query object.
1940
  */
1968
  /**
1969
  * Checks whether Avatar UI should be loaded.
1970
  *
1971
+ * @since 2.3.0
1972
  *
1973
  * @return bool True if Avatar UI should load, false otherwise.
1974
  */
2000
  * - Load the avatar UI for a component that is !groups or !user (return true regarding your conditions)
2001
  * - Completely disable the avatar UI introduced in 2.3 (eg: __return_false())
2002
  *
2003
+ * @since 2.3.0
2004
  *
2005
  * @param bool $retval Whether or not to load the Avatar UI.
2006
  */
2010
  /**
2011
  * Checks whether the Webcam Avatar UI part should be loaded.
2012
  *
2013
+ * @since 2.3.0
2014
  *
2015
  * @global $is_safari
2016
  * @global $is_IE
2031
  /**
2032
  * Bail when the browser does not support getUserMedia.
2033
  *
2034
+ * @see http://caniuse.com/#feat=stream
2035
  */
2036
  if ( $is_safari || $is_IE || ( $is_chrome && ! is_ssl() ) ) {
2037
  return false;
2051
  /**
2052
  * Template function to load the Avatar UI javascript templates.
2053
  *
2054
+ * @since 2.3.0
2055
  */
2056
  function bp_avatar_get_templates() {
2057
  if ( ! bp_avatar_is_front_edit() ) {
2067
  * If the "avatar templates" are not including the new template tag, this will
2068
  * help users to get the avatar UI.
2069
  *
2070
+ * @since 2.3.0
2071
  */
2072
  function bp_avatar_template_check() {
2073
  if ( ! bp_avatar_is_front_edit() ) {
bp-core/bp-core-buddybar.php CHANGED
@@ -33,7 +33,7 @@ defined( 'ABSPATH' ) || exit;
33
  * @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav
34
  * item is clicked.
35
  * }
36
- * @param string $component The component the navigation is attached to. Defaults to 'members'.
37
  * @return bool|null Returns false on failure.
38
  */
39
  function bp_core_new_nav_item( $args, $component = 'members' ) {
@@ -107,7 +107,7 @@ function bp_core_new_nav_item( $args, $component = 'members' ) {
107
  * @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav
108
  * item is clicked.
109
  * }
110
- * @param string $component Optional. Component that the nav belongs to.
111
  * @return bool|BP_Nav_Item Returns false on failure, new nav item on success.
112
  */
113
  function bp_core_create_nav_link( $args = '', $component = 'members' ) {
@@ -214,9 +214,9 @@ function bp_core_register_nav_screen_function( $args = '' ) {
214
  }
215
 
216
  /**
217
- * If this is for site admins only and the user is not one,
218
- * don't register this screen function.
219
- */
220
  if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) {
221
  return false;
222
  }
@@ -321,7 +321,7 @@ function bp_core_new_nav_default( $args = '' ) {
321
  }
322
  }
323
 
324
- // Edit the screen function for the parent nav
325
  $bp->members->nav->edit_nav( array(
326
  'screen_function' => &$r['screen_function'],
327
  'default_subnav_slug' => $r['subnav_slug'],
@@ -394,7 +394,7 @@ function bp_core_new_nav_default( $args = '' ) {
394
  * @type bool $show_in_admin_bar Optional. Whether the nav item should be added into the group's "Edit"
395
  * Admin Bar menu for group admins. Default: false.
396
  * }
397
- * @param string $component The component the navigation is attached to. Defaults to 'members'.
398
  * @return bool|null Returns false on failure.
399
  */
400
  function bp_core_new_subnav_item( $args, $component = null ) {
@@ -405,7 +405,7 @@ function bp_core_new_subnav_item( $args, $component = null ) {
405
  * Assume that this item is intended to belong to the current group if:
406
  * a) the 'parent_slug' is the same as the slug of the current group, or
407
  * b) the 'parent_slug' starts with the slug of the current group, and the members nav doesn't have
408
- * a primary item with that slug
409
  */
410
  $group_slug = bp_get_current_group_slug();
411
  if (
@@ -474,8 +474,8 @@ function bp_core_new_subnav_item( $args, $component = null ) {
474
  * the group's "Edit" Admin Bar menu for group admins.
475
  * Default: false.
476
  * }
477
- * @param string $component The component the navigation is attached to. Defaults to 'members'.
478
- * @return bool|BP_Nav_Item Returns false on failure, new nav item on success.
479
  */
480
  function bp_core_create_subnav_link( $args = '', $component = 'members' ) {
481
  $bp = buddypress();
@@ -570,7 +570,7 @@ function bp_core_create_subnav_link( $args = '', $component = 'members' ) {
570
  * the group's "Edit" Admin Bar menu for group admins.
571
  * Default: false.
572
  * }
573
- * @param string $component The component the navigation is attached to. Defaults to 'members'.
574
  * @return bool|null Returns false on failure.
575
  */
576
  function bp_core_register_subnav_screen_function( $args = '', $component = 'members' ) {
33
  * @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav
34
  * item is clicked.
35
  * }
36
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
37
  * @return bool|null Returns false on failure.
38
  */
39
  function bp_core_new_nav_item( $args, $component = 'members' ) {
107
  * @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav
108
  * item is clicked.
109
  * }
110
+ * @param string $component Optional. Component that the nav belongs to.
111
  * @return bool|BP_Nav_Item Returns false on failure, new nav item on success.
112
  */
113
  function bp_core_create_nav_link( $args = '', $component = 'members' ) {
214
  }
215
 
216
  /**
217
+ * If this is for site admins only and the user is not one,
218
+ * don't register this screen function.
219
+ */
220
  if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) {
221
  return false;
222
  }
321
  }
322
  }
323
 
324
+ // Edit the screen function for the parent nav.
325
  $bp->members->nav->edit_nav( array(
326
  'screen_function' => &$r['screen_function'],
327
  'default_subnav_slug' => $r['subnav_slug'],
394
  * @type bool $show_in_admin_bar Optional. Whether the nav item should be added into the group's "Edit"
395
  * Admin Bar menu for group admins. Default: false.
396
  * }
397
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
398
  * @return bool|null Returns false on failure.
399
  */
400
  function bp_core_new_subnav_item( $args, $component = null ) {
405
  * Assume that this item is intended to belong to the current group if:
406
  * a) the 'parent_slug' is the same as the slug of the current group, or
407
  * b) the 'parent_slug' starts with the slug of the current group, and the members nav doesn't have
408
+ * a primary item with that slug.
409
  */
410
  $group_slug = bp_get_current_group_slug();
411
  if (
474
  * the group's "Edit" Admin Bar menu for group admins.
475
  * Default: false.
476
  * }
477
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
478
+ * @return bool|object Returns false on failure, new BP_Nav_Item instance on success.
479
  */
480
  function bp_core_create_subnav_link( $args = '', $component = 'members' ) {
481
  $bp = buddypress();
570
  * the group's "Edit" Admin Bar menu for group admins.
571
  * Default: false.
572
  * }
573
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
574
  * @return bool|null Returns false on failure.
575
  */
576
  function bp_core_register_subnav_screen_function( $args = '', $component = 'members' ) {
bp-core/bp-core-cache.php CHANGED
@@ -115,7 +115,17 @@ add_action( 'update_option', 'bp_core_clear_directory_pages_cache_settings_edit'
115
  * @param string $option Option name.
116
  */
117
  function bp_core_clear_root_options_cache( $option ) {
 
 
 
 
 
118
  $keys = array_keys( bp_get_default_options() );
 
 
 
 
 
119
  $keys = array_merge( $keys, array(
120
  'registration',
121
  'avatar_default',
@@ -252,3 +262,100 @@ function bp_update_meta_cache( $args = array() ) {
252
 
253
  return $cache;
254
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  * @param string $option Option name.
116
  */
117
  function bp_core_clear_root_options_cache( $option ) {
118
+ foreach ( array( 'add_option', 'add_site_option', 'update_option', 'update_site_option' ) as $action ) {
119
+ remove_action( $action, 'bp_core_clear_root_options_cache' );
120
+ }
121
+
122
+ // Surrounding code prevents infinite loops on WP < 4.4.
123
  $keys = array_keys( bp_get_default_options() );
124
+
125
+ foreach ( array( 'add_option', 'add_site_option', 'update_option', 'update_site_option' ) as $action ) {
126
+ add_action( $action, 'bp_core_clear_root_options_cache' );
127
+ }
128
+
129
  $keys = array_merge( $keys, array(
130
  'registration',
131
  'avatar_default',
262
 
263
  return $cache;
264
  }
265
+
266
+ /**
267
+ * Gets a value that has been cached using an incremented key.
268
+ *
269
+ * A utility function for use by query methods like BP_Activity_Activity::get().
270
+ *
271
+ * @since 2.7.0
272
+ * @see bp_core_set_incremented_cache()
273
+ *
274
+ * @param string $key Unique key for the query. Usually a SQL string.
275
+ * @param string $group Cache group. Eg 'bp_activity'.
276
+ * @return array|bool False if no cached values are found, otherwise an array of IDs.
277
+ */
278
+ function bp_core_get_incremented_cache( $key, $group ) {
279
+ $cache_key = bp_core_get_incremented_cache_key( $key, $group );
280
+ return wp_cache_get( $cache_key, $group );
281
+ }
282
+
283
+ /**
284
+ * Caches a value using an incremented key.
285
+ *
286
+ * An "incremented key" is a cache key that is hashed with a unique incrementor,
287
+ * allowing for bulk invalidation.
288
+ *
289
+ * Use this method when caching data that should be invalidated whenever any
290
+ * object of a given type is created, updated, or deleted. This usually means
291
+ * data related to object queries, which can only reliably cached until the
292
+ * underlying set of objects has been modified. See, eg, BP_Activity_Activity::get().
293
+ *
294
+ * @since 2.7.0
295
+ *
296
+ * @param string $key Unique key for the query. Usually a SQL string.
297
+ * @param string $group Cache group. Eg 'bp_activity'.
298
+ * @param array $ids Array of IDs.
299
+ * @return bool
300
+ */
301
+ function bp_core_set_incremented_cache( $key, $group, $ids ) {
302
+ $cache_key = bp_core_get_incremented_cache_key( $key, $group );
303
+ return wp_cache_set( $cache_key, $ids, $group );
304
+ }
305
+
306
+ /**
307
+ * Gets the key to be used when caching a value using an incremented cache key.
308
+ *
309
+ * The $key is hashed with a component-specific incrementor, which is used to
310
+ * invalidate multiple caches at once.
311
+
312
+ * @since 2.7.0
313
+ *
314
+ * @param string $key Unique key for the query. Usually a SQL string.
315
+ * @param string $group Cache group. Eg 'bp_activity'.
316
+ * @return string
317
+ */
318
+ function bp_core_get_incremented_cache_key( $key, $group ) {
319
+ $incrementor = bp_core_get_incrementor( $group );
320
+ $cache_key = md5( $key . $incrementor );
321
+ return $cache_key;
322
+ }
323
+
324
+ /**
325
+ * Gets a group-specific cache incrementor.
326
+ *
327
+ * The incrementor is paired with query identifiers (like SQL strings) to
328
+ * create cache keys that can be invalidated en masse.
329
+ *
330
+ * If an incrementor does not yet exist for the given `$group`, one will
331
+ * be created.
332
+ *
333
+ * @since 2.7.0
334
+ *
335
+ * @param string $group Cache group. Eg 'bp_activity'.
336
+ * @return string
337
+ */
338
+ function bp_core_get_incrementor( $group ) {
339
+ $incrementor = wp_cache_get( 'incrementor', $group );
340
+ if ( ! $incrementor ) {
341
+ $incrementor = microtime();
342
+ wp_cache_set( 'incrementor', $incrementor, $group );
343
+ }
344
+
345
+ return $incrementor;
346
+ }
347
+
348
+ /**
349
+ * Reset a group-specific cache incrementor.
350
+ *
351
+ * Call this function when all incrementor-based caches associated with a given
352
+ * cache group should be invalidated.
353
+ *
354
+ * @since 2.7.0
355
+ *
356
+ * @param string $group Cache group. Eg 'bp_activity'.
357
+ * @return bool True on success, false on failure.
358
+ */
359
+ function bp_core_reset_incrementor( $group ) {
360
+ return wp_cache_delete( 'incrementor', $group );
361
+ }
bp-core/bp-core-caps.php CHANGED
@@ -20,7 +20,7 @@ defined( 'ABSPATH' ) || exit;
20
  *
21
  * @since 2.1.0
22
  *
23
- * @return array
24
  */
25
  function bp_get_current_blog_roles() {
26
  global $wp_roles;
@@ -56,7 +56,6 @@ function bp_get_current_blog_roles() {
56
  * This is called on plugin activation.
57
  *
58
  * @since 1.6.0
59
- *
60
  */
61
  function bp_add_caps() {
62
  global $wp_roles;
@@ -89,7 +88,6 @@ function bp_add_caps() {
89
  * This is called on plugin deactivation.
90
  *
91
  * @since 1.6.0
92
- *
93
  */
94
  function bp_remove_caps() {
95
  global $wp_roles;
@@ -218,9 +216,6 @@ function bp_get_caps_for_role( $role = '' ) {
218
  * already have a role or capability on.
219
  *
220
  * @since 1.6.0
221
- *
222
- * @global BuddyPress $bp Global BuddyPress settings object.
223
- *
224
  */
225
  function bp_set_current_user_default_role() {
226
 
@@ -248,55 +243,105 @@ function bp_set_current_user_default_role() {
248
  *
249
  * @since 1.6.0
250
  * @since 2.4.0 Second argument modified to accept an array, rather than `$blog_id`.
 
251
  *
252
  * @param string $capability Capability or role name.
253
  * @param array|int $args {
254
  * Array of extra arguments applicable to the capability check.
255
- * @type int $blog_id Optional. Blog ID. Defaults to the BP root blog.
 
256
  * @type mixed $a,... Optional. Extra arguments applicable to the capability check.
257
  * }
258
  * @return bool True if the user has the cap for the given parameters.
259
  */
260
  function bp_current_user_can( $capability, $args = array() ) {
261
- $blog_id = 0;
262
-
263
  // Backward compatibility for older $blog_id parameter.
264
  if ( is_int( $args ) ) {
265
- $blog_id = $args;
266
  $args = array();
 
267
 
268
  // New format for second parameter.
269
  } elseif ( is_array( $args ) && isset( $args['blog_id'] ) ) {
270
  // Get the blog ID if set, but don't pass along to `current_user_can_for_blog()`.
271
- $blog_id = (int) $args['blog_id'];
272
  unset( $args['blog_id'] );
273
  }
274
 
275
- // Backward compatibility for older bp_current_user_can() checks
276
- if ( empty( $args ) ) {
277
- $args = null;
278
- }
279
 
280
  // Use root blog if no ID passed.
281
- if ( empty( $blog_id ) ) {
282
- $blog_id = bp_get_root_blog_id();
283
  }
284
 
285
- $args = array( $blog_id, $capability, $args );
286
- $retval = call_user_func_array( 'current_user_can_for_blog', $args );
 
 
 
287
 
288
  /**
289
  * Filters whether or not the current user has a given capability.
290
  *
291
  * @since 1.6.0
292
  * @since 2.4.0 Pass `$args` variable.
 
293
  *
294
  * @param bool $retval Whether or not the current user has the capability.
295
  * @param string $capability The capability being checked for.
296
  * @param int $blog_id Blog ID. Defaults to the BP root blog.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  * @param array $args Array of extra arguments passed.
298
  */
299
- return (bool) apply_filters( 'bp_current_user_can', $retval, $capability, $blog_id, $args );
 
 
 
 
 
 
300
  }
301
 
302
  /**
20
  *
21
  * @since 2.1.0
22
  *
23
+ * @return object
24
  */
25
  function bp_get_current_blog_roles() {
26
  global $wp_roles;
56
  * This is called on plugin activation.
57
  *
58
  * @since 1.6.0
 
59
  */
60
  function bp_add_caps() {
61
  global $wp_roles;
88
  * This is called on plugin deactivation.
89
  *
90
  * @since 1.6.0
 
91
  */
92
  function bp_remove_caps() {
93
  global $wp_roles;
216
  * already have a role or capability on.
217
  *
218
  * @since 1.6.0
 
 
 
219
  */
220
  function bp_set_current_user_default_role() {
221
 
243
  *
244
  * @since 1.6.0
245
  * @since 2.4.0 Second argument modified to accept an array, rather than `$blog_id`.
246
+ * @since 2.7.0 Deprecated $args['blog_id'] in favor of $args['site_id'].
247
  *
248
  * @param string $capability Capability or role name.
249
  * @param array|int $args {
250
  * Array of extra arguments applicable to the capability check.
251
+ * @type int $site_id Optional. Blog ID. Defaults to the BP root blog.
252
+ * @type int $blog_id Deprecated. Use $site_id instead.
253
  * @type mixed $a,... Optional. Extra arguments applicable to the capability check.
254
  * }
255
  * @return bool True if the user has the cap for the given parameters.
256
  */
257
  function bp_current_user_can( $capability, $args = array() ) {
 
 
258
  // Backward compatibility for older $blog_id parameter.
259
  if ( is_int( $args ) ) {
260
+ $site_id = $args;
261
  $args = array();
262
+ $args['site_id'] = $site_id;
263
 
264
  // New format for second parameter.
265
  } elseif ( is_array( $args ) && isset( $args['blog_id'] ) ) {
266
  // Get the blog ID if set, but don't pass along to `current_user_can_for_blog()`.
267
+ $args['site_id'] = (int) $args['blog_id'];
268
  unset( $args['blog_id'] );
269
  }
270
 
271
+ // Cast $args as an array.
272
+ $args = (array) $args;
 
 
273
 
274
  // Use root blog if no ID passed.
275
+ if ( empty( $args['site_id'] ) ) {
276
+ $args['site_id'] = bp_get_root_blog_id();
277
  }
278
 
279
+ /** This filter is documented in /bp-core/bp-core-template.php */
280
+ $current_user_id = apply_filters( 'bp_loggedin_user_id', get_current_user_id() );
281
+
282
+ // Call bp_user_can().
283
+ $retval = bp_user_can( $current_user_id, $capability, $args );
284
 
285
  /**
286
  * Filters whether or not the current user has a given capability.
287
  *
288
  * @since 1.6.0
289
  * @since 2.4.0 Pass `$args` variable.
290
+ * @since 2.7.0 Change format of $args variable array.
291
  *
292
  * @param bool $retval Whether or not the current user has the capability.
293
  * @param string $capability The capability being checked for.
294
  * @param int $blog_id Blog ID. Defaults to the BP root blog.
295
+ * @param array $args Array of extra arguments as originally passed.
296
+ */
297
+ return (bool) apply_filters( 'bp_current_user_can', $retval, $capability, $args['site_id'], $args );
298
+ }
299
+
300
+ /**
301
+ * Check whether the specified user has a given capability on a given site.
302
+ *
303
+ * @since 2.7.0
304
+ *
305
+ * @param int $user_id
306
+ * @param string $capability Capability or role name.
307
+ * @param array|int $args {
308
+ * Array of extra arguments applicable to the capability check.
309
+ *
310
+ * @type int $site_id Optional. Site ID. Defaults to the BP root blog.
311
+ * @type mixed $a,... Optional. Extra arguments applicable to the capability check.
312
+ * }
313
+ * @return bool True if the user has the cap for the given parameters.
314
+ */
315
+ function bp_user_can( $user_id, $capability, $args = array() ) {
316
+ $site_id = bp_get_root_blog_id();
317
+
318
+ // Get the site ID if set, but don't pass along to user_can().
319
+ if ( isset( $args['site_id'] ) ) {
320
+ $site_id = (int) $args['site_id'];
321
+ unset( $args['site_id'] );
322
+ }
323
+
324
+ $switched = is_multisite() ? switch_to_blog( $site_id ) : false;
325
+ $retval = call_user_func_array( 'user_can', array( $user_id, $capability, $args ) );
326
+
327
+ /**
328
+ * Filters whether or not the specified user has a given capability on a given site.
329
+ *
330
+ * @since 2.7.0
331
+ *
332
+ * @param bool $retval Whether or not the current user has the capability.
333
+ * @param int $user_id
334
+ * @param string $capability The capability being checked for.
335
+ * @param int $site_id Site ID. Defaults to the BP root blog.
336
  * @param array $args Array of extra arguments passed.
337
  */
338
+ $retval = (bool) apply_filters( 'bp_user_can', $retval, $user_id, $capability, $site_id, $args );
339
+
340
+ if ( $switched ) {
341
+ restore_current_blog();
342
+ }
343
+
344
+ return $retval;
345
  }
346
 
347
  /**
bp-core/bp-core-catchuri.php CHANGED
@@ -218,7 +218,7 @@ function bp_core_set_uri_globals() {
218
  /**
219
  * Filter the portion of the URI that is the displayed user's slug.
220
  *
221
- * eg. example.com/ADMIN (when root profiles is enabled)
222
  * example.com/members/ADMIN (when root profiles isn't enabled)
223
  *
224
  * ADMIN would be the displayed user's slug.
@@ -553,16 +553,18 @@ function bp_core_catch_profile_uri() {
553
  * @since 2.6.0
554
  *
555
  * @param string $member_slug The current member slug.
 
556
  */
557
  function bp_core_members_shortlink_redirector( $member_slug ) {
 
558
  /**
559
  * Shortlink slug to redirect to logged-in user.
560
  *
561
- * x.com/members/me/* will redirect to x.com/members/{LOGGED_IN_USER_SLUG}/*
562
  *
563
  * @since 2.6.0
564
  *
565
- * @var string $slug Defaults to 'me'.
566
  */
567
  $me_slug = apply_filters( 'bp_core_members_shortlink_slug', 'me' );
568
 
@@ -635,9 +637,9 @@ function bp_core_no_access( $args = '' ) {
635
  $redirect_url .= $_SERVER['REQUEST_URI'];
636
 
637
  $defaults = array(
638
- 'mode' => 2, // 1 = $root, 2 = wp-login.php
639
- 'redirect' => $redirect_url, // the URL you get redirected to when a user successfully logs in
640
- 'root' => bp_get_root_domain(), // the landing page you get redirected to when a user doesn't have access
641
  'message' => __( 'You must log in to access the page you requested.', 'buddypress' )
642
  );
643
 
@@ -654,7 +656,7 @@ function bp_core_no_access( $args = '' ) {
654
  extract( $r, EXTR_SKIP );
655
 
656
  /*
657
- * @ignore Ignore these filters and use 'bp_core_no_access' above
658
  */
659
  $mode = apply_filters( 'bp_no_access_mode', $mode, $root, $redirect, $message );
660
  $redirect = apply_filters( 'bp_no_access_redirect', $redirect, $root, $message, $mode );
@@ -664,7 +666,7 @@ function bp_core_no_access( $args = '' ) {
664
 
665
  switch ( $mode ) {
666
 
667
- // Option to redirect to wp-login.php
668
  // Error message is displayed with bp_core_no_access_wp_login_error().
669
  case 2 :
670
  if ( !empty( $redirect ) ) {
@@ -675,7 +677,7 @@ function bp_core_no_access( $args = '' ) {
675
 
676
  break;
677
 
678
- // Redirect to root with "redirect_to" parameter
679
  // Error message is displayed with bp_core_add_message().
680
  case 1 :
681
  default :
@@ -696,16 +698,18 @@ function bp_core_no_access( $args = '' ) {
696
  }
697
 
698
  /**
699
- * Add an error message to wp-login.php.
700
- *
701
- * Hooks into the "bpnoaccess" action defined in bp_core_no_access().
702
  *
703
  * @since 1.5.0
 
704
  *
705
- * @global string $error Error message to pass to wp-login.php.
 
706
  */
707
- function bp_core_no_access_wp_login_error() {
708
- global $error;
 
 
709
 
710
  /**
711
  * Filters the error message for wp-login.php when needing to log in before accessing.
@@ -715,12 +719,27 @@ function bp_core_no_access_wp_login_error() {
715
  * @param string $value Error message to display.
716
  * @param string $value URL to redirect user to after successful login.
717
  */
718
- $error = apply_filters( 'bp_wp_login_error', __( 'You must log in to access the page you requested.', 'buddypress' ), $_REQUEST['redirect_to'] );
 
 
719
 
720
- // Shake shake shake!.
721
- add_action( 'login_head', 'wp_shake_js', 12 );
722
  }
723
- add_action( 'login_form_bpnoaccess', 'bp_core_no_access_wp_login_error' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
 
725
  /**
726
  * Canonicalize BuddyPress URLs.
@@ -939,7 +958,6 @@ function bp_get_requested_url() {
939
  * notice in future versions of BuddyPress.
940
  *
941
  * @since 1.6.0
942
- *
943
  */
944
  function _bp_maybe_remove_redirect_canonical() {
945
  if ( ! bp_is_blog_page() )
@@ -997,3 +1015,36 @@ function _bp_maybe_remove_rel_canonical() {
997
  }
998
  }
999
  add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  /**
219
  * Filter the portion of the URI that is the displayed user's slug.
220
  *
221
+ * Eg. example.com/ADMIN (when root profiles is enabled)
222
  * example.com/members/ADMIN (when root profiles isn't enabled)
223
  *
224
  * ADMIN would be the displayed user's slug.
553
  * @since 2.6.0
554
  *
555
  * @param string $member_slug The current member slug.
556
+ * @return string $member_slug The current member slug.
557
  */
558
  function bp_core_members_shortlink_redirector( $member_slug ) {
559
+
560
  /**
561
  * Shortlink slug to redirect to logged-in user.
562
  *
563
+ * The x.com/members/me/* url will redirect to x.com/members/{LOGGED_IN_USER_SLUG}/*
564
  *
565
  * @since 2.6.0
566
  *
567
+ * @param string $slug Defaults to 'me'.
568
  */
569
  $me_slug = apply_filters( 'bp_core_members_shortlink_slug', 'me' );
570
 
637
  $redirect_url .= $_SERVER['REQUEST_URI'];
638
 
639
  $defaults = array(
640
+ 'mode' => 2, // 1 = $root, 2 = wp-login.php.
641
+ 'redirect' => $redirect_url, // the URL you get redirected to when a user successfully logs in.
642
+ 'root' => bp_get_root_domain(), // the landing page you get redirected to when a user doesn't have access.
643
  'message' => __( 'You must log in to access the page you requested.', 'buddypress' )
644
  );
645
 
656
  extract( $r, EXTR_SKIP );
657
 
658
  /*
659
+ * @ignore Ignore these filters and use 'bp_core_no_access' above.
660
  */
661
  $mode = apply_filters( 'bp_no_access_mode', $mode, $root, $redirect, $message );
662
  $redirect = apply_filters( 'bp_no_access_redirect', $redirect, $root, $message, $mode );
666
 
667
  switch ( $mode ) {
668
 
669
+ // Option to redirect to wp-login.php.
670
  // Error message is displayed with bp_core_no_access_wp_login_error().
671
  case 2 :
672
  if ( !empty( $redirect ) ) {
677
 
678
  break;
679
 
680
+ // Redirect to root with "redirect_to" parameter.
681
  // Error message is displayed with bp_core_add_message().
682
  case 1 :
683
  default :
698
  }
699
 
700
  /**
701
+ * Add a custom BuddyPress no access error message to wp-login.php.
 
 
702
  *
703
  * @since 1.5.0
704
+ * @since 2.7.0 Hook moved to 'wp_login_errors' made available since WP 3.6.0.
705
  *
706
+ * @param WP_Error $errors Current error container.
707
+ * @return WP_Error
708
  */
709
+ function bp_core_no_access_wp_login_error( $errors ) {
710
+ if ( empty( $_GET['action'] ) || 'bpnoaccess' !== $_GET['action'] ) {
711
+ return $errors;
712
+ }
713
 
714
  /**
715
  * Filters the error message for wp-login.php when needing to log in before accessing.
719
  * @param string $value Error message to display.
720
  * @param string $value URL to redirect user to after successful login.
721
  */
722
+ $message = apply_filters( 'bp_wp_login_error', __( 'You must log in to access the page you requested.', 'buddypress' ), $_REQUEST['redirect_to'] );
723
+
724
+ $errors->add( 'bp_no_access', $message );
725
 
726
+ return $errors;
 
727
  }
728
+ add_filter( 'wp_login_errors', 'bp_core_no_access_wp_login_error' );
729
+
730
+ /**
731
+ * Add our custom error code to WP login's shake error codes.
732
+ *
733
+ * @since 2.7.0
734
+ *
735
+ * @param array $codes Array of WP error codes.
736
+ * @return array
737
+ */
738
+ function bp_core_login_filter_shake_codes( $codes ) {
739
+ $codes[] = 'bp_no_access';
740
+ return $codes;
741
+ }
742
+ add_filter( 'shake_error_codes', 'bp_core_login_filter_shake_codes' );
743
 
744
  /**
745
  * Canonicalize BuddyPress URLs.
958
  * notice in future versions of BuddyPress.
959
  *
960
  * @since 1.6.0
 
961
  */
962
  function _bp_maybe_remove_redirect_canonical() {
963
  if ( ! bp_is_blog_page() )
1015
  }
1016
  }
1017
  add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 );
1018
+
1019
+ /**
1020
+ * Stop WordPress performing a DB query for its main loop.
1021
+ *
1022
+ * As of WordPress 4.6, it is possible to bypass the main WP_Query entirely.
1023
+ * This saves us one unnecessary database query! :)
1024
+ *
1025
+ * @since 2.7.0
1026
+ *
1027
+ * @param null $retval Current return value for filter.
1028
+ * @param WP_Query $query Current WordPress query object.
1029
+ * @return null|array
1030
+ */
1031
+ function bp_core_filter_wp_query( $retval, $query ) {
1032
+ if ( ! $query->is_main_query() ) {
1033
+ return $retval;
1034
+ }
1035
+
1036
+ /*
1037
+ * If not on a BP single page, bail.
1038
+ * Too early to use bp_is_single_item(), so use BP conditionals.
1039
+ */
1040
+ if ( false === ( bp_is_group() || bp_is_user() || bp_is_single_activity() ) ) {
1041
+ return $retval;
1042
+ }
1043
+
1044
+ // Set default properties as recommended in the 'posts_pre_query' DocBlock.
1045
+ $query->found_posts = 0;
1046
+ $query->max_num_pages = 0;
1047
+
1048
+ // Return something other than a null value to bypass WP_Query.
1049
+ return array();
1050
+ }
bp-core/bp-core-classes.php CHANGED
@@ -33,6 +33,7 @@ require dirname( __FILE__ ) . '/classes/class-bp-phpmailer.php';
33
  require dirname( __FILE__ ) . '/classes/class-bp-core-nav.php';
34
  require dirname( __FILE__ ) . '/classes/class-bp-core-nav-item.php';
35
  require dirname( __FILE__ ) . '/classes/class-bp-core-oembed-extension.php';
 
36
 
37
  if ( buddypress()->do_nav_backcompat ) {
38
  require dirname( __FILE__ ) . '/classes/class-bp-core-bp-nav-backcompat.php';
33
  require dirname( __FILE__ ) . '/classes/class-bp-core-nav.php';
34
  require dirname( __FILE__ ) . '/classes/class-bp-core-nav-item.php';
35
  require dirname( __FILE__ ) . '/classes/class-bp-core-oembed-extension.php';
36
+ require dirname( __FILE__ ) . '/classes/class-bp-core-html-element.php';
37
 
38
  if ( buddypress()->do_nav_backcompat ) {
39
  require dirname( __FILE__ ) . '/classes/class-bp-core-bp-nav-backcompat.php';
bp-core/bp-core-cssjs.php CHANGED
@@ -29,24 +29,27 @@ function bp_core_register_common_scripts() {
29
  $scripts = apply_filters( 'bp_core_register_common_scripts', array(
30
 
31
  // Legacy.
32
- 'bp-confirm' => array( 'file' => "{$url}confirm{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
33
  'bp-widget-members' => array( 'file' => "{$url}widget-members{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
34
- 'bp-jquery-query' => array( 'file' => "{$url}jquery-query{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
35
- 'bp-jquery-cookie' => array( 'file' => "{$url}jquery-cookie{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
36
- 'bp-jquery-scroll-to' => array( 'file' => "{$url}jquery-scroll-to{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
37
 
38
- // 2.1
39
- 'jquery-caret' => array( 'file' => "{$url}jquery.caret{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => true ),
40
- 'jquery-atwho' => array( 'file' => "{$url}jquery.atwho{$min}.js", 'dependencies' => array( 'jquery', 'jquery-caret' ), 'footer' => true ),
41
 
42
- // 2.3
43
  'bp-plupload' => array( 'file' => "{$url}bp-plupload{$min}.js", 'dependencies' => array( 'plupload', 'jquery', 'json2', 'wp-backbone' ), 'footer' => true ),
44
  'bp-avatar' => array( 'file' => "{$url}avatar{$min}.js", 'dependencies' => array( 'jcrop' ), 'footer' => true ),
45
  'bp-webcam' => array( 'file' => "{$url}webcam{$min}.js", 'dependencies' => array( 'bp-avatar' ), 'footer' => true ),
46
 
47
- // 2.4
48
  'bp-cover-image' => array( 'file' => "{$url}cover-image{$min}.js", 'dependencies' => array(), 'footer' => true ),
49
 
 
 
 
50
  ) );
51
 
52
  $version = bp_get_version();
@@ -106,7 +109,7 @@ add_action( 'bp_enqueue_scripts', 'bp_core_register_common_styles', 1 );
106
  add_action( 'bp_admin_enqueue_scripts', 'bp_core_register_common_styles', 1 );
107
 
108
  /**
109
- * Load the JS for "Are you sure?" .confirm links.
110
  *
111
  * @since 1.1.0
112
  */
@@ -128,7 +131,7 @@ add_action( 'bp_admin_enqueue_scripts', 'bp_core_confirmation_js' );
128
  /**
129
  * Enqueues the css and js required by the Avatar UI.
130
  *
131
- * @since 2.3.0
132
  */
133
  function bp_core_avatar_scripts() {
134
  if ( ! bp_avatar_is_front_edit() ) {
@@ -148,7 +151,7 @@ add_action( 'bp_enqueue_scripts', 'bp_core_avatar_scripts' );
148
  /**
149
  * Enqueues the css and js required by the Cover Image UI.
150
  *
151
- * @since 2.4.0
152
  */
153
  function bp_core_cover_image_scripts() {
154
  if ( ! bp_attachments_cover_image_is_edit() ) {
@@ -361,11 +364,11 @@ function bp_core_get_js_dependencies() {
361
  }
362
 
363
  /**
364
- * Add inline css to display the component's single item cover image
365
  *
366
  * @since 2.4.0
367
  *
368
- * @param bool $return True to get the inline css.
369
  * @return string|array the inline css or an associative array containing
370
  * the css rules and the style handle
371
  */
@@ -460,3 +463,90 @@ function bp_add_cover_image_inline_css( $return = false ) {
460
  }
461
  }
462
  add_action( 'bp_enqueue_scripts', 'bp_add_cover_image_inline_css', 11 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  $scripts = apply_filters( 'bp_core_register_common_scripts', array(
30
 
31
  // Legacy.
32
+ 'bp-confirm' => array( 'file' => "{$url}confirm{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
33
  'bp-widget-members' => array( 'file' => "{$url}widget-members{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
34
+ 'bp-jquery-query' => array( 'file' => "{$url}jquery-query{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
35
+ 'bp-jquery-cookie' => array( 'file' => "{$url}vendor/jquery-cookie{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
36
+ 'bp-jquery-scroll-to' => array( 'file' => "{$url}vendor/jquery-scroll-to{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),
37
 
38
+ // Version 2.1.
39
+ 'jquery-caret' => array( 'file' => "{$url}vendor/jquery.caret{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => true ),
40
+ 'jquery-atwho' => array( 'file' => "{$url}vendor/jquery.atwho{$min}.js", 'dependencies' => array( 'jquery', 'jquery-caret' ), 'footer' => true ),
41
 
42
+ // Version 2.3.
43
  'bp-plupload' => array( 'file' => "{$url}bp-plupload{$min}.js", 'dependencies' => array( 'plupload', 'jquery', 'json2', 'wp-backbone' ), 'footer' => true ),
44
  'bp-avatar' => array( 'file' => "{$url}avatar{$min}.js", 'dependencies' => array( 'jcrop' ), 'footer' => true ),
45
  'bp-webcam' => array( 'file' => "{$url}webcam{$min}.js", 'dependencies' => array( 'bp-avatar' ), 'footer' => true ),
46
 
47
+ // Version 2.4.
48
  'bp-cover-image' => array( 'file' => "{$url}cover-image{$min}.js", 'dependencies' => array(), 'footer' => true ),
49
 
50
+ // Version 2.7.
51
+ 'bp-moment' => array( 'file' => "{$url}vendor/moment{$min}.js", 'dependencies' => array(), 'footer' => true ),
52
+ 'bp-livestamp' => array( 'file' => "{$url}vendor/livestamp{$min}.js", 'dependencies' => array( 'jquery', 'bp-moment' ), 'footer' => true ),
53
  ) );
54
 
55
  $version = bp_get_version();
109
  add_action( 'bp_admin_enqueue_scripts', 'bp_core_register_common_styles', 1 );
110
 
111
  /**
112
+ * Load the JS for "Are you sure?" confirm links.
113
  *
114
  * @since 1.1.0
115
  */
131
  /**
132
  * Enqueues the css and js required by the Avatar UI.
133
  *
134
+ * @since 2.3.0
135
  */
136
  function bp_core_avatar_scripts() {
137
  if ( ! bp_avatar_is_front_edit() ) {
151
  /**
152
  * Enqueues the css and js required by the Cover Image UI.
153
  *
154
+ * @since 2.4.0
155
  */
156
  function bp_core_cover_image_scripts() {
157
  if ( ! bp_attachments_cover_image_is_edit() ) {
364
  }
365
 
366
  /**
367
+ * Add inline css to display the component's single item cover image.
368
  *
369
  * @since 2.4.0
370
  *
371
+ * @param bool $return True to get the inline css.
372
  * @return string|array the inline css or an associative array containing
373
  * the css rules and the style handle
374
  */
463
  }
464
  }
465
  add_action( 'bp_enqueue_scripts', 'bp_add_cover_image_inline_css', 11 );
466
+
467
+ /**
468
+ * Enqueues livestamp.js on BuddyPress pages.
469
+ *
470
+ * @since 2.7.0
471
+ */
472
+ function bp_core_add_livestamp() {
473
+ if ( ! is_buddypress() ) {
474
+ return;
475
+ }
476
+
477
+ bp_core_enqueue_livestamp();
478
+ }
479
+ add_action( 'bp_enqueue_scripts', 'bp_core_add_livestamp' );
480
+
481
+ /**
482
+ * Enqueue and localize livestamp.js script.
483
+ *
484
+ * @since 2.7.0
485
+ */
486
+ function bp_core_enqueue_livestamp() {
487
+ // If bp-livestamp isn't enqueued, do it now.
488
+ if ( wp_script_is( 'bp-livestamp' ) ) {
489
+ return;
490
+ }
491
+
492
+ wp_enqueue_script( 'bp-livestamp' );
493
+
494
+ // We're only localizing the relative time strings for moment.js since that's all we need for now.
495
+ wp_localize_script( 'bp-livestamp', 'BP_Moment_i18n', array(
496
+ 'future' => __( 'in %s', 'buddypress' ),
497
+ 'past' => __( '%s ago', 'buddypress' ),
498
+ 's' => __( 'a few seconds', 'buddypress' ),
499
+ 'm' => __( 'a minute', 'buddypress' ),
500
+ 'mm' => __( '%d minutes', 'buddypress' ),
501
+ 'h' => __( 'an hour', 'buddypress' ),
502
+ 'hh' => __( '%d hours', 'buddypress' ),
503
+ 'd' => __( 'a day', 'buddypress' ),
504
+ 'dd' => __( '%d days', 'buddypress' ),
505
+ 'M' => __( 'a month', 'buddypress' ),
506
+ 'MM' => __( '%d months', 'buddypress' ),
507
+ 'y' => __( 'a year', 'buddypress' ),
508
+ 'yy' => __( '%d years', 'buddypress' ),
509
+ ) );
510
+
511
+ if ( function_exists( 'wp_add_inline_script' ) ) {
512
+ wp_add_inline_script ( 'bp-livestamp', bp_core_moment_js_config() );
513
+ } else {
514
+ add_action( 'wp_footer', '_bp_core_moment_js_config_footer', 20 );
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Return moment.js config.
520
+ *
521
+ * @since 2.7.0
522
+ *
523
+ * @return string
524
+ */
525
+ function bp_core_moment_js_config() {
526
+ $inline_js = <<<EOD
527
+ jQuery(function() {
528
+ moment.locale( 'bp', {
529
+ relativeTime : BP_Moment_i18n
530
+ });
531
+ });
532
+ EOD;
533
+
534
+ return $inline_js;
535
+ }
536
+
537
+ /**
538
+ * Print moment.js config in page footer.
539
+ *
540
+ * Will be removed once we set our minimum version of WP 4.5.
541
+ *
542
+ * @since 2.7.0
543
+ *
544
+ * @access private
545
+ */
546
+ function _bp_core_moment_js_config_footer() {
547
+ if ( ! wp_script_is( 'bp-livestamp' ) ) {
548
+ return;
549
+ }
550
+
551
+ printf( '<script>%s</script>', bp_core_moment_js_config() );
552
+ }
bp-core/bp-core-customizer-email.php CHANGED
@@ -2,10 +2,9 @@
2
  /**
3
  * BuddyPress Customizer implementation for email.
4
  *
5
- * @since 2.5.0
6
- *
7
  * @package BuddyPress
8
  * @subpackage Core
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -65,7 +64,6 @@ function bp_email_init_customizer( WP_Customize_Manager $wp_customize ) {
65
  $wp_customize->add_control( new $args['class']( $wp_customize, $control_id, $args ) );
66
  }
67
 
68
-
69
  /*
70
  * Hook actions/filters for further configuration.
71
  */
@@ -90,7 +88,7 @@ function bp_email_init_customizer( WP_Customize_Manager $wp_customize ) {
90
  true
91
  );
92
 
93
- // Include the preview loading style
94
  add_action( 'wp_footer', array( $wp_customize, 'customize_preview_loading_style' ) );
95
  }
96
  }
@@ -112,7 +110,7 @@ function bp_is_email_customizer() {
112
  *
113
  * @since 2.5.0
114
  *
115
- * @param $active Whether the Customizer section is active.
116
  * @param WP_Customize_Section $section {@see WP_Customize_Section} instance.
117
  * @return bool
118
  */
2
  /**
3
  * BuddyPress Customizer implementation for email.
4
  *
 
 
5
  * @package BuddyPress
6
  * @subpackage Core
7
+ * @since 2.5.0
8
  */
9
 
10
  // Exit if accessed directly.
64
  $wp_customize->add_control( new $args['class']( $wp_customize, $control_id, $args ) );
65
  }
66
 
 
67
  /*
68
  * Hook actions/filters for further configuration.
69
  */
88
  true
89
  );
90
 
91
+ // Include the preview loading style.
92
  add_action( 'wp_footer', array( $wp_customize, 'customize_preview_loading_style' ) );
93
  }
94
  }
110
  *
111
  * @since 2.5.0
112
  *
113
+ * @param bool $active Whether the Customizer section is active.
114
  * @param WP_Customize_Section $section {@see WP_Customize_Section} instance.
115
  * @return bool
116
  */
bp-core/bp-core-dependency.php CHANGED
@@ -215,7 +215,6 @@ function bp_setup_cache_groups() {
215
  *
216
  * @link https://buddypress.trac.wordpress.org/ticket/6046
217
  * @link https://core.trac.wordpress.org/ticket/24169
218
- *
219
  */
220
  function bp_setup_current_user() {
221
  $skip_warning = (
@@ -406,7 +405,6 @@ function bp_head() {
406
  * who do not have the proper permission to access certain content.
407
  *
408
  * @since 1.6.0
409
- *
410
  */
411
  function bp_template_redirect() {
412
 
@@ -426,7 +424,6 @@ function bp_template_redirect() {
426
  * The main action used registering theme directories.
427
  *
428
  * @since 1.5.0
429
- *
430
  */
431
  function bp_register_theme_directory() {
432
 
@@ -446,7 +443,6 @@ function bp_register_theme_directory() {
446
  * The main action used registering theme packages.
447
  *
448
  * @since 1.7.0
449
- *
450
  */
451
  function bp_register_theme_packages() {
452
 
@@ -462,7 +458,6 @@ function bp_register_theme_packages() {
462
  * Fire the 'bp_enqueue_scripts' action, where BP enqueues its CSS and JS.
463
  *
464
  * @since 1.6.0
465
- *
466
  */
467
  function bp_enqueue_scripts() {
468
 
@@ -496,7 +491,6 @@ function bp_enqueue_embed_scripts() {
496
  * Fire the 'bp_add_rewrite_tag' action, where BP adds its custom rewrite tags.
497
  *
498
  * @since 1.8.0
499
- *
500
  */
501
  function bp_add_rewrite_tags() {
502
 
@@ -512,7 +506,6 @@ function bp_add_rewrite_tags() {
512
  * Fire the 'bp_add_rewrite_rules' action, where BP adds its custom rewrite rules.
513
  *
514
  * @since 1.9.0
515
- *
516
  */
517
  function bp_add_rewrite_rules() {
518
 
@@ -528,7 +521,6 @@ function bp_add_rewrite_rules() {
528
  * Fire the 'bp_add_permastructs' action, where BP adds its BP-specific permalink structure.
529
  *
530
  * @since 1.9.0
531
- *
532
  */
533
  function bp_add_permastructs() {
534
 
@@ -547,7 +539,6 @@ function bp_add_permastructs() {
547
  * BuddyPress-specific functionality.
548
  *
549
  * @since 1.6.0
550
- *
551
  */
552
  function bp_setup_theme() {
553
 
@@ -570,7 +561,6 @@ function bp_setup_theme() {
570
  * before our theme compatibility layer kicks in.
571
  *
572
  * @since 1.6.0
573
- *
574
  */
575
  function bp_after_setup_theme() {
576
 
@@ -699,7 +689,6 @@ function bp_allowed_themes( $themes ) {
699
  * The main action used for handling theme-side POST requests.
700
  *
701
  * @since 1.9.0
702
- *
703
  */
704
  function bp_post_request() {
705
 
@@ -742,7 +731,6 @@ function bp_post_request() {
742
  * The main action used for handling theme-side GET requests.
743
  *
744
  * @since 1.9.0
745
- *
746
  */
747
  function bp_get_request() {
748
 
215
  *
216
  * @link https://buddypress.trac.wordpress.org/ticket/6046
217
  * @link https://core.trac.wordpress.org/ticket/24169
 
218
  */
219
  function bp_setup_current_user() {
220
  $skip_warning = (
405
  * who do not have the proper permission to access certain content.
406
  *
407
  * @since 1.6.0
 
408
  */
409
  function bp_template_redirect() {
410
 
424
  * The main action used registering theme directories.
425
  *
426
  * @since 1.5.0
 
427
  */
428
  function bp_register_theme_directory() {
429
 
443
  * The main action used registering theme packages.
444
  *
445
  * @since 1.7.0
 
446
  */
447
  function bp_register_theme_packages() {
448
 
458
  * Fire the 'bp_enqueue_scripts' action, where BP enqueues its CSS and JS.
459
  *
460
  * @since 1.6.0
 
461
  */
462
  function bp_enqueue_scripts() {
463
 
491
  * Fire the 'bp_add_rewrite_tag' action, where BP adds its custom rewrite tags.
492
  *
493
  * @since 1.8.0
 
494
  */
495
  function bp_add_rewrite_tags() {
496
 
506
  * Fire the 'bp_add_rewrite_rules' action, where BP adds its custom rewrite rules.
507
  *
508
  * @since 1.9.0
 
509
  */
510
  function bp_add_rewrite_rules() {
511
 
521
  * Fire the 'bp_add_permastructs' action, where BP adds its BP-specific permalink structure.
522
  *
523
  * @since 1.9.0
 
524
  */
525
  function bp_add_permastructs() {
526
 
539
  * BuddyPress-specific functionality.
540
  *
541
  * @since 1.6.0
 
542
  */
543
  function bp_setup_theme() {
544
 
561
  * before our theme compatibility layer kicks in.
562
  *
563
  * @since 1.6.0
 
564
  */
565
  function bp_after_setup_theme() {
566
 
689
  * The main action used for handling theme-side POST requests.
690
  *
691
  * @since 1.9.0
 
692
  */
693
  function bp_post_request() {
694
 
731
  * The main action used for handling theme-side GET requests.
732
  *
733
  * @since 1.9.0
 
734
  */
735
  function bp_get_request() {
736
 
bp-core/bp-core-filters.php CHANGED
@@ -75,6 +75,9 @@ add_filter( 'bp_get_template_stack', 'bp_add_template_stack_locations' );
75
  // Turn comments off for BuddyPress pages.
76
  add_filter( 'comments_open', 'bp_comments_open', 10, 2 );
77
 
 
 
 
78
  /**
79
  * Prevent specific pages (eg 'Activate') from showing on page listings.
80
  *
@@ -175,7 +178,7 @@ function bp_core_menu_highlight_parent_page( $retval, $page ) {
175
  foreach ( (array) buddypress()->pages as $component => $bp_page ) {
176
  // Handles the majority of components.
177
  if ( bp_is_current_component( $component ) ) {
178
- $page_id = (int) $bp_page->id;
179
  }
180
 
181
  // Stop if not on a user page.
@@ -308,7 +311,7 @@ function bp_core_login_redirect( $redirect_to, $redirect_to_raw, $user ) {
308
  *
309
  * @since 1.6.0
310
  *
311
- * @param bool $value Whether or not to redirect.
312
  * @param string $redirect_to Sanitized URL to be redirected to.
313
  * @param string $redirect_to_raw Unsanitized URL to be redirected to.
314
  * @param WP_User $user The WP_User object corresponding to a
@@ -349,6 +352,7 @@ add_filter( 'bp_login_redirect', 'bp_core_login_redirect', 10, 3 );
349
  * @param string $retval Current email content.
350
  * @param string $prop Email property to check against.
351
  * @param string $transform Either 'raw' or 'replace-tokens'.
 
352
  */
353
  function bp_email_plaintext_entity_decode( $retval, $prop, $transform ) {
354
  switch ( $prop ) {
@@ -545,9 +549,9 @@ add_filter( 'wpmu_signup_user_notification', 'bp_core_activation_signup_user_not
545
  * @see wp_title()
546
  * @global object $bp BuddyPress global settings.
547
  *
548
- * @param string $title Original page title.
549
- * @param string $sep How to separate the various items within the page title.
550
- * @param string $seplocation Direction to display title.
551
  * @return string New page title.
552
  */
553
  function bp_modify_page_title( $title = '', $sep = '&raquo;', $seplocation = 'right' ) {
@@ -570,7 +574,7 @@ function bp_modify_page_title( $title = '', $sep = '&raquo;', $seplocation = 'ri
570
  * @link https://buddypress.trac.wordpress.org/ticket/6107
571
  * @see wp_title()
572
  */
573
- $title_tag_compatibility = (bool) ( ! empty( $_wp_theme_features['title-tag'] ) || strstr( $title, $blogname ) );
574
 
575
  // Append the site title to title parts if theme supports title tag.
576
  if ( true === $title_tag_compatibility ) {
@@ -595,12 +599,12 @@ function bp_modify_page_title( $title = '', $sep = '&raquo;', $seplocation = 'ri
595
  /**
596
  * Filters the older 'wp_title' page title for BuddyPress pages.
597
  *
598
- * @since 1.5.0
599
  *
600
- * @param string $new_title The BuddyPress page title.
601
- * @param string $title The original WordPress page title.
602
- * @param string $sep The title parts separator.
603
- * @param string $seplocation Location of the separator (left or right).
604
  */
605
  return apply_filters( 'bp_modify_page_title', $new_title, $title, $sep, $seplocation );
606
  }
@@ -648,10 +652,10 @@ function bp_modify_document_title_parts( $title = array() ) {
648
  /**
649
  * Filters BuddyPress title parts that will be used into the document title.
650
  *
651
- * @since 2.4.3
652
  *
653
- * @param array $bp_title The BuddyPress page title parts.
654
- * @param array $title The original WordPress title parts.
655
  */
656
  return apply_filters( 'bp_modify_document_title_parts', $bp_title, $title );
657
  }
@@ -749,13 +753,13 @@ add_filter( 'wp_setup_nav_menu_item', 'bp_setup_nav_menu_item', 10, 1 );
749
  /**
750
  * Populate BuddyPress user nav items for the customizer.
751
  *
752
- * @since 2.3.3
753
  *
754
- * @param array $items The array of menu items.
755
- * @param string $type The requested type.
756
- * @param string $object The requested object name.
757
- * @param integer $page The page num being requested.
758
- * @return array The paginated BuddyPress user nav items.
759
  */
760
  function bp_customizer_nav_menus_get_items( $items = array(), $type = '', $object = '', $page = 0 ) {
761
  if ( 'bp_loggedin_nav' === $object ) {
@@ -786,9 +790,9 @@ add_filter( 'customize_nav_menu_available_items', 'bp_customizer_nav_menus_get_i
786
  /**
787
  * Set BuddyPress item navs for the customizer.
788
  *
789
- * @since 2.3.3
790
  *
791
- * @param array $item_types An associative array structured for the customizer.
792
  * @return array $item_types An associative array structured for the customizer.
793
  */
794
  function bp_customizer_nav_menus_set_item_types( $item_types = array() ) {
@@ -852,8 +856,8 @@ function bp_filter_metaid_column_name( $q ) {
852
  *
853
  * @since 2.1.0
854
  *
855
- * @param string $edit_link The edit link.
856
- * @param int $post_id Post ID.
857
  * @return bool|string Will be a boolean (false) if $post_id is 0. Will be a string (the unchanged edit link)
858
  * otherwise
859
  */
@@ -899,7 +903,8 @@ add_filter( 'bp_activity_maybe_load_mentions_scripts', 'bp_maybe_load_mentions_s
899
  * @access private
900
  *
901
  * @global array $wp_registered_widgets Current registered widgets.
902
- * @param array $params Current sidebar params.
 
903
  * @return array
904
  */
905
  function _bp_core_inject_bp_widget_css_class( $params ) {
@@ -951,9 +956,9 @@ add_filter( 'dynamic_sidebar_params', '_bp_core_inject_bp_widget_css_class' );
951
  *
952
  * @since 2.5.0
953
  *
954
- * @param string $value Property value.
955
- * @param string $property_name
956
- * @param string $transform How the return value was transformed.
957
  * @return string Updated value.
958
  */
959
  function bp_email_add_link_color_to_template( $value, $property_name, $transform ) {
@@ -990,10 +995,10 @@ add_filter( 'bp_email_get_property', 'bp_email_add_link_color_to_template', 6, 3
990
  *
991
  * @since 2.5.0
992
  *
993
- * @param array $headers
994
- * @param string $property Name of property. Unused.
995
- * @param string $transform Return value transformation. Unused.
996
- * @param BP_Email $email Email object reference.
997
  * @return array
998
  */
999
  function bp_email_set_default_headers( $headers, $property, $transform, $email ) {
@@ -1009,10 +1014,10 @@ add_filter( 'bp_email_get_headers', 'bp_email_set_default_headers', 6, 4 );
1009
  *
1010
  * @since 2.5.0
1011
  *
1012
- * @param array $tokens Email tokens.
1013
- * @param string $property_name Unused.
1014
- * @param string $transform Unused.
1015
- * @param BP_Email $email Email being sent.
1016
  * @return array
1017
  */
1018
  function bp_email_set_default_tokens( $tokens, $property_name, $transform, $email ) {
@@ -1028,7 +1033,6 @@ function bp_email_set_default_tokens( $tokens, $property_name, $transform, $emai
1028
  $tokens['recipient.email'] = '';
1029
  $tokens['recipient.name'] = '';
1030
  $tokens['recipient.username'] = '';
1031
- $tokens['unsubscribe'] = site_url( 'wp-login.php' );
1032
 
1033
 
1034
  // Who is the email going to?
@@ -1045,16 +1049,22 @@ function bp_email_set_default_tokens( $tokens, $property_name, $transform, $emai
1045
  }
1046
 
1047
  if ( $user_obj ) {
1048
- // Unsubscribe link.
1049
- $tokens['unsubscribe'] = esc_url( sprintf(
1050
- '%s%s/notifications/',
1051
- bp_core_get_user_domain( $user_obj->ID ),
1052
- function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings'
1053
- ) );
1054
  $tokens['recipient.username'] = $user_obj->user_login;
 
 
 
 
 
 
 
1055
  }
1056
  }
1057
 
 
 
 
 
 
1058
  // Email preheader.
1059
  $post = $email->get_post_object();
1060
  if ( $post ) {
75
  // Turn comments off for BuddyPress pages.
76
  add_filter( 'comments_open', 'bp_comments_open', 10, 2 );
77
 
78
+ // Prevent DB query for WP's main loop.
79
+ add_filter( 'posts_pre_query', 'bp_core_filter_wp_query', 10, 2 );
80
+
81
  /**
82
  * Prevent specific pages (eg 'Activate') from showing on page listings.
83
  *
178
  foreach ( (array) buddypress()->pages as $component => $bp_page ) {
179
  // Handles the majority of components.
180
  if ( bp_is_current_component( $component ) ) {
181
+ $page_id = (int) $bp_page->id;
182
  }
183
 
184
  // Stop if not on a user page.
311
  *
312
  * @since 1.6.0
313
  *
314
+ * @param bool $value Whether or not to redirect.
315
  * @param string $redirect_to Sanitized URL to be redirected to.
316
  * @param string $redirect_to_raw Unsanitized URL to be redirected to.
317
  * @param WP_User $user The WP_User object corresponding to a
352
  * @param string $retval Current email content.
353
  * @param string $prop Email property to check against.
354
  * @param string $transform Either 'raw' or 'replace-tokens'.
355
+ * @return string $retval Modified email content.
356
  */
357
  function bp_email_plaintext_entity_decode( $retval, $prop, $transform ) {
358
  switch ( $prop ) {
549
  * @see wp_title()
550
  * @global object $bp BuddyPress global settings.
551
  *
552
+ * @param string $title Original page title.
553
+ * @param string $sep How to separate the various items within the page title.
554
+ * @param string $seplocation Direction to display title.
555
  * @return string New page title.
556
  */
557
  function bp_modify_page_title( $title = '', $sep = '&raquo;', $seplocation = 'right' ) {
574
  * @link https://buddypress.trac.wordpress.org/ticket/6107
575
  * @see wp_title()
576
  */
577
+ $title_tag_compatibility = (bool) ( ! empty( $_wp_theme_features['title-tag'] ) || ( $blogname && strstr( $title, $blogname ) ) );
578
 
579
  // Append the site title to title parts if theme supports title tag.
580
  if ( true === $title_tag_compatibility ) {
599
  /**
600
  * Filters the older 'wp_title' page title for BuddyPress pages.
601
  *
602
+ * @since 1.5.0
603
  *
604
+ * @param string $new_title The BuddyPress page title.
605
+ * @param string $title The original WordPress page title.
606
+ * @param string $sep The title parts separator.
607
+ * @param string $seplocation Location of the separator (left or right).
608
  */
609
  return apply_filters( 'bp_modify_page_title', $new_title, $title, $sep, $seplocation );
610
  }
652
  /**
653
  * Filters BuddyPress title parts that will be used into the document title.
654
  *
655
+ * @since 2.4.3
656
  *
657
+ * @param array $bp_title The BuddyPress page title parts.
658
+ * @param array $title The original WordPress title parts.
659
  */
660
  return apply_filters( 'bp_modify_document_title_parts', $bp_title, $title );
661
  }
753
  /**
754
  * Populate BuddyPress user nav items for the customizer.
755
  *
756
+ * @since 2.3.3
757
  *
758
+ * @param array $items The array of menu items.
759
+ * @param string $type The requested type.
760
+ * @param string $object The requested object name.
761
+ * @param integer $page The page num being requested.
762
+ * @return array The paginated BuddyPress user nav items.
763
  */
764
  function bp_customizer_nav_menus_get_items( $items = array(), $type = '', $object = '', $page = 0 ) {
765
  if ( 'bp_loggedin_nav' === $object ) {
790
  /**
791
  * Set BuddyPress item navs for the customizer.
792
  *
793
+ * @since 2.3.3
794
  *
795
+ * @param array $item_types An associative array structured for the customizer.
796
  * @return array $item_types An associative array structured for the customizer.
797
  */
798
  function bp_customizer_nav_menus_set_item_types( $item_types = array() ) {
856
  *
857
  * @since 2.1.0
858
  *
859
+ * @param string $edit_link The edit link.
860
+ * @param int $post_id Post ID.
861
  * @return bool|string Will be a boolean (false) if $post_id is 0. Will be a string (the unchanged edit link)
862
  * otherwise
863
  */
903
  * @access private
904
  *
905
  * @global array $wp_registered_widgets Current registered widgets.
906
+ *
907
+ * @param array $params Current sidebar params.
908
  * @return array
909
  */
910
  function _bp_core_inject_bp_widget_css_class( $params ) {
956
  *
957
  * @since 2.5.0
958
  *
959
+ * @param string $value Property value.
960
+ * @param string $property_name Email template property name.
961
+ * @param string $transform How the return value was transformed.
962
  * @return string Updated value.
963
  */
964
  function bp_email_add_link_color_to_template( $value, $property_name, $transform ) {
995
  *
996
  * @since 2.5.0
997
  *
998
+ * @param array $headers Array of email headers.
999
+ * @param string $property Name of property. Unused.
1000
+ * @param string $transform Return value transformation. Unused.
1001
+ * @param BP_Email $email Email object reference.
1002
  * @return array
1003
  */
1004
  function bp_email_set_default_headers( $headers, $property, $transform, $email ) {
1014
  *
1015
  * @since 2.5.0
1016
  *
1017
+ * @param array $tokens Email tokens.
1018
+ * @param string $property_name Unused.
1019
+ * @param string $transform Unused.
1020
+ * @param BP_Email $email Email being sent.
1021
  * @return array
1022
  */
1023
  function bp_email_set_default_tokens( $tokens, $property_name, $transform, $email ) {
1033
  $tokens['recipient.email'] = '';
1034
  $tokens['recipient.name'] = '';
1035
  $tokens['recipient.username'] = '';
 
1036
 
1037
 
1038
  // Who is the email going to?
1049
  }
1050
 
1051
  if ( $user_obj ) {
 
 
 
 
 
 
1052
  $tokens['recipient.username'] = $user_obj->user_login;
1053
+ if ( bp_is_active( 'settings' ) && empty( $tokens['unsubscribe'] ) ) {
1054
+ $tokens['unsubscribe'] = esc_url( sprintf(
1055
+ '%s%s/notifications/',
1056
+ bp_core_get_user_domain( $user_obj->ID ),
1057
+ bp_get_settings_slug()
1058
+ ) );
1059
+ }
1060
  }
1061
  }
1062
 
1063
+ // Set default unsubscribe link if not passed.
1064
+ if ( empty( $tokens['unsubscribe'] ) ) {
1065
+ $tokens['unsubscribe'] = site_url( 'wp-login.php' );
1066
+ }
1067
+
1068
  // Email preheader.
1069
  $post = $email->get_post_object();
1070
  if ( $post ) {
bp-core/bp-core-functions.php CHANGED
@@ -108,14 +108,23 @@ function bp_core_get_table_prefix() {
108
  * your own awkward callback function for usort().
109
  *
110
  * @since 2.2.0
 
 
 
 
 
 
 
 
111
  *
112
- * @param array $items The items to be sorted. Its constituent items can be either associative arrays or objects.
113
- * @param string|int $key The array index or property name to sort by.
114
- * @param string $type Sort type. 'alpha' for alphabetical, 'num' for numeric. Default: 'alpha'.
115
  * @return array $items The sorted array.
116
  */
117
- function bp_sort_by_key( $items, $key, $type = 'alpha' ) {
118
- usort( $items, array( new BP_Core_Sort_By_Key_Callback( $key, $type ), 'sort_callback' ) );
 
 
 
 
119
 
120
  return $items;
121
  }
@@ -630,14 +639,7 @@ function bp_core_add_page_mappings( $components, $existing = 'keep' ) {
630
  $pages = array();
631
  }
632
 
633
- $page_titles = array(
634
- 'activity' => _x( 'Activity', 'Page title for the Activity directory.', 'buddypress' ),
635
- 'groups' => _x( 'Groups', 'Page title for the Groups directory.', 'buddypress' ),
636
- 'sites' => _x( 'Sites', 'Page title for the Sites directory.', 'buddypress' ),
637
- 'members' => _x( 'Members', 'Page title for the Members directory.', 'buddypress' ),
638
- 'activate' => _x( 'Activate', 'Page title for the user activation screen.', 'buddypress' ),
639
- 'register' => _x( 'Register', 'Page title for the user registration screen.', 'buddypress' ),
640
- );
641
 
642
  $pages_to_create = array();
643
  foreach ( array_keys( $components ) as $component_name ) {
@@ -657,8 +659,8 @@ function bp_core_add_page_mappings( $components, $existing = 'keep' ) {
657
  }
658
 
659
  // No need for a Sites directory unless we're on multisite.
660
- if ( ! is_multisite() && isset( $pages_to_create['sites'] ) ) {
661
- unset( $pages_to_create['sites'] );
662
  }
663
 
664
  // Members must always have a page, no matter what.
@@ -693,6 +695,33 @@ function bp_core_add_page_mappings( $components, $existing = 'keep' ) {
693
  }
694
  }
695
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
696
  /**
697
  * Remove the entry from bp_pages when the corresponding WP page is deleted.
698
  *
@@ -850,11 +879,17 @@ function bp_core_add_illegal_names() {
850
  * Get the 'search' query argument for a given component.
851
  *
852
  * @since 2.4.0
 
 
853
  *
854
- * @param string $component Component name.
855
  * @return string|bool Query argument on success. False on failure.
856
  */
857
- function bp_core_get_component_search_query_arg( $component ) {
 
 
 
 
858
  $query_arg = false;
859
  if ( isset( buddypress()->{$component}->search_query_arg ) ) {
860
  $query_arg = sanitize_title( buddypress()->{$component}->search_query_arg );
@@ -1258,6 +1293,41 @@ function bp_core_time_since( $older_date, $newer_date = false ) {
1258
  return apply_filters( 'bp_core_time_since', $output, $older_date, $newer_date );
1259
  }
1260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1261
  /** Messages ******************************************************************/
1262
 
1263
  /**
@@ -1414,7 +1484,7 @@ function bp_core_record_activity() {
1414
  }
1415
 
1416
  // Get current time.
1417
- $current_time = bp_core_current_time();
1418
 
1419
  // Use this action to detect the very first activity for a given member.
1420
  if ( empty( $activity ) ) {
@@ -1432,8 +1502,8 @@ function bp_core_record_activity() {
1432
  }
1433
 
1434
  // If it's been more than 5 minutes, record a newer last-activity time.
1435
- if ( empty( $activity ) || ( strtotime( $current_time ) >= strtotime( '+5 minutes', $activity ) ) ) {
1436
- bp_update_user_last_activity( $user_id, $current_time );
1437
  }
1438
  }
1439
  add_action( 'wp_head', 'bp_core_record_activity' );
@@ -1673,8 +1743,8 @@ function bp_use_embed_in_private_messages() {
1673
  *
1674
  * @since 2.6.0
1675
  *
1676
- * @param string $content The content to check.
1677
- * @param string|int $type The type to check. Can also use a bitmask. See the class constants in the
1678
  * BP_Media_Extractor class for more info.
1679
  * @return array|bool If media exists, will return array of media metadata. Else, boolean false.
1680
  */
@@ -2691,7 +2761,7 @@ function bp_core_get_suggestions( $args ) {
2691
  *
2692
  * @since 2.3.0
2693
  *
2694
- * @return string
2695
  */
2696
  function bp_upload_dir() {
2697
  $bp = buddypress();
@@ -3189,8 +3259,8 @@ function bp_email_get_template( WP_Post $object ) {
3189
  *
3190
  * @since 2.5.0
3191
  *
3192
- * @param string $text
3193
- * @param array $tokens Token names and replacement values for the $text.
3194
  * @return string
3195
  */
3196
  function bp_core_replace_tokens_in_text( $text, $tokens ) {
@@ -3227,7 +3297,7 @@ function bp_core_replace_tokens_in_text( $text, $tokens ) {
3227
 
3228
  /**
3229
  * Get a list of emails for populating the email post type.
3230
- *t
3231
  * @since 2.5.1
3232
  *
3233
  * @return array
@@ -3304,7 +3374,7 @@ function bp_email_get_schema() {
3304
  /* translators: do not remove {} brackets or translate its contents. */
3305
  'post_content' => __( "Group details for the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot; were updated:\n<blockquote>{{changed_text}}</blockquote>", 'buddypress' ),
3306
  /* translators: do not remove {} brackets or translate its contents. */
3307
- 'post_excerpt' => __( "Group details for the group &quot;{{group.name}}&quot; were updated:\n\n{{changed_text}}\n\nTo view the group, visit: {{{group.url}}}", 'buddypress' ),
3308
  ),
3309
  'groups-invitation' => array(
3310
  /* translators: do not remove {} brackets or translate its contents. */
@@ -3312,7 +3382,7 @@ function bp_email_get_schema() {
3312
  /* translators: do not remove {} brackets or translate its contents. */
3313
  'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: &quot;{{group.name}}&quot;.\n<a href=\"{{{invites.url}}}\">Go here to accept your invitation</a> or <a href=\"{{{group.url}}}\">visit the group</a> to learn more.", 'buddypress' ),
3314
  /* translators: do not remove {} brackets or translate its contents. */
3315
- 'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: &quot;{{group.name}}&quot;.\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
3316
  ),
3317
  'groups-member-promoted' => array(
3318
  /* translators: do not remove {} brackets or translate its contents. */
@@ -3320,7 +3390,7 @@ function bp_email_get_schema() {
3320
  /* translators: do not remove {} brackets or translate its contents. */
3321
  'post_content' => __( "You have been promoted to <b>{{promoted_to}}</b> in the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot;.", 'buddypress' ),
3322
  /* translators: do not remove {} brackets or translate its contents. */
3323
- 'post_excerpt' => __( "You have been promoted to {{promoted_to}} in the group: &quot;{{group.name}}&quot;.\n\nTo visit the group, go to: {{{group.url}}}", 'buddypress' ),
3324
  ),
3325
  'groups-membership-request' => array(
3326
  /* translators: do not remove {} brackets or translate its contents. */
@@ -3328,7 +3398,7 @@ function bp_email_get_schema() {
3328
  /* translators: do not remove {} brackets or translate its contents. */
3329
  'post_content' => __( "<a href=\"{{{profile.url}}}\">{{requesting-user.name}}</a> wants to join the group &quot;{{group.name}}&quot;. As you are an administrator of this group, you must either accept or reject the membership request.\n\n<a href=\"{{{group-requests.url}}}\">Go here to manage this</a> and all other pending requests.", 'buddypress' ),
3330
  /* translators: do not remove {} brackets or translate its contents. */
3331
- 'post_excerpt' => __( "{{requesting-user.name}} wants to join the group &quot;{{group.name}}&quot;. As you are the administrator of this group, you must either accept or reject the membership request.\n\nTo manage this and all other pending requests, visit: {{{group-requests.url}}}\n\nTo view {{requesting-user.name}}'s profile, visit: {{{profile.url}}}", 'buddypress' ),
3332
  ),
3333
  'messages-unread' => array(
3334
  /* translators: do not remove {} brackets or translate its contents. */
@@ -3336,7 +3406,7 @@ function bp_email_get_schema() {
3336
  /* translators: do not remove {} brackets or translate its contents. */
3337
  'post_content' => __( "{{sender.name}} sent you a new message: &quot;{{usersubject}}&quot;\n\n<blockquote>&quot;{{usermessage}}&quot;</blockquote>\n\n<a href=\"{{{message.url}}}\">Go to the discussion</a> to reply or catch up on the conversation.", 'buddypress' ),
3338
  /* translators: do not remove {} brackets or translate its contents. */
3339
- 'post_excerpt' => __( "{{sender.name}} sent you a new message: &quot;{{usersubject}}&quot;\n\n&quot;{{usermessage}}&quot;\n\nGo to the discussion to reply or catch up on the conversation: {{{message.url}}}", 'buddypress' ),
3340
  ),
3341
  'settings-verify-email-change' => array(
3342
  /* translators: do not remove {} brackets or translate its contents. */
@@ -3352,7 +3422,7 @@ function bp_email_get_schema() {
3352
  /* translators: do not remove {} brackets or translate its contents. */
3353
  'post_content' => __( "Your membership request for the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot; has been accepted.", 'buddypress' ),
3354
  /* translators: do not remove {} brackets or translate its contents. */
3355
- 'post_excerpt' => __( "Your membership request for the group &quot;{{group.name}}&quot; has been accepted.\n\nTo view the group, visit: {{{group.url}}}", 'buddypress' ),
3356
  ),
3357
  'groups-membership-request-rejected' => array(
3358
  /* translators: do not remove {} brackets or translate its contents. */
@@ -3360,7 +3430,7 @@ function bp_email_get_schema() {
3360
  /* translators: do not remove {} brackets or translate its contents. */
3361
  'post_content' => __( "Your membership request for the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot; has been rejected.", 'buddypress' ),
3362
  /* translators: do not remove {} brackets or translate its contents. */
3363
- 'post_excerpt' => __( "Your membership request for the group &quot;{{group.name}}&quot; has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ),
3364
  ),
3365
  );
3366
  }
@@ -3369,26 +3439,309 @@ function bp_email_get_schema() {
3369
  * Get a list of emails for populating email type taxonomy terms.
3370
  *
3371
  * @since 2.5.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3372
  *
3373
- * @return array
3374
  */
3375
- function bp_email_get_type_schema() {
3376
- return array(
3377
- 'activity-comment' => __( 'A member has replied to an activity update that the recipient posted.', 'buddypress' ),
3378
- 'activity-comment-author' => __( 'A member has replied to a comment on an activity update that the recipient posted.', 'buddypress' ),
3379
- 'activity-at-message' => __( 'Recipient was mentioned in an activity update.', 'buddypress' ),
3380
- 'groups-at-message' => __( 'Recipient was mentioned in a group activity update.', 'buddypress' ),
3381
- 'core-user-registration' => __( 'Recipient has registered for an account.', 'buddypress' ),
3382
- 'core-user-registration-with-blog' => __( 'Recipient has registered for an account and site.', 'buddypress' ),
3383
- 'friends-request' => __( 'A member has sent a friend request to the recipient.', 'buddypress' ),
3384
- 'friends-request-accepted' => __( 'Recipient has had a friend request accepted by a member.', 'buddypress' ),
3385
- 'groups-details-updated' => __( "A group's details were updated.", 'buddypress' ),
3386
- 'groups-invitation' => __( 'A member has sent a group invitation to the recipient.', 'buddypress' ),
3387
- 'groups-member-promoted' => __( "Recipient's status within a group has changed.", 'buddypress' ),
3388
- 'groups-membership-request' => __( 'A member has requested permission to join a group.', 'buddypress' ),
3389
- 'messages-unread' => __( 'Recipient has received a private message.', 'buddypress' ),
3390
- 'settings-verify-email-change' => __( 'Recipient has changed their email address.', 'buddypress' ),
3391
- 'groups-membership-request-accepted' => __( 'Recipient had requested to join a group, which was accepted.', 'buddypress' ),
3392
- 'groups-membership-request-rejected' => __( 'Recipient had requested to join a group, which was rejected.', 'buddypress' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3393
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3394
  }
108
  * your own awkward callback function for usort().
109
  *
110
  * @since 2.2.0
111
+ * @since 2.7.0 Added $preserve_keys parameter.
112
+ *
113
+ * @param array $items The items to be sorted. Its constituent items
114
+ * can be either associative arrays or objects.
115
+ * @param string|int $key The array index or property name to sort by.
116
+ * @param string $type Sort type. 'alpha' for alphabetical, 'num'
117
+ * for numeric. Default: 'alpha'.
118
+ * @param bool $preserve_keys Whether to keep the keys or not.
119
  *
 
 
 
120
  * @return array $items The sorted array.
121
  */
122
+ function bp_sort_by_key( $items, $key, $type = 'alpha', $preserve_keys = false ) {
123
+ if ( true === $preserve_keys ) {
124
+ uasort( $items, array( new BP_Core_Sort_By_Key_Callback( $key, $type ), 'sort_callback' ) );
125
+ } else {
126
+ usort( $items, array( new BP_Core_Sort_By_Key_Callback( $key, $type ), 'sort_callback' ) );
127
+ }
128
 
129
  return $items;
130
  }
639
  $pages = array();
640
  }
641
 
642
+ $page_titles = bp_core_get_directory_page_default_titles();
 
 
 
 
 
 
 
643
 
644
  $pages_to_create = array();
645
  foreach ( array_keys( $components ) as $component_name ) {
659
  }
660
 
661
  // No need for a Sites directory unless we're on multisite.
662
+ if ( ! is_multisite() && isset( $pages_to_create['blogs'] ) ) {
663
+ unset( $pages_to_create['blogs'] );
664
  }
665
 
666
  // Members must always have a page, no matter what.
695
  }
696
  }
697
 
698
+ /**
699
+ * Get the default page titles for BP directory pages.
700
+ *
701
+ * @since 2.7.0
702
+ *
703
+ * @return array
704
+ */
705
+ function bp_core_get_directory_page_default_titles() {
706
+ $page_default_titles = array(
707
+ 'activity' => _x( 'Activity', 'Page title for the Activity directory.', 'buddypress' ),
708
+ 'groups' => _x( 'Groups', 'Page title for the Groups directory.', 'buddypress' ),
709
+ 'blogs' => _x( 'Sites', 'Page title for the Sites directory.', 'buddypress' ),
710
+ 'members' => _x( 'Members', 'Page title for the Members directory.', 'buddypress' ),
711
+ 'activate' => _x( 'Activate', 'Page title for the user activation screen.', 'buddypress' ),
712
+ 'register' => _x( 'Register', 'Page title for the user registration screen.', 'buddypress' ),
713
+ );
714
+
715
+ /**
716
+ * Filters the default page titles array
717
+ *
718
+ * @since 2.7.0
719
+ *
720
+ * @param array $page_default_titles the array of default WP (post_title) titles.
721
+ */
722
+ return apply_filters( 'bp_core_get_directory_page_default_titles', $page_default_titles );
723
+ }
724
+
725
  /**
726
  * Remove the entry from bp_pages when the corresponding WP page is deleted.
727
  *
879
  * Get the 'search' query argument for a given component.
880
  *
881
  * @since 2.4.0
882
+ * @since 2.7.0 The `$component` parameter was made optional, with the current component
883
+ * as the fallback value.
884
  *
885
+ * @param string $component Optional. Component name. Defaults to current component.
886
  * @return string|bool Query argument on success. False on failure.
887
  */
888
+ function bp_core_get_component_search_query_arg( $component = null ) {
889
+ if ( ! $component ) {
890
+ $component = bp_current_component();
891
+ }
892
+
893
  $query_arg = false;
894
  if ( isset( buddypress()->{$component}->search_query_arg ) ) {
895
  $query_arg = sanitize_title( buddypress()->{$component}->search_query_arg );
1293
  return apply_filters( 'bp_core_time_since', $output, $older_date, $newer_date );
1294
  }
1295
 
1296
+ /**
1297
+ * Output an ISO-8601 date from a date string.
1298
+ *
1299
+ * @since 2.7.0
1300
+ *
1301
+ * @param string String of date to convert. Timezone should be UTC before using this.
1302
+ * @return string
1303
+ */
1304
+ function bp_core_iso8601_date( $timestamp = '' ) {
1305
+ echo bp_core_get_iso8601_date( $timestamp );
1306
+ }
1307
+ /**
1308
+ * Return an ISO-8601 date from a date string.
1309
+ *
1310
+ * @since 2.7.0
1311
+ *
1312
+ * @param string String of date to convert. Timezone should be UTC before using this.
1313
+ * @return string
1314
+ */
1315
+ function bp_core_get_iso8601_date( $timestamp = '' ) {
1316
+ if ( ! $timestamp ) {
1317
+ return '';
1318
+ }
1319
+
1320
+ try {
1321
+ $date = new DateTime( $timestamp, new DateTimeZone( 'UTC' ) );
1322
+
1323
+ // Not a valid date, so return blank string.
1324
+ } catch( Exception $e ) {
1325
+ return '';
1326
+ }
1327
+
1328
+ return $date->format( DateTime::ISO8601 );
1329
+ }
1330
+
1331
  /** Messages ******************************************************************/
1332
 
1333
  /**
1484
  }
1485
 
1486
  // Get current time.
1487
+ $current_time = bp_core_current_time( true, 'timestamp' );
1488
 
1489
  // Use this action to detect the very first activity for a given member.
1490
  if ( empty( $activity ) ) {
1502
  }
1503
 
1504
  // If it's been more than 5 minutes, record a newer last-activity time.
1505
+ if ( empty( $activity ) || ( $current_time >= strtotime( '+5 minutes', $activity ) ) ) {
1506
+ bp_update_user_last_activity( $user_id, date( 'Y-m-d H:i:s', $current_time ) );
1507
  }
1508
  }
1509
  add_action( 'wp_head', 'bp_core_record_activity' );
1743
  *
1744
  * @since 2.6.0
1745
  *
1746
+ * @param string $content The content to check.
1747
+ * @param string|int $type The type to check. Can also use a bitmask. See the class constants in the
1748
  * BP_Media_Extractor class for more info.
1749
  * @return array|bool If media exists, will return array of media metadata. Else, boolean false.
1750
  */
2761
  *
2762
  * @since 2.3.0
2763
  *
2764
+ * @return bool|array
2765
  */
2766
  function bp_upload_dir() {
2767
  $bp = buddypress();
3259
  *
3260
  * @since 2.5.0
3261
  *
3262
+ * @param string $text Text to replace tokens in.
3263
+ * @param array $tokens Token names and replacement values for the $text.
3264
  * @return string
3265
  */
3266
  function bp_core_replace_tokens_in_text( $text, $tokens ) {
3297
 
3298
  /**
3299
  * Get a list of emails for populating the email post type.
3300
+ *
3301
  * @since 2.5.1
3302
  *
3303
  * @return array
3374
  /* translators: do not remove {} brackets or translate its contents. */
3375
  'post_content' => __( "Group details for the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot; were updated:\n<blockquote>{{changed_text}}</blockquote>", 'buddypress' ),
3376
  /* translators: do not remove {} brackets or translate its contents. */
3377
+ 'post_excerpt' => __( "Group details for the group \"{{group.name}}\" were updated:\n\n{{changed_text}}\n\nTo view the group, visit: {{{group.url}}}", 'buddypress' ),
3378
  ),
3379
  'groups-invitation' => array(
3380
  /* translators: do not remove {} brackets or translate its contents. */
3382
  /* translators: do not remove {} brackets or translate its contents. */
3383
  'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: &quot;{{group.name}}&quot;.\n<a href=\"{{{invites.url}}}\">Go here to accept your invitation</a> or <a href=\"{{{group.url}}}\">visit the group</a> to learn more.", 'buddypress' ),
3384
  /* translators: do not remove {} brackets or translate its contents. */
3385
+ 'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: \"{{group.name}}\".\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
3386
  ),
3387
  'groups-member-promoted' => array(
3388
  /* translators: do not remove {} brackets or translate its contents. */
3390
  /* translators: do not remove {} brackets or translate its contents. */
3391
  'post_content' => __( "You have been promoted to <b>{{promoted_to}}</b> in the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot;.", 'buddypress' ),
3392
  /* translators: do not remove {} brackets or translate its contents. */
3393
+ 'post_excerpt' => __( "You have been promoted to {{promoted_to}} in the group: \"{{group.name}}\".\n\nTo visit the group, go to: {{{group.url}}}", 'buddypress' ),
3394
  ),
3395
  'groups-membership-request' => array(
3396
  /* translators: do not remove {} brackets or translate its contents. */
3398
  /* translators: do not remove {} brackets or translate its contents. */
3399
  'post_content' => __( "<a href=\"{{{profile.url}}}\">{{requesting-user.name}}</a> wants to join the group &quot;{{group.name}}&quot;. As you are an administrator of this group, you must either accept or reject the membership request.\n\n<a href=\"{{{group-requests.url}}}\">Go here to manage this</a> and all other pending requests.", 'buddypress' ),
3400
  /* translators: do not remove {} brackets or translate its contents. */
3401
+ 'post_excerpt' => __( "{{requesting-user.name}} wants to join the group \"{{group.name}}\". As you are the administrator of this group, you must either accept or reject the membership request.\n\nTo manage this and all other pending requests, visit: {{{group-requests.url}}}\n\nTo view {{requesting-user.name}}'s profile, visit: {{{profile.url}}}", 'buddypress' ),
3402
  ),
3403
  'messages-unread' => array(
3404
  /* translators: do not remove {} brackets or translate its contents. */
3406
  /* translators: do not remove {} brackets or translate its contents. */
3407
  'post_content' => __( "{{sender.name}} sent you a new message: &quot;{{usersubject}}&quot;\n\n<blockquote>&quot;{{usermessage}}&quot;</blockquote>\n\n<a href=\"{{{message.url}}}\">Go to the discussion</a> to reply or catch up on the conversation.", 'buddypress' ),
3408
  /* translators: do not remove {} brackets or translate its contents. */
3409
+ 'post_excerpt' => __( "{{sender.name}} sent you a new message: \"{{usersubject}}\"\n\n\"{{usermessage}}\"\n\nGo to the discussion to reply or catch up on the conversation: {{{message.url}}}", 'buddypress' ),
3410
  ),
3411
  'settings-verify-email-change' => array(
3412
  /* translators: do not remove {} brackets or translate its contents. */
3422
  /* translators: do not remove {} brackets or translate its contents. */
3423
  'post_content' => __( "Your membership request for the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot; has been accepted.", 'buddypress' ),
3424
  /* translators: do not remove {} brackets or translate its contents. */
3425
+ 'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been accepted.\n\nTo view the group, visit: {{{group.url}}}", 'buddypress' ),
3426
  ),
3427
  'groups-membership-request-rejected' => array(
3428
  /* translators: do not remove {} brackets or translate its contents. */
3430
  /* translators: do not remove {} brackets or translate its contents. */
3431
  'post_content' => __( "Your membership request for the group &quot;<a href=\"{{{group.url}}}\">{{group.name}}</a>&quot; has been rejected.", 'buddypress' ),
3432
  /* translators: do not remove {} brackets or translate its contents. */
3433
+ 'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ),
3434
  ),
3435
  );
3436
  }
3439
  * Get a list of emails for populating email type taxonomy terms.
3440
  *
3441
  * @since 2.5.1
3442
+ * @since 2.7.0 $field argument added.
3443
+ *
3444
+ * @param string $field Optional; defaults to "description" for backwards compatibility. Other values: "all".
3445
+ * @return array {
3446
+ * The array of email types and their schema.
3447
+ *
3448
+ * @type string $description The description of the action which causes this to trigger.
3449
+ * @type array $unsubscribe {
3450
+ * Replacing this with false indicates that a user cannot unsubscribe from this type.
3451
+ *
3452
+ * @type string $meta_key The meta_key used to toggle the email setting for this notification.
3453
+ * @type string $message The message shown when the user has successfully unsubscribed.
3454
+ * }
3455
+ */
3456
+ function bp_email_get_type_schema( $field = 'description' ) {
3457
+ $activity_comment = array(
3458
+ 'description' => __( 'A member has replied to an activity update that the recipient posted.', 'buddypress' ),
3459
+ 'unsubscribe' => array(
3460
+ 'meta_key' => 'notification_activity_new_reply',
3461
+ 'message' => __( 'You will no longer receive emails when someone replies to an update or comment you posted.', 'buddypress' ),
3462
+ ),
3463
+ );
3464
+
3465
+ $activity_comment_author = array(
3466
+ 'description' => __( 'A member has replied to a comment on an activity update that the recipient posted.', 'buddypress' ),
3467
+ 'unsubscribe' => array(
3468
+ 'meta_key' => 'notification_activity_new_reply',
3469
+ 'message' => __( 'You will no longer receive emails when someone replies to an update or comment you posted.', 'buddypress' ),
3470
+ ),
3471
+ );
3472
+
3473
+ $activity_at_message = array(
3474
+ 'description' => __( 'Recipient was mentioned in an activity update.', 'buddypress' ),
3475
+ 'unsubscribe' => array(
3476
+ 'meta_key' => 'notification_activity_new_mention',
3477
+ 'message' => __( 'You will no longer receive emails when someone mentions you in an update.', 'buddypress' ),
3478
+ ),
3479
+ );
3480
+
3481
+ $groups_at_message = array(
3482
+ 'description' => __( 'Recipient was mentioned in a group activity update.', 'buddypress' ),
3483
+ 'unsubscribe' => array(
3484
+ 'meta_key' => 'notification_activity_new_mention',
3485
+ 'message' => __( 'You will no longer receive emails when someone mentions you in an update.', 'buddypress' ),
3486
+ ),
3487
+ );
3488
+
3489
+ $core_user_registration = array(
3490
+ 'description' => __( 'Recipient has registered for an account.', 'buddypress' ),
3491
+ 'unsubscribe' => false,
3492
+ );
3493
+
3494
+ $core_user_registration_with_blog = array(
3495
+ 'description' => __( 'Recipient has registered for an account and site.', 'buddypress' ),
3496
+ 'unsubscribe' => false,
3497
+ );
3498
+
3499
+ $friends_request = array(
3500
+ 'description' => __( 'A member has sent a friend request to the recipient.', 'buddypress' ),
3501
+ 'unsubscribe' => array(
3502
+ 'meta_key' => 'notification_friends_friendship_request',
3503
+ 'message' => __( 'You will no longer receive emails when someone sends you a friend request.', 'buddypress' ),
3504
+ ),
3505
+ );
3506
+
3507
+ $friends_request_accepted = array(
3508
+ 'description' => __( 'Recipient has had a friend request accepted by a member.', 'buddypress' ),
3509
+ 'unsubscribe' => array(
3510
+ 'meta_key' => 'notification_friends_friendship_accepted',
3511
+ 'message' => __( 'You will no longer receive emails when someone accepts your friendship request.', 'buddypress' ),
3512
+ ),
3513
+ );
3514
+
3515
+ $groups_details_updated = array(
3516
+ 'description' => __( "A group's details were updated.", 'buddypress' ),
3517
+ 'unsubscribe' => array(
3518
+ 'meta_key' => 'notification_groups_group_updated',
3519
+ 'message' => __( 'You will no longer receive emails when one of your groups is updated.', 'buddypress' ),
3520
+ ),
3521
+ );
3522
+
3523
+ $groups_details_updated = array(
3524
+ 'description' => __( "A group's details were updated.", 'buddypress' ),
3525
+ 'unsubscribe' => array(
3526
+ 'meta_key' => 'notification_groups_group_updated',
3527
+ 'message' => __( 'You will no longer receive emails when one of your groups is updated.', 'buddypress' ),
3528
+ ),
3529
+ );
3530
+
3531
+ $groups_invitation = array(
3532
+ 'description' => __( 'A member has sent a group invitation to the recipient.', 'buddypress' ),
3533
+ 'unsubscribe' => array(
3534
+ 'meta_key' => 'notification_groups_invite',
3535
+ 'message' => __( 'You will no longer receive emails when you are invited to join a group.', 'buddypress' ),
3536
+ ),
3537
+ );
3538
+
3539
+ $groups_member_promoted = array(
3540
+ 'description' => __( "Recipient's status within a group has changed.", 'buddypress' ),
3541
+ 'unsubscribe' => array(
3542
+ 'meta_key' => 'notification_groups_admin_promotion',
3543
+ 'message' => __( 'You will no longer receive emails when you have been promoted in a group.', 'buddypress' ),
3544
+ ),
3545
+ );
3546
+
3547
+ $groups_member_promoted = array(
3548
+ 'description' => __( "Recipient's status within a group has changed.", 'buddypress' ),
3549
+ 'unsubscribe' => array(
3550
+ 'meta_key' => 'notification_groups_admin_promotion',
3551
+ 'message' => __( 'You will no longer receive emails when you have been promoted in a group.', 'buddypress' ),
3552
+ ),
3553
+ );
3554
+
3555
+ $groups_membership_request = array(
3556
+ 'description' => __( 'A member has requested permission to join a group.', 'buddypress' ),
3557
+ 'unsubscribe' => array(
3558
+ 'meta_key' => 'notification_groups_membership_request',
3559
+ 'message' => __( 'You will no longer receive emails when someone requests to be a member of your group.', 'buddypress' ),
3560
+ ),
3561
+ );
3562
+
3563
+ $messages_unread = array(
3564
+ 'description' => __( 'Recipient has received a private message.', 'buddypress' ),
3565
+ 'unsubscribe' => array(
3566
+ 'meta_key' => 'notification_messages_new_message',
3567
+ 'message' => __( 'You will no longer receive emails when someone sends you a message.', 'buddypress' ),
3568
+ ),
3569
+ );
3570
+
3571
+ $settings_verify_email_change = array(
3572
+ 'description' => __( 'Recipient has changed their email address.', 'buddypress' ),
3573
+ 'unsubscribe' => false,
3574
+ );
3575
+
3576
+ $groups_membership_request_accepted = array(
3577
+ 'description' => __( 'Recipient had requested to join a group, which was accepted.', 'buddypress' ),
3578
+ 'unsubscribe' => array(
3579
+ 'meta_key' => 'notification_membership_request_completed',
3580
+ 'message' => __( 'You will no longer receive emails when your request to join a group has been accepted or denied.', 'buddypress' ),
3581
+ ),
3582
+ );
3583
+
3584
+ $groups_membership_request_rejected = array(
3585
+ 'description' => __( 'Recipient had requested to join a group, which was rejected.', 'buddypress' ),
3586
+ 'unsubscribe' => array(
3587
+ 'meta_key' => 'notification_membership_request_completed',
3588
+ 'message' => __( 'You will no longer receive emails when your request to join a group has been accepted or denied.', 'buddypress' ),
3589
+ ),
3590
+ );
3591
+
3592
+ $types = array(
3593
+ 'activity-comment' => $activity_comment,
3594
+ 'activity-comment-author' => $activity_comment_author,
3595
+ 'activity-at-message' => $activity_at_message,
3596
+ 'groups-at-message' => $groups_at_message,
3597
+ 'core-user-registration' => $core_user_registration,
3598
+ 'core-user-registration-with-blog' => $core_user_registration_with_blog,
3599
+ 'friends-request' => $friends_request,
3600
+ 'friends-request-accepted' => $friends_request_accepted,
3601
+ 'groups-details-updated' => $groups_details_updated,
3602
+ 'groups-invitation' => $groups_invitation,
3603
+ 'groups-member-promoted' => $groups_member_promoted,
3604
+ 'groups-membership-request' => $groups_membership_request,
3605
+ 'messages-unread' => $messages_unread,
3606
+ 'settings-verify-email-change' => $settings_verify_email_change,
3607
+ 'groups-membership-request-accepted' => $groups_membership_request_accepted,
3608
+ 'groups-membership-request-rejected' => $groups_membership_request_rejected,
3609
+ );
3610
+
3611
+ if ( $field !== 'all' ) {
3612
+ return wp_list_pluck( $types, $field );
3613
+ } else {
3614
+ return $types;
3615
+ }
3616
+ }
3617
+
3618
+ /**
3619
+ * Handles unsubscribing user from notification emails.
3620
  *
3621
+ * @since 2.7.0
3622
  */
3623
+ function bp_email_unsubscribe_handler() {
3624
+ $emails = bp_email_get_type_schema( 'all' );
3625
+ $raw_email_type = ! empty( $_GET['nt'] ) ? $_GET['nt'] : '';
3626
+ $raw_hash = ! empty( $_GET['nh'] ) ? $_GET['nh'] : '';
3627
+ $raw_user_id = ! empty( $_GET['uid'] ) ? absint( $_GET['uid'] ) : 0;
3628
+ $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() );
3629
+
3630
+ // Check required values.
3631
+ if ( ! $raw_user_id || ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) {
3632
+ $redirect_to = site_url( 'wp-login.php' );
3633
+ $result_msg = __( 'Something has gone wrong.', 'buddypress' );
3634
+ $unsub_msg = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' );
3635
+
3636
+ // Check valid hash.
3637
+ } elseif ( ! hash_equals( $new_hash, $raw_hash ) ) {
3638
+ $redirect_to = site_url( 'wp-login.php' );
3639
+ $result_msg = __( 'Something has gone wrong.', 'buddypress' );
3640
+ $unsub_msg = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' );
3641
+
3642
+ // Don't let authenticated users unsubscribe other users' email notifications.
3643
+ } elseif ( is_user_logged_in() && get_current_user_id() !== $raw_user_id ) {
3644
+ $result_msg = __( 'Something has gone wrong.', 'buddypress' );
3645
+ $unsub_msg = __( 'Please go to your notifications settings to unsubscribe from emails.', 'buddypress' );
3646
+
3647
+ if ( bp_is_active( 'settings' ) ) {
3648
+ $redirect_to = sprintf(
3649
+ '%s%s/notifications/',
3650
+ bp_core_get_user_domain( get_current_user_id() ),
3651
+ bp_get_settings_slug()
3652
+ );
3653
+ } else {
3654
+ $redirect_to = bp_core_get_user_domain( get_current_user_id() );
3655
+ }
3656
+
3657
+ } else {
3658
+ if ( bp_is_active( 'settings' ) ) {
3659
+ $redirect_to = sprintf(
3660
+ '%s%s/notifications/',
3661
+ bp_core_get_user_domain( $raw_user_id ),
3662
+ bp_get_settings_slug()
3663
+ );
3664
+ } else {
3665
+ $redirect_to = bp_core_get_user_domain( $raw_user_id );
3666
+ }
3667
+
3668
+ // Unsubscribe.
3669
+ $meta_key = $emails[ $raw_email_type ]['unsubscribe']['meta_key'];
3670
+ bp_update_user_meta( $raw_user_id, $meta_key, 'no' );
3671
+
3672
+ $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message'];
3673
+ $unsub_msg = __( 'You can change this or any other email notification preferences in your email settings.', 'buddypress' );
3674
+ }
3675
+
3676
+ $message = sprintf(
3677
+ '%1$s <a href="%2$s">%3$s</a>',
3678
+ $result_msg,
3679
+ esc_url( $redirect_to ),
3680
+ esc_html( $unsub_msg )
3681
+ );
3682
+
3683
+ bp_core_add_message( $message );
3684
+ bp_core_redirect( bp_core_get_user_domain( $raw_user_id ) );
3685
+
3686
+ exit;
3687
+ }
3688
+
3689
+ /**
3690
+ * Creates unsubscribe link for notification emails.
3691
+ *
3692
+ * @since 2.7.0
3693
+ *
3694
+ * @param string $redirect_to The URL to which the unsubscribe query string is appended.
3695
+ * @param array $args {
3696
+ * Used to build unsubscribe query string.
3697
+ *
3698
+ * @type string $notification_type Which notification type is being sent.
3699
+ * @type string $user_id The ID of the user to whom the notification is sent.
3700
+ * @type string $redirect_to Optional. The url to which the user will be redirected. Default is the activity directory.
3701
+ * }
3702
+ * @return string The unsubscribe link.
3703
+ */
3704
+ function bp_email_get_unsubscribe_link( $args ) {
3705
+ $emails = bp_email_get_type_schema( 'all' );
3706
+
3707
+ if ( empty( $args['notification_type'] ) || ! array_key_exists( $args['notification_type'], $emails ) ) {
3708
+ return site_url( 'wp-login.php' );
3709
+ }
3710
+
3711
+ $email_type = $args['notification_type'];
3712
+ $redirect_to = ! empty( $args['redirect_to'] ) ? $args['redirect_to'] : site_url();
3713
+ $user_id = (int) $args['user_id'];
3714
+
3715
+ // Bail out if the activity type is not un-unsubscribable.
3716
+ if ( empty( $emails[ $email_type ]['unsubscribe'] ) ) {
3717
+ return '';
3718
+ }
3719
+
3720
+ $link = add_query_arg(
3721
+ array(
3722
+ 'action' => 'unsubscribe',
3723
+ 'nh' => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ),
3724
+ 'nt' => $args['notification_type'],
3725
+ 'uid' => $user_id,
3726
+ ),
3727
+ $redirect_to
3728
  );
3729
+
3730
+ /**
3731
+ * Filters the unsubscribe link.
3732
+ *
3733
+ * @since 2.7.0
3734
+ */
3735
+ return apply_filters( 'bp_email_get_link', $link, $redirect_to, $args );
3736
+ }
3737
+
3738
+ /**
3739
+ * Get a persistent salt for email unsubscribe links.
3740
+ *
3741
+ * @since 2.7.0
3742
+ *
3743
+ * @return string|null Returns null if value isn't set, otherwise string.
3744
+ */
3745
+ function bp_email_get_salt() {
3746
+ return bp_get_option( 'bp-emails-unsubscribe-salt', null );
3747
  }
bp-core/bp-core-loader.php CHANGED
@@ -18,11 +18,9 @@ if ( ! buddypress()->do_autoload ) {
18
  }
19
 
20
  /**
21
- * Set up the BuddyPress Core component.
22
  *
23
  * @since 1.6.0
24
- *
25
- * @global BuddyPress $bp BuddyPress global settings object.
26
  */
27
  function bp_setup_core() {
28
  buddypress()->core = new BP_Core();
18
  }
19
 
20
  /**
21
+ * Set up the bp-core component.
22
  *
23
  * @since 1.6.0
 
 
24
  */
25
  function bp_setup_core() {
26
  buddypress()->core = new BP_Core();
bp-core/bp-core-options.php CHANGED
@@ -13,6 +13,9 @@ defined( 'ABSPATH' ) || exit;
13
  /**
14
  * Get the default site options and their values.
15
  *
 
 
 
16
  * @since 1.6.0
17
  *
18
  * @return array Filtered option names and values.
@@ -73,6 +76,9 @@ function bp_get_default_options() {
73
  // The ID for the current theme package.
74
  '_bp_theme_package_id' => 'legacy',
75
 
 
 
 
76
  /* Groups ************************************************************/
77
 
78
  // @todo Move this into the groups component
@@ -94,11 +100,14 @@ function bp_get_default_options() {
94
  // Force the BuddyBar.
95
  '_bp_force_buddybar' => false,
96
 
97
- /* Legacy theme *********************************************/
98
 
99
  // Whether to register the bp-default themes directory.
100
  '_bp_retain_bp_default' => false,
101
 
 
 
 
102
  /* Widgets **************************************************/
103
  'widget_bp_core_login_widget' => false,
104
  'widget_bp_core_members_widget' => false,
@@ -125,7 +134,6 @@ function bp_get_default_options() {
125
  * Non-destructive, so existing settings will not be overridden.
126
  *
127
  * @since 1.6.0
128
- *
129
  */
130
  function bp_add_options() {
131
 
@@ -156,7 +164,6 @@ function bp_add_options() {
156
  * Currently unused.
157
  *
158
  * @since 1.6.0
159
- *
160
  */
161
  function bp_delete_options() {
162
 
@@ -184,7 +191,6 @@ function bp_delete_options() {
184
  * Currently unused.
185
  *
186
  * @since 1.6.0
187
- *
188
  */
189
  function bp_setup_option_filters() {
190
 
@@ -411,61 +417,16 @@ function bp_core_get_root_options() {
411
  $root_blog_options_meta = array_merge( $root_blog_options_meta, $network_options_meta );
412
  }
413
 
414
- // Missing some options, so do some one-time fixing.
415
- if ( empty( $root_blog_options_meta ) || ( count( $root_blog_options_meta ) < count( $root_blog_option_keys ) ) ) {
416
-
417
- // Get a list of the keys that are already populated.
418
- $existing_options = array();
419
- foreach( $root_blog_options_meta as $already_option ) {
420
- $existing_options[$already_option->name] = $already_option->value;
421
- }
422
-
423
- // Unset the query - We'll be resetting it soon.
424
- unset( $root_blog_options_meta );
425
-
426
- // Loop through options.
427
- foreach ( $root_blog_options as $old_meta_key => $old_meta_default ) {
428
-
429
- if ( isset( $existing_options[$old_meta_key] ) ) {
430
- continue;
431
- }
432
-
433
- // Get old site option.
434
- if ( is_multisite() ) {
435
- $old_meta_value = get_site_option( $old_meta_key );
436
- }
437
-
438
- // No site option so look in root blog.
439
- if ( empty( $old_meta_value ) ) {
440
- $old_meta_value = bp_get_option( $old_meta_key, $old_meta_default );
441
- }
442
-
443
- // Update the root blog option.
444
- bp_update_option( $old_meta_key, $old_meta_value );
445
-
446
- // Update the global array.
447
- $root_blog_options_meta[$old_meta_key] = $old_meta_value;
448
-
449
- // Clear out the value for the next time around.
450
- unset( $old_meta_value );
451
- }
452
-
453
- $root_blog_options_meta = array_merge( $root_blog_options_meta, $existing_options );
454
- unset( $existing_options );
455
-
456
- // We're all matched up.
457
- } else {
458
- // Loop through our results and make them usable.
459
- foreach ( $root_blog_options_meta as $root_blog_option ) {
460
- $root_blog_options[$root_blog_option->name] = $root_blog_option->value;
461
- }
462
 
463
- // Copy the options no the return val.
464
- $root_blog_options_meta = $root_blog_options;
465
 
466
- // Clean up our temporary copy.
467
- unset( $root_blog_options );
468
- }
469
 
470
  wp_cache_set( 'root_blog_options', $root_blog_options_meta, 'bp' );
471
  }
@@ -489,7 +450,7 @@ function bp_core_get_root_options() {
489
  *
490
  * @since 2.3.0
491
  *
492
- * @param string $option Name of the option key.
493
  * @return mixed Value, if found.
494
  */
495
  function bp_core_get_root_option( $option ) {
@@ -754,7 +715,6 @@ function bp_group_forums_root_id( $default = '0' ) {
754
  *
755
  * @since 1.6.0
756
  *
757
- *
758
  * @param bool|string $default Optional. Default: '0'.
759
  * @return int The ID of the group forums root forum.
760
  */
13
  /**
14
  * Get the default site options and their values.
15
  *
16
+ * Default values should not be set by calls to `get_option()` or `get_site_option()` due to
17
+ * these causing load order problems with `bp_core_clear_root_options_cache()`; see #BP7227.
18
+ *
19
  * @since 1.6.0
20
  *
21
  * @return array Filtered option names and values.
76
  // The ID for the current theme package.
77
  '_bp_theme_package_id' => 'legacy',
78
 
79
+ // Email unsubscribe salt.
80
+ 'bp-emails-unsubscribe-salt' => '',
81
+
82
  /* Groups ************************************************************/
83
 
84
  // @todo Move this into the groups component
100
  // Force the BuddyBar.
101
  '_bp_force_buddybar' => false,
102
 
103
+ /* Legacy *********************************************/
104
 
105
  // Whether to register the bp-default themes directory.
106
  '_bp_retain_bp_default' => false,
107
 
108
+ // Whether to load deprecated code.
109
+ '_bp_ignore_deprecated_code' => true,
110
+
111
  /* Widgets **************************************************/
112
  'widget_bp_core_login_widget' => false,
113
  'widget_bp_core_members_widget' => false,
134
  * Non-destructive, so existing settings will not be overridden.
135
  *
136
  * @since 1.6.0
 
137
  */
138
  function bp_add_options() {
139
 
164
  * Currently unused.
165
  *
166
  * @since 1.6.0
 
167
  */
168
  function bp_delete_options() {
169
 
191
  * Currently unused.
192
  *
193
  * @since 1.6.0
 
194
  */
195
  function bp_setup_option_filters() {
196
 
417
  $root_blog_options_meta = array_merge( $root_blog_options_meta, $network_options_meta );
418
  }
419
 
420
+ // Loop through our results and make them usable.
421
+ foreach ( $root_blog_options_meta as $root_blog_option ) {
422
+ $root_blog_options[$root_blog_option->name] = $root_blog_option->value;
423
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
 
425
+ // Copy the options no the return val.
426
+ $root_blog_options_meta = $root_blog_options;
427
 
428
+ // Clean up our temporary copy.
429
+ unset( $root_blog_options );
 
430
 
431
  wp_cache_set( 'root_blog_options', $root_blog_options_meta, 'bp' );
432
  }
450
  *
451
  * @since 2.3.0
452
  *
453
+ * @param string $option Name of the option key.
454
  * @return mixed Value, if found.
455
  */
456
  function bp_core_get_root_option( $option ) {
715
  *
716
  * @since 1.6.0
717
  *
 
718
  * @param bool|string $default Optional. Default: '0'.
719
  * @return int The ID of the group forums root forum.
720
  */
bp-core/bp-core-taxonomy.php CHANGED
@@ -21,7 +21,7 @@ defined( 'ABSPATH' ) || exit;
21
  */
22
  function bp_register_default_taxonomies() {
23
  // Member Type.
24
- register_taxonomy( 'bp_member_type', 'user', array(
25
  'public' => false,
26
  ) );
27
 
@@ -51,6 +51,7 @@ add_action( 'bp_register_taxonomies', 'bp_register_default_taxonomies' );
51
  *
52
  * @since 2.6.0
53
  *
 
54
  * @return int
55
  */
56
  function bp_get_taxonomy_term_site_id( $taxonomy = '' ) {
@@ -61,8 +62,8 @@ function bp_get_taxonomy_term_site_id( $taxonomy = '' ) {
61
  *
62
  * @since 2.6.0
63
  *
64
- * @param int $site_id
65
- * @param string $taxonomy
66
  */
67
  return (int) apply_filters( 'bp_get_taxonomy_term_site_id', $site_id, $taxonomy );
68
  }
@@ -90,13 +91,25 @@ function bp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) {
90
  $switched = true;
91
  }
92
 
93
- $retval = wp_set_object_terms( $object_id, $terms, $taxonomy, $append );
94
 
95
  if ( $switched ) {
96
  restore_current_blog();
97
  }
98
 
99
- return $retval;
 
 
 
 
 
 
 
 
 
 
 
 
100
  }
101
 
102
  /**
@@ -167,5 +180,100 @@ function bp_remove_object_terms( $object_id, $terms, $taxonomy ) {
167
  restore_current_blog();
168
  }
169
 
 
 
 
 
 
 
 
 
 
 
 
170
  return $retval;
171
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  */
22
  function bp_register_default_taxonomies() {
23
  // Member Type.
24
+ register_taxonomy( bp_get_member_type_tax_name(), 'user', array(
25
  'public' => false,
26
  ) );
27
 
51
  *
52
  * @since 2.6.0
53
  *
54
+ * @param string $taxonomy Taxonomy slug to check for.
55
  * @return int
56
  */
57
  function bp_get_taxonomy_term_site_id( $taxonomy = '' ) {
62
  *
63
  * @since 2.6.0
64
  *
65
+ * @param int $site_id Site ID to cehck for.
66
+ * @param string $taxonomy Taxonomy slug to check for.
67
  */
68
  return (int) apply_filters( 'bp_get_taxonomy_term_site_id', $site_id, $taxonomy );
69
  }
91
  $switched = true;
92
  }
93
 
94
+ $tt_ids = wp_set_object_terms( $object_id, $terms, $taxonomy, $append );
95
 
96
  if ( $switched ) {
97
  restore_current_blog();
98
  }
99
 
100
+ /**
101
+ * Fires when taxonomy terms have been set on BuddyPress objects.
102
+ *
103
+ * @since 2.7.0
104
+ *
105
+ * @param int $object_id Object ID.
106
+ * @param array $terms Term or terms to remove.
107
+ * @param array $tt_ids Array of term taxonomy IDs.
108
+ * @param string $taxonomy Taxonomy name.
109
+ */
110
+ do_action( 'bp_set_object_terms', $object_id, $terms, $tt_ids, $taxonomy );
111
+
112
+ return $tt_ids;
113
  }
114
 
115
  /**
180
  restore_current_blog();
181
  }
182
 
183
+ /**
184
+ * Fires when taxonomy terms have been removed from BuddyPress objects.
185
+ *
186
+ * @since 2.7.0
187
+ *
188
+ * @param int $object_id Object ID.
189
+ * @param array $terms Term or terms to remove.
190
+ * @param string $taxonomy Taxonomy name.
191
+ */
192
+ do_action( 'bp_remove_object_terms', $object_id, $terms, $taxonomy );
193
+
194
  return $retval;
195
  }
196
+
197
+ /**
198
+ * Retrieve IDs of objects in valid taxonomies and terms for BuddyPress-related taxonomies.
199
+ *
200
+ * Note that object IDs are from the `bp_get_taxonomy_term_site_id()`, which on some
201
+ * multisite configurations may not be the same as the current site.
202
+ *
203
+ * @since 2.7.0
204
+ *
205
+ * @see get_objects_in_term() for a full description of function and parameters.
206
+ *
207
+ * @param int|array $term_ids Term id or array of term ids of terms that will be used.
208
+ * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
209
+ * @param array|string $args Change the order of the object_ids, either ASC or DESC.
210
+ *
211
+ * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success,
212
+ * the array can be empty, meaning that there are no $object_ids found. When
213
+ * object IDs are found, an array of those IDs will be returned.
214
+ */
215
+ function bp_get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
216
+ // Different taxonomies may be stored on different sites.
217
+ $taxonomy_site_map = array();
218
+ foreach ( (array) $taxonomies as $taxonomy ) {
219
+ $taxonomy_site_id = bp_get_taxonomy_term_site_id( $taxonomy );
220
+ $taxonomy_site_map[ $taxonomy_site_id ][] = $taxonomy;
221
+ }
222
+
223
+ $retval = array();
224
+ foreach ( $taxonomy_site_map as $taxonomy_site_id => $site_taxonomies ) {
225
+ $switched = false;
226
+ if ( $taxonomy_site_id !== get_current_blog_id() ) {
227
+ switch_to_blog( $taxonomy_site_id );
228
+ bp_register_taxonomies();
229
+ $switched = true;
230
+ }
231
+
232
+ $site_objects = get_objects_in_term( $term_ids, $site_taxonomies, $args );
233
+ $retval = array_merge( $retval, $site_objects );
234
+
235
+ if ( $switched ) {
236
+ restore_current_blog();
237
+ }
238
+ }
239
+
240
+ return $retval;
241
+ }
242
+
243
+ /**
244
+ * Get term data for terms in BuddyPress taxonomies.
245
+ *
246
+ * Note that term data is from the `bp_get_taxonomy_term_site_id()`, which on some
247
+ * multisite configurations may not be the same as the current site.
248
+ *
249
+ * @since 2.7.0
250
+ *
251
+ * @see get_term_by() for a full description of function and parameters.
252
+ *
253
+ * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
254
+ * @param string|int $value Search for this term value
255
+ * @param string $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
256
+ * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
257
+ * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
258
+ *
259
+ * @return WP_Term|bool WP_Term instance on success. Will return false if `$taxonomy` does not exist
260
+ * or `$term` was not found.
261
+ */
262
+ function bp_get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
263
+ $site_id = bp_get_taxonomy_term_site_id( $taxonomy );
264
+
265
+ $switched = false;
266
+ if ( $site_id !== get_current_blog_id() ) {
267
+ switch_to_blog( $site_id );
268
+ bp_register_taxonomies();
269
+ $switched = true;
270
+ }
271
+
272
+ $term = get_term_by( $field, $value, $taxonomy, $output, $filter );
273
+
274
+ if ( $switched ) {
275
+ restore_current_blog();
276
+ }
277
+
278
+ return $term;
279
+ }
bp-core/bp-core-template-loader.php CHANGED
@@ -70,6 +70,10 @@ function bp_get_template_part( $slug, $name = null ) {
70
  * @since 2.6.0
71
  *
72
  * @see bp_get_template_part() for full documentation.
 
 
 
 
73
  */
74
  function bp_get_asset_template_part( $slug, $name = null ) {
75
  return bp_get_template_part( "assets/{$slug}", $name );
@@ -156,7 +160,7 @@ function bp_locate_template( $template_names, $load = false, $require_once = tru
156
  *
157
  * @since 2.6.0
158
  *
159
- * @param string Relative filename to search for.
160
  * @return array|bool Array of asset data if one is located (includes absolute filepath and URI).
161
  * Boolean false on failure.
162
  */
70
  * @since 2.6.0
71
  *
72
  * @see bp_get_template_part() for full documentation.
73
+ *
74
+ * @param string $slug Template slug.
75
+ * @param string|null $name Template name.
76
+ * @return string
77
  */
78
  function bp_get_asset_template_part( $slug, $name = null ) {
79
  return bp_get_template_part( "assets/{$slug}", $name );
160
  *
161
  * @since 2.6.0
162
  *
163
+ * @param string $filename Relative filename to search for.
164
  * @return array|bool Array of asset data if one is located (includes absolute filepath and URI).
165
  * Boolean false on failure.
166
  */
bp-core/bp-core-template.php CHANGED
@@ -584,6 +584,71 @@ function bp_search_form_type_select() {
584
  return apply_filters( 'bp_search_form_type_select', $selection_box );
585
  }
586
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  /**
588
  * Output the default text for the search box for a given component.
589
  *
@@ -2399,7 +2464,7 @@ function bp_is_user_change_avatar() {
2399
  *
2400
  * Eg http://example.com/members/joe/profile/change-cover-image/ (or a subpage thereof).
2401
  *
2402
- * @since 2.4.0
2403
  *
2404
  * @return bool True if the current page is a user's profile edit cover image page.
2405
  */
@@ -2621,7 +2686,7 @@ function bp_is_user_settings_profile() {
2621
  * @return True if the current page is the groups directory.
2622
  */
2623
  function bp_is_groups_directory() {
2624
- if ( bp_is_groups_component() && ! bp_current_action() && ! bp_current_item() ) {
2625
  return true;
2626
  }
2627
 
@@ -3154,7 +3219,7 @@ function bp_get_title_parts( $seplocation = 'right' ) {
3154
  *
3155
  * @since 2.4.3
3156
  *
3157
- * @param array $bp_title_parts Current BuddyPress title parts
3158
  * @return array
3159
  */
3160
  return (array) apply_filters( 'bp_get_title_parts', $bp_title_parts );
@@ -3724,9 +3789,9 @@ function bp_nav_menu( $args = array() ) {
3724
  /**
3725
  * Prints the Recipient Salutation.
3726
  *
3727
- * @since 2.5.0
3728
  *
3729
- * @param array $settings Email Settings.
3730
  */
3731
  function bp_email_the_salutation( $settings = array() ) {
3732
  echo bp_email_get_salutation( $settings );
@@ -3735,9 +3800,9 @@ function bp_email_the_salutation( $settings = array() ) {
3735
  /**
3736
  * Gets the Recipient Salutation.
3737
  *
3738
- * @since 2.5.0
3739
  *
3740
- * @param array $settings Email Settings.
3741
  * @return string The Recipient Salutation.
3742
  */
3743
  function bp_email_get_salutation( $settings = array() ) {
@@ -3746,7 +3811,7 @@ function bp_email_the_salutation( $settings = array() ) {
3746
  /**
3747
  * Filters The Recipient Salutation inside the Email Template.
3748
  *
3749
- * @since 2.5.0
3750
  *
3751
  * @param string $value The Recipient Salutation.
3752
  * @param array $settings Email Settings.
584
  return apply_filters( 'bp_search_form_type_select', $selection_box );
585
  }
586
 
587
+ /**
588
+ * Output the 'name' attribute for search form input element.
589
+ *
590
+ * @since 2.7.0
591
+ *
592
+ * @param string $component See bp_get_search_input_name().
593
+ */
594
+ function bp_search_input_name( $component = '' ) {
595
+ echo esc_attr( bp_get_search_input_name( $component ) );
596
+ }
597
+
598
+ /**
599
+ * Get the 'name' attribute for the search form input element.
600
+ *
601
+ * @since 2.7.0
602
+ *
603
+ * @param string $component Component name. Defaults to current component.
604
+ * @return string Text for the 'name' attribute.
605
+ */
606
+ function bp_get_search_input_name( $component = '' ) {
607
+ if ( ! $component ) {
608
+ $component = bp_current_component();
609
+ }
610
+
611
+ $bp = buddypress();
612
+
613
+ $name = '';
614
+ if ( isset( $bp->{$component}->id ) ) {
615
+ $name = $bp->{$component}->id . '_search';
616
+ }
617
+
618
+ return $name;
619
+ }
620
+
621
+ /**
622
+ * Output the placeholder text for the search box for a given component.
623
+ *
624
+ * @since 2.7.0
625
+ *
626
+ * @param string $component See bp_get_search_placeholder().
627
+ */
628
+ function bp_search_placeholder( $component = '' ) {
629
+ echo esc_attr( bp_get_search_placeholder( $component ) );
630
+ }
631
+
632
+ /**
633
+ * Get the placeholder text for the search box for a given component.
634
+ *
635
+ * @since 2.7.0
636
+ *
637
+ * @param string $component Component name. Defaults to current component.
638
+ * @return string Placeholder text for the search field.
639
+ */
640
+ function bp_get_search_placeholder( $component = '' ) {
641
+ $query_arg = bp_core_get_component_search_query_arg( $component );
642
+
643
+ if ( $query_arg && ! empty( $_REQUEST[ $query_arg ] ) ) {
644
+ $placeholder = wp_unslash( $_REQUEST[ $query_arg ] );
645
+ } else {
646
+ $placeholder = bp_get_search_default_text( $component );
647
+ }
648
+
649
+ return $placeholder;
650
+ }
651
+
652
  /**
653
  * Output the default text for the search box for a given component.
654
  *
2464
  *
2465
  * Eg http://example.com/members/joe/profile/change-cover-image/ (or a subpage thereof).
2466
  *
2467
+ * @since 2.4.0
2468
  *
2469
  * @return bool True if the current page is a user's profile edit cover image page.
2470
  */
2686
  * @return True if the current page is the groups directory.
2687
  */
2688
  function bp_is_groups_directory() {
2689
+ if ( bp_is_groups_component() && ! bp_is_group() && ( ! bp_current_action() || ( bp_action_variable() && bp_is_current_action( bp_get_groups_group_type_base() ) ) ) ) {
2690
  return true;
2691
  }
2692
 
3219
  *
3220
  * @since 2.4.3
3221
  *
3222
+ * @param array $bp_title_parts Current BuddyPress title parts.
3223
  * @return array
3224
  */
3225
  return (array) apply_filters( 'bp_get_title_parts', $bp_title_parts );
3789
  /**
3790
  * Prints the Recipient Salutation.
3791
  *
3792
+ * @since 2.5.0
3793
  *
3794
+ * @param array $settings Email Settings.
3795
  */
3796
  function bp_email_the_salutation( $settings = array() ) {
3797
  echo bp_email_get_salutation( $settings );
3800
  /**
3801
  * Gets the Recipient Salutation.
3802
  *
3803
+ * @since 2.5.0
3804
  *
3805
+ * @param array $settings Email Settings.
3806
  * @return string The Recipient Salutation.
3807
  */
3808
  function bp_email_get_salutation( $settings = array() ) {
3811
  /**
3812
  * Filters The Recipient Salutation inside the Email Template.
3813
  *
3814
+ * @since 2.5.0
3815
  *
3816
  * @param string $value The Recipient Salutation.
3817
  * @param array $settings Email Settings.
bp-core/bp-core-theme-compatibility.php CHANGED
@@ -319,8 +319,8 @@ function bp_set_theme_compat_original_template( $template = '' ) {
319
  *
320
  * @since 2.4.0
321
  *
322
- * @param string $theme_id The theme id (eg: legacy).
323
- * @param array $feature An associative array (eg: array( name => 'feature_name', 'settings' => array() )).
324
  */
325
  function bp_set_theme_compat_feature( $theme_id, $feature = array() ) {
326
  if ( empty( $theme_id ) || empty( $feature['name'] ) ) {
@@ -379,8 +379,8 @@ function bp_set_theme_compat_feature( $theme_id, $feature = array() ) {
379
  *
380
  * @since 2.4.0
381
  *
382
- * @param string $feature The feature (eg: cover_image).
383
- * @return object The feature settings.
384
  */
385
  function bp_get_theme_compat_feature( $feature = '' ) {
386
  // Get current theme compat theme.
@@ -397,7 +397,7 @@ function bp_get_theme_compat_feature( $feature = '' ) {
397
  }
398
 
399
  /**
400
- * Setup the theme's features
401
  *
402
  * Note: BP Legacy's buddypress-functions.php is not loaded in WP Administration
403
  * as it's loaded using bp_locate_template(). That's why this function is here.
@@ -646,7 +646,7 @@ function bp_theme_compat_reset_post( $args = array() ) {
646
  unset( $dummy );
647
 
648
  /**
649
- * Force the header back to 200 status if not a deliberate 404
650
  *
651
  * @see https://bbpress.trac.wordpress.org/ticket/1973
652
  */
@@ -957,10 +957,12 @@ function bp_comments_open( $open, $post_id = 0 ) {
957
  function bp_theme_compat_toggle_is_page( $retval = '' ) {
958
  global $wp_query;
959
 
960
- $wp_query->is_page = false;
 
961
 
962
- // Set a switch so we know that we've toggled these WP_Query properties.
963
- buddypress()->theme_compat->is_page_toggled = true;
 
964
 
965
  return $retval;
966
  }
319
  *
320
  * @since 2.4.0
321
  *
322
+ * @param string $theme_id The theme id (eg: legacy).
323
+ * @param array $feature An associative array (eg: array( name => 'feature_name', 'settings' => array() )).
324
  */
325
  function bp_set_theme_compat_feature( $theme_id, $feature = array() ) {
326
  if ( empty( $theme_id ) || empty( $feature['name'] ) ) {
379
  *
380
  * @since 2.4.0
381
  *
382
+ * @param string $feature The feature (eg: cover_image).
383
+ * @return object The feature settings.
384
  */
385
  function bp_get_theme_compat_feature( $feature = '' ) {
386
  // Get current theme compat theme.
397
  }
398
 
399
  /**
400
+ * Setup the theme's features.
401
  *
402
  * Note: BP Legacy's buddypress-functions.php is not loaded in WP Administration
403
  * as it's loaded using bp_locate_template(). That's why this function is here.
646
  unset( $dummy );
647
 
648
  /**
649
+ * Force the header back to 200 status if not a deliberate 404.
650
  *
651
  * @see https://bbpress.trac.wordpress.org/ticket/1973
652
  */
957
  function bp_theme_compat_toggle_is_page( $retval = '' ) {
958
  global $wp_query;
959
 
960
+ if ( $wp_query->is_page ) {
961
+ $wp_query->is_page = false;
962
 
963
+ // Set a switch so we know that we've toggled these WP_Query properties.
964
+ buddypress()->theme_compat->is_page_toggled = true;
965
+ }
966
 
967
  return $retval;
968
  }
bp-core/bp-core-update.php CHANGED
@@ -139,7 +139,6 @@ function bp_is_deactivation( $basename = '' ) {
139
  * Update the BP version stored in the database to the current version.
140
  *
141
  * @since 1.6.0
142
- *
143
  */
144
  function bp_version_bump() {
145
  bp_update_option( '_bp_db_version', bp_get_db_version() );
@@ -192,10 +191,11 @@ function bp_version_updater() {
192
  'notifications' => 1,
193
  ) );
194
 
 
195
  require_once( buddypress()->plugin_dir . '/bp-core/admin/bp-core-admin-schema.php' );
196
  $switched_to_root_blog = false;
197
 
198
- // Make sure the current blog is set to the root blog
199
  if ( ! bp_is_root_blog() ) {
200
  switch_to_blog( bp_get_root_blog_id() );
201
  bp_register_taxonomies();
@@ -218,51 +218,56 @@ function bp_version_updater() {
218
  // Run the schema install to update tables.
219
  bp_core_install();
220
 
221
- // 1.5.0
222
  if ( $raw_db_version < 1801 ) {
223
  bp_update_to_1_5();
224
  bp_core_add_page_mappings( $default_components, 'delete' );
225
  }
226
 
227
- // 1.6.0
228
  if ( $raw_db_version < 6067 ) {
229
  bp_update_to_1_6();
230
  }
231
 
232
- // 1.9.0
233
  if ( $raw_db_version < 7553 ) {
234
  bp_update_to_1_9();
235
  }
236
 
237
- // 1.9.2
238
  if ( $raw_db_version < 7731 ) {
239
  bp_update_to_1_9_2();
240
  }
241
 
242
- // 2.0.0
243
  if ( $raw_db_version < 7892 ) {
244
  bp_update_to_2_0();
245
  }
246
 
247
- // 2.0.1
248
  if ( $raw_db_version < 8311 ) {
249
  bp_update_to_2_0_1();
250
  }
251
 
252
- // 2.2.0
253
  if ( $raw_db_version < 9181 ) {
254
  bp_update_to_2_2();
255
  }
256
 
257
- // 2.3.0
258
  if ( $raw_db_version < 9615 ) {
259
  bp_update_to_2_3();
260
  }
261
 
262
- // 2.5.0
263
  if ( $raw_db_version < 10440 ) {
264
  bp_update_to_2_5();
265
  }
 
 
 
 
 
266
  }
267
 
268
  /* All done! *************************************************************/
@@ -331,7 +336,7 @@ function bp_update_to_1_5() {
331
  }
332
 
333
  /**
334
- * Remove unused metadata from database when upgrading from < 1.6.
335
  *
336
  * Database update methods based on version numbers.
337
  *
@@ -380,7 +385,7 @@ function bp_update_to_1_9() {
380
  }
381
 
382
  /**
383
- * Perform database updates for BP 1.9.2
384
  *
385
  * In 1.9, BuddyPress stopped registering its theme directory when it detected
386
  * that bp-default (or a child theme) was not currently being used, in effect
@@ -389,6 +394,7 @@ function bp_update_to_1_9() {
389
  * bp-default would no longer be available, with no obvious way (outside of
390
  * a manual filter) to restore it. In 1.9.2, we add an option that flags
391
  * whether bp-default or a child theme is active at the time of upgrade; if so,
 
392
  * the theme directory will continue to be registered even if the theme is
393
  * deactivated temporarily. Thus, new installations will not see bp-default,
394
  * but legacy installations using the theme will continue to see it.
@@ -440,8 +446,6 @@ function bp_update_to_2_0() {
440
  * 2.0.1 database upgrade routine.
441
  *
442
  * @since 2.0.1
443
- *
444
- * @return void
445
  */
446
  function bp_update_to_2_0_1() {
447
 
@@ -501,6 +505,43 @@ function bp_update_to_2_5() {
501
  bp_core_install_emails();
502
  }
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  /**
505
  * Updates the component field for new_members type.
506
  *
@@ -539,7 +580,6 @@ function bp_migrate_new_member_activity_component() {
539
  * Remove all hidden friendship activities.
540
  *
541
  * @since 2.2.0
542
- *
543
  */
544
  function bp_cleanup_friendship_activities() {
545
  bp_activity_delete( array(
@@ -549,13 +589,61 @@ function bp_cleanup_friendship_activities() {
549
  ) );
550
  }
551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552
  /**
553
  * Redirect user to BP's What's New page on first page load after activation.
554
  *
555
  * @since 1.7.0
556
  *
557
  * @internal Used internally to redirect BuddyPress to the about page on activation.
558
- *
559
  */
560
  function bp_add_activation_redirect() {
561
 
@@ -624,7 +712,6 @@ function bp_core_maybe_install_signups() {
624
  * Runs on BuddyPress activation.
625
  *
626
  * @since 1.6.0
627
- *
628
  */
629
  function bp_activation() {
630
 
@@ -637,13 +724,13 @@ function bp_activation() {
637
  /**
638
  * Fires during the activation of BuddyPress.
639
  *
640
- * Use as of (1.6.0)
641
  *
642
  * @since 1.6.0
643
  */
644
  do_action( 'bp_activation' );
645
 
646
- // @deprecated as of (1.6)
647
  do_action( 'bp_loader_activate' );
648
  }
649
 
@@ -653,7 +740,6 @@ function bp_activation() {
653
  * Runs on BuddyPress deactivation.
654
  *
655
  * @since 1.6.0
656
- *
657
  */
658
  function bp_deactivation() {
659
 
@@ -671,13 +757,13 @@ function bp_deactivation() {
671
  /**
672
  * Fires during the deactivation of BuddyPress.
673
  *
674
- * Use as of (1.6.0)
675
  *
676
  * @since 1.6.0
677
  */
678
  do_action( 'bp_deactivation' );
679
 
680
- // @deprecated as of (1.6)
681
  do_action( 'bp_loader_deactivate' );
682
  }
683
 
@@ -687,7 +773,6 @@ function bp_deactivation() {
687
  * Runs when uninstalling BuddyPress.
688
  *
689
  * @since 1.6.0
690
- *
691
  */
692
  function bp_uninstall() {
693
 
139
  * Update the BP version stored in the database to the current version.
140
  *
141
  * @since 1.6.0
 
142
  */
143
  function bp_version_bump() {
144
  bp_update_option( '_bp_db_version', bp_get_db_version() );
191
  'notifications' => 1,
192
  ) );
193
 
194
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
195
  require_once( buddypress()->plugin_dir . '/bp-core/admin/bp-core-admin-schema.php' );
196
  $switched_to_root_blog = false;
197
 
198
+ // Make sure the current blog is set to the root blog.
199
  if ( ! bp_is_root_blog() ) {
200
  switch_to_blog( bp_get_root_blog_id() );
201
  bp_register_taxonomies();
218
  // Run the schema install to update tables.
219
  bp_core_install();
220
 
221
+ // Version 1.5.0.
222
  if ( $raw_db_version < 1801 ) {
223
  bp_update_to_1_5();
224
  bp_core_add_page_mappings( $default_components, 'delete' );
225
  }
226
 
227
+ // Version 1.6.0.
228
  if ( $raw_db_version < 6067 ) {
229
  bp_update_to_1_6();
230
  }
231
 
232
+ // Version 1.9.0.
233
  if ( $raw_db_version < 7553 ) {
234
  bp_update_to_1_9();
235
  }
236
 
237
+ // Version 1.9.2.
238
  if ( $raw_db_version < 7731 ) {
239
  bp_update_to_1_9_2();
240
  }
241
 
242
+ // Version 2.0.0.
243
  if ( $raw_db_version < 7892 ) {
244
  bp_update_to_2_0();
245
  }
246
 
247
+ // Version 2.0.1.
248
  if ( $raw_db_version < 8311 ) {
249
  bp_update_to_2_0_1();
250
  }
251
 
252
+ // Version 2.2.0.
253
  if ( $raw_db_version < 9181 ) {
254
  bp_update_to_2_2();
255
  }
256
 
257
+ // Version 2.3.0.
258
  if ( $raw_db_version < 9615 ) {
259
  bp_update_to_2_3();
260
  }
261
 
262
+ // Version 2.5.0.
263
  if ( $raw_db_version < 10440 ) {
264
  bp_update_to_2_5();
265
  }
266
+
267
+ // Version 2.7.0.
268
+ if ( $raw_db_version < 11105 ) {
269
+ bp_update_to_2_7();
270
+ }
271
  }
272
 
273
  /* All done! *************************************************************/
336
  }
337
 
338
  /**
339
+ * Remove unused metadata from database when upgrading from < 1.6.0.
340
  *
341
  * Database update methods based on version numbers.
342
  *
385
  }
386
 
387
  /**
388
+ * Perform database updates for BP 1.9.2.
389
  *
390
  * In 1.9, BuddyPress stopped registering its theme directory when it detected
391
  * that bp-default (or a child theme) was not currently being used, in effect
394
  * bp-default would no longer be available, with no obvious way (outside of
395
  * a manual filter) to restore it. In 1.9.2, we add an option that flags
396
  * whether bp-default or a child theme is active at the time of upgrade; if so,
397
+ *
398
  * the theme directory will continue to be registered even if the theme is
399
  * deactivated temporarily. Thus, new installations will not see bp-default,
400
  * but legacy installations using the theme will continue to see it.
446
  * 2.0.1 database upgrade routine.
447
  *
448
  * @since 2.0.1
 
 
449
  */
450
  function bp_update_to_2_0_1() {
451
 
505
  bp_core_install_emails();
506
  }
507
 
508
+ /**
509
+ * 2.7.0 update routine.
510
+ *
511
+ * - Add email unsubscribe salt.
512
+ * - Save legacy directory titles to the corresponding WP pages.
513
+ * - Add ignore deprecated code option (false for updates).
514
+ *
515
+ * @since 2.7.0
516
+ */
517
+ function bp_update_to_2_7() {
518
+ bp_add_option( 'bp-emails-unsubscribe-salt', base64_encode( wp_generate_password( 64, true, true ) ) );
519
+
520
+ // Update post_titles
521
+ bp_migrate_directory_page_titles();
522
+
523
+ /*
524
+ * Add `parent_id` column to groups table.
525
+ * Also handled by `bp_core_install()`.
526
+ */
527
+ if ( bp_is_active( 'groups' ) ) {
528
+ bp_core_install_groups();
529
+
530
+ // Invalidate all cached group objects.
531
+ global $wpdb;
532
+ $bp = buddypress();
533
+
534
+ $group_ids = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name}" );
535
+
536
+ foreach ( $group_ids as $group_id ) {
537
+ wp_cache_delete( $group_id, 'bp_groups' );
538
+ }
539
+ }
540
+
541
+ // Load deprecated code for existing installs.
542
+ bp_add_option( '_bp_ignore_deprecated_code', false );
543
+ }
544
+
545
  /**
546
  * Updates the component field for new_members type.
547
  *
580
  * Remove all hidden friendship activities.
581
  *
582
  * @since 2.2.0
 
583
  */
584
  function bp_cleanup_friendship_activities() {
585
  bp_activity_delete( array(
589
  ) );
590
  }
591
 
592
+ /**
593
+ * Update WP pages so that their post_title matches the legacy component directory title.
594
+ *
595
+ * As of 2.7.0, component directory titles come from the `post_title` attribute of the corresponding WP post object,
596
+ * instead of being hardcoded. To ensure that directory titles don't change for existing installations, we update these
597
+ * WP posts with the formerly hardcoded titles.
598
+ *
599
+ * @since 2.7.0
600
+ */
601
+ function bp_migrate_directory_page_titles() {
602
+ $bp_pages = bp_core_get_directory_page_ids( 'all' );
603
+
604
+ $default_titles = bp_core_get_directory_page_default_titles();
605
+
606
+ $legacy_titles = array(
607
+ 'activity' => _x( 'Site-Wide Activity', 'component directory title', 'buddypress' ),
608
+ 'blogs' => _x( 'Sites', 'component directory title', 'buddypress' ),
609
+ 'groups' => _x( 'Groups', 'component directory title', 'buddypress' ),
610
+ 'members' => _x( 'Members', 'component directory title', 'buddypress' ),
611
+ );
612
+
613
+ foreach ( $bp_pages as $component => $page_id ) {
614
+ if ( ! isset( $legacy_titles[ $component ] ) ) {
615
+ continue;
616
+ }
617
+
618
+ $page = get_post( $page_id );
619
+ if ( ! $page ) {
620
+ continue;
621
+ }
622
+
623
+ // If the admin has changed the default title, don't touch it.
624
+ if ( isset( $default_titles[ $component ] ) && $default_titles[ $component ] !== $page->post_title ) {
625
+ continue;
626
+ }
627
+
628
+ // If the saved page title is the same as the legacy title, there's nothing to do.
629
+ if ( $legacy_titles[ $component ] == $page->post_title ) {
630
+ continue;
631
+ }
632
+
633
+ // Update the page with the legacy title.
634
+ wp_update_post( array(
635
+ 'ID' => $page_id,
636
+ 'post_title' => $legacy_titles[ $component ],
637
+ ) );
638
+ }
639
+ }
640
+
641
  /**
642
  * Redirect user to BP's What's New page on first page load after activation.
643
  *
644
  * @since 1.7.0
645
  *
646
  * @internal Used internally to redirect BuddyPress to the about page on activation.
 
647
  */
648
  function bp_add_activation_redirect() {
649
 
712
  * Runs on BuddyPress activation.
713
  *
714
  * @since 1.6.0
 
715
  */
716
  function bp_activation() {
717
 
724
  /**
725
  * Fires during the activation of BuddyPress.
726
  *
727
+ * Use as of 1.6.0.
728
  *
729
  * @since 1.6.0
730
  */
731
  do_action( 'bp_activation' );
732
 
733
+ // @deprecated as of 1.6.0
734
  do_action( 'bp_loader_activate' );
735
  }
736
 
740
  * Runs on BuddyPress deactivation.
741
  *
742
  * @since 1.6.0
 
743
  */
744
  function bp_deactivation() {
745
 
757
  /**
758
  * Fires during the deactivation of BuddyPress.
759
  *
760
+ * Use as of 1.6.0.
761
  *
762
  * @since 1.6.0
763
  */
764
  do_action( 'bp_deactivation' );
765
 
766
+ // @deprecated as of 1.6.0
767
  do_action( 'bp_loader_deactivate' );
768
  }
769
 
773
  * Runs when uninstalling BuddyPress.
774
  *
775
  * @since 1.6.0
 
776
  */
777
  function bp_uninstall() {
778
 
bp-core/bp-core-wpabstraction.php CHANGED
@@ -52,7 +52,6 @@ if ( !is_multisite() ) {
52
  * @param int $blog_id Blog ID to fetch for. Not used.
53
  * @param string $option_name Option name to fetch.
54
  * @param bool $default Whether or not default.
55
- *
56
  * @return mixed
57
  */
58
  function get_blog_option( $blog_id, $option_name, $default = false ) {
@@ -72,7 +71,6 @@ if ( !is_multisite() ) {
72
  * @param int $blog_id Blog ID to add for. Not used.
73
  * @param string $option_name Option name to add.
74
  * @param mixed $option_value Option value to add.
75
- *
76
  * @return mixed
77
  */
78
  function add_blog_option( $blog_id, $option_name, $option_value ) {
@@ -92,7 +90,6 @@ if ( !is_multisite() ) {
92
  * @param int $blog_id Blog ID to update for. Not used.
93
  * @param string $option_name Option name to update.
94
  * @param mixed $value Option value to update.
95
- *
96
  * @return mixed
97
  */
98
  function update_blog_option( $blog_id, $option_name, $value ) {
@@ -111,7 +108,6 @@ if ( !is_multisite() ) {
111
  *
112
  * @param int $blog_id Blog ID to delete for. Not used.
113
  * @param string $option_name Option name to delete.
114
- *
115
  * @return mixed
116
  */
117
  function delete_blog_option( $blog_id, $option_name ) {
@@ -130,7 +126,6 @@ if ( !is_multisite() ) {
130
  *
131
  * @param mixed $new_blog New blog to switch to. Not used.
132
  * @param null $deprecated Whether or not deprecated. Not used.
133
- *
134
  * @return int
135
  */
136
  function switch_to_blog( $new_blog, $deprecated = null ) {
@@ -165,7 +160,6 @@ if ( !is_multisite() ) {
165
  *
166
  * @param int $user_id ID of the user. Not used.
167
  * @param bool $all Whether or not to return all. Not used.
168
- *
169
  * @return false
170
  */
171
  function get_blogs_of_user( $user_id, $all = false ) {
@@ -186,7 +180,6 @@ if ( !is_multisite() ) {
186
  * @param mixed $pref Preference. Not used.
187
  * @param string $value Value. Not used.
188
  * @param null $deprecated Whether or not deprecated. Not used.
189
- *
190
  * @return true
191
  */
192
  function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) {
52
  * @param int $blog_id Blog ID to fetch for. Not used.
53
  * @param string $option_name Option name to fetch.
54
  * @param bool $default Whether or not default.
 
55
  * @return mixed
56
  */
57
  function get_blog_option( $blog_id, $option_name, $default = false ) {
71
  * @param int $blog_id Blog ID to add for. Not used.
72
  * @param string $option_name Option name to add.
73
  * @param mixed $option_value Option value to add.
 
74
  * @return mixed
75
  */
76
  function add_blog_option( $blog_id, $option_name, $option_value ) {
90
  * @param int $blog_id Blog ID to update for. Not used.
91
  * @param string $option_name Option name to update.
92
  * @param mixed $value Option value to update.
 
93
  * @return mixed
94
  */
95
  function update_blog_option( $blog_id, $option_name, $value ) {
108
  *
109
  * @param int $blog_id Blog ID to delete for. Not used.
110
  * @param string $option_name Option name to delete.
 
111
  * @return mixed
112
  */
113
  function delete_blog_option( $blog_id, $option_name ) {
126
  *
127
  * @param mixed $new_blog New blog to switch to. Not used.
128
  * @param null $deprecated Whether or not deprecated. Not used.
 
129
  * @return int
130
  */
131
  function switch_to_blog( $new_blog, $deprecated = null ) {
160
  *
161
  * @param int $user_id ID of the user. Not used.
162
  * @param bool $all Whether or not to return all. Not used.
 
163
  * @return false
164
  */
165
  function get_blogs_of_user( $user_id, $all = false ) {
180
  * @param mixed $pref Preference. Not used.
181
  * @param string $value Value. Not used.
182
  * @param null $deprecated Whether or not deprecated. Not used.
 
183
  * @return true
184
  */
185
  function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) {
bp-core/classes/class-bp-admin.php CHANGED
@@ -193,8 +193,6 @@ class BP_Admin {
193
  * Contextually hooked to site or network-admin depending on current configuration.
194
  *
195
  * @since 1.6.0
196
- *
197
- * section.
198
  */
199
  public function admin_menus() {
200
 
@@ -868,10 +866,12 @@ class BP_Admin {
868
  <a href="https://github.com/ichord/At.js">At.js</a>,
869
  <a href="https://bbpress.org">bbPress</a>,
870
  <a href="https://github.com/ichord/Caret.js">Caret.js</a>,
871
- <a href="http://tedgoas.github.io/Cerberus/">Cerberus</a>,
872
- <a href="http://ionicons.com/">Ionicons</a>,
873
  <a href="https://github.com/carhartl/jquery-cookie">jquery.cookie</a>,
 
874
  <a href="https://www.mediawiki.org/wiki/MediaWiki">MediaWiki</a>,
 
875
  <a href="https://wordpress.org">WordPress</a>.
876
  </p>
877
 
@@ -889,7 +889,7 @@ class BP_Admin {
889
 
890
  // Switch welcome text based on whether this is a new installation or not.
891
  $welcome_text = ( self::is_new_install() )
892
- ? __( 'Thank you for installing BuddyPress! BuddyPress helps you build any type of community website using WordPress, with member profiles, activity streams, user groups, messaging, and more.', 'buddypress' )
893
  : __( 'Thank you for updating! BuddyPress %s has many new features that you will enjoy.', 'buddypress' );
894
 
895
  ?>
@@ -939,7 +939,7 @@ class BP_Admin {
939
  *
940
  * @since 2.6.0
941
  *
942
- * @param array $columns Current column data.
943
  * @return array
944
  */
945
  public function emails_register_situation_column( $columns = array() ) {
193
  * Contextually hooked to site or network-admin depending on current configuration.
194
  *
195
  * @since 1.6.0
 
 
196
  */
197
  public function admin_menus() {
198
 
866
  <a href="https://github.com/ichord/At.js">At.js</a>,
867
  <a href="https://bbpress.org">bbPress</a>,
868
  <a href="https://github.com/ichord/Caret.js">Caret.js</a>,
869
+ <a href="https://tedgoas.github.io/Cerberus/">Cerberus</a>,
870
+ <a href="https://ionicons.com/">Ionicons</a>,
871
  <a href="https://github.com/carhartl/jquery-cookie">jquery.cookie</a>,
872
+ <a href="https://mattbradley.github.io/livestampjs/">Livestamp.js</a>,
873
  <a href="https://www.mediawiki.org/wiki/MediaWiki">MediaWiki</a>,
874
+ <a href="http://momentjs.com/">Moment.js</a>,
875
  <a href="https://wordpress.org">WordPress</a>.
876
  </p>
877
 
889
 
890
  // Switch welcome text based on whether this is a new installation or not.
891
  $welcome_text = ( self::is_new_install() )
892
+ ? __( 'Thank you for installing BuddyPress! BuddyPress helps site builders and WordPress developers add community features to their websites, with user profile fields, activity streams, messaging, and notifications.', 'buddypress' )
893
  : __( 'Thank you for updating! BuddyPress %s has many new features that you will enjoy.', 'buddypress' );
894
 
895
  ?>
939
  *
940
  * @since 2.6.0
941
  *
942
+ * @param array $columns Current column data.
943
  * @return array
944
  */
945
  public function emails_register_situation_column( $columns = array() ) {
bp-core/classes/class-bp-attachment-avatar.php CHANGED
@@ -61,7 +61,6 @@ class BP_Attachment_Avatar extends BP_Attachment {
61
  * Set Upload Dir data for avatars.
62
  *
63
  * @since 2.3.0
64
- *
65
  */
66
  public function set_upload_dir() {
67
  if ( bp_core_avatar_upload_path() && bp_core_avatar_url() ) {
@@ -81,8 +80,7 @@ class BP_Attachment_Avatar extends BP_Attachment {
81
  *
82
  * @since 2.3.0
83
  *
84
- *
85
- * @param array $file the temporary file attributes (before it has been moved).
86
  * @return array the file with extra errors if needed.
87
  */
88
  public function validate_upload( $file = array() ) {
@@ -110,7 +108,6 @@ class BP_Attachment_Avatar extends BP_Attachment {
110
  * @since 2.3.0
111
  * @since 2.4.0 Add the $ui_available_width parameter, to inform about the Avatar UI width.
112
  *
113
- *
114
  * @param string $file The absolute path to the file.
115
  * @param int $ui_available_width Available width for the UI.
116
  * @return mixed
61
  * Set Upload Dir data for avatars.
62
  *
63
  * @since 2.3.0
 
64
  */
65
  public function set_upload_dir() {
66
  if ( bp_core_avatar_upload_path() && bp_core_avatar_url() ) {
80
  *
81
  * @since 2.3.0
82
  *
83
+ * @param array $file the temporary file attributes (before it has been moved).
 
84
  * @return array the file with extra errors if needed.
85
  */
86
  public function validate_upload( $file = array() ) {
108
  * @since 2.3.0
109
  * @since 2.4.0 Add the $ui_available_width parameter, to inform about the Avatar UI width.
110
  *
 
111
  * @param string $file The absolute path to the file.
112
  * @param int $ui_available_width Available width for the UI.
113
  * @return mixed
bp-core/classes/class-bp-attachment-cover-image.php CHANGED
@@ -1,291 +1,291 @@
1
- <?php
2
- /**
3
- * Core Cover Image attachment class.
4
- *
5
- * @package BuddyPress
6
- * @subpackage Core
7
- * @since 2.4.0
8
- */
9
-
10
- // Exit if accessed directly.
11
- defined( 'ABSPATH' ) || exit;
12
-
13
- /**
14
- * BP Attachment Cover Image class.
15
- *
16
- * Extends BP Attachment to manage the cover images uploads.
17
- *
18
- * @since 2.4.0
19
- */
20
- class BP_Attachment_Cover_Image extends BP_Attachment {
21
- /**
22
- * The constuctor.
23
- *
24
- * @since 2.4.0
25
- */
26
- public function __construct() {
27
- // Allowed cover image types & upload size.
28
- $allowed_types = bp_attachments_get_allowed_types( 'cover_image' );
29
- $max_upload_file_size = bp_attachments_get_max_upload_file_size( 'cover_image' );
30
-
31
- parent::__construct( array(
32
- 'action' => 'bp_cover_image_upload',
33
- 'file_input' => 'file',
34
- 'original_max_filesize' => $max_upload_file_size,
35
- 'base_dir' => bp_attachments_uploads_dir_get( 'dir' ),
36
- 'required_wp_files' => array( 'file', 'image' ),
37
-
38
- // Specific errors for cover images.
39
- 'upload_error_strings' => array(
40
- 11 => sprintf( __( 'That image is too big. Please upload one smaller than %s', 'buddypress' ), size_format( $max_upload_file_size ) ),
41
- 12 => sprintf( _n( 'Please upload only this file type: %s.', 'Please upload only these file types: %s.', count( $allowed_types ), 'buddypress' ), self::get_cover_image_types( $allowed_types ) ),
42
- ),
43
- ) );
44
- }
45
-
46
- /**
47
- * Gets the available cover image types.
48
- *
49
- * @since 2.4.0
50
- *
51
- * @param array $allowed_types Array of allowed cover image types.
52
- * @return string $value Comma-separated list of allowed cover image types.
53
- */
54
- public static function get_cover_image_types( $allowed_types = array() ) {
55
- $types = array_map( 'strtoupper', $allowed_types );
56
- $comma = _x( ',', 'cover image types separator', 'buddypress' );
57
- return join( $comma . ' ', $types );
58
- }
59
-
60
- /**
61
- * Cover image specific rules.
62
- *
63
- * Adds an error if the cover image size or type don't match BuddyPress needs.
64
- * The error code is the index of $upload_error_strings.
65
- *
66
- * @since 2.4.0
67
- *
68
- * @param array $file The temporary file attributes (before it has been moved).
69
- * @return array $file The file with extra errors if needed.
70
- */
71
- public function validate_upload( $file = array() ) {
72
- // Bail if already an error.
73
- if ( ! empty( $file['error'] ) ) {
74
- return $file;
75
- }
76
-
77
- // File size is too big.
78
- if ( $file['size'] > $this->original_max_filesize ) {
79
- $file['error'] = 11;
80
-
81
- // File is of invalid type.
82
- } elseif ( ! bp_attachments_check_filetype( $file['tmp_name'], $file['name'], bp_attachments_get_allowed_mimes( 'cover_image' ) ) ) {
83
- $file['error'] = 12;
84
- }
85
-
86
- // Return with error code attached.
87
- return $file;
88
- }
89
-
90
- /**
91
- * Set the directory when uploading a file.
92
- *
93
- * @since 2.4.0
94
- *
95
- * @param array $upload_dir The original Uploads dir.
96
- * @return array $value Upload data (path, url, basedir...).
97
- */
98
- public function upload_dir_filter( $upload_dir = array() ) {
99
- // Default values are for profiles.
100
- $object_id = bp_displayed_user_id();
101
-
102
- if ( empty( $object_id ) ) {
103
- $object_id = bp_loggedin_user_id();
104
- }
105
-
106
- $object_directory = 'members';
107
-
108
- // We're in a group, edit default values.
109
- if ( bp_is_group() || bp_is_group_create() ) {
110
- $object_id = bp_get_current_group_id();
111
- $object_directory = 'groups';
112
- }
113
-
114
- // Set the subdir.
115
- $subdir = '/' . $object_directory . '/' . $object_id . '/cover-image';
116
-
117
- /**
118
- * Filters the cover image upload directory.
119
- *
120
- * @since 2.4.0
121
- *
122
- * @param array $value Array containing the path, URL, and other helpful settings.
123
- * @param array $upload_dir The original Uploads dir.
124
- */
125
- return apply_filters( 'bp_attachments_cover_image_upload_dir', array(
126
- 'path' => $this->upload_path . $subdir,
127
- 'url' => $this->url . $subdir,
128
- 'subdir' => $subdir,
129
- 'basedir' => $this->upload_path,
130
- 'baseurl' => $this->url,
131
- 'error' => false
132
- ), $upload_dir );
133
- }
134
-
135
- /**
136
- * Adjust the cover image to fit with advised width & height.
137
- *
138
- * @since 2.4.0
139
- *
140
- * @param string $file The absolute path to the file.
141
- * @param array $dimensions Array of dimensions for the cover image.
142
- * @return mixed
143
- */
144
- public function fit( $file = '', $dimensions = array() ) {
145
- if ( empty( $dimensions['width'] ) || empty( $dimensions['height'] ) ) {
146
- return false;
147
- }
148
-
149
- // Get image size.
150
- $cover_data = parent::get_image_data( $file );
151
-
152
- // Init the edit args.
153
- $edit_args = array();
154
-
155
- // Do we need to resize the image?
156
- if ( ( isset( $cover_data['width'] ) && $cover_data['width'] > $dimensions['width'] ) ||
157
- ( isset( $cover_data['height'] ) && $cover_data['height'] > $dimensions['height'] ) ) {
158
- $edit_args = array(
159
- 'max_w' => $dimensions['width'],
160
- 'max_h' => $dimensions['height'],
161
- 'crop' => true,
162
- );
163
- }
164
-
165
- // Do we need to rotate the image?
166
- $angles = array(
167
- 3 => 180,
168
- 6 => -90,
169
- 8 => 90,
170
- );
171
-
172
- if ( isset( $cover_data['meta']['orientation'] ) && isset( $angles[ $cover_data['meta']['orientation'] ] ) ) {
173
- $edit_args['rotate'] = $angles[ $cover_data['meta']['orientation'] ];
174
- }
175
-
176
- // No need to edit the avatar, original file will be used.
177
- if ( empty( $edit_args ) ) {
178
- return false;
179
-
180
- // Add the file to the edit arguments.
181
- } else {
182
- $edit_args = array_merge( $edit_args, array( 'file' => $file, 'save' => false ) );
183
- }
184
-
185
- // Get the editor so that we can use a specific save method.
186
- $editor = parent::edit_image( 'cover_image', $edit_args );
187
-
188
- if ( is_wp_error( $editor ) ) {
189
- return $editor;
190
- } elseif ( ! is_a( $editor, 'WP_Image_Editor' ) ) {
191
- return false;
192
- }
193
-
194
- // Save the new image file.
195
- return $editor->save( $this->generate_filename( $file ) );
196
- }
197
-
198
- /**
199
- * Generate a filename for the cover image.
200
- *
201
- * @since 2.4.0
202
- *
203
- * @param string $file The absolute path to the file.
204
- * @return string $value The absolute path to the new file name.
205
- */
206
- public function generate_filename( $file = '' ) {
207
- if ( empty( $file ) || ! file_exists( $file ) ) {
208
- return false;
209
- }
210
-
211
- $info = pathinfo( $file );
212
- $ext = strtolower( $info['extension'] );
213
- $name = wp_unique_filename( $info['dirname'], uniqid() . "-bp-cover-image.$ext" );
214
-
215
- return trailingslashit( $info['dirname'] ) . $name;
216
- }
217
-
218
- /**
219
- * Build script datas for the Uploader UI.
220
- *
221
- * @since 2.4.0
222
- *
223
- * @return array The javascript localization data
224
- */
225
- public function script_data() {
226
- // Get default script data.
227
- $script_data = parent::script_data();
228
-
229
- if ( bp_is_user() ) {
230
- $item_id = bp_displayed_user_id();
231
-
232
- $script_data['bp_params'] = array(
233
- 'object' => 'user',
234
- 'item_id' => $item_id,
235
- 'has_cover_image' => bp_attachments_get_user_has_cover_image( $item_id ),
236
- 'nonces' => array(
237
- 'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
238
- ),
239
- );
240
-
241
- // Set feedback messages.
242
- $script_data['feedback_messages'] = array(
243
- 1 => __( 'Your new cover image was uploaded successfully.', 'buddypress' ),
244
- 2 => __( 'There was a problem deleting your cover image. Please try again.', 'buddypress' ),
245
- 3 => __( 'Your cover image was deleted successfully!', 'buddypress' ),
246
- );
247
- } elseif ( bp_is_group() ) {
248
- $item_id = bp_get_current_group_id();
249
-
250
- $script_data['bp_params'] = array(
251
- 'object' => 'group',
252
- 'item_id' => bp_get_current_group_id(),
253
- 'has_cover_image' => bp_attachments_get_group_has_cover_image( $item_id ),
254
- 'nonces' => array(
255
- 'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
256
- ),
257
- );
258
-
259
- // Set feedback messages.
260
- $script_data['feedback_messages'] = array(
261
- 1 => __( 'The group cover image was uploaded successfully.', 'buddypress' ),
262
- 2 => __( 'There was a problem deleting the group cover image. Please try again.', 'buddypress' ),
263
- 3 => __( 'The group cover image was deleted successfully!', 'buddypress' ),
264
- );
265
- } else {
266
-
267
- /**
268
- * Filters the cover image params to include specific BuddyPress params for your object.
269
- * e.g. Cover image for blogs single item.
270
- *
271
- * @since 2.4.0
272
- *
273
- * @param array $value The cover image specific BuddyPress parameters.
274
- */
275
- $script_data['bp_params'] = apply_filters( 'bp_attachment_cover_image_params', array() );
276
- }
277
-
278
- // Include our specific js & css.
279
- $script_data['extra_js'] = array( 'bp-cover-image' );
280
- $script_data['extra_css'] = array( 'bp-avatar' );
281
-
282
- /**
283
- * Filters the cover image script data.
284
- *
285
- * @since 2.4.0
286
- *
287
- * @param array $script_data Array of data for the cover image.
288
- */
289
- return apply_filters( 'bp_attachments_cover_image_script_data', $script_data );
290
- }
291
- }
1
+ <?php
2
+ /**
3
+ * Core Cover Image attachment class.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Core
7
+ * @since 2.4.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * BP Attachment Cover Image class.
15
+ *
16
+ * Extends BP Attachment to manage the cover images uploads.
17
+ *
18
+ * @since 2.4.0
19
+ */
20
+ class BP_Attachment_Cover_Image extends BP_Attachment {
21
+ /**
22
+ * The constuctor.
23
+ *
24
+ * @since 2.4.0
25
+ */
26
+ public function __construct() {
27
+ // Allowed cover image types & upload size.
28
+ $allowed_types = bp_attachments_get_allowed_types( 'cover_image' );
29
+ $max_upload_file_size = bp_attachments_get_max_upload_file_size( 'cover_image' );
30
+
31
+ parent::__construct( array(
32
+ 'action' => 'bp_cover_image_upload',
33
+ 'file_input' => 'file',
34
+ 'original_max_filesize' => $max_upload_file_size,
35
+ 'base_dir' => bp_attachments_uploads_dir_get( 'dir' ),
36
+ 'required_wp_files' => array( 'file', 'image' ),
37
+
38
+ // Specific errors for cover images.
39
+ 'upload_error_strings' => array(
40
+ 11 => sprintf( __( 'That image is too big. Please upload one smaller than %s', 'buddypress' ), size_format( $max_upload_file_size ) ),
41
+ 12 => sprintf( _n( 'Please upload only this file type: %s.', 'Please upload only these file types: %s.', count( $allowed_types ), 'buddypress' ), self::get_cover_image_types( $allowed_types ) ),
42
+ ),
43
+ ) );
44
+ }
45
+
46
+ /**
47
+ * Gets the available cover image types.
48
+ *
49
+ * @since 2.4.0
50
+ *
51
+ * @param array $allowed_types Array of allowed cover image types.
52
+ * @return string $value Comma-separated list of allowed cover image types.
53
+ */
54
+ public static function get_cover_image_types( $allowed_types = array() ) {
55
+ $types = array_map( 'strtoupper', $allowed_types );
56
+ $comma = _x( ',', 'cover image types separator', 'buddypress' );
57
+ return join( $comma . ' ', $types );
58
+ }
59
+
60
+ /**
61
+ * Cover image specific rules.
62
+ *
63
+ * Adds an error if the cover image size or type don't match BuddyPress needs.
64
+ * The error code is the index of $upload_error_strings.
65
+ *
66
+ * @since 2.4.0
67
+ *
68
+ * @param array $file The temporary file attributes (before it has been moved).
69
+ * @return array $file The file with extra errors if needed.
70
+ */
71
+ public function validate_upload( $file = array() ) {
72
+ // Bail if already an error.
73
+ if ( ! empty( $file['error'] ) ) {
74
+ return $file;
75
+ }
76
+
77
+ // File size is too big.
78
+ if ( $file['size'] > $this->original_max_filesize ) {
79
+ $file['error'] = 11;
80
+
81
+ // File is of invalid type.
82
+ } elseif ( ! bp_attachments_check_filetype( $file['tmp_name'], $file['name'], bp_attachments_get_allowed_mimes( 'cover_image' ) ) ) {
83
+ $file['error'] = 12;
84
+ }
85
+
86
+ // Return with error code attached.
87
+ return $file;
88
+ }
89
+
90
+ /**
91
+ * Set the directory when uploading a file.
92
+ *
93
+ * @since 2.4.0
94
+ *
95
+ * @param array $upload_dir The original Uploads dir.
96
+ * @return array $value Upload data (path, url, basedir...).
97
+ */
98
+ public function upload_dir_filter( $upload_dir = array() ) {
99
+ // Default values are for profiles.
100
+ $object_id = bp_displayed_user_id();
101
+
102
+ if ( empty( $object_id ) ) {
103
+ $object_id = bp_loggedin_user_id();
104
+ }
105
+
106
+ $object_directory = 'members';
107
+
108
+ // We're in a group, edit default values.
109
+ if ( bp_is_group() || bp_is_group_create() ) {
110
+ $object_id = bp_get_current_group_id();
111
+ $object_directory = 'groups';
112
+ }
113
+
114
+ // Set the subdir.
115
+ $subdir = '/' . $object_directory . '/' . $object_id . '/cover-image';
116
+
117
+ /**
118
+ * Filters the cover image upload directory.
119
+ *
120
+ * @since 2.4.0
121
+ *
122
+ * @param array $value Array containing the path, URL, and other helpful settings.
123
+ * @param array $upload_dir The original Uploads dir.
124
+ */
125
+ return apply_filters( 'bp_attachments_cover_image_upload_dir', array(
126
+ 'path' => $this->upload_path . $subdir,
127
+ 'url' => $this->url . $subdir,
128
+ 'subdir' => $subdir,
129
+ 'basedir' => $this->upload_path,
130
+ 'baseurl' => $this->url,
131
+ 'error' => false
132
+ ), $upload_dir );
133
+ }
134
+
135
+ /**
136
+ * Adjust the cover image to fit with advised width & height.
137
+ *
138
+ * @since 2.4.0
139
+ *
140
+ * @param string $file The absolute path to the file.
141
+ * @param array $dimensions Array of dimensions for the cover image.
142
+ * @return mixed
143
+ */
144
+ public function fit( $file = '', $dimensions = array() ) {
145
+ if ( empty( $dimensions['width'] ) || empty( $dimensions['height'] ) ) {
146
+ return false;
147
+ }
148
+
149
+ // Get image size.
150
+ $cover_data = parent::get_image_data( $file );
151
+
152
+ // Init the edit args.
153
+ $edit_args = array();
154
+
155
+ // Do we need to resize the image?
156
+ if ( ( isset( $cover_data['width'] ) && $cover_data['width'] > $dimensions['width'] ) ||
157
+ ( isset( $cover_data['height'] ) && $cover_data['height'] > $dimensions['height'] ) ) {
158
+ $edit_args = array(
159
+ 'max_w' => $dimensions['width'],
160
+ 'max_h' => $dimensions['height'],
161
+ 'crop' => true,
162
+ );
163
+ }
164
+
165
+ // Do we need to rotate the image?
166
+ $angles = array(
167
+ 3 => 180,
168
+ 6 => -90,
169
+ 8 => 90,
170
+ );
171
+
172
+ if ( isset( $cover_data['meta']['orientation'] ) && isset( $angles[ $cover_data['meta']['orientation'] ] ) ) {
173
+ $edit_args['rotate'] = $angles[ $cover_data['meta']['orientation'] ];
174
+ }
175
+
176
+ // No need to edit the avatar, original file will be used.
177
+ if ( empty( $edit_args ) ) {
178
+ return false;
179
+
180
+ // Add the file to the edit arguments.
181
+ } else {
182
+ $edit_args = array_merge( $edit_args, array( 'file' => $file, 'save' => false ) );
183
+ }
184
+
185
+ // Get the editor so that we can use a specific save method.
186
+ $editor = parent::edit_image( 'cover_image', $edit_args );
187
+
188
+ if ( is_wp_error( $editor ) ) {
189
+ return $editor;
190
+ } elseif ( ! is_a( $editor, 'WP_Image_Editor' ) ) {
191
+ return false;
192
+ }
193
+
194
+ // Save the new image file.
195
+ return $editor->save( $this->generate_filename( $file ) );
196
+ }
197
+
198
+ /**
199
+ * Generate a filename for the cover image.
200
+ *
201
+ * @since 2.4.0
202
+ *
203
+ * @param string $file The absolute path to the file.
204
+ * @return string $value The absolute path to the new file name.
205
+ */
206
+ public function generate_filename( $file = '' ) {
207
+ if ( empty( $file ) || ! file_exists( $file ) ) {
208
+ return false;
209
+ }
210
+
211
+ $info = pathinfo( $file );
212
+ $ext = strtolower( $info['extension'] );
213
+ $name = wp_unique_filename( $info['dirname'], uniqid() . "-bp-cover-image.$ext" );
214
+
215
+ return trailingslashit( $info['dirname'] ) . $name;
216
+ }
217
+
218
+ /**
219
+ * Build script datas for the Uploader UI.
220
+ *
221
+ * @since 2.4.0
222
+ *
223
+ * @return array The javascript localization data
224
+ */
225
+ public function script_data() {
226
+ // Get default script data.
227
+ $script_data = parent::script_data();
228
+
229
+ if ( bp_is_user() ) {
230
+ $item_id = bp_displayed_user_id();
231
+
232
+ $script_data['bp_params'] = array(
233
+ 'object' => 'user',
234
+ 'item_id' => $item_id,
235
+ 'has_cover_image' => bp_attachments_get_user_has_cover_image( $item_id ),
236
+ 'nonces' => array(
237
+ 'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
238
+ ),
239
+ );
240
+
241
+ // Set feedback messages.
242
+ $script_data['feedback_messages'] = array(
243
+ 1 => __( 'Your new cover image was uploaded successfully.', 'buddypress' ),
244
+ 2 => __( 'There was a problem deleting your cover image. Please try again.', 'buddypress' ),
245
+ 3 => __( 'Your cover image was deleted successfully!', 'buddypress' ),
246
+ );
247
+ } elseif ( bp_is_group() ) {
248
+ $item_id = bp_get_current_group_id();
249
+
250
+ $script_data['bp_params'] = array(
251
+ 'object' => 'group',
252
+ 'item_id' => bp_get_current_group_id(),
253
+ 'has_cover_image' => bp_attachments_get_group_has_cover_image( $item_id ),
254
+ 'nonces' => array(
255
+ 'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
256
+ ),
257
+ );
258
+
259
+ // Set feedback messages.
260
+ $script_data['feedback_messages'] = array(
261
+ 1 => __( 'The group cover image was uploaded successfully.', 'buddypress' ),
262
+ 2 => __( 'There was a problem deleting the group cover image. Please try again.', 'buddypress' ),
263
+ 3 => __( 'The group cover image was deleted successfully!', 'buddypress' ),
264
+ );
265
+ } else {
266
+
267
+ /**
268
+ * Filters the cover image params to include specific BuddyPress params for your object.
269
+ * e.g. Cover image for blogs single item.
270
+ *
271
+ * @since 2.4.0
272
+ *
273
+ * @param array $value The cover image specific BuddyPress parameters.
274
+ */
275
+ $script_data['bp_params'] = apply_filters( 'bp_attachment_cover_image_params', array() );
276
+ }
277
+
278
+ // Include our specific js & css.
279
+ $script_data['extra_js'] = array( 'bp-cover-image' );
280
+ $script_data['extra_css'] = array( 'bp-avatar' );
281
+
282
+ /**
283
+ * Filters the cover image script data.
284
+ *
285
+ * @since 2.4.0
286
+ *
287
+ * @param array $script_data Array of data for the cover image.
288
+ */
289
+ return apply_filters( 'bp_attachments_cover_image_script_data', $script_data );
290
+ }
291
+ }
bp-core/classes/class-bp-attachment.php CHANGED
@@ -197,17 +197,17 @@ abstract class BP_Attachment {
197
  *
198
  * @since 2.3.0
199
  *
200
- *
201
- * @param array $file The appropriate entry the from $_FILES superglobal.
202
- * @param string $upload_dir_filter A specific filter to be applied to 'upload_dir' (optional).
203
- * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
204
  * @return array On success, returns an associative array of file attributes.
205
  * On failure, returns an array containing the error message
206
  * (eg: array( 'error' => $message ) )
207
  */
208
  public function upload( $file, $upload_dir_filter = '', $time = null ) {
209
  /**
210
- * Upload action and the file input name are required parameters
 
211
  * @see BP_Attachment:__construct()
212
  */
213
  if ( empty( $this->action ) || empty( $this->file_input ) ) {
@@ -320,7 +320,7 @@ abstract class BP_Attachment {
320
  *
321
  * @since 2.3.0
322
  *
323
- * @param array $file The temporary file attributes (before it has been moved).
324
  * @return array The file.
325
  */
326
  public function validate_upload( $file = array() ) {
@@ -345,7 +345,7 @@ abstract class BP_Attachment {
345
  *
346
  * regarding to context
347
  *
348
- * @param array $upload_dir The original Uploads dir.
349
  * @return array The upload directory data.
350
  */
351
  public function upload_dir_filter( $upload_dir = array() ) {
@@ -522,9 +522,9 @@ abstract class BP_Attachment {
522
  /**
523
  * Get full data for an image
524
  *
525
- * @since 2.4.0
526
  *
527
- * @param string $file Absolute path to the uploaded image.
528
  * @return bool|array An associate array containing the width, height and metadatas.
529
  * False in case an important image attribute is missing.
530
  */
@@ -574,9 +574,9 @@ abstract class BP_Attachment {
574
  /**
575
  * Filter here to add/remove/edit data to the image full data
576
  *
577
- * @since 2.4.0
578
  *
579
- * @param array $image_data An associate array containing the width, height and metadatas.
580
  */
581
  return apply_filters( 'bp_attachments_get_image_data', $image_data );
582
  }
@@ -584,7 +584,7 @@ abstract class BP_Attachment {
584
  /**
585
  * Edit an image file to resize it or rotate it
586
  *
587
- * @since 2.4.0
588
  *
589
  * @param string $attachment_type The attachment type (eg: avatar or cover_image). Required.
590
  * @param array $args {
197
  *
198
  * @since 2.3.0
199
  *
200
+ * @param array $file The appropriate entry the from $_FILES superglobal.
201
+ * @param string $upload_dir_filter A specific filter to be applied to 'upload_dir' (optional).
202
+ * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
 
203
  * @return array On success, returns an associative array of file attributes.
204
  * On failure, returns an array containing the error message
205
  * (eg: array( 'error' => $message ) )
206
  */
207
  public function upload( $file, $upload_dir_filter = '', $time = null ) {
208
  /**
209
+ * Upload action and the file input name are required parameters.
210
+ *
211
  * @see BP_Attachment:__construct()
212
  */
213
  if ( empty( $this->action ) || empty( $this->file_input ) ) {
320
  *
321
  * @since 2.3.0
322
  *
323
+ * @param array $file The temporary file attributes (before it has been moved).
324
  * @return array The file.
325
  */
326
  public function validate_upload( $file = array() ) {
345
  *
346
  * regarding to context
347
  *
348
+ * @param array $upload_dir The original Uploads dir.
349
  * @return array The upload directory data.
350
  */
351
  public function upload_dir_filter( $upload_dir = array() ) {
522
  /**
523
  * Get full data for an image
524
  *
525
+ * @since 2.4.0
526
  *
527
+ * @param string $file Absolute path to the uploaded image.
528
  * @return bool|array An associate array containing the width, height and metadatas.
529
  * False in case an important image attribute is missing.
530
  */
574
  /**
575
  * Filter here to add/remove/edit data to the image full data
576
  *
577
+ * @since 2.4.0
578
  *
579
+ * @param array $image_data An associate array containing the width, height and metadatas.
580
  */
581
  return apply_filters( 'bp_attachments_get_image_data', $image_data );
582
  }
584
  /**
585
  * Edit an image file to resize it or rotate it
586
  *
587
+ * @since 2.4.0
588
  *
589
  * @param string $attachment_type The attachment type (eg: avatar or cover_image). Required.
590
  * @param array $args {
bp-core/classes/class-bp-button.php CHANGED
@@ -14,35 +14,35 @@ defined( 'ABSPATH' ) || exit;
14
  * API to create BuddyPress buttons.
15
  *
16
  * @since 1.2.6
 
 
 
 
17
  *
18
  * @param array $args {
19
  * Array of arguments.
20
  *
21
  * @type string $id String describing the button type.
22
- * @type string $component The name of the component the button belongs to.
23
- * Default: 'core'.
24
- * @type bool $must_be_logged_in Optional. Does the user need to be logged
25
- * in to see this button? Default: true.
26
- * @type bool $block_self Optional. True if the button should be hidden
27
- * when a user is viewing his own profile.
28
- * Default: true.
29
- * @type string|bool $wrapper Optional. HTML element type that should wrap
30
- * the button: 'div', 'span', 'p', or 'li'.
31
- * False for no wrapper at all. Default: 'div'.
32
- * @type string $wrapper_id Optional. DOM ID of the button wrapper element.
33
- * Default: ''.
34
- * @type string $wrapper_class Optional. DOM class of the button wrapper
35
- * element. Default: ''.
36
- * @type string $link_href Optional. Destination link of the button.
37
- * Default: ''.
38
- * @type string $link_class Optional. DOM class of the button. Default: ''.
39
- * @type string $link_id Optional. DOM ID of the button. Default: ''.
40
- * @type string $link_rel Optional. DOM 'rel' attribute of the button.
41
- * Default: ''.
42
- * @type string $link_title Optional. Title attribute of the button.
43
- * Default: ''.
44
- * @type string $link_text Optional. Text to appear on the button.
45
- * Default: ''.
46
  * }
47
  */
48
  class BP_Button {
@@ -52,6 +52,8 @@ class BP_Button {
52
  /**
53
  * The button ID.
54
  *
 
 
55
  * @var string
56
  */
57
  public $id = '';
@@ -59,6 +61,8 @@ class BP_Button {
59
  /**
60
  * The name of the component that the button belongs to.
61
  *
 
 
62
  * @var string
63
  */
64
  public $component = 'core';
@@ -66,6 +70,8 @@ class BP_Button {
66
  /**
67
  * Does the user need to be logged in to see this button?
68
  *
 
 
69
  * @var bool
70
  */
71
  public $must_be_logged_in = true;
@@ -73,22 +79,88 @@ class BP_Button {
73
  /**
74
  * Whether the button should be hidden when viewing your own profile.
75
  *
 
 
76
  * @var bool
77
  */
78
  public $block_self = true;
79
 
80
  /** Wrapper ***************************************************************/
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  /**
83
  * The type of DOM element to use for a wrapper.
84
  *
85
- * @var string|bool 'div', 'span', 'p', 'li', or false for no wrapper.
 
 
 
86
  */
87
- public $wrapper = 'div';
88
 
89
  /**
90
  * The DOM class of the button wrapper.
91
  *
 
 
 
92
  * @var string
93
  */
94
  public $wrapper_class = '';
@@ -96,15 +168,19 @@ class BP_Button {
96
  /**
97
  * The DOM ID of the button wrapper.
98
  *
 
 
 
99
  * @var string
100
  */
101
  public $wrapper_id = '';
102
 
103
- /** Button ****************************************************************/
104
-
105
  /**
106
  * The destination link of the button.
107
  *
 
 
 
108
  * @var string
109
  */
110
  public $link_href = '';
@@ -112,6 +188,9 @@ class BP_Button {
112
  /**
113
  * The DOM class of the button link.
114
  *
 
 
 
115
  * @var string
116
  */
117
  public $link_class = '';
@@ -119,6 +198,9 @@ class BP_Button {
119
  /**
120
  * The DOM ID of the button link.
121
  *
 
 
 
122
  * @var string
123
  */
124
  public $link_id = '';
@@ -126,6 +208,9 @@ class BP_Button {
126
  /**
127
  * The DOM rel value of the button link.
128
  *
 
 
 
129
  * @var string
130
  */
131
  public $link_rel = '';
@@ -133,22 +218,12 @@ class BP_Button {
133
  /**
134
  * Title of the button link.
135
  *
136
- * @var string
137
- */
138
- public $link_title = '';
139
-
140
- /**
141
- * The contents of the button link.
142
  *
143
  * @var string
144
  */
145
- public $link_text = '';
146
-
147
- /** HTML result
148
- *
149
- * @var string
150
- */
151
- public $contents = '';
152
 
153
  /** Methods ***************************************************************/
154
 
@@ -163,76 +238,95 @@ class BP_Button {
163
 
164
  $r = wp_parse_args( $args, get_class_vars( __CLASS__ ) );
165
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  // Required button properties.
167
  $this->id = $r['id'];
168
  $this->component = $r['component'];
169
  $this->must_be_logged_in = (bool) $r['must_be_logged_in'];
170
  $this->block_self = (bool) $r['block_self'];
171
- $this->wrapper = $r['wrapper'];
172
 
173
- // $id and $component are required
174
- if ( empty( $r['id'] ) || empty( $r['component'] ) )
175
- return false;
176
-
177
- // No button if component is not active.
178
- if ( ! bp_is_active( $this->component ) )
179
  return false;
 
180
 
181
  // No button for guests if must be logged in.
182
- if ( true == $this->must_be_logged_in && ! is_user_logged_in() )
183
  return false;
 
184
 
185
  // The block_self property.
186
  if ( true == $this->block_self ) {
187
- // No button if you are the current user in a members loop
188
- // This condition takes precedence, because members loops
189
- // can be found on user profiles.
 
 
 
190
  if ( bp_get_member_user_id() ) {
191
  if ( is_user_logged_in() && bp_loggedin_user_id() == bp_get_member_user_id() ) {
192
  return false;
193
  }
194
 
195
- // No button if viewing your own profile (and not in
196
- // a members loop).
197
  } elseif ( bp_is_my_profile() ) {
198
  return false;
199
  }
200
  }
201
 
202
- // Wrapper properties.
203
- if ( false !== $this->wrapper ) {
204
-
205
- // Wrapper ID.
206
- if ( !empty( $r['wrapper_id'] ) ) {
207
- $this->wrapper_id = ' id="' . $r['wrapper_id'] . '"';
208
  }
209
 
210
- // Wrapper class.
211
- if ( !empty( $r['wrapper_class'] ) ) {
212
- $this->wrapper_class = ' class="generic-button ' . $r['wrapper_class'] . '"';
213
- } else {
214
- $this->wrapper_class = ' class="generic-button"';
 
215
  }
216
 
 
 
 
 
 
 
217
  // Set before and after.
218
- $before = '<' . $r['wrapper'] . $this->wrapper_class . $this->wrapper_id . '>';
219
- $after = '</' . $r['wrapper'] . '>';
220
 
221
- // No wrapper.
222
  } else {
223
  $before = $after = '';
224
  }
225
 
226
- // Link properties.
227
- if ( !empty( $r['link_id'] ) ) $this->link_id = ' id="' . $r['link_id'] . '"';
228
- if ( !empty( $r['link_href'] ) ) $this->link_href = ' href="' . $r['link_href'] . '"';
229
- if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"';
230
- if ( !empty( $r['link_rel'] ) ) $this->link_rel = ' rel="' . $r['link_rel'] . '"';
231
- if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"';
232
- if ( !empty( $r['link_text'] ) ) $this->link_text = $r['link_text'];
 
 
 
233
 
234
  // Build the button.
235
- $this->contents = $before . '<a'. $this->link_href . $this->link_title . $this->link_id . $this->link_rel . $this->link_class . '>' . $this->link_text . '</a>' . $after;
236
 
237
  /**
238
  * Filters the button based on class parameters.
@@ -241,15 +335,76 @@ class BP_Button {
241
  * allows button to be manipulated externally.
242
  *
243
  * @since 1.2.6
 
244
  *
245
  * @param string $contents HTML being used for the button.
246
  * @param BP_Button $this Current BP_Button instance.
247
  * @param string $before HTML appended before the actual button.
248
  * @param string $after HTML appended after the actual button.
 
249
  */
250
- $this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after );
251
  }
252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  /**
254
  * Return the markup for the generated button.
255
  *
14
  * API to create BuddyPress buttons.
15
  *
16
  * @since 1.2.6
17
+ * @since 2.7.0 Introduced $parent_element, $parent_attr, $button_element, $button_attr as
18
+ * $args parameters.
19
+ * Deprecated $wrapper, $wrapper_id, $wrapper_class, $link_href, $link_class,
20
+ * $link_id, $link_rel, $link_title as $args params.
21
  *
22
  * @param array $args {
23
  * Array of arguments.
24
  *
25
  * @type string $id String describing the button type.
26
+ * @type string $component The name of the component the button belongs to. Default: 'core'.
27
+ * @type bool $must_be_logged_in Optional. Does the user need to be logged in to see this button? Default:
28
+ * true.
29
+ * @type bool $block_self Optional. True if the button should be hidden when a user is viewing his
30
+ * own profile. Default: true.
31
+ * @type string $parent_element Optional. Parent element to wrap button around. Default: 'div'.
32
+ * @type array $parent_attr Optional. Element attributes for parent element. Set whatever attributes
33
+ * like 'id', 'class' as array keys.
34
+ * @type string $button_element Optional. Button element. Default: 'a'.
35
+ * @type array $button_attr Optional. Button attributes. Set whatever attributes like 'id', 'class' as
36
+ * array keys.
37
+ * @type string $link_text Optional. Text to appear on the button. Default: ''.
38
+ * @type string|bool $wrapper Deprecated. Use $parent_element instead.
39
+ * @type string $wrapper_id Deprecated. Use $parent_attr and set 'id' as array key.
40
+ * @type string $wrapper_class Deprecated. Use $parent_attr and set 'class' as array key.
41
+ * @type string $link_href Deprecated. Use $button_attr and set 'href' as array key.
42
+ * @type string $link_class Deprecated. Use $button_attr and set 'class' as array key.
43
+ * @type string $link_id Deprecated. Use $button_attr and set 'id' as array key.
44
+ * @type string $link_rel Deprecated. Use $button_attr and set 'rel' as array key.
45
+ * @type string $link_title Deprecated. Use $button_attr and set 'title' as array key.
 
 
 
 
46
  * }
47
  */
48
  class BP_Button {
52
  /**
53
  * The button ID.
54
  *
55
+ * @since 1.2.6
56
+ *
57
  * @var string
58
  */
59
  public $id = '';
61
  /**
62
  * The name of the component that the button belongs to.
63
  *
64
+ * @since 1.2.6
65
+ *
66
  * @var string
67
  */
68
  public $component = 'core';
70
  /**
71
  * Does the user need to be logged in to see this button?
72
  *
73
+ * @since 1.2.6
74
+ *
75
  * @var bool
76
  */
77
  public $must_be_logged_in = true;
79
  /**
80
  * Whether the button should be hidden when viewing your own profile.
81
  *
82
+ * @since 1.2.6
83
+ *
84
  * @var bool
85
  */
86
  public $block_self = true;
87
 
88
  /** Wrapper ***************************************************************/
89
 
90
+ /**
91
+ * Parent element to wrap button around.
92
+ *
93
+ * @since 2.7.0
94
+ *
95
+ * @var string Default: 'div'.
96
+ */
97
+ public $parent_element = 'div';
98
+
99
+ /**
100
+ * Element attributes for parent element.
101
+ *
102
+ * @since 2.7.0
103
+ *
104
+ * @var array Set whatever attributes like 'id', 'class' as array key.
105
+ */
106
+ public $parent_attr = array();
107
+
108
+ /** Button ****************************************************************/
109
+
110
+ /**
111
+ * Button element.
112
+ *
113
+ * @since 2.7.0
114
+ *
115
+ * @var string Default: 'a'.
116
+ */
117
+ public $button_element = 'a';
118
+
119
+ /**
120
+ * Button attributes.
121
+ *
122
+ * @since 2.7.0
123
+ *
124
+ * @var array Set whatever attributes like 'id', 'href' as array key.
125
+ */
126
+ public $button_attr = array();
127
+
128
+ /**
129
+ * The contents of the button link.
130
+ *
131
+ * @since 1.2.6
132
+ *
133
+ * @var string
134
+ */
135
+ public $link_text = '';
136
+
137
+ /**
138
+ * HTML result.
139
+ *
140
+ * @since 1.2.6
141
+ *
142
+ * @var string
143
+ */
144
+ public $contents = '';
145
+
146
+ /** Deprecated ***********************************************************/
147
+
148
  /**
149
  * The type of DOM element to use for a wrapper.
150
  *
151
+ * @since 1.2.6
152
+ * @deprecated 2.7.0 Use $parent_element instead.
153
+ *
154
+ * @var string|bool
155
  */
156
+ public $wrapper = '';
157
 
158
  /**
159
  * The DOM class of the button wrapper.
160
  *
161
+ * @since 1.2.6
162
+ * @deprecated 2.7.0 Set 'class' key in $parent_attr instead.
163
+ *
164
  * @var string
165
  */
166
  public $wrapper_class = '';
168
  /**
169
  * The DOM ID of the button wrapper.
170
  *
171
+ * @since 1.2.6
172
+ * @deprecated 2.7.0 Set 'id' key in $parent_attr instead.
173
+ *
174
  * @var string
175
  */
176
  public $wrapper_id = '';
177
 
 
 
178
  /**
179
  * The destination link of the button.
180
  *
181
+ * @since 1.2.6
182
+ * @deprecated 2.7.0 Set 'href' key in $button_attr instead.
183
+ *
184
  * @var string
185
  */
186
  public $link_href = '';
188
  /**
189
  * The DOM class of the button link.
190
  *
191
+ * @since 1.2.6
192
+ * @deprecated 2.7.0 Set 'class' key in $button_attr instead.
193
+ *
194
  * @var string
195
  */
196
  public $link_class = '';
198
  /**
199
  * The DOM ID of the button link.
200
  *
201
+ * @since 1.2.6
202
+ * @deprecated 2.7.0 Set 'id' key in $button_attr instead.
203
+ *
204
  * @var string
205
  */
206
  public $link_id = '';
208
  /**
209
  * The DOM rel value of the button link.
210
  *
211
+ * @since 1.2.6
212
+ * @deprecated 2.7.0 Set 'rel' key in $button_attr instead.
213
+ *
214
  * @var string
215
  */
216
  public $link_rel = '';
218
  /**
219
  * Title of the button link.
220
  *
221
+ * @since 1.2.6
222
+ * @deprecated 2.7.0 Set 'title' key in $button_attr instead.
 
 
 
 
223
  *
224
  * @var string
225
  */
226
+ public $link_title = '';
 
 
 
 
 
 
227
 
228
  /** Methods ***************************************************************/
229
 
238
 
239
  $r = wp_parse_args( $args, get_class_vars( __CLASS__ ) );
240
 
241
+ // Backward compatibility with deprecated parameters.
242
+ $r = $this->backward_compatibility_args( $r );
243
+
244
+ // Deprecated. Subject to removal in a future release.
245
+ $this->wrapper = $r['wrapper'];
246
+ if ( !empty( $r['link_id'] ) ) $this->link_id = ' id="' . $r['link_id'] . '"';
247
+ if ( !empty( $r['link_href'] ) ) $this->link_href = ' href="' . $r['link_href'] . '"';
248
+ if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"';
249
+ if ( !empty( $r['link_rel'] ) ) $this->link_rel = ' rel="' . $r['link_rel'] . '"';
250
+ if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"';
251
+ if ( !empty( $r['link_text'] ) ) $this->link_text = $r['link_text'];
252
+
253
  // Required button properties.
254
  $this->id = $r['id'];
255
  $this->component = $r['component'];
256
  $this->must_be_logged_in = (bool) $r['must_be_logged_in'];
257
  $this->block_self = (bool) $r['block_self'];
 
258
 
259
+ // $id and $component are required and component must be active.
260
+ if ( empty( $r['id'] ) || empty( $r['component'] ) || ! bp_is_active( $this->component ) ) {
 
 
 
 
261
  return false;
262
+ }
263
 
264
  // No button for guests if must be logged in.
265
+ if ( true == $this->must_be_logged_in && ! is_user_logged_in() ) {
266
  return false;
267
+ }
268
 
269
  // The block_self property.
270
  if ( true == $this->block_self ) {
271
+ /*
272
+ * No button if you are the current user in a members loop.
273
+ *
274
+ * This condition takes precedence, because members loops can be found on user
275
+ * profiles.
276
+ */
277
  if ( bp_get_member_user_id() ) {
278
  if ( is_user_logged_in() && bp_loggedin_user_id() == bp_get_member_user_id() ) {
279
  return false;
280
  }
281
 
282
+ // No button if viewing your own profile (and not in a members loop).
 
283
  } elseif ( bp_is_my_profile() ) {
284
  return false;
285
  }
286
  }
287
 
288
+ // Should we use a parent element?
289
+ if ( ! empty( $r['parent_element'] ) ) {
290
+ if ( ! isset( $r['parent_attr']['class'] ) ) {
291
+ $r['parent_attr']['class'] = '';
 
 
292
  }
293
 
294
+ // Always add 'generic-button' class.
295
+ if ( false === strpos( $r['parent_attr']['class'], 'generic-button' ) ) {
296
+ if ( ! empty( $r['parent_attr']['class'] ) ) {
297
+ $r['parent_attr']['class'] .= ' ';
298
+ }
299
+ $r['parent_attr']['class'] .= 'generic-button';
300
  }
301
 
302
+ // Render parent element attributes.
303
+ $parent_elem = new BP_Core_HTML_Element( array(
304
+ 'element' => $r['parent_element'],
305
+ 'attr' => $r['parent_attr']
306
+ ) );
307
+
308
  // Set before and after.
309
+ $before = $parent_elem->get( 'open_tag' );
310
+ $after = $parent_elem->get( 'close_tag' );
311
 
312
+ // No parent element.
313
  } else {
314
  $before = $after = '';
315
  }
316
 
317
+ // Button properties.
318
+ $button = '';
319
+ if ( ! empty( $r['button_element'] ) ) {
320
+ $button = new BP_Core_HTML_Element( array(
321
+ 'element' => $r['button_element'],
322
+ 'attr' => $r['button_attr'],
323
+ 'inner_html' => ! empty( $r['link_text'] ) ? $r['link_text'] : ''
324
+ ) );
325
+ $button = $button->contents();
326
+ }
327
 
328
  // Build the button.
329
+ $this->contents = $before . $button . $after;
330
 
331
  /**
332
  * Filters the button based on class parameters.
335
  * allows button to be manipulated externally.
336
  *
337
  * @since 1.2.6
338
+ * @since 2.7.0 Added $r as a parameter.
339
  *
340
  * @param string $contents HTML being used for the button.
341
  * @param BP_Button $this Current BP_Button instance.
342
  * @param string $before HTML appended before the actual button.
343
  * @param string $after HTML appended after the actual button.
344
+ * @param array $r Parsed button arguments.
345
  */
346
+ $this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after, $r );
347
  }
348
 
349
+
350
+ /**
351
+ * Provide backward compatibility for deprecated button arguments.
352
+ *
353
+ * @since 2.7.0.
354
+ *
355
+ * @param array $r See {@link BP_Button} class for full documentation.
356
+ * @return array
357
+ */
358
+ protected function backward_compatibility_args( $r = array() ) {
359
+ // Array of deprecated arguments.
360
+ $backpat_args = array(
361
+ 'wrapper', 'wrapper_class', 'wrapper_id',
362
+ 'link_href', 'link_class', 'link_id', 'link_rel', 'link_title'
363
+ );
364
+
365
+ foreach ( $backpat_args as $prop ) {
366
+ if ( empty( $r[ $prop ] ) ) {
367
+ continue;
368
+ }
369
+
370
+ $parent = $child = false;
371
+ $sep = strpos( $prop, '_' );
372
+
373
+ // Check if this is an attribute.
374
+ if ( false !== $sep ) {
375
+ $child = true;
376
+ $parent = substr( $prop, 0, $sep );
377
+ } else {
378
+ $parent = $prop;
379
+ }
380
+
381
+ if ( 'wrapper' === $parent ) {
382
+ $parent = 'parent';
383
+ } else {
384
+ $parent = 'button';
385
+ }
386
+
387
+ // Set element.
388
+ if ( false === $child ) {
389
+ $r[ "{$parent}_element" ] = $r[ $prop ];
390
+
391
+ // Set attributes.
392
+ } elseif ( true === $child ) {
393
+ $new_prop = substr( $prop, strpos( $prop, '_' ) +1 );
394
+ if ( empty( $r[ "{$parent}_attr" ] ) ) {
395
+ $r[ "{$parent}_attr" ] = array();
396
+ }
397
+
398
+ if ( empty( $r[ "{$parent}_attr" ][ $new_prop ] ) ) {
399
+ $r[ "{$parent}_attr" ][ $new_prop ] = $r[ $prop ];
400
+ }
401
+ }
402
+ }
403
+
404
+ return $r;
405
+ }
406
+
407
+
408
  /**
409
  * Return the markup for the generated button.
410
  *
bp-core/classes/class-bp-core-html-element.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Core component classes.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Core
7
+ * @since 2.7.0
8
+ */
9
+
10
+ /**
11
+ * Generate markup for an HTML element.
12
+ *
13
+ * @since 2.7.0
14
+ */
15
+ class BP_Core_HTML_Element {
16
+ /**
17
+ * Open tag for an element.
18
+ *
19
+ * This would include attributes if applicable. eg. '<a href="" class="">'
20
+ *
21
+ * @since 2.7.0
22
+ *
23
+ * @var string
24
+ */
25
+ public $open_tag = '';
26
+
27
+ /**
28
+ * Inner HTML for an element.
29
+ *
30
+ * For example, this could be anchor text within an <a> element.
31
+ *
32
+ * @since 2.7.0
33
+ *
34
+ * @var string
35
+ */
36
+ public $inner_html = '';
37
+
38
+ /**
39
+ * Closing tag for an element.
40
+ *
41
+ * For example, "</a>".
42
+ *
43
+ * @since 2.7.0
44
+ *
45
+ * @var string
46
+ */
47
+ public $close_tag = '';
48
+
49
+ /**
50
+ * Constructor.
51
+ *
52
+ * @since 2.7.0
53
+ *
54
+ * @param array $r {
55
+ * An array of arguments.
56
+ * @type string $element The element to render. eg. 'a' for the anchor element.
57
+ * @type array $attr Optional. The element's attributes set as key/value pairs. eg.
58
+ * array( 'href' => 'http://example.com', 'class' => 'my-class' )
59
+ * @type string $inner_html Optional. The inner HTML for the element if applicable. Please note that
60
+ * this isn't sanitized, so you should use your own sanitization routine
61
+ * before using this parameter.
62
+ * }
63
+ */
64
+ public function __construct( $r = array() ) {
65
+ $elem = sanitize_html_class( $r['element'] );
66
+ if ( empty( $elem ) ) {
67
+ return;
68
+ }
69
+
70
+ // Render attributes.
71
+ $attributes = '';
72
+ foreach( (array) $r['attr'] as $attr => $val ) {
73
+ // If attribute is empty, skip.
74
+ if ( empty( $val ) ) {
75
+ continue;
76
+ }
77
+
78
+ if ( 'href' === $attr || 'formaction' === $attr || 'src' === $attr ) {
79
+ $val = esc_url( $val );
80
+ } elseif ( 'id' === $attr ) {
81
+ $val = sanitize_html_class( $val );
82
+ } else {
83
+ $val = esc_attr( $val );
84
+ }
85
+
86
+ $attributes .= sprintf( '%s="%s" ', sanitize_html_class( $attr ), $val );
87
+ }
88
+
89
+ // <input> / <img> is self-closing.
90
+ if ( 'input' === $elem || 'img' === $elem ) {
91
+ $this->open_tag = sprintf( '<%1$s %2$s />', $elem, $attributes );
92
+
93
+ // All other elements.
94
+ } else {
95
+ $this->open_tag = sprintf( '<%1$s %2$s>', $elem, $attributes );
96
+ $this->inner_html = ! empty( $r['inner_html'] ) ? $r['inner_html'] : '';
97
+ $this->close_tag = sprintf( '</%1$s>', $elem );
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Returns a property from this class.
103
+ *
104
+ * @since 2.7.0
105
+ *
106
+ * @param string $prop Property name. Either 'open_tag', 'inner_html', 'close_tag'.
107
+ * @return string
108
+ */
109
+ public function get( $prop = '' ) {
110
+ if ( ! isset( $this->{$prop} ) ) {
111
+ return '';
112
+ }
113
+
114
+ return $this->{$prop};
115
+ }
116
+
117
+ /**
118
+ * Returns full contents of HTML element.
119
+ *
120
+ * @since 2.7.0
121
+ *
122
+ * @return string
123
+ */
124
+ public function contents() {
125
+ return $this->open_tag . $this->inner_html . $this->close_tag;
126
+ }
127
+ }
bp-core/classes/class-bp-core-nav.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * @package BuddyPress
6
  * @subpackage Core
7
- * @since 2.6.0
8
  */
9
 
10
  // Exit if accessed directly.
@@ -56,7 +56,7 @@ class BP_Core_Nav {
56
  *
57
  * @since 2.6.0
58
  *
59
- * @param string $key The requested nav slug.
60
  * @return bool True if the nav item is set, false otherwise.
61
  */
62
  public function __isset( $key ) {
@@ -68,7 +68,7 @@ class BP_Core_Nav {
68
  *
69
  * @since 2.6.0
70
  *
71
- * @param string $key The requested nav slug.
72
  * @return mixed The value corresponding to the requested nav item.
73
  */
74
  public function __get( $key ) {
@@ -84,8 +84,8 @@ class BP_Core_Nav {
84
  *
85
  * @since 2.6.0
86
  *
87
- * @param string $key The requested nav slug.
88
- * @param mixed $value The value of the nav item.
89
  */
90
  public function __set( $key, $value ) {
91
  if ( is_array( $value ) ) {
@@ -100,7 +100,7 @@ class BP_Core_Nav {
100
  *
101
  * @since 2.6.0
102
  *
103
- * @param string $key The nav item slug to get. Optional.
104
  * @return mixed An array of nav item, a single nav item, or null if none found.
105
  */
106
  public function get( $key = '' ) {
@@ -276,7 +276,7 @@ class BP_Core_Nav {
276
  unset( $this->nav[ $this->object_id ][ $nav_item->slug ] );
277
 
278
  // Return the deleted item's screen functions.
279
- return array_unique( $screen_functions );
280
  }
281
  }
282
 
@@ -320,14 +320,14 @@ class BP_Core_Nav {
320
  *
321
  * @since 2.6.0
322
  *
323
- * @param array $args Filters to select the specific primary items. See wp_list_filter().
324
- * @param bool $sort True to sort the nav items. False otherwise.
325
  * @return array The list of primary objects nav
326
  */
327
  public function get_primary( $args = array(), $sort = true ) {
328
  $params = wp_parse_args( $args, array( 'primary' => true ) );
329
 
330
- // This parameter is not overridable
331
  if ( empty( $params['primary'] ) ) {
332
  return false;
333
  }
@@ -350,14 +350,14 @@ class BP_Core_Nav {
350
  *
351
  * @since 2.6.0
352
  *
353
- * @param array $args Filters to select the specific secondary items. See wp_list_filter().
354
- * @param bool $sort True to sort the nav items. False otherwise.
355
  * @return array The list of secondary objects nav
356
  */
357
  public function get_secondary( $args = array(), $sort = true ) {
358
  $params = wp_parse_args( $args, array( 'parent_slug' => '' ) );
359
 
360
- // No need to search children if the parent is not set
361
  if ( empty( $params['parent_slug'] ) && empty( $params['secondary'] ) ) {
362
  return false;
363
  }
@@ -387,11 +387,11 @@ class BP_Core_Nav {
387
 
388
  if ( $primary_nav_items ) {
389
  foreach( $primary_nav_items as $key_nav => $primary_nav ) {
390
- // Try to get the children
391
  $children = $this->get_secondary( array( 'parent_slug' => $primary_nav->slug, 'user_has_access' => true ) );
392
 
393
  if ( $children ) {
394
- $primary_nav_items[ $key_nav ] = clone( $primary_nav );
395
  $primary_nav_items[ $key_nav ]->children = $children;
396
  }
397
  }
4
  *
5
  * @package BuddyPress
6
  * @subpackage Core
7
+ * @since 2.6.0
8
  */
9
 
10
  // Exit if accessed directly.
56
  *
57
  * @since 2.6.0
58
  *
59
+ * @param string $key The requested nav slug.
60
  * @return bool True if the nav item is set, false otherwise.
61
  */
62
  public function __isset( $key ) {
68
  *
69
  * @since 2.6.0
70
  *
71
+ * @param string $key The requested nav slug.
72
  * @return mixed The value corresponding to the requested nav item.
73
  */
74
  public function __get( $key ) {
84
  *
85
  * @since 2.6.0
86
  *
87
+ * @param string $key The requested nav slug.
88
+ * @param mixed $value The value of the nav item.
89
  */
90
  public function __set( $key, $value ) {
91
  if ( is_array( $value ) ) {
100
  *
101
  * @since 2.6.0
102
  *
103
+ * @param string $key The nav item slug to get. Optional.
104
  * @return mixed An array of nav item, a single nav item, or null if none found.
105
  */
106
  public function get( $key = '' ) {
276
  unset( $this->nav[ $this->object_id ][ $nav_item->slug ] );
277
 
278
  // Return the deleted item's screen functions.
279
+ return $screen_functions;
280
  }
281
  }
282
 
320
  *
321
  * @since 2.6.0
322
  *
323
+ * @param array $args Filters to select the specific primary items. See wp_list_filter().
324
+ * @param bool $sort True to sort the nav items. False otherwise.
325
  * @return array The list of primary objects nav
326
  */
327
  public function get_primary( $args = array(), $sort = true ) {
328
  $params = wp_parse_args( $args, array( 'primary' => true ) );
329
 
330
+ // This parameter is not overridable.
331
  if ( empty( $params['primary'] ) ) {
332
  return false;
333
  }
350
  *
351
  * @since 2.6.0
352
  *
353
+ * @param array $args Filters to select the specific secondary items. See wp_list_filter().
354
+ * @param bool $sort True to sort the nav items. False otherwise.
355
  * @return array The list of secondary objects nav
356
  */
357
  public function get_secondary( $args = array(), $sort = true ) {
358
  $params = wp_parse_args( $args, array( 'parent_slug' => '' ) );
359
 
360
+ // No need to search children if the parent is not set.
361
  if ( empty( $params['parent_slug'] ) && empty( $params['secondary'] ) ) {
362
  return false;
363
  }
387
 
388
  if ( $primary_nav_items ) {
389
  foreach( $primary_nav_items as $key_nav => $primary_nav ) {
390
+ // Try to get the children.
391
  $children = $this->get_secondary( array( 'parent_slug' => $primary_nav->slug, 'user_has_access' => true ) );
392
 
393
  if ( $children ) {
394
+ $primary_nav_items[ $key_nav ] = clone $primary_nav;
395
  $primary_nav_items[ $key_nav ]->children = $children;
396
  }
397
  }
bp-core/classes/class-bp-core-oembed-extension.php CHANGED
@@ -4,6 +4,7 @@
4
  *
5
  * @package BuddyPress
6
  * @subpackage Core
 
7
  */
8
 
9
  // Exit if accessed directly.
@@ -71,6 +72,7 @@ abstract class BP_Core_oEmbed_Extension {
71
  *
72
  * @since 2.6.0
73
  *
 
74
  * @return int Your item ID
75
  */
76
  abstract protected function validate_url_to_item_id( $url );
@@ -80,7 +82,7 @@ abstract class BP_Core_oEmbed_Extension {
80
  *
81
  * @since 2.6.0
82
  *
83
- * @param int $item_id Your item ID to do checks against.
84
  * @return array Should contain 'content', 'title', 'author_url', 'author_name' as array
85
  * keys. 'author_url' and 'author_name' is optional; the rest are required.
86
  */
@@ -94,7 +96,7 @@ abstract class BP_Core_oEmbed_Extension {
94
  *
95
  * @since 2.6.0
96
  *
97
- * @param int $item_id Your item ID to do checks against.
98
  * @return string Fallback HTML you want to output.
99
  */
100
  abstract protected function set_fallback_html( $item_id );
@@ -122,7 +124,6 @@ abstract class BP_Core_oEmbed_Extension {
122
  * @since 2.6.0
123
  *
124
  * @param int $item_id The item ID to do checks for.
125
- * @return string
126
  */
127
  protected function set_iframe_title( $item_id ) {}
128
 
@@ -145,7 +146,7 @@ abstract class BP_Core_oEmbed_Extension {
145
  protected function set_permalink() {
146
  $url = bp_get_requested_url();
147
 
148
- // Remove querystring from bp_get_requested_url()
149
  if ( false !== strpos( bp_get_requested_url(), '?' ) ) {
150
  $url = substr( bp_get_requested_url(), 0, strpos( bp_get_requested_url(), '?' ) );
151
  }
@@ -239,7 +240,7 @@ abstract class BP_Core_oEmbed_Extension {
239
  *
240
  * @since 2.6.0
241
  *
242
- * @param string $template File path to current embed template.
243
  * @return string
244
  */
245
  public function setup_template_parts( $template ) {
@@ -263,6 +264,9 @@ abstract class BP_Core_oEmbed_Extension {
263
  * and inject our own template for BuddyPress use.
264
  *
265
  * @since 2.6.0
 
 
 
266
  */
267
  public function content_buffer_start( $slug, $name ) {
268
  if ( 'embed' !== $slug || 'content' !== $name ) {
@@ -280,6 +284,8 @@ abstract class BP_Core_oEmbed_Extension {
280
  * and inject our own template for BuddyPress use.
281
  *
282
  * @since 2.6.0
 
 
283
  */
284
  public function content_buffer_end( $name ) {
285
  if ( 'embed' !== $name || is_404() ) {
@@ -318,7 +324,7 @@ abstract class BP_Core_oEmbed_Extension {
318
  *
319
  * @since 2.6.0
320
  *
321
- * @param string $retval Current discovery links.
322
  * @return string
323
  */
324
  public function add_oembed_discovery_links( $retval ) {
@@ -353,8 +359,8 @@ abstract class BP_Core_oEmbed_Extension {
353
  *
354
  * @link http://oembed.com/ View the 'Response parameters' section for more details.
355
  *
356
- * @param array $item Custom oEmbed response data.
357
- * @param int $width The requested width.
358
  * @return array
359
  */
360
  protected function get_oembed_response_data( $item, $width ) {
@@ -403,7 +409,7 @@ abstract class BP_Core_oEmbed_Extension {
403
  *
404
  * @since 2.6.0
405
  *
406
- * @param WP_REST_Request $request Full data about the request.
407
  * @return WP_Error|array oEmbed response data or WP_Error on failure.
408
  */
409
  public function get_item( $request ) {
@@ -508,7 +514,7 @@ abstract class BP_Core_oEmbed_Extension {
508
  *
509
  * @see bp_activity_embed_rest_route_callback()
510
  *
511
- * @param string $retval Current embed URL
512
  * @return string
513
  */
514
  public function filter_embed_url( $retval ) {
@@ -520,7 +526,7 @@ abstract class BP_Core_oEmbed_Extension {
520
  $url = trailingslashit( $url );
521
 
522
  // This is for the 'WordPress Embed' block
523
- // @see bp_activity_embed_comments_button()
524
  if ( 'the_permalink' !== current_filter() ) {
525
  $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) );
526
 
@@ -540,7 +546,7 @@ abstract class BP_Core_oEmbed_Extension {
540
  *
541
  * @since 2.6.0
542
  *
543
- * @param string $retval Current embed HTML
544
  * @return string
545
  */
546
  public function filter_embed_html( $retval ) {
@@ -567,7 +573,7 @@ abstract class BP_Core_oEmbed_Extension {
567
  $retval = str_replace( '<iframe', '<iframe style="max-width:100%"', $retval );
568
  }
569
 
570
- // Remove default <blockquote>
571
  $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 );
572
 
573
  // Set up new fallback HTML
@@ -594,7 +600,7 @@ abstract class BP_Core_oEmbed_Extension {
594
  *
595
  * @see add_oembed_discovery_links()
596
  *
597
- * @param string $retval Current oEmbed endpoint URL
598
  * @return string
599
  */
600
  public function filter_rest_url( $retval = '' ) {
@@ -613,4 +619,4 @@ abstract class BP_Core_oEmbed_Extension {
613
 
614
  $this->content();
615
  }
616
- }
4
  *
5
  * @package BuddyPress
6
  * @subpackage Core
7
+ * @since 2.6.0
8
  */
9
 
10
  // Exit if accessed directly.
72
  *
73
  * @since 2.6.0
74
  *
75
+ * @param string $url URL to validate.
76
  * @return int Your item ID
77
  */
78
  abstract protected function validate_url_to_item_id( $url );
82
  *
83
  * @since 2.6.0
84
  *
85
+ * @param int $item_id Your item ID to do checks against.
86
  * @return array Should contain 'content', 'title', 'author_url', 'author_name' as array
87
  * keys. 'author_url' and 'author_name' is optional; the rest are required.
88
  */
96
  *
97
  * @since 2.6.0
98
  *
99
+ * @param int $item_id Your item ID to do checks against.
100
  * @return string Fallback HTML you want to output.
101
  */
102
  abstract protected function set_fallback_html( $item_id );
124
  * @since 2.6.0
125
  *
126
  * @param int $item_id The item ID to do checks for.
 
127
  */
128
  protected function set_iframe_title( $item_id ) {}
129
 
146
  protected function set_permalink() {
147
  $url = bp_get_requested_url();
148
 
149
+ // Remove querystring from bp_get_requested_url().
150
  if ( false !== strpos( bp_get_requested_url(), '?' ) ) {
151
  $url = substr( bp_get_requested_url(), 0, strpos( bp_get_requested_url(), '?' ) );
152
  }
240
  *
241
  * @since 2.6.0
242
  *
243
+ * @param string $template File path to current embed template.
244
  * @return string
245
  */
246
  public function setup_template_parts( $template ) {
264
  * and inject our own template for BuddyPress use.
265
  *
266
  * @since 2.6.0
267
+ *
268
+ * @param string $slug Template slug.
269
+ * @param string $name Template name.
270
  */
271
  public function content_buffer_start( $slug, $name ) {
272
  if ( 'embed' !== $slug || 'content' !== $name ) {
284
  * and inject our own template for BuddyPress use.
285
  *
286
  * @since 2.6.0
287
+ *
288
+ * @param string $name Template name.
289
  */
290
  public function content_buffer_end( $name ) {
291
  if ( 'embed' !== $name || is_404() ) {
324
  *
325
  * @since 2.6.0
326
  *
327
+ * @param string $retval Current discovery links.
328
  * @return string
329
  */
330
  public function add_oembed_discovery_links( $retval ) {
359
  *
360
  * @link http://oembed.com/ View the 'Response parameters' section for more details.
361
  *
362
+ * @param array $item Custom oEmbed response data.
363
+ * @param int $width The requested width.
364
  * @return array
365
  */
366
  protected function get_oembed_response_data( $item, $width ) {
409
  *
410
  * @since 2.6.0
411
  *
412
+ * @param WP_REST_Request $request Full data about the request.
413
  * @return WP_Error|array oEmbed response data or WP_Error on failure.
414
  */
415
  public function get_item( $request ) {
514
  *
515
  * @see bp_activity_embed_rest_route_callback()
516
  *
517
+ * @param string $retval Current embed URL.
518
  * @return string
519
  */
520
  public function filter_embed_url( $retval ) {
526
  $url = trailingslashit( $url );
527
 
528
  // This is for the 'WordPress Embed' block
529
+ // @see bp_activity_embed_comments_button().
530
  if ( 'the_permalink' !== current_filter() ) {
531
  $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) );
532
 
546
  *
547
  * @since 2.6.0
548
  *
549
+ * @param string $retval Current embed HTML.
550
  * @return string
551
  */
552
  public function filter_embed_html( $retval ) {
573
  $retval = str_replace( '<iframe', '<iframe style="max-width:100%"', $retval );
574
  }
575
 
576
+ // Remove default <blockquote>.
577
  $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 );
578
 
579
  // Set up new fallback HTML
600
  *
601
  * @see add_oembed_discovery_links()
602
  *
603
+ * @param string $retval Current oEmbed endpoint URL.
604
  * @return string
605
  */
606
  public function filter_rest_url( $retval = '' ) {
619
 
620
  $this->content();
621
  }
622
+ }
bp-core/classes/class-bp-core-user.php CHANGED
@@ -811,6 +811,13 @@ class BP_Core_User {
811
  $retval = array();
812
  foreach ( $user_ids as $user_id ) {
813
  $retval[ $user_id ] = wp_cache_get( $user_id, 'bp_last_activity' );
 
 
 
 
 
 
 
814
  }
815
 
816
  return $retval;
@@ -905,6 +912,16 @@ class BP_Core_User {
905
  // Set cache.
906
  wp_cache_set( $user_id, $activity[ $user_id ], 'bp_last_activity' );
907
 
 
 
 
 
 
 
 
 
 
 
908
  return $updated;
909
  }
910
 
811
  $retval = array();
812
  foreach ( $user_ids as $user_id ) {
813
  $retval[ $user_id ] = wp_cache_get( $user_id, 'bp_last_activity' );
814
+
815
+ if ( isset( $retval['user_id'] ) ) {
816
+ $retval[ $user_id ]['user_id'] = (int) $retval[ $user_id ]['user_id'];
817
+ }
818
+ if ( isset( $retval['activity_id'] ) ) {
819
+ $retval[ $user_id ]['activity_id'] = (int) $retval[ $user_id ]['activity_id'];
820
+ }
821
  }
822
 
823
  return $retval;
912
  // Set cache.
913
  wp_cache_set( $user_id, $activity[ $user_id ], 'bp_last_activity' );
914
 
915
+ /**
916
+ * Fires when a user's last_activity value has been updated.
917
+ *
918
+ * @since 2.7.0
919
+ *
920
+ * @param int $user_id ID of the user.
921
+ * @param string $time Last activity timestamp, in 'Y-m-d H:i:s' format.
922
+ */
923
+ do_action( 'bp_core_user_updated_last_activity', $user_id, $time );
924
+
925
  return $updated;
926
  }
927
 
bp-core/classes/class-bp-theme-compat.php CHANGED
@@ -50,7 +50,7 @@ class BP_Theme_Compat {
50
  *
51
  * @param array $properties Array of properties for BP_Theme_Compat.
52
  */
53
- public function __construct( Array $properties = array() ) {
54
  $this->_data = $properties;
55
  }
56
 
50
  *
51
  * @param array $properties Array of properties for BP_Theme_Compat.
52
  */
53
+ public function __construct( Array $properties = array() ) {
54
  $this->_data = $properties;
55
  }
56
 
bp-core/classes/class-bp-user-query.php CHANGED
@@ -364,7 +364,11 @@ class BP_User_Query {
364
  // 'include' - User ids to include in the results.
365
  $include = false !== $include ? wp_parse_id_list( $include ) : array();
366
  $include_ids = $this->get_include_ids( $include );
367
- if ( ! empty( $include_ids ) ) {
 
 
 
 
368
  $include_ids = implode( ',', wp_parse_id_list( $include_ids ) );
369
  $sql['where'][] = "u.{$this->uid_name} IN ({$include_ids})";
370
  }
@@ -591,11 +595,14 @@ class BP_User_Query {
591
  // Match up to the user ids from the main query.
592
  foreach ( $this->user_ids as $key => $uid ) {
593
  if ( isset( $r[ $uid ] ) ) {
 
 
 
594
  $this->results[ $uid ] = $r[ $uid ];
595
 
596
  // The BP template functions expect an 'id'
597
  // (as opposed to 'ID') property.
598
- $this->results[ $uid ]->id = $uid;
599
 
600
  // Remove user ID from original user_ids property.
601
  } else {
@@ -780,7 +787,7 @@ class BP_User_Query {
780
 
781
  $tax_query = new WP_Tax_Query( array(
782
  array(
783
- 'taxonomy' => 'bp_member_type',
784
  'field' => 'name',
785
  'operator' => $operator,
786
  'terms' => $types,
@@ -788,7 +795,7 @@ class BP_User_Query {
788
  ) );
789
 
790
  // Switch to the root blog, where member type taxonomies live.
791
- $site_id = bp_get_taxonomy_term_site_id( 'bp_member_type' );
792
  $switched = false;
793
  if ( $site_id !== get_current_blog_id() ) {
794
  switch_to_blog( $site_id );
364
  // 'include' - User ids to include in the results.
365
  $include = false !== $include ? wp_parse_id_list( $include ) : array();
366
  $include_ids = $this->get_include_ids( $include );
367
+
368
+ // An array containing nothing but 0 should always fail.
369
+ if ( 1 === count( $include_ids ) && 0 == reset( $include_ids ) ) {
370
+ $sql['where'][] = $this->no_results['where'];
371
+ } elseif ( ! empty( $include_ids ) ) {
372
  $include_ids = implode( ',', wp_parse_id_list( $include_ids ) );
373
  $sql['where'][] = "u.{$this->uid_name} IN ({$include_ids})";
374
  }
595
  // Match up to the user ids from the main query.
596
  foreach ( $this->user_ids as $key => $uid ) {
597
  if ( isset( $r[ $uid ] ) ) {
598
+ $r[ $uid ]->ID = (int) $uid;
599
+ $r[ $uid ]->user_status = (int) $r[ $uid ]->user_status;
600
+
601
  $this->results[ $uid ] = $r[ $uid ];
602
 
603
  // The BP template functions expect an 'id'
604
  // (as opposed to 'ID') property.
605
+ $this->results[ $uid ]->id = (int) $uid;
606
 
607
  // Remove user ID from original user_ids property.
608
  } else {
787
 
788
  $tax_query = new WP_Tax_Query( array(
789
  array(
790
+ 'taxonomy' => bp_get_member_type_tax_name(),
791
  'field' => 'name',
792
  'operator' => $operator,
793
  'terms' => $types,
795
  ) );
796
 
797
  // Switch to the root blog, where member type taxonomies live.
798
+ $site_id = bp_get_taxonomy_term_site_id( bp_get_member_type_tax_name() );
799
  $switched = false;
800
  if ( $site_id !== get_current_blog_id() ) {
801
  switch_to_blog( $site_id );
bp-core/css/avatar-rtl.css CHANGED
@@ -165,7 +165,7 @@ div.bp-avatar-nav {
165
  }
166
 
167
  .drag-drop .drag-drop-inside p {
168
- color: #aaa;
169
  font-size: 110%;
170
  margin: 5px 0;
171
  text-align: center;
165
  }
166
 
167
  .drag-drop .drag-drop-inside p {
168
+ color: #767676;
169
  font-size: 110%;
170
  margin: 5px 0;
171
  text-align: center;
bp-core/css/avatar-rtl.min.css CHANGED
@@ -1 +1 @@
1
- div.bp-avatar-status,div.bp-cover-image-status{clear:both;margin:1em 0}div.bp-avatar-status p.updated,div.bp-cover-image-status p.updated{display:block;padding:10px 15px}div.bp-avatar-status p.success,div.bp-cover-image-status p.success{background-color:#efc;border:1px solid #591;color:#250}div.bp-avatar-status p.error,div.bp-cover-image-status p.error{background-color:#fdc;border:1px solid #a00;color:#800}div.bp-avatar-status .bp-progress,div.bp-cover-image-status .bp-progress{background:0 0;border:1px solid #d1d1d1;float:left;height:22px;line-height:2em;margin:6px 0 2px 10px;padding:0;overflow:hidden;width:200px}div.bp-avatar-status .bp-bar,div.bp-cover-image-status .bp-bar{background-color:#c3ff88;width:0;height:100%;z-index:9}.bp-uploader-progress div.error{background-color:#fdc;border:1px solid #a00;color:#800;display:block;font-size:90%;padding:10px 15px}#buddypress p.warning,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{background-color:#ffd;border:1px solid #cb2;color:#440;display:block;font-size:90%;margin:1em 0;padding:10px 15px}div.bp-avatar-nav{background:0 0;clear:both;margin:10px 0;overflow:hidden}.avatar-nav-items{margin:0;padding:0}.bp-avatar-nav .avatar-nav-items li.avatar-nav-item{float:right!important;margin:0;list-style:none}.avatar-nav-items li a{display:block;padding:5px 10px;text-decoration:none}.bp-avatar-nav ul:after,.bp-avatar-nav ul:before{content:" ";display:table}.bp-avatar-nav ul:after{clear:both}.bp-avatar-nav ul{border-bottom:1px solid #ccc;margin-bottom:10px}.bp-avatar-nav ul.avatar-nav-items li.current{border:1px solid #ccc;border-bottom-color:#fff;border-top-right-radius:4px;border-top-left-radius:4px;margin-bottom:-1px}.bp-avatar-nav li.current a{background:0 0;color:inherit;font-weight:700;opacity:.8;outline:0}#drag-drop-area{border:4px dashed #bbb;height:200px}.drag-drop.drag-over #drag-drop-area{border-color:#83b4d8}.drag-drop-inside p{display:none}.drag-drop-inside p.drag-drop-buttons{margin-top:80px;text-align:center}.drag-drop .drag-drop-inside p.drag-drop-buttons{margin:auto;text-align:inherit}.drag-drop #drag-drop-area{box-sizing:border-box;display:table;height:100%;width:100%}.drag-drop .drag-drop-inside{display:table-cell;padding:40px 0;text-align:center;vertical-align:middle}.drag-drop .drag-drop-inside p,.drag-drop-inside p.drag-drop-buttons{display:block}.drag-drop .drag-drop-inside p{color:#aaa;font-size:110%;margin:5px 0;text-align:center}.drag-drop-inside p.drag-drop-info{margin-top:0}@supports (-ms-accelerator:true){.drag-drop-inside p.drag-drop-info{display:block}}#avatar-to-crop{margin:0 auto 20px;text-align:right}#bp-webcam-avatar #avatar-to-crop{float:right;margin:0 0 20px}#avatar-to-crop .jcrop-holder{margin:0 auto}.avatar-crop-management{clear:right;overflow:hidden;padding-top:20px;text-align:center}#bp-webcam-avatar .avatar-crop-management{clear:none;float:none;overflow:visible;padding-top:0;width:auto}#avatar-crop-pane{margin:0 auto;overflow:hidden}#bp-webcam-avatar #avatar-to-crop{border:1px solid #eee;max-width:100%;width:100%}@media screen and (min-width:801px){#bp-webcam-avatar #avatar-to-crop{max-width:64%;width:64%}}#avatar-crop-actions a{display:block}#bp-webcam-avatar #avatar-crop-actions{float:right;margin:0 0 20px;width:50%}#avatar-crop-actions a.button{margin-top:10px}#bp-webcam-avatar #avatar-crop-actions a.button{display:block;margin:0 0 5px;padding:4px 0;width:100%}#avatar-crop-pane canvas,#avatar-crop-pane img,#avatar-to-crop img,#avatar-upload-form img,#create-group-form img,#group-settings-form img{border:none!important;max-width:none!important}#bp-webcam-avatar video{float:right;margin-bottom:0;max-width:100%;width:100%;-webkit-transform:scaleX(-1);transform:scaleX(-1)}#bp-webcam-avatar #avatar-crop-pane{border:2px dashed #bbb;clear:right;float:left;margin:0 0 10px 40px;overflow:hidden}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{max-width:150px;max-height:150px}#avatar-crop-pane canvas{height:auto;width:100%;max-width:100%}.group-avatar .bp-avatar .avatar-crop-management{margin-right:0;padding-top:0;width:auto}.bp-avatar .item{overflow:hidden}.bp-avatar .avatar-crop-management.adjust{float:right;clear:none;padding-top:0}.bp-avatar #avatar-to-crop.adjust{float:right;margin-left:20px}@media screen and (max-width:480px){#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions,#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{width:auto}}@media screen and (min-width:801px){#bp-webcam-avatar .avatar-crop-management{clear:none;float:left}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none;margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{float:right;width:100%}}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent{height:95%!important;width:95%!important}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{display:block;padding:10px 15px}.wp-admin #TB_window .bp-avatar #avatar-to-crop{float:right;margin:0}.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{margin-bottom:20px}@media screen and (min-width:783px){.wp-admin #TB_window .bp-avatar .avatar-crop-management{clear:none;float:right;margin-right:20px;padding-top:0;text-align:center}}.wp-admin #TB_window .bp-avatar #avatar-to-crop video{width:100%}.wp-admin #TB_window .bp-avatar .avatar-crop-management a.button{height:auto;line-height:inherit}@media screen and (min-width:810px){.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{max-width:none;width:76%}.wp-admin #TB_window #bp-webcam-avatar .avatar-crop-management{max-width:none;width:auto}}
1
+ div.bp-avatar-status,div.bp-cover-image-status{clear:both;margin:1em 0}div.bp-avatar-status p.updated,div.bp-cover-image-status p.updated{display:block;padding:10px 15px}div.bp-avatar-status p.success,div.bp-cover-image-status p.success{background-color:#efc;border:1px solid #591;color:#250}div.bp-avatar-status p.error,div.bp-cover-image-status p.error{background-color:#fdc;border:1px solid #a00;color:#800}div.bp-avatar-status .bp-progress,div.bp-cover-image-status .bp-progress{background:0 0;border:1px solid #d1d1d1;float:left;height:22px;line-height:2em;margin:6px 0 2px 10px;padding:0;overflow:hidden;width:200px}div.bp-avatar-status .bp-bar,div.bp-cover-image-status .bp-bar{background-color:#c3ff88;width:0;height:100%;z-index:9}.bp-uploader-progress div.error{background-color:#fdc;border:1px solid #a00;color:#800;display:block;font-size:90%;padding:10px 15px}#buddypress p.warning,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{background-color:#ffd;border:1px solid #cb2;color:#440;display:block;font-size:90%;margin:1em 0;padding:10px 15px}div.bp-avatar-nav{background:0 0;clear:both;margin:10px 0;overflow:hidden}.avatar-nav-items{margin:0;padding:0}.bp-avatar-nav .avatar-nav-items li.avatar-nav-item{float:right!important;margin:0;list-style:none}.avatar-nav-items li a{display:block;padding:5px 10px;text-decoration:none}.bp-avatar-nav ul:after,.bp-avatar-nav ul:before{content:" ";display:table}.bp-avatar-nav ul:after{clear:both}.bp-avatar-nav ul{border-bottom:1px solid #ccc;margin-bottom:10px}.bp-avatar-nav ul.avatar-nav-items li.current{border:1px solid #ccc;border-bottom-color:#fff;border-top-right-radius:4px;border-top-left-radius:4px;margin-bottom:-1px}.bp-avatar-nav li.current a{background:0 0;color:inherit;font-weight:700;opacity:.8;outline:0}#drag-drop-area{border:4px dashed #bbb;height:200px}.drag-drop.drag-over #drag-drop-area{border-color:#83b4d8}.drag-drop-inside p{display:none}.drag-drop-inside p.drag-drop-buttons{margin-top:80px;text-align:center}.drag-drop .drag-drop-inside p.drag-drop-buttons{margin:auto;text-align:inherit}.drag-drop #drag-drop-area{box-sizing:border-box;display:table;height:100%;width:100%}.drag-drop .drag-drop-inside{display:table-cell;padding:40px 0;text-align:center;vertical-align:middle}.drag-drop .drag-drop-inside p,.drag-drop-inside p.drag-drop-buttons{display:block}.drag-drop .drag-drop-inside p{color:#767676;font-size:110%;margin:5px 0;text-align:center}.drag-drop-inside p.drag-drop-info{margin-top:0}@supports (-ms-accelerator:true){.drag-drop-inside p.drag-drop-info{display:block}}#avatar-to-crop{margin:0 auto 20px;text-align:right}#bp-webcam-avatar #avatar-to-crop{float:right;margin:0 0 20px}#avatar-to-crop .jcrop-holder{margin:0 auto}.avatar-crop-management{clear:right;overflow:hidden;padding-top:20px;text-align:center}#bp-webcam-avatar .avatar-crop-management{clear:none;float:none;overflow:visible;padding-top:0;width:auto}#avatar-crop-pane{margin:0 auto;overflow:hidden}#bp-webcam-avatar #avatar-to-crop{border:1px solid #eee;max-width:100%;width:100%}@media screen and (min-width:801px){#bp-webcam-avatar #avatar-to-crop{max-width:64%;width:64%}}#avatar-crop-actions a{display:block}#bp-webcam-avatar #avatar-crop-actions{float:right;margin:0 0 20px;width:50%}#avatar-crop-actions a.button{margin-top:10px}#bp-webcam-avatar #avatar-crop-actions a.button{display:block;margin:0 0 5px;padding:4px 0;width:100%}#avatar-crop-pane canvas,#avatar-crop-pane img,#avatar-to-crop img,#avatar-upload-form img,#create-group-form img,#group-settings-form img{border:none!important;max-width:none!important}#bp-webcam-avatar video{float:right;margin-bottom:0;max-width:100%;width:100%;-webkit-transform:scaleX(-1);transform:scaleX(-1)}#bp-webcam-avatar #avatar-crop-pane{border:2px dashed #bbb;clear:right;float:left;margin:0 0 10px 40px;overflow:hidden}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{max-width:150px;max-height:150px}#avatar-crop-pane canvas{height:auto;width:100%;max-width:100%}.group-avatar .bp-avatar .avatar-crop-management{margin-right:0;padding-top:0;width:auto}.bp-avatar .item{overflow:hidden}.bp-avatar .avatar-crop-management.adjust{float:right;clear:none;padding-top:0}.bp-avatar #avatar-to-crop.adjust{float:right;margin-left:20px}@media screen and (max-width:480px){#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions,#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{width:auto}}@media screen and (min-width:801px){#bp-webcam-avatar .avatar-crop-management{clear:none;float:left}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none;margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{float:right;width:100%}}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent{height:95%!important;width:95%!important}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{display:block;padding:10px 15px}.wp-admin #TB_window .bp-avatar #avatar-to-crop{float:right;margin:0}.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{margin-bottom:20px}@media screen and (min-width:783px){.wp-admin #TB_window .bp-avatar .avatar-crop-management{clear:none;float:right;margin-right:20px;padding-top:0;text-align:center}}.wp-admin #TB_window .bp-avatar #avatar-to-crop video{width:100%}.wp-admin #TB_window .bp-avatar .avatar-crop-management a.button{height:auto;line-height:inherit}@media screen and (min-width:810px){.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{max-width:none;width:76%}.wp-admin #TB_window #bp-webcam-avatar .avatar-crop-management{max-width:none;width:auto}}
bp-core/css/avatar.css CHANGED
@@ -165,7 +165,7 @@ div.bp-avatar-nav {
165
  }
166
 
167
  .drag-drop .drag-drop-inside p {
168
- color: #aaa;
169
  font-size: 110%;
170
  margin: 5px 0;
171
  text-align: center;
165
  }
166
 
167
  .drag-drop .drag-drop-inside p {
168
+ color: #767676;
169
  font-size: 110%;
170
  margin: 5px 0;
171
  text-align: center;
bp-core/css/avatar.min.css CHANGED
@@ -1 +1 @@
1
- div.bp-avatar-status,div.bp-cover-image-status{clear:both;margin:1em 0}div.bp-avatar-status p.updated,div.bp-cover-image-status p.updated{display:block;padding:10px 15px}div.bp-avatar-status p.success,div.bp-cover-image-status p.success{background-color:#efc;border:1px solid #591;color:#250}div.bp-avatar-status p.error,div.bp-cover-image-status p.error{background-color:#fdc;border:1px solid #a00;color:#800}div.bp-avatar-status .bp-progress,div.bp-cover-image-status .bp-progress{background:0 0;border:1px solid #d1d1d1;float:right;height:22px;line-height:2em;margin:6px 10px 2px 0;padding:0;overflow:hidden;width:200px}div.bp-avatar-status .bp-bar,div.bp-cover-image-status .bp-bar{background-color:#c3ff88;width:0;height:100%;z-index:9}.bp-uploader-progress div.error{background-color:#fdc;border:1px solid #a00;color:#800;display:block;font-size:90%;padding:10px 15px}#buddypress p.warning,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{background-color:#ffd;border:1px solid #cb2;color:#440;display:block;font-size:90%;margin:1em 0;padding:10px 15px}div.bp-avatar-nav{background:0 0;clear:both;margin:10px 0;overflow:hidden}.avatar-nav-items{margin:0;padding:0}.bp-avatar-nav .avatar-nav-items li.avatar-nav-item{float:left!important;margin:0;list-style:none}.avatar-nav-items li a{display:block;padding:5px 10px;text-decoration:none}.bp-avatar-nav ul:after,.bp-avatar-nav ul:before{content:" ";display:table}.bp-avatar-nav ul:after{clear:both}.bp-avatar-nav ul{border-bottom:1px solid #ccc;margin-bottom:10px}.bp-avatar-nav ul.avatar-nav-items li.current{border:1px solid #ccc;border-bottom-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;margin-bottom:-1px}.bp-avatar-nav li.current a{background:0 0;color:inherit;font-weight:700;opacity:.8;outline:0}#drag-drop-area{border:4px dashed #bbb;height:200px}.drag-drop.drag-over #drag-drop-area{border-color:#83b4d8}.drag-drop-inside p{display:none}.drag-drop-inside p.drag-drop-buttons{margin-top:80px;text-align:center}.drag-drop .drag-drop-inside p.drag-drop-buttons{margin:auto;text-align:inherit}.drag-drop #drag-drop-area{box-sizing:border-box;display:table;height:100%;width:100%}.drag-drop .drag-drop-inside{display:table-cell;padding:40px 0;text-align:center;vertical-align:middle}.drag-drop .drag-drop-inside p,.drag-drop-inside p.drag-drop-buttons{display:block}.drag-drop .drag-drop-inside p{color:#aaa;font-size:110%;margin:5px 0;text-align:center}.drag-drop-inside p.drag-drop-info{margin-top:0}@supports (-ms-accelerator:true){.drag-drop-inside p.drag-drop-info{display:block}}#avatar-to-crop{margin:0 auto 20px;text-align:left}#bp-webcam-avatar #avatar-to-crop{float:left;margin:0 0 20px}#avatar-to-crop .jcrop-holder{margin:0 auto}.avatar-crop-management{clear:left;overflow:hidden;padding-top:20px;text-align:center}#bp-webcam-avatar .avatar-crop-management{clear:none;float:none;overflow:visible;padding-top:0;width:auto}#avatar-crop-pane{margin:0 auto;overflow:hidden}#bp-webcam-avatar #avatar-to-crop{border:1px solid #eee;max-width:100%;width:100%}@media screen and (min-width:801px){#bp-webcam-avatar #avatar-to-crop{max-width:64%;width:64%}}#avatar-crop-actions a{display:block}#bp-webcam-avatar #avatar-crop-actions{float:left;margin:0 0 20px;width:50%}#avatar-crop-actions a.button{margin-top:10px}#bp-webcam-avatar #avatar-crop-actions a.button{display:block;margin:0 0 5px;padding:4px 0;width:100%}#avatar-crop-pane canvas,#avatar-crop-pane img,#avatar-to-crop img,#avatar-upload-form img,#create-group-form img,#group-settings-form img{border:none!important;max-width:none!important}#bp-webcam-avatar video{float:left;margin-bottom:0;max-width:100%;width:100%;-webkit-transform:scaleX(-1);transform:scaleX(-1)}#bp-webcam-avatar #avatar-crop-pane{border:2px dashed #bbb;clear:left;float:right;margin:0 40px 10px 0;overflow:hidden}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{max-width:150px;max-height:150px}#avatar-crop-pane canvas{height:auto;width:100%;max-width:100%}.group-avatar .bp-avatar .avatar-crop-management{margin-left:0;padding-top:0;width:auto}.bp-avatar .item{overflow:hidden}.bp-avatar .avatar-crop-management.adjust{float:left;clear:none;padding-top:0}.bp-avatar #avatar-to-crop.adjust{float:left;margin-right:20px}@media screen and (max-width:480px){#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions,#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{width:auto}}@media screen and (min-width:801px){#bp-webcam-avatar .avatar-crop-management{clear:none;float:right}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none;margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{float:left;width:100%}}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent{height:95%!important;width:95%!important}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{display:block;padding:10px 15px}.wp-admin #TB_window .bp-avatar #avatar-to-crop{float:left;margin:0}.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{margin-bottom:20px}@media screen and (min-width:783px){.wp-admin #TB_window .bp-avatar .avatar-crop-management{clear:none;float:left;margin-left:20px;padding-top:0;text-align:center}}.wp-admin #TB_window .bp-avatar #avatar-to-crop video{width:100%}.wp-admin #TB_window .bp-avatar .avatar-crop-management a.button{height:auto;line-height:inherit}@media screen and (min-width:810px){.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{max-width:none;width:76%}.wp-admin #TB_window #bp-webcam-avatar .avatar-crop-management{max-width:none;width:auto}}
1
+ div.bp-avatar-status,div.bp-cover-image-status{clear:both;margin:1em 0}div.bp-avatar-status p.updated,div.bp-cover-image-status p.updated{display:block;padding:10px 15px}div.bp-avatar-status p.success,div.bp-cover-image-status p.success{background-color:#efc;border:1px solid #591;color:#250}div.bp-avatar-status p.error,div.bp-cover-image-status p.error{background-color:#fdc;border:1px solid #a00;color:#800}div.bp-avatar-status .bp-progress,div.bp-cover-image-status .bp-progress{background:0 0;border:1px solid #d1d1d1;float:right;height:22px;line-height:2em;margin:6px 10px 2px 0;padding:0;overflow:hidden;width:200px}div.bp-avatar-status .bp-bar,div.bp-cover-image-status .bp-bar{background-color:#c3ff88;width:0;height:100%;z-index:9}.bp-uploader-progress div.error{background-color:#fdc;border:1px solid #a00;color:#800;display:block;font-size:90%;padding:10px 15px}#buddypress p.warning,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{background-color:#ffd;border:1px solid #cb2;color:#440;display:block;font-size:90%;margin:1em 0;padding:10px 15px}div.bp-avatar-nav{background:0 0;clear:both;margin:10px 0;overflow:hidden}.avatar-nav-items{margin:0;padding:0}.bp-avatar-nav .avatar-nav-items li.avatar-nav-item{float:left!important;margin:0;list-style:none}.avatar-nav-items li a{display:block;padding:5px 10px;text-decoration:none}.bp-avatar-nav ul:after,.bp-avatar-nav ul:before{content:" ";display:table}.bp-avatar-nav ul:after{clear:both}.bp-avatar-nav ul{border-bottom:1px solid #ccc;margin-bottom:10px}.bp-avatar-nav ul.avatar-nav-items li.current{border:1px solid #ccc;border-bottom-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;margin-bottom:-1px}.bp-avatar-nav li.current a{background:0 0;color:inherit;font-weight:700;opacity:.8;outline:0}#drag-drop-area{border:4px dashed #bbb;height:200px}.drag-drop.drag-over #drag-drop-area{border-color:#83b4d8}.drag-drop-inside p{display:none}.drag-drop-inside p.drag-drop-buttons{margin-top:80px;text-align:center}.drag-drop .drag-drop-inside p.drag-drop-buttons{margin:auto;text-align:inherit}.drag-drop #drag-drop-area{box-sizing:border-box;display:table;height:100%;width:100%}.drag-drop .drag-drop-inside{display:table-cell;padding:40px 0;text-align:center;vertical-align:middle}.drag-drop .drag-drop-inside p,.drag-drop-inside p.drag-drop-buttons{display:block}.drag-drop .drag-drop-inside p{color:#767676;font-size:110%;margin:5px 0;text-align:center}.drag-drop-inside p.drag-drop-info{margin-top:0}@supports (-ms-accelerator:true){.drag-drop-inside p.drag-drop-info{display:block}}#avatar-to-crop{margin:0 auto 20px;text-align:left}#bp-webcam-avatar #avatar-to-crop{float:left;margin:0 0 20px}#avatar-to-crop .jcrop-holder{margin:0 auto}.avatar-crop-management{clear:left;overflow:hidden;padding-top:20px;text-align:center}#bp-webcam-avatar .avatar-crop-management{clear:none;float:none;overflow:visible;padding-top:0;width:auto}#avatar-crop-pane{margin:0 auto;overflow:hidden}#bp-webcam-avatar #avatar-to-crop{border:1px solid #eee;max-width:100%;width:100%}@media screen and (min-width:801px){#bp-webcam-avatar #avatar-to-crop{max-width:64%;width:64%}}#avatar-crop-actions a{display:block}#bp-webcam-avatar #avatar-crop-actions{float:left;margin:0 0 20px;width:50%}#avatar-crop-actions a.button{margin-top:10px}#bp-webcam-avatar #avatar-crop-actions a.button{display:block;margin:0 0 5px;padding:4px 0;width:100%}#avatar-crop-pane canvas,#avatar-crop-pane img,#avatar-to-crop img,#avatar-upload-form img,#create-group-form img,#group-settings-form img{border:none!important;max-width:none!important}#bp-webcam-avatar video{float:left;margin-bottom:0;max-width:100%;width:100%;-webkit-transform:scaleX(-1);transform:scaleX(-1)}#bp-webcam-avatar #avatar-crop-pane{border:2px dashed #bbb;clear:left;float:right;margin:0 40px 10px 0;overflow:hidden}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{max-width:150px;max-height:150px}#avatar-crop-pane canvas{height:auto;width:100%;max-width:100%}.group-avatar .bp-avatar .avatar-crop-management{margin-left:0;padding-top:0;width:auto}.bp-avatar .item{overflow:hidden}.bp-avatar .avatar-crop-management.adjust{float:left;clear:none;padding-top:0}.bp-avatar #avatar-to-crop.adjust{float:left;margin-right:20px}@media screen and (max-width:480px){#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions,#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{width:auto}}@media screen and (min-width:801px){#bp-webcam-avatar .avatar-crop-management{clear:none;float:right}#bp-webcam-avatar .avatar-crop-management #avatar-crop-pane{float:none;margin:0 auto 10px}#bp-webcam-avatar .avatar-crop-management #avatar-crop-actions{float:left;width:100%}}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent{height:95%!important;width:95%!important}body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.profile_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.updated,body.users_page_bp-profile-edit.modal-open #TB_ajaxContent p.warning{display:block;padding:10px 15px}.wp-admin #TB_window .bp-avatar #avatar-to-crop{float:left;margin:0}.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{margin-bottom:20px}@media screen and (min-width:783px){.wp-admin #TB_window .bp-avatar .avatar-crop-management{clear:none;float:left;margin-left:20px;padding-top:0;text-align:center}}.wp-admin #TB_window .bp-avatar #avatar-to-crop video{width:100%}.wp-admin #TB_window .bp-avatar .avatar-crop-management a.button{height:auto;line-height:inherit}@media screen and (min-width:810px){.wp-admin #TB_window .bp-avatar #bp-webcam-avatar #avatar-to-crop{max-width:none;width:76%}.wp-admin #TB_window #bp-webcam-avatar .avatar-crop-management{max-width:none;width:auto}}
bp-core/deprecated/2.7.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Deprecated functions.
4
+ *
5
+ * @deprecated 2.7.0
6
+ */
7
+
8
+ // Exit if accessed directly.
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Get the DB schema to use for BuddyPress components.
13
+ *
14
+ * @since 1.1.0
15
+ * @deprecated 2.7.0
16
+ *
17
+ * @return string The default database character-set, if set.
18
+ */
19
+ function bp_core_set_charset() {
20
+ global $wpdb;
21
+
22
+ _deprecated_function( __FUNCTION__, '2.7', 'wpdb::get_charset_collate()' );
23
+
24
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
25
+ return !empty( $wpdb->charset ) ? "DEFAULT CHARACTER SET {$wpdb->charset}" : '';
26
+ }
bp-core/js/bp-plupload.min.js CHANGED
@@ -1 +1 @@
1
- window.wp=window.wp||{},window.bp=window.bp||{},function(a,b){"undefined"!=typeof BP_Uploader&&(_.extend(bp,_.pick(wp,"Backbone","ajax","template")),bp.Models=bp.Models||{},bp.Collections=bp.Collections||{},bp.Views=bp.Views||{},bp.Uploader={},bp.Uploader.uploader=function(){var a=this,c=-1!==navigator.userAgent.indexOf("Trident/")||-1!==navigator.userAgent.indexOf("MSIE ");return this.params=BP_Uploader.settings,this.strings=BP_Uploader.strings,this.supports={upload:this.params.browser.supported},this.supported=this.supports.upload,this.supported?(c||"flash"!==plupload.predictRuntime(this.params.defaults)||this.params.defaults.required_features&&this.params.defaults.required_features.hasOwnProperty("send_binary_string")||(this.params.defaults.required_features=this.params.defaults.required_features||{},this.params.defaults.required_features.send_binary_string=!0),this.uploader=new plupload.Uploader(this.params.defaults),this.uploader.bind("Init",function(c){var d=b("#"+a.params.defaults.container),e=b("#"+a.params.defaults.drop_element);"html4"===c.runtime&&(c.settings.multipart_params.html4=!0),"bp_avatar_upload"===c.settings.multipart_params.action&&(c.settings.multipart_params.bp_params.ui_available_width=d.width()),c.features.dragdrop&&!a.params.browser.mobile?(d.addClass("drag-drop"),e.bind("dragover.wp-uploader",function(){d.addClass("drag-over")}).bind("dragleave.wp-uploader, drop.wp-uploader",function(){d.removeClass("drag-over")})):(d.removeClass("drag-drop"),e.unbind(".wp-uploader"))}),this.uploader.init(),this.feedback=function(a,b,c){!_.isNull(c)&&c.item&&c.item.clear(),bp.Uploader.filesError.unshift({message:a,data:b,file:c})},this.uploader.bind("FilesAdded",function(c,d){var e=104857600,f=parseInt(c.settings.max_file_size,10),g=this;if(!c.settings.multi_selection&&d.length>1){for(var h in d)c.removeFile(d[h]);return void b(a).trigger("bp-uploader-warning",a.strings.unique_file_warning)}_.each(d,function(a){var b;plupload.FAILED!==a.status&&(f>e&&a.size>e&&"html5"!==c.runtime?g.uploadSizeError(c,a,!0):(b=_.extend({id:a.id,file:a,uploading:!0,date:new Date,filename:a.name},_.pick(a,"loaded","size","percent")),a.item=new bp.Models.File(b),bp.Uploader.filesQueue.add(a.item)))}),c.refresh(),c.start()}),this.uploader.bind("UploadProgress",function(a,b){b.item.set(_.pick(b,"loaded","percent"))}),this.uploader.bind("FileUploaded",function(b,c,d){var e=a.strings.default_error;try{d=JSON.parse(d.response)}catch(f){return a.feedback(e,f,c)}return!_.isObject(d)||_.isUndefined(d.success)?a.feedback(e,null,c):d.success?(_.each(["file","loaded","size","percent"],function(a){c.item.unset(a)}),c.item.set(_.extend(d.data,{uploading:!1})),void bp.Uploader.filesUploaded.add(c.item)):(d.data&&d.data.message&&(e=d.data.message),a.feedback(e,d.data,c))}),this.uploader.bind("BeforeUpload",function(c,d){b(a).trigger("bp-uploader-new-upload",c,d)}),this.uploader.bind("UploadComplete",function(c,d){b(a).trigger("bp-uploader-upload-complete",c,d),bp.Uploader.filesQueue.reset()}),void this.uploader.bind("Error",function(c,d){var e,f=a.strings.default_error,g={FAILED:a.strings.upload_failed,FILE_EXTENSION_ERROR:a.strings.invalid_filetype,IMAGE_FORMAT_ERROR:a.strings.not_an_image,IMAGE_MEMORY_ERROR:a.strings.image_memory_exceeded,IMAGE_DIMENSIONS_ERROR:a.strings.image_dimensions_exceeded,GENERIC_ERROR:a.strings.upload_failed,IO_ERROR:a.strings.io_error,HTTP_ERROR:a.strings.http_error,SECURITY_ERROR:a.strings.security_error,FILE_SIZE_ERROR:a.strings.file_exceeds_size_limit.replace("%s",d.file.name)};for(e in g)if(d.code===plupload[e]){f=g[e];break}b(a).trigger("bp-uploader-warning",f),c.refresh()})):void(BP_Uploader=void 0)},bp.Models.File=Backbone.Model.extend({file:{}}),b.extend(bp.Uploader,{filesQueue:new Backbone.Collection,filesUploaded:new Backbone.Collection,filesError:new Backbone.Collection}),bp.View=bp.Backbone.View.extend({inject:function(a){this.render(),b(a).html(this.el),this.views.ready()},prepare:function(){return!_.isUndefined(this.model)&&_.isFunction(this.model.toJSON)?this.model.toJSON():{}}}),bp.Views.Uploader=bp.View.extend({className:"bp-uploader-window",template:bp.template("upload-window"),defaults:_.pick(BP_Uploader.settings.defaults,"container","drop_element","browse_button"),initialize:function(){this.warnings=[],this.model=new Backbone.Model(this.defaults),this.on("ready",this.initUploader)},initUploader:function(){this.uploader=new bp.Uploader.uploader,b(this.uploader).on("bp-uploader-warning",_.bind(this.setWarning,this)),b(this.uploader).on("bp-uploader-new-upload",_.bind(this.resetWarning,this))},setWarning:function(a,b){if(!_.isUndefined(b)){var c=new bp.Views.uploaderWarning({value:b}).render();this.warnings.push(c),this.$el.after(c.el)}},resetWarning:function(){0!==this.warnings.length&&(_.each(this.warnings,function(a){a.remove()}),this.warnings=[])}}),bp.Views.uploaderWarning=bp.View.extend({tagName:"p",className:"warning",initialize:function(){this.value=this.options.value},render:function(){return this.$el.html(this.value),this}}),bp.Views.uploaderStatus=bp.View.extend({className:"files",initialize:function(){_.each(this.collection.models,this.addFile,this),this.collection.on("change:percent",this.progress,this),bp.Uploader.filesError.on("add",this.feedback,this)},addFile:function(a){this.views.add(new bp.Views.uploaderProgress({model:a}))},progress:function(a){_.isUndefined(a.get("percent"))||b("#"+a.get("id")+" .bp-progress .bp-bar").css("width",a.get("percent")+"%")},feedback:function(a){_.isUndefined(a.get("message"))||_.isUndefined(a.get("file"))||b("#"+a.get("file").id).html(a.get("message")).addClass("error")}}),bp.Views.uploaderProgress=bp.View.extend({className:"bp-uploader-progress",template:bp.template("progress-window")}))}(bp,jQuery);
1
+ window.wp=window.wp||{},window.bp=window.bp||{},function(a,b){"undefined"!=typeof BP_Uploader&&(_.extend(bp,_.pick(wp,"Backbone","ajax","template")),bp.Models=bp.Models||{},bp.Collections=bp.Collections||{},bp.Views=bp.Views||{},bp.Uploader={},bp.Uploader.uploader=function(){var a=this,c=navigator.userAgent.indexOf("Trident/")!==-1||navigator.userAgent.indexOf("MSIE ")!==-1;return this.params=BP_Uploader.settings,this.strings=BP_Uploader.strings,this.supports={upload:this.params.browser.supported},this.supported=this.supports.upload,this.supported?(c||"flash"!==plupload.predictRuntime(this.params.defaults)||this.params.defaults.required_features&&this.params.defaults.required_features.hasOwnProperty("send_binary_string")||(this.params.defaults.required_features=this.params.defaults.required_features||{},this.params.defaults.required_features.send_binary_string=!0),this.uploader=new plupload.Uploader(this.params.defaults),this.uploader.bind("Init",function(c){var d=b("#"+a.params.defaults.container),e=b("#"+a.params.defaults.drop_element);"html4"===c.runtime&&(c.settings.multipart_params.html4=!0),"bp_avatar_upload"===c.settings.multipart_params.action&&(c.settings.multipart_params.bp_params.ui_available_width=d.width()),c.features.dragdrop&&!a.params.browser.mobile?(d.addClass("drag-drop"),e.bind("dragover.wp-uploader",function(){d.addClass("drag-over")}).bind("dragleave.wp-uploader, drop.wp-uploader",function(){d.removeClass("drag-over")})):(d.removeClass("drag-drop"),e.unbind(".wp-uploader"))}),this.uploader.init(),this.feedback=function(a,b,c){!_.isNull(c)&&c.item&&c.item.clear(),bp.Uploader.filesError.unshift({message:a,data:b,file:c})},this.uploader.bind("FilesAdded",function(c,d){var e=104857600,f=parseInt(c.settings.max_file_size,10),g=this;if(!c.settings.multi_selection&&d.length>1){for(var h in d)c.removeFile(d[h]);return void b(a).trigger("bp-uploader-warning",a.strings.unique_file_warning)}_.each(d,function(a){var b;plupload.FAILED!==a.status&&(f>e&&a.size>e&&"html5"!==c.runtime?g.uploadSizeError(c,a,!0):(b=_.extend({id:a.id,file:a,uploading:!0,date:new Date,filename:a.name},_.pick(a,"loaded","size","percent")),a.item=new bp.Models.File(b),bp.Uploader.filesQueue.add(a.item)))}),c.refresh(),c.start()}),this.uploader.bind("UploadProgress",function(a,b){b.item.set(_.pick(b,"loaded","percent"))}),this.uploader.bind("FileUploaded",function(b,c,d){var e=a.strings.default_error;try{d=JSON.parse(d.response)}catch(b){return a.feedback(e,b,c)}return!_.isObject(d)||_.isUndefined(d.success)?a.feedback(e,null,c):d.success?(_.each(["file","loaded","size","percent"],function(a){c.item.unset(a)}),c.item.set(_.extend(d.data,{uploading:!1})),void bp.Uploader.filesUploaded.add(c.item)):(d.data&&d.data.message&&(e=d.data.message),a.feedback(e,d.data,c))}),this.uploader.bind("BeforeUpload",function(c,d){b(a).trigger("bp-uploader-new-upload",c,d)}),this.uploader.bind("UploadComplete",function(c,d){b(a).trigger("bp-uploader-upload-complete",c,d),bp.Uploader.filesQueue.reset()}),void this.uploader.bind("Error",function(c,d){var e,f=a.strings.default_error,g={FAILED:a.strings.upload_failed,FILE_EXTENSION_ERROR:a.strings.invalid_filetype,IMAGE_FORMAT_ERROR:a.strings.not_an_image,IMAGE_MEMORY_ERROR:a.strings.image_memory_exceeded,IMAGE_DIMENSIONS_ERROR:a.strings.image_dimensions_exceeded,GENERIC_ERROR:a.strings.upload_failed,IO_ERROR:a.strings.io_error,HTTP_ERROR:a.strings.http_error,SECURITY_ERROR:a.strings.security_error,FILE_SIZE_ERROR:a.strings.file_exceeds_size_limit.replace("%s",d.file.name)};for(e in g)if(d.code===plupload[e]){f=g[e];break}b(a).trigger("bp-uploader-warning",f),c.refresh()})):void(BP_Uploader=void 0)},bp.Models.File=Backbone.Model.extend({file:{}}),b.extend(bp.Uploader,{filesQueue:new Backbone.Collection,filesUploaded:new Backbone.Collection,filesError:new Backbone.Collection}),bp.View=bp.Backbone.View.extend({inject:function(a){this.render(),b(a).html(this.el),this.views.ready()},prepare:function(){return!_.isUndefined(this.model)&&_.isFunction(this.model.toJSON)?this.model.toJSON():{}}}),bp.Views.Uploader=bp.View.extend({className:"bp-uploader-window",template:bp.template("upload-window"),defaults:_.pick(BP_Uploader.settings.defaults,"container","drop_element","browse_button"),initialize:function(){this.warnings=[],this.model=new Backbone.Model(this.defaults),this.on("ready",this.initUploader)},initUploader:function(){this.uploader=new bp.Uploader.uploader,b(this.uploader).on("bp-uploader-warning",_.bind(this.setWarning,this)),b(this.uploader).on("bp-uploader-new-upload",_.bind(this.resetWarning,this))},setWarning:function(a,b){if(!_.isUndefined(b)){var c=new bp.Views.uploaderWarning({value:b}).render();this.warnings.push(c),this.$el.after(c.el)}},resetWarning:function(){0!==this.warnings.length&&(_.each(this.warnings,function(a){a.remove()}),this.warnings=[])}}),bp.Views.uploaderWarning=bp.View.extend({tagName:"p",className:"warning",initialize:function(){this.value=this.options.value},render:function(){return this.$el.html(this.value),this}}),bp.Views.uploaderStatus=bp.View.extend({className:"files",initialize:function(){_.each(this.collection.models,this.addFile,this),this.collection.on("change:percent",this.progress,this),bp.Uploader.filesError.on("add",this.feedback,this)},addFile:function(a){this.views.add(new bp.Views.uploaderProgress({model:a}))},progress:function(a){_.isUndefined(a.get("percent"))||b("#"+a.get("id")+" .bp-progress .bp-bar").css("width",a.get("percent")+"%")},feedback:function(a){_.isUndefined(a.get("message"))||_.isUndefined(a.get("file"))||b("#"+a.get("file").id).html(a.get("message")).addClass("error")}}),bp.Views.uploaderProgress=bp.View.extend({className:"bp-uploader-progress",template:bp.template("progress-window")}))}(bp,jQuery);
bp-core/js/confirm.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(){jQuery("a.confirm").click(function(){return confirm(BP_Confirm.are_you_sure)?!0:!1})});
1
+ jQuery(document).ready(function(){jQuery("a.confirm").click(function(){return!!confirm(BP_Confirm.are_you_sure)})});
bp-core/js/cover-image.js CHANGED
@@ -1,277 +1,277 @@
1
- /* global bp, BP_Uploader, _, Backbone */
2
-
3
- window.bp = window.bp || {};
4
-
5
- ( function( exports, $ ) {
6
-
7
- // Bail if not set
8
- if ( typeof BP_Uploader === 'undefined' ) {
9
- return;
10
- }
11
-
12
- bp.Models = bp.Models || {};
13
- bp.Collections = bp.Collections || {};
14
- bp.Views = bp.Views || {};
15
-
16
- bp.CoverImage = {
17
- start: function() {
18
-
19
- // Init some vars
20
- this.views = new Backbone.Collection();
21
- this.warning = null;
22
-
23
- // The Cover Image Attachment object.
24
- this.Attachment = new Backbone.Model();
25
-
26
- // Set up views
27
- this.uploaderView();
28
-
29
- // Inform about the needed dimensions
30
- this.displayWarning( BP_Uploader.strings.cover_image_warnings.dimensions );
31
-
32
- // Set up the delete view if needed
33
- if ( true === BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image ) {
34
- this.deleteView();
35
- }
36
- },
37
-
38
- uploaderView: function() {
39
- // Listen to the Queued uploads
40
- bp.Uploader.filesQueue.on( 'add', this.uploadProgress, this );
41
-
42
- // Create the BuddyPress Uploader
43
- var uploader = new bp.Views.Uploader();
44
-
45
- // Add it to views
46
- this.views.add( { id: 'upload', view: uploader } );
47
-
48
- // Display it
49
- uploader.inject( '.bp-cover-image' );
50
- },
51
-
52
- uploadProgress: function() {
53
- // Create the Uploader status view
54
- var coverImageUploadProgress = new bp.Views.coverImageUploadProgress( { collection: bp.Uploader.filesQueue } );
55
-
56
- if ( ! _.isUndefined( this.views.get( 'status' ) ) ) {
57
- this.views.set( { id: 'status', view: coverImageUploadProgress } );
58
- } else {
59
- this.views.add( { id: 'status', view: coverImageUploadProgress } );
60
- }
61
-
62
- // Display it
63
- coverImageUploadProgress.inject( '.bp-cover-image-status' );
64
- },
65
-
66
- deleteView: function() {
67
- // Create the delete model
68
- var delete_model = new Backbone.Model( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params,
69
- ['object', 'item_id', 'nonces']
70
- ) );
71
-
72
- // Do not add it if already there!
73
- if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
74
- return;
75
- }
76
-
77
- // Create the delete view
78
- var deleteView = new bp.Views.DeleteCoverImage( { model: delete_model } );
79
-
80
- // Add it to views
81
- this.views.add( { id: 'delete', view: deleteView } );
82
-
83
- // Display it
84
- deleteView.inject( '.bp-cover-image-manage' );
85
- },
86
-
87
- deleteCoverImage: function( model ) {
88
- var self = this,
89
- deleteView;
90
-
91
- // Remove the delete view
92
- if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
93
- deleteView = this.views.get( 'delete' );
94
- deleteView.get( 'view' ).remove();
95
- this.views.remove( { id: 'delete', view: deleteView } );
96
- }
97
-
98
- // Remove the cover image !
99
- bp.ajax.post( 'bp_cover_image_delete', {
100
- json: true,
101
- item_id: model.get( 'item_id' ),
102
- object: model.get( 'object' ),
103
- nonce: model.get( 'nonces' ).remove
104
- } ).done( function( response ) {
105
- var coverImageStatus = new bp.Views.CoverImageStatus( {
106
- value : BP_Uploader.strings.feedback_messages[ response.feedback_code ],
107
- type : 'success'
108
- } );
109
-
110
- self.views.add( {
111
- id : 'status',
112
- view : coverImageStatus
113
- } );
114
-
115
- coverImageStatus.inject( '.bp-cover-image-status' );
116
-
117
- // Reset the header of the page
118
- if ( '' === response.reset_url ) {
119
- $( '#header-cover-image' ).css( {
120
- 'background-image': 'none'
121
- } );
122
- } else {
123
- $( '#header-cover-image' ).css( {
124
- 'background-image': 'url( ' + response.reset_url + ' )'
125
- } );
126
- }
127
-
128
- // Reset the has_cover_image bp_param
129
- BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image = false;
130
-
131
- /**
132
- * Reset the Attachment object
133
- *
134
- * You can run extra actions once the cover image is set using:
135
- * bp.CoverImage.Attachment.on( 'change:url', function( data ) { your code } );
136
- *
137
- * In this case data.attributes will include the default url for the
138
- * cover image (most of the time: ''), the object and the item_id concerned.
139
- */
140
- self.Attachment.set( _.extend(
141
- _.pick( model.attributes, ['object', 'item_id'] ),
142
- { url: response.reset_url, action: 'deleted' }
143
- ) );
144
-
145
- } ).fail( function( response ) {
146
- var feedback = BP_Uploader.strings.default_error;
147
- if ( ! _.isUndefined( response ) ) {
148
- feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ];
149
- }
150
-
151
- var coverImageStatus = new bp.Views.CoverImageStatus( {
152
- value : feedback,
153
- type : 'error'
154
- } );
155
-
156
- self.views.add( {
157
- id : 'status',
158
- view : coverImageStatus
159
- } );
160
-
161
- coverImageStatus.inject( '.bp-cover-image-status' );
162
-
163
- // Put back the delete view
164
- bp.CoverImage.deleteView();
165
- } );
166
- },
167
-
168
- removeWarning: function() {
169
- if ( ! _.isNull( this.warning ) ) {
170
- this.warning.remove();
171
- }
172
- },
173
-
174
- displayWarning: function( message ) {
175
- this.removeWarning();
176
-
177
- this.warning = new bp.Views.uploaderWarning( {
178
- value: message
179
- } );
180
-
181
- this.warning.inject( '.bp-cover-image-status' );
182
- }
183
- };
184
-
185
- // Custom Uploader Files view
186
- bp.Views.coverImageUploadProgress = bp.Views.uploaderStatus.extend( {
187
- className: 'files',
188
-
189
- initialize: function() {
190
- bp.Views.uploaderStatus.prototype.initialize.apply( this, arguments );
191
-
192
- this.collection.on( 'change:url', this.uploadResult, this );
193
- },
194
-
195
- uploadResult: function( model ) {
196
- var message, type;
197
-
198
- if ( ! _.isUndefined( model.get( 'url' ) ) ) {
199
-
200
- // Image is too small
201
- if ( 0 === model.get( 'feedback_code' ) ) {
202
- message = BP_Uploader.strings.cover_image_warnings.dimensions;
203
- type = 'warning';
204
-
205
- // Success, Rock n roll!
206
- } else {
207
- message = BP_Uploader.strings.feedback_messages[ model.get( 'feedback_code' ) ];
208
- type = 'success';
209
- }
210
-
211
- this.views.set( '.bp-uploader-progress', new bp.Views.CoverImageStatus( {
212
- value : message,
213
- type : type
214
- } ) );
215
-
216
- // Update the header of the page
217
- $( '#header-cover-image' ).css( {
218
- 'background-image': 'url( ' + model.get( 'url' ) + ' )'
219
- } );
220
-
221
- // Add the delete view
222
- bp.CoverImage.deleteView();
223
-
224
- /**
225
- * Set the Attachment object
226
- *
227
- * You can run extra actions once the cover image is set using:
228
- * bp.CoverImage.Attachment.on( 'change:url', function( data ) { your code } );
229
- *
230
- * In this case data.attributes will include the url to the newly
231
- * uploaded cover image, the object and the item_id concerned.
232
- */
233
- bp.CoverImage.Attachment.set( _.extend(
234
- _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, ['object', 'item_id'] ),
235
- { url: model.get( 'url' ), action: 'uploaded' }
236
- ) );
237
- }
238
- }
239
- } );
240
-
241
- // BuddyPress Cover Image Feedback view
242
- bp.Views.CoverImageStatus = bp.View.extend( {
243
- tagName: 'p',
244
- className: 'updated',
245
- id: 'bp-cover-image-feedback',
246
-
247
- initialize: function() {
248
- this.el.className += ' ' + this.options.type;
249
- this.value = this.options.value;
250
- },
251
-
252
- render: function() {
253
- this.$el.html( this.value );
254
- return this;
255
- }
256
- } );
257
-
258
- // BuddyPress Cover Image Delete view
259
- bp.Views.DeleteCoverImage = bp.View.extend( {
260
- tagName: 'div',
261
- id: 'bp-delete-cover-image-container',
262
- template: bp.template( 'bp-cover-image-delete' ),
263
-
264
- events: {
265
- 'click #bp-delete-cover-image': 'deleteCoverImage'
266
- },
267
-
268
- deleteCoverImage: function( event ) {
269
- event.preventDefault();
270
-
271
- bp.CoverImage.deleteCoverImage( this.model );
272
- }
273
- } );
274
-
275
- bp.CoverImage.start();
276
-
277
- })( bp, jQuery );
1
+ /* global bp, BP_Uploader, _, Backbone */
2
+
3
+ window.bp = window.bp || {};
4
+
5
+ ( function( exports, $ ) {
6
+
7
+ // Bail if not set
8
+ if ( typeof BP_Uploader === 'undefined' ) {
9
+ return;
10
+ }
11
+
12
+ bp.Models = bp.Models || {};
13
+ bp.Collections = bp.Collections || {};
14
+ bp.Views = bp.Views || {};
15
+
16
+ bp.CoverImage = {
17
+ start: function() {
18
+
19
+ // Init some vars
20
+ this.views = new Backbone.Collection();
21
+ this.warning = null;
22
+
23
+ // The Cover Image Attachment object.
24
+ this.Attachment = new Backbone.Model();
25
+
26
+ // Set up views
27
+ this.uploaderView();
28
+
29
+ // Inform about the needed dimensions
30
+ this.displayWarning( BP_Uploader.strings.cover_image_warnings.dimensions );
31
+
32
+ // Set up the delete view if needed
33
+ if ( true === BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image ) {
34
+ this.deleteView();
35
+ }
36
+ },
37
+
38
+ uploaderView: function() {
39
+ // Listen to the Queued uploads
40
+ bp.Uploader.filesQueue.on( 'add', this.uploadProgress, this );
41
+
42
+ // Create the BuddyPress Uploader
43
+ var uploader = new bp.Views.Uploader();
44
+
45
+ // Add it to views
46
+ this.views.add( { id: 'upload', view: uploader } );
47
+
48
+ // Display it
49
+ uploader.inject( '.bp-cover-image' );
50
+ },
51
+
52
+ uploadProgress: function() {
53
+ // Create the Uploader status view
54
+ var coverImageUploadProgress = new bp.Views.coverImageUploadProgress( { collection: bp.Uploader.filesQueue } );
55
+
56
+ if ( ! _.isUndefined( this.views.get( 'status' ) ) ) {
57
+ this.views.set( { id: 'status', view: coverImageUploadProgress } );
58
+ } else {
59
+ this.views.add( { id: 'status', view: coverImageUploadProgress } );
60
+ }
61
+
62
+ // Display it
63
+ coverImageUploadProgress.inject( '.bp-cover-image-status' );
64
+ },
65
+
66
+ deleteView: function() {
67
+ // Create the delete model
68
+ var delete_model = new Backbone.Model( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params,
69
+ ['object', 'item_id', 'nonces']
70
+ ) );
71
+
72
+ // Do not add it if already there!
73
+ if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
74
+ return;
75
+ }
76
+
77
+ // Create the delete view
78
+ var deleteView = new bp.Views.DeleteCoverImage( { model: delete_model } );
79
+
80
+ // Add it to views
81
+ this.views.add( { id: 'delete', view: deleteView } );
82
+
83
+ // Display it
84
+ deleteView.inject( '.bp-cover-image-manage' );
85
+ },
86
+
87
+ deleteCoverImage: function( model ) {
88
+ var self = this,
89
+ deleteView;
90
+
91
+ // Remove the delete view
92
+ if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
93
+ deleteView = this.views.get( 'delete' );
94
+ deleteView.get( 'view' ).remove();
95
+ this.views.remove( { id: 'delete', view: deleteView } );
96
+ }
97
+
98
+ // Remove the cover image !
99
+ bp.ajax.post( 'bp_cover_image_delete', {
100
+ json: true,
101
+ item_id: model.get( 'item_id' ),
102
+ object: model.get( 'object' ),
103
+ nonce: model.get( 'nonces' ).remove
104
+ } ).done( function( response ) {
105
+ var coverImageStatus = new bp.Views.CoverImageStatus( {
106
+ value : BP_Uploader.strings.feedback_messages[ response.feedback_code ],
107
+ type : 'success'
108
+ } );
109
+
110
+ self.views.add( {
111
+ id : 'status',
112
+ view : coverImageStatus
113
+ } );
114
+
115
+ coverImageStatus.inject( '.bp-cover-image-status' );
116
+
117
+ // Reset the header of the page
118
+ if ( '' === response.reset_url ) {
119
+ $( '#header-cover-image' ).css( {
120
+ 'background-image': 'none'
121
+ } );
122
+ } else {
123
+ $( '#header-cover-image' ).css( {
124
+ 'background-image': 'url( ' + response.reset_url + ' )'
125
+ } );
126
+ }
127
+
128
+ // Reset the has_cover_image bp_param
129
+ BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image = false;
130
+
131
+ /**
132
+ * Reset the Attachment object
133
+ *
134
+ * You can run extra actions once the cover image is set using:
135
+ * bp.CoverImage.Attachment.on( 'change:url', function( data ) { your code } );
136
+ *
137
+ * In this case data.attributes will include the default url for the
138
+ * cover image (most of the time: ''), the object and the item_id concerned.
139
+ */
140
+ self.Attachment.set( _.extend(
141
+ _.pick( model.attributes, ['object', 'item_id'] ),
142
+ { url: response.reset_url, action: 'deleted' }
143
+ ) );
144
+
145
+ } ).fail( function( response ) {
146
+ var feedback = BP_Uploader.strings.default_error;
147
+ if ( ! _.isUndefined( response ) ) {
148
+ feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ];
149
+ }
150
+
151
+ var coverImageStatus = new bp.Views.CoverImageStatus( {
152
+ value : feedback,
153
+ type : 'error'
154
+ } );
155
+
156
+ self.views.add( {
157
+ id : 'status',
158
+ view : coverImageStatus
159
+ } );
160
+
161
+ coverImageStatus.inject( '.bp-cover-image-status' );
162
+
163
+ // Put back the delete view
164
+ bp.CoverImage.deleteView();
165
+ } );
166
+ },
167
+
168
+ removeWarning: function() {
169
+ if ( ! _.isNull( this.warning ) ) {
170
+ this.warning.remove();
171
+ }
172
+ },
173
+
174
+ displayWarning: function( message ) {
175
+ this.removeWarning();
176
+
177
+ this.warning = new bp.Views.uploaderWarning( {
178
+ value: message
179
+ } );
180
+
181
+ this.warning.inject( '.bp-cover-image-status' );
182
+ }
183
+ };
184
+
185
+ // Custom Uploader Files view
186
+ bp.Views.coverImageUploadProgress = bp.Views.uploaderStatus.extend( {
187
+ className: 'files',
188
+
189
+ initialize: function() {
190
+ bp.Views.uploaderStatus.prototype.initialize.apply( this, arguments );
191
+
192
+ this.collection.on( 'change:url', this.uploadResult, this );
193
+ },
194
+
195
+ uploadResult: function( model ) {
196
+ var message, type;
197
+
198
+ if ( ! _.isUndefined( model.get( 'url' ) ) ) {
199
+
200
+ // Image is too small
201
+ if ( 0 === model.get( 'feedback_code' ) ) {
202
+ message = BP_Uploader.strings.cover_image_warnings.dimensions;
203
+ type = 'warning';
204
+
205
+ // Success, Rock n roll!
206
+ } else {
207
+ message = BP_Uploader.strings.feedback_messages[ model.get( 'feedback_code' ) ];
208
+ type = 'success';
209
+ }
210
+
211
+ this.views.set( '.bp-uploader-progress', new bp.Views.CoverImageStatus( {
212
+ value : message,
213
+ type : type
214
+ } ) );
215
+
216
+ // Update the header of the page
217
+ $( '#header-cover-image' ).css( {
218
+ 'background-image': 'url( ' + model.get( 'url' ) + ' )'
219
+ } );
220
+
221
+ // Add the delete view
222
+ bp.CoverImage.deleteView();
223
+
224
+ /**
225
+ * Set the Attachment object
226
+ *
227
+ * You can run extra actions once the cover image is set using:
228
+ * bp.CoverImage.Attachment.on( 'change:url', function( data ) { your code } );
229
+ *
230
+ * In this case data.attributes will include the url to the newly
231
+ * uploaded cover image, the object and the item_id concerned.
232
+ */
233
+ bp.CoverImage.Attachment.set( _.extend(
234
+ _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, ['object', 'item_id'] ),
235
+ { url: model.get( 'url' ), action: 'uploaded' }
236
+ ) );
237
+ }
238
+ }
239
+ } );
240
+
241
+ // BuddyPress Cover Image Feedback view
242
+ bp.Views.CoverImageStatus = bp.View.extend( {
243
+ tagName: 'p',
244
+ className: 'updated',
245
+ id: 'bp-cover-image-feedback',
246
+
247
+ initialize: function() {
248
+ this.el.className += ' ' + this.options.type;
249
+ this.value = this.options.value;
250
+ },
251
+
252
+ render: function() {
253
+ this.$el.html( this.value );
254
+ return this;
255
+ }
256
+ } );
257
+
258
+ // BuddyPress Cover Image Delete view
259
+ bp.Views.DeleteCoverImage = bp.View.extend( {
260
+ tagName: 'div',
261
+ id: 'bp-delete-cover-image-container',
262
+ template: bp.template( 'bp-cover-image-delete' ),
263
+
264
+ events: {
265
+ 'click #bp-delete-cover-image': 'deleteCoverImage'
266
+ },
267
+
268
+ deleteCoverImage: function( event ) {
269
+ event.preventDefault();
270
+
271
+ bp.CoverImage.deleteCoverImage( this.model );
272
+ }
273
+ } );
274
+
275
+ bp.CoverImage.start();
276
+
277
+ })( bp, jQuery );
bp-core/js/jquery.atwho.min.js DELETED
@@ -1 +0,0 @@
1
- !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.returnExportsGlobal=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){var b,c,d,e,f,g,h,i=[].slice;c=function(){function b(b){this.current_flag=null,this.controllers={},this.alias_maps={},this.$inputor=a(b),this.setIframe(),this.listen()}return b.prototype.createContainer=function(b){return 0===(this.$el=a("#atwho-container",b)).length?a(b.body).append(this.$el=a("<div id='atwho-container'></div>")):void 0},b.prototype.setIframe=function(a,b){var c;return null==b&&(b=!1),a?(this.window=a.contentWindow,this.document=a.contentDocument||this.window.document,this.iframe=a):(this.document=document,this.window=window,this.iframe=null),(this.iframeStandalone=b)?(null!=(c=this.$el)&&c.remove(),this.createContainer(this.document)):this.createContainer(document)},b.prototype.controller=function(a){var b,c,d,e;if(this.alias_maps[a])c=this.controllers[this.alias_maps[a]];else{e=this.controllers;for(d in e)if(b=e[d],d===a){c=b;break}}return c?c:this.controllers[this.current_flag]},b.prototype.set_context_for=function(a){return this.current_flag=a,this},b.prototype.reg=function(a,b){var c,e;return c=(e=this.controllers)[a]||(e[a]=new d(this,a)),b.alias&&(this.alias_maps[b.alias]=a),c.init(b),this},b.prototype.listen=function(){return this.$inputor.on("keyup.atwhoInner",function(a){return function(b){return a.on_keyup(b)}}(this)).on("keydown.atwhoInner",function(a){return function(b){return a.on_keydown(b)}}(this)).on("scroll.atwhoInner",function(a){return function(b){var c;return null!=(c=a.controller())?c.view.hide(b):void 0}}(this)).on("blur.atwhoInner",function(a){return function(b){var c;return(c=a.controller())?c.view.hide(b,c.get_opt("display_timeout")):void 0}}(this)).on("click.atwhoInner",function(a){return function(b){return a.dispatch()}}(this))},b.prototype.shutdown=function(){var a,b,c;c=this.controllers;for(b in c)a=c[b],a.destroy(),delete this.controllers[b];return this.$inputor.off(".atwhoInner"),this.$el.remove()},b.prototype.dispatch=function(){return a.map(this.controllers,function(a){return function(b){var c;return(c=b.get_opt("delay"))?(clearTimeout(a.delayedCallback),a.delayedCallback=setTimeout(function(){return b.look_up()?a.set_context_for(b.at):void 0},c)):b.look_up()?a.set_context_for(b.at):void 0}}(this))},b.prototype.on_keyup=function(b){var c;switch(b.keyCode){case f.ESC:b.preventDefault(),null!=(c=this.controller())&&c.view.hide();break;case f.DOWN:case f.UP:case f.CTRL:a.noop();break;case f.P:case f.N:b.ctrlKey||this.dispatch();break;default:this.dispatch()}},b.prototype.on_keydown=function(b){var c,d;if(c=null!=(d=this.controller())?d.view:void 0,c&&c.visible())switch(b.keyCode){case f.ESC:b.preventDefault(),c.hide(b);break;case f.UP:b.preventDefault(),c.prev();break;case f.DOWN:b.preventDefault(),c.next();break;case f.P:if(!b.ctrlKey)return;b.preventDefault(),c.prev();break;case f.N:if(!b.ctrlKey)return;b.preventDefault(),c.next();break;case f.TAB:case f.ENTER:if(!c.visible())return;b.preventDefault(),c.choose(b);break;default:a.noop()}},b}(),d=function(){function b(b,c){this.app=b,this.at=c,this.$inputor=this.app.$inputor,this.id=this.$inputor[0].id||this.uid(),this.setting=null,this.query=null,this.pos=0,this.cur_rect=null,this.range=null,0===(this.$el=a("#atwho-ground-"+this.id,this.app.$el)).length&&this.app.$el.append(this.$el=a("<div id='atwho-ground-"+this.id+"'></div>")),this.model=new g(this),this.view=new h(this)}return b.prototype.uid=function(){return(Math.random().toString(16)+"000000000").substr(2,8)+(new Date).getTime()},b.prototype.init=function(b){return this.setting=a.extend({},this.setting||a.fn.atwho["default"],b),this.view.init(),this.model.reload(this.setting.data)},b.prototype.destroy=function(){return this.trigger("beforeDestroy"),this.model.destroy(),this.view.destroy(),this.$el.remove()},b.prototype.call_default=function(){var b,c,d;d=arguments[0],b=2<=arguments.length?i.call(arguments,1):[];try{return e[d].apply(this,b)}catch(f){return c=f,a.error(""+c+" Or maybe At.js doesn't have function "+d)}},b.prototype.trigger=function(a,b){var c,d;return null==b&&(b=[]),b.push(this),c=this.get_opt("alias"),d=c?""+a+"-"+c+".atwho":""+a+".atwho",this.$inputor.trigger(d,b)},b.prototype.callbacks=function(a){return this.get_opt("callbacks")[a]||e[a]},b.prototype.get_opt=function(a,b){var c;try{return this.setting[a]}catch(d){return c=d,null}},b.prototype.content=function(){var a;if(this.$inputor.is("textarea, input"))return this.$inputor.val();if(a=this.mark_range())return(a.startContainer.textContent||"").slice(0,a.startOffset)},b.prototype.catch_query=function(){var a,b,c,d,e,f;return b=this.content(),a=this.$inputor.caret("pos",{iframe:this.app.iframe}),f=b.slice(0,a),d=this.callbacks("matcher").call(this,this.at,f,this.get_opt("start_with_space")),"string"==typeof d&&d.length<=this.get_opt("max_len",20)?(e=a-d.length,c=e+d.length,this.pos=e,d={text:d,head_pos:e,end_pos:c},this.trigger("matched",[this.at,d.text])):(d=null,this.view.hide()),this.query=d},b.prototype.rect=function(){var b,c,d;if(b=this.$inputor.caret("offset",this.pos-1,{iframe:this.app.iframe}))return this.app.iframe&&!this.app.iframeStandalone&&(c=a(this.app.iframe).offset(),b.left+=c.left,b.top+=c.top),this.$inputor.is("[contentEditable]")&&(b=this.cur_rect||(this.cur_rect=b)),d=this.app.document.selection?0:2,{left:b.left,top:b.top,bottom:b.top+b.height+d}},b.prototype.reset_rect=function(){return this.$inputor.is("[contentEditable]")?this.cur_rect=null:void 0},b.prototype.mark_range=function(){var a;if(this.$inputor.is("[contentEditable]"))return this.app.window.getSelection&&(a=this.app.window.getSelection()).rangeCount>0?this.range=a.getRangeAt(0):this.app.document.selection?this.ie8_range=this.app.document.selection.createRange():void 0},b.prototype.insert_content_for=function(b){var c,d,e;return d=b.data("value"),e=this.get_opt("insert_tpl"),this.$inputor.is("textarea, input")||!e?d:(c=a.extend({},b.data("item-data"),{"atwho-data-value":d,"atwho-at":this.at}),this.callbacks("tpl_eval").call(this,e,c))},b.prototype.insert=function(b,c){var d,e,f,g,h,i,j,k,l,m,n,o;if(d=this.$inputor,l=this.callbacks("inserting_wrapper").call(this,d,b,this.get_opt("suffix")),d.is("textarea, input"))i=d.val(),j=i.slice(0,Math.max(this.query.head_pos-this.at.length,0)),k=""+j+l+i.slice(this.query.end_pos||0),d.val(k),d.caret("pos",j.length+l.length,{iframe:this.app.iframe});else if(g=this.range){for(f=g.startOffset-(this.query.end_pos-this.query.head_pos)-this.at.length,g.setStart(g.endContainer,Math.max(f,0)),g.setEnd(g.endContainer,g.endOffset),g.deleteContents(),o=a(l,this.app.document),m=0,n=o.length;n>m;m++)e=o[m],g.insertNode(e),g.setEndAfter(e),g.collapse(!1);h=this.app.window.getSelection(),h.removeAllRanges(),h.addRange(g)}else(g=this.ie8_range)&&(g.moveStart("character",this.query.end_pos-this.query.head_pos-this.at.length),g.pasteHTML(l),g.collapse(!1),g.select());return d.is(":focus")||d.focus(),d.change()},b.prototype.render_view=function(a){var b;return b=this.get_opt("search_key"),a=this.callbacks("sorter").call(this,this.query.text,a.slice(0,1001),b),this.view.render(a.slice(0,this.get_opt("limit")))},b.prototype.look_up=function(){var b,c;if(b=this.catch_query())return c=function(a){return a&&a.length>0?this.render_view(a):this.view.hide()},this.model.query(b.text,a.proxy(c,this)),b},b}(),g=function(){function b(a){this.context=a,this.at=this.context.at,this.storage=this.context.$inputor}return b.prototype.destroy=function(){return this.storage.data(this.at,null)},b.prototype.saved=function(){return this.fetch()>0},b.prototype.query=function(a,b){var c,d,e;return c=this.fetch(),d=this.context.get_opt("search_key"),c=this.context.callbacks("filter").call(this.context,a,c,d)||[],e=this.context.callbacks("remote_filter"),c.length>0||!e&&0===c.length?b(c):e.call(this.context,a,b)},b.prototype.fetch=function(){return this.storage.data(this.at)||[]},b.prototype.save=function(a){return this.storage.data(this.at,this.context.callbacks("before_save").call(this.context,a||[]))},b.prototype.load=function(a){return!this.saved()&&a?this._load(a):void 0},b.prototype.reload=function(a){return this._load(a)},b.prototype._load=function(b){return"string"==typeof b?a.ajax(b,{dataType:"json"}).done(function(a){return function(b){return a.save(b)}}(this)):this.save(b)},b}(),h=function(){function b(b){this.context=b,this.$el=a("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>"),this.timeout_id=null,this.context.$el.append(this.$el),this.bind_event()}return b.prototype.init=function(){var a;return a=this.context.get_opt("alias")||this.context.at.charCodeAt(0),this.$el.attr({id:"at-view-"+a})},b.prototype.destroy=function(){return this.$el.remove()},b.prototype.bind_event=function(){var b;return b=this.$el.find("ul"),b.on("mouseenter.atwho-view","li",function(c){return b.find(".cur").removeClass("cur"),a(c.currentTarget).addClass("cur")}).on("click.atwho-view","li",function(c){return function(d){return b.find(".cur").removeClass("cur"),a(d.currentTarget).addClass("cur"),c.choose(d),d.preventDefault()}}(this))},b.prototype.visible=function(){return this.$el.is(":visible")},b.prototype.choose=function(a){var b,c;return(b=this.$el.find(".cur")).length&&(c=this.context.insert_content_for(b),this.context.insert(this.context.callbacks("before_insert").call(this.context,c,b),b),this.context.trigger("inserted",[b,a]),this.hide(a)),this.context.get_opt("hide_without_suffix")?this.stop_showing=!0:void 0},b.prototype.reposition=function(b){var c,d,e,f;return f=this.context.app.iframeStandalone?this.context.app.window:window,b.bottom+this.$el.height()-a(f).scrollTop()>a(f).height()&&(b.bottom=b.top-this.$el.height()),b.left>(d=a(f).width()-this.$el.width()-5)&&(b.left=d),c={left:b.left,top:b.bottom},null!=(e=this.context.callbacks("before_reposition"))&&e.call(this.context,c),this.$el.offset(c),this.context.trigger("reposition",[c])},b.prototype.next=function(){var a,b;return a=this.$el.find(".cur").removeClass("cur"),b=a.next(),b.length||(b=this.$el.find("li:first")),b.addClass("cur"),this.$el.animate({scrollTop:Math.max(0,a.innerHeight()*(b.index()+2)-this.$el.height())},150)},b.prototype.prev=function(){var a,b;return a=this.$el.find(".cur").removeClass("cur"),b=a.prev(),b.length||(b=this.$el.find("li:last")),b.addClass("cur"),this.$el.animate({scrollTop:Math.max(0,a.innerHeight()*(b.index()+2)-this.$el.height())},150)},b.prototype.show=function(){var a;return this.stop_showing?void(this.stop_showing=!1):(this.context.mark_range(),this.visible()||(this.$el.show(),this.$el.scrollTop(0),this.context.trigger("shown")),(a=this.context.rect())?this.reposition(a):void 0)},b.prototype.hide=function(a,b){var c;if(this.visible())return isNaN(b)?(this.context.reset_rect(),this.$el.hide(),this.context.trigger("hidden",[a])):(c=function(a){return function(){return a.hide()}}(this),clearTimeout(this.timeout_id),this.timeout_id=setTimeout(c,b))},b.prototype.render=function(b){var c,d,e,f,g,h,i;if(!(a.isArray(b)&&b.length>0))return void this.hide();for(this.$el.find("ul").empty(),d=this.$el.find("ul"),g=this.context.get_opt("tpl"),h=0,i=b.length;i>h;h++)e=b[h],e=a.extend({},e,{"atwho-at":this.context.at}),f=this.context.callbacks("tpl_eval").call(this.context,g,e),c=a(this.context.callbacks("highlighter").call(this.context,f,this.context.query.text)),c.data("item-data",e),d.append(c);return this.show(),this.context.get_opt("highlight_first")?d.find("li:first").addClass("cur"):void 0},b}(),f={DOWN:40,UP:38,ESC:27,TAB:9,ENTER:13,CTRL:17,P:80,N:78},e={before_save:function(b){var c,d,e,f;if(!a.isArray(b))return b;for(f=[],d=0,e=b.length;e>d;d++)c=b[d],a.isPlainObject(c)?f.push(c):f.push({name:c});return f},matcher:function(a,b,c){var d,e,f,g;return a=a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),c&&(a="(?:^|\\s)"+a),f=decodeURI("%C3%80"),g=decodeURI("%C3%BF"),e=new RegExp(""+a+"([A-Za-z"+f+"-"+g+"0-9_+-]*)$|"+a+"([^\\x00-\\xff]*)$","gi"),d=e.exec(b),d?d[2]||d[1]:null},filter:function(a,b,c){var d,e,f,g;for(g=[],e=0,f=b.length;f>e;e++)d=b[e],~new String(d[c]).toLowerCase().indexOf(a.toLowerCase())&&g.push(d);return g},remote_filter:null,sorter:function(a,b,c){var d,e,f,g;if(!a)return b;for(g=[],e=0,f=b.length;f>e;e++)d=b[e],d.atwho_order=new String(d[c]).toLowerCase().indexOf(a.toLowerCase()),d.atwho_order>-1&&g.push(d);return g.sort(function(a,b){return a.atwho_order-b.atwho_order})},tpl_eval:function(a,b){var c;try{return a.replace(/\$\{([^\}]*)\}/g,function(a,c,d){return b[c]})}catch(d){return c=d,""}},highlighter:function(a,b){var c;return b?(c=new RegExp(">\\s*(\\w*?)("+b.replace("+","\\+")+")(\\w*)\\s*<","ig"),a.replace(c,function(a,b,c,d){return"> "+b+"<strong>"+c+"</strong>"+d+" <"})):a},before_insert:function(a,b){return a},inserting_wrapper:function(a,b,c){var d;return c=""===c?c:c||" ",a.is("textarea, input")?""+b+c:"true"===a.attr("contentEditable")?(c=" "===c?"&nbsp;":c,/firefox/i.test(navigator.userAgent)?d="<span>"+b+c+"</span>":(c="<span contenteditable='false'>"+c+"</span>",d="<span contenteditable='false'>"+b+c+"</span>"),this.app.document.selection&&(d="<span contenteditable='true'>"+b+"</span>"),d+"<span></span>"):void 0}},b={load:function(a,b){var c;return(c=this.controller(a))?c.model.load(b):void 0},setIframe:function(a,b){return this.setIframe(a,b),null},run:function(){return this.dispatch()},destroy:function(){return this.shutdown(),this.$inputor.data("atwho",null)}},a.fn.atwho=function(d){var e,f;return f=arguments,e=null,this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function(){var g,h;return(h=(g=a(this)).data("atwho"))||g.data("atwho",h=new c(this)),"object"!=typeof d&&d?b[d]&&h?e=b[d].apply(h,Array.prototype.slice.call(f,1)):a.error("Method "+d+" does not exist on jQuery.caret"):h.reg(d.at,d)}),e||this},a.fn.atwho["default"]={at:void 0,alias:void 0,data:null,tpl:"<li data-value='${atwho-at}${name}'>${name}</li>",insert_tpl:"<span id='${id}'>${atwho-data-value}</span>",callbacks:e,search_key:"name",suffix:void 0,hide_without_suffix:!1,start_with_space:!0,highlight_first:!0,limit:5,max_len:20,display_timeout:300,delay:null}});
 
bp-core/js/{jquery-cookie.js → vendor/jquery-cookie.js} RENAMED
File without changes
bp-core/js/{jquery-cookie.min.js → vendor/jquery-cookie.min.js} RENAMED
@@ -1 +1 @@
1
- !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
1
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(a){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;n<o;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0!==a.cookie(b)&&(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
bp-core/js/{jquery-scroll-to.js → vendor/jquery-scroll-to.js} RENAMED
File without changes
bp-core/js/{jquery-scroll-to.min.js → vendor/jquery-scroll-to.min.js} RENAMED
@@ -1 +1 @@
1
- !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(b){return a.isFunction(b)||"object"==typeof b?b:{top:b,left:b}}var c=a.scrollTo=function(b,c,d){return a(window).scrollTo(b,c,d)};return c.defaults={axis:"xy",duration:parseFloat(a.fn.jquery)>=1.3?0:1,limit:!0},c.window=function(){return a(window)._scrollable()},a.fn._scrollable=function(){return this.map(function(){var b=this,c=!b.nodeName||-1!==a.inArray(b.nodeName.toLowerCase(),["iframe","#document","html","body"]);if(!c)return b;var d=(b.contentWindow||b).document||b.ownerDocument||b;return/webkit/i.test(navigator.userAgent)||"BackCompat"===d.compatMode?d.body:d.documentElement})},a.fn.scrollTo=function(d,e,f){return"object"==typeof e&&(f=e,e=0),"function"==typeof f&&(f={onAfter:f}),"max"===d&&(d=9e9),f=a.extend({},c.defaults,f),e=e||f.duration,f.queue=f.queue&&f.axis.length>1,f.queue&&(e/=2),f.offset=b(f.offset),f.over=b(f.over),this._scrollable().each(function(){function g(a){j.animate(l,e,f.easing,a&&function(){a.call(this,k,f)})}if(null!==d){var h,i=this,j=a(i),k=d,l={},m=j.is("html,body");switch(typeof k){case"number":case"string":if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(k)){k=b(k);break}if(k=m?a(k):a(k,this),!k.length)return;case"object":(k.is||k.style)&&(h=(k=a(k)).offset())}var n=a.isFunction(f.offset)&&f.offset(i,k)||f.offset;a.each(f.axis.split(""),function(a,b){var d="x"===b?"Left":"Top",e=d.toLowerCase(),o="scroll"+d,p=i[o],q=c.max(i,b);if(h)l[o]=h[e]+(m?0:p-j.offset()[e]),f.margin&&(l[o]-=parseInt(k.css("margin"+d))||0,l[o]-=parseInt(k.css("border"+d+"Width"))||0),l[o]+=n[e]||0,f.over[e]&&(l[o]+=k["x"===b?"width":"height"]()*f.over[e]);else{var r=k[e];l[o]=r.slice&&"%"===r.slice(-1)?parseFloat(r)/100*q:r}f.limit&&/^\d+$/.test(l[o])&&(l[o]=l[o]<=0?0:Math.min(l[o],q)),!a&&f.queue&&(p!==l[o]&&g(f.onAfterFirst),delete l[o])}),g(f.onAfter)}}).end()},c.max=function(b,c){var d="x"===c?"Width":"Height",e="scroll"+d;if(!a(b).is("html,body"))return b[e]-a(b)[d.toLowerCase()]();var f="client"+d,g=b.ownerDocument.documentElement,h=b.ownerDocument.body;return Math.max(g[e],h[e])-Math.min(g[f],h[f])},c});
1
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(b){return a.isFunction(b)||"object"==typeof b?b:{top:b,left:b}}var c=a.scrollTo=function(b,c,d){return a(window).scrollTo(b,c,d)};return c.defaults={axis:"xy",duration:parseFloat(a.fn.jquery)>=1.3?0:1,limit:!0},c.window=function(){return a(window)._scrollable()},a.fn._scrollable=function(){return this.map(function(){var b=this,c=!b.nodeName||a.inArray(b.nodeName.toLowerCase(),["iframe","#document","html","body"])!==-1;if(!c)return b;var d=(b.contentWindow||b).document||b.ownerDocument||b;return/webkit/i.test(navigator.userAgent)||"BackCompat"===d.compatMode?d.body:d.documentElement})},a.fn.scrollTo=function(d,e,f){return"object"==typeof e&&(f=e,e=0),"function"==typeof f&&(f={onAfter:f}),"max"===d&&(d=9e9),f=a.extend({},c.defaults,f),e=e||f.duration,f.queue=f.queue&&f.axis.length>1,f.queue&&(e/=2),f.offset=b(f.offset),f.over=b(f.over),this._scrollable().each(function(){function g(a){j.animate(l,e,f.easing,a&&function(){a.call(this,k,f)})}if(null!==d){var h,i=this,j=a(i),k=d,l={},m=j.is("html,body");switch(typeof k){case"number":case"string":if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(k)){k=b(k);break}if(k=m?a(k):a(k,this),!k.length)return;case"object":(k.is||k.style)&&(h=(k=a(k)).offset())}var n=a.isFunction(f.offset)&&f.offset(i,k)||f.offset;a.each(f.axis.split(""),function(a,b){var d="x"===b?"Left":"Top",e=d.toLowerCase(),o="scroll"+d,p=i[o],q=c.max(i,b);if(h)l[o]=h[e]+(m?0:p-j.offset()[e]),f.margin&&(l[o]-=parseInt(k.css("margin"+d))||0,l[o]-=parseInt(k.css("border"+d+"Width"))||0),l[o]+=n[e]||0,f.over[e]&&(l[o]+=k["x"===b?"width":"height"]()*f.over[e]);else{var r=k[e];l[o]=r.slice&&"%"===r.slice(-1)?parseFloat(r)/100*q:r}f.limit&&/^\d+$/.test(l[o])&&(l[o]=l[o]<=0?0:Math.min(l[o],q)),!a&&f.queue&&(p!==l[o]&&g(f.onAfterFirst),delete l[o])}),g(f.onAfter)}}).end()},c.max=function(b,c){var d="x"===c?"Width":"Height",e="scroll"+d;if(!a(b).is("html,body"))return b[e]-a(b)[d.toLowerCase()]();var f="client"+d,g=b.ownerDocument.documentElement,h=b.ownerDocument.body;return Math.max(g[e],h[e])-Math.min(g[f],h[f])},c});
bp-core/js/{jquery.atwho.js → vendor/jquery.atwho.js} RENAMED
File without changes
bp-core/js/vendor/jquery.atwho.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.returnExportsGlobal=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){var b,c,d,e,f,g,h,i=[].slice;c=function(){function b(b){this.current_flag=null,this.controllers={},this.alias_maps={},this.$inputor=a(b),this.setIframe(),this.listen()}return b.prototype.createContainer=function(b){if(0===(this.$el=a("#atwho-container",b)).length)return a(b.body).append(this.$el=a("<div id='atwho-container'></div>"))},b.prototype.setIframe=function(a,b){var c;return null==b&&(b=!1),a?(this.window=a.contentWindow,this.document=a.contentDocument||this.window.document,this.iframe=a):(this.document=document,this.window=window,this.iframe=null),(this.iframeStandalone=b)?(null!=(c=this.$el)&&c.remove(),this.createContainer(this.document)):this.createContainer(document)},b.prototype.controller=function(a){var b,c,d,e;if(this.alias_maps[a])c=this.controllers[this.alias_maps[a]];else{e=this.controllers;for(d in e)if(b=e[d],d===a){c=b;break}}return c?c:this.controllers[this.current_flag]},b.prototype.set_context_for=function(a){return this.current_flag=a,this},b.prototype.reg=function(a,b){var c,e;return c=(e=this.controllers)[a]||(e[a]=new d(this,a)),b.alias&&(this.alias_maps[b.alias]=a),c.init(b),this},b.prototype.listen=function(){return this.$inputor.on("keyup.atwhoInner",function(a){return function(b){return a.on_keyup(b)}}(this)).on("keydown.atwhoInner",function(a){return function(b){return a.on_keydown(b)}}(this)).on("scroll.atwhoInner",function(a){return function(b){var c;return null!=(c=a.controller())?c.view.hide(b):void 0}}(this)).on("blur.atwhoInner",function(a){return function(b){var c;if(c=a.controller())return c.view.hide(b,c.get_opt("display_timeout"))}}(this)).on("click.atwhoInner",function(a){return function(b){return a.dispatch()}}(this))},b.prototype.shutdown=function(){var a,b,c;c=this.controllers;for(b in c)a=c[b],a.destroy(),delete this.controllers[b];return this.$inputor.off(".atwhoInner"),this.$el.remove()},b.prototype.dispatch=function(){return a.map(this.controllers,function(a){return function(b){var c;return(c=b.get_opt("delay"))?(clearTimeout(a.delayedCallback),a.delayedCallback=setTimeout(function(){if(b.look_up())return a.set_context_for(b.at)},c)):b.look_up()?a.set_context_for(b.at):void 0}}(this))},b.prototype.on_keyup=function(b){var c;switch(b.keyCode){case f.ESC:b.preventDefault(),null!=(c=this.controller())&&c.view.hide();break;case f.DOWN:case f.UP:case f.CTRL:a.noop();break;case f.P:case f.N:b.ctrlKey||this.dispatch();break;default:this.dispatch()}},b.prototype.on_keydown=function(b){var c,d;if(c=null!=(d=this.controller())?d.view:void 0,c&&c.visible())switch(b.keyCode){case f.ESC:b.preventDefault(),c.hide(b);break;case f.UP:b.preventDefault(),c.prev();break;case f.DOWN:b.preventDefault(),c.next();break;case f.P:if(!b.ctrlKey)return;b.preventDefault(),c.prev();break;case f.N:if(!b.ctrlKey)return;b.preventDefault(),c.next();break;case f.TAB:case f.ENTER:if(!c.visible())return;b.preventDefault(),c.choose(b);break;default:a.noop()}},b}(),d=function(){function b(b,c){this.app=b,this.at=c,this.$inputor=this.app.$inputor,this.id=this.$inputor[0].id||this.uid(),this.setting=null,this.query=null,this.pos=0,this.cur_rect=null,this.range=null,0===(this.$el=a("#atwho-ground-"+this.id,this.app.$el)).length&&this.app.$el.append(this.$el=a("<div id='atwho-ground-"+this.id+"'></div>")),this.model=new g(this),this.view=new h(this)}return b.prototype.uid=function(){return(Math.random().toString(16)+"000000000").substr(2,8)+(new Date).getTime()},b.prototype.init=function(b){return this.setting=a.extend({},this.setting||a.fn.atwho.default,b),this.view.init(),this.model.reload(this.setting.data)},b.prototype.destroy=function(){return this.trigger("beforeDestroy"),this.model.destroy(),this.view.destroy(),this.$el.remove()},b.prototype.call_default=function(){var b,c,d;d=arguments[0],b=2<=arguments.length?i.call(arguments,1):[];try{return e[d].apply(this,b)}catch(b){return c=b,a.error(""+c+" Or maybe At.js doesn't have function "+d)}},b.prototype.trigger=function(a,b){var c,d;return null==b&&(b=[]),b.push(this),c=this.get_opt("alias"),d=c?""+a+"-"+c+".atwho":""+a+".atwho",this.$inputor.trigger(d,b)},b.prototype.callbacks=function(a){return this.get_opt("callbacks")[a]||e[a]},b.prototype.get_opt=function(a,b){var c;try{return this.setting[a]}catch(a){return c=a,null}},b.prototype.content=function(){var a;if(this.$inputor.is("textarea, input"))return this.$inputor.val();if(a=this.mark_range())return(a.startContainer.textContent||"").slice(0,a.startOffset)},b.prototype.catch_query=function(){var a,b,c,d,e,f;return b=this.content(),a=this.$inputor.caret("pos",{iframe:this.app.iframe}),f=b.slice(0,a),d=this.callbacks("matcher").call(this,this.at,f,this.get_opt("start_with_space")),"string"==typeof d&&d.length<=this.get_opt("max_len",20)?(e=a-d.length,c=e+d.length,this.pos=e,d={text:d,head_pos:e,end_pos:c},this.trigger("matched",[this.at,d.text])):(d=null,this.view.hide()),this.query=d},b.prototype.rect=function(){var b,c,d;if(b=this.$inputor.caret("offset",this.pos-1,{iframe:this.app.iframe}))return this.app.iframe&&!this.app.iframeStandalone&&(c=a(this.app.iframe).offset(),b.left+=c.left,b.top+=c.top),this.$inputor.is("[contentEditable]")&&(b=this.cur_rect||(this.cur_rect=b)),d=this.app.document.selection?0:2,{left:b.left,top:b.top,bottom:b.top+b.height+d}},b.prototype.reset_rect=function(){if(this.$inputor.is("[contentEditable]"))return this.cur_rect=null},b.prototype.mark_range=function(){var a;if(this.$inputor.is("[contentEditable]"))return this.app.window.getSelection&&(a=this.app.window.getSelection()).rangeCount>0?this.range=a.getRangeAt(0):this.app.document.selection?this.ie8_range=this.app.document.selection.createRange():void 0},b.prototype.insert_content_for=function(b){var c,d,e;return d=b.data("value"),e=this.get_opt("insert_tpl"),this.$inputor.is("textarea, input")||!e?d:(c=a.extend({},b.data("item-data"),{"atwho-data-value":d,"atwho-at":this.at}),this.callbacks("tpl_eval").call(this,e,c))},b.prototype.insert=function(b,c){var d,e,f,g,h,i,j,k,l,m,n,o;if(d=this.$inputor,l=this.callbacks("inserting_wrapper").call(this,d,b,this.get_opt("suffix")),d.is("textarea, input"))i=d.val(),j=i.slice(0,Math.max(this.query.head_pos-this.at.length,0)),k=""+j+l+i.slice(this.query.end_pos||0),d.val(k),d.caret("pos",j.length+l.length,{iframe:this.app.iframe});else if(g=this.range){for(f=g.startOffset-(this.query.end_pos-this.query.head_pos)-this.at.length,g.setStart(g.endContainer,Math.max(f,0)),g.setEnd(g.endContainer,g.endOffset),g.deleteContents(),o=a(l,this.app.document),m=0,n=o.length;m<n;m++)e=o[m],g.insertNode(e),g.setEndAfter(e),g.collapse(!1);h=this.app.window.getSelection(),h.removeAllRanges(),h.addRange(g)}else(g=this.ie8_range)&&(g.moveStart("character",this.query.end_pos-this.query.head_pos-this.at.length),g.pasteHTML(l),g.collapse(!1),g.select());return d.is(":focus")||d.focus(),d.change()},b.prototype.render_view=function(a){var b;return b=this.get_opt("search_key"),a=this.callbacks("sorter").call(this,this.query.text,a.slice(0,1001),b),this.view.render(a.slice(0,this.get_opt("limit")))},b.prototype.look_up=function(){var b,c;if(b=this.catch_query())return c=function(a){return a&&a.length>0?this.render_view(a):this.view.hide()},this.model.query(b.text,a.proxy(c,this)),b},b}(),g=function(){function b(a){this.context=a,this.at=this.context.at,this.storage=this.context.$inputor}return b.prototype.destroy=function(){return this.storage.data(this.at,null)},b.prototype.saved=function(){return this.fetch()>0},b.prototype.query=function(a,b){var c,d,e;return c=this.fetch(),d=this.context.get_opt("search_key"),c=this.context.callbacks("filter").call(this.context,a,c,d)||[],e=this.context.callbacks("remote_filter"),c.length>0||!e&&0===c.length?b(c):e.call(this.context,a,b)},b.prototype.fetch=function(){return this.storage.data(this.at)||[]},b.prototype.save=function(a){return this.storage.data(this.at,this.context.callbacks("before_save").call(this.context,a||[]))},b.prototype.load=function(a){if(!this.saved()&&a)return this._load(a)},b.prototype.reload=function(a){return this._load(a)},b.prototype._load=function(b){return"string"==typeof b?a.ajax(b,{dataType:"json"}).done(function(a){return function(b){return a.save(b)}}(this)):this.save(b)},b}(),h=function(){function b(b){this.context=b,this.$el=a("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>"),this.timeout_id=null,this.context.$el.append(this.$el),this.bind_event()}return b.prototype.init=function(){var a;return a=this.context.get_opt("alias")||this.context.at.charCodeAt(0),this.$el.attr({id:"at-view-"+a})},b.prototype.destroy=function(){return this.$el.remove()},b.prototype.bind_event=function(){var b;return b=this.$el.find("ul"),b.on("mouseenter.atwho-view","li",function(c){return b.find(".cur").removeClass("cur"),a(c.currentTarget).addClass("cur")}).on("click.atwho-view","li",function(c){return function(d){return b.find(".cur").removeClass("cur"),a(d.currentTarget).addClass("cur"),c.choose(d),d.preventDefault()}}(this))},b.prototype.visible=function(){return this.$el.is(":visible")},b.prototype.choose=function(a){var b,c;if((b=this.$el.find(".cur")).length&&(c=this.context.insert_content_for(b),this.context.insert(this.context.callbacks("before_insert").call(this.context,c,b),b),this.context.trigger("inserted",[b,a]),this.hide(a)),this.context.get_opt("hide_without_suffix"))return this.stop_showing=!0},b.prototype.reposition=function(b){var c,d,e,f;return f=this.context.app.iframeStandalone?this.context.app.window:window,b.bottom+this.$el.height()-a(f).scrollTop()>a(f).height()&&(b.bottom=b.top-this.$el.height()),b.left>(d=a(f).width()-this.$el.width()-5)&&(b.left=d),c={left:b.left,top:b.bottom},null!=(e=this.context.callbacks("before_reposition"))&&e.call(this.context,c),this.$el.offset(c),this.context.trigger("reposition",[c])},b.prototype.next=function(){var a,b;return a=this.$el.find(".cur").removeClass("cur"),b=a.next(),b.length||(b=this.$el.find("li:first")),b.addClass("cur"),this.$el.animate({scrollTop:Math.max(0,a.innerHeight()*(b.index()+2)-this.$el.height())},150)},b.prototype.prev=function(){var a,b;return a=this.$el.find(".cur").removeClass("cur"),b=a.prev(),b.length||(b=this.$el.find("li:last")),b.addClass("cur"),this.$el.animate({scrollTop:Math.max(0,a.innerHeight()*(b.index()+2)-this.$el.height())},150)},b.prototype.show=function(){var a;return this.stop_showing?void(this.stop_showing=!1):(this.context.mark_range(),this.visible()||(this.$el.show(),this.$el.scrollTop(0),this.context.trigger("shown")),(a=this.context.rect())?this.reposition(a):void 0)},b.prototype.hide=function(a,b){var c;if(this.visible())return isNaN(b)?(this.context.reset_rect(),this.$el.hide(),this.context.trigger("hidden",[a])):(c=function(a){return function(){return a.hide()}}(this),clearTimeout(this.timeout_id),this.timeout_id=setTimeout(c,b))},b.prototype.render=function(b){var c,d,e,f,g,h,i;if(!(a.isArray(b)&&b.length>0))return void this.hide();for(this.$el.find("ul").empty(),d=this.$el.find("ul"),g=this.context.get_opt("tpl"),h=0,i=b.length;h<i;h++)e=b[h],e=a.extend({},e,{"atwho-at":this.context.at}),f=this.context.callbacks("tpl_eval").call(this.context,g,e),c=a(this.context.callbacks("highlighter").call(this.context,f,this.context.query.text)),c.data("item-data",e),d.append(c);return this.show(),this.context.get_opt("highlight_first")?d.find("li:first").addClass("cur"):void 0},b}(),f={DOWN:40,UP:38,ESC:27,TAB:9,ENTER:13,CTRL:17,P:80,N:78},e={before_save:function(b){var c,d,e,f;if(!a.isArray(b))return b;for(f=[],d=0,e=b.length;d<e;d++)c=b[d],a.isPlainObject(c)?f.push(c):f.push({name:c});return f},matcher:function(a,b,c){var d,e,f,g;return a=a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),c&&(a="(?:^|\\s)"+a),f=decodeURI("%C3%80"),g=decodeURI("%C3%BF"),e=new RegExp(""+a+"([A-Za-z"+f+"-"+g+"0-9_+-]*)$|"+a+"([^\\x00-\\xff]*)$","gi"),d=e.exec(b),d?d[2]||d[1]:null},filter:function(a,b,c){var d,e,f,g;for(g=[],e=0,f=b.length;e<f;e++)d=b[e],~new String(d[c]).toLowerCase().indexOf(a.toLowerCase())&&g.push(d);return g},remote_filter:null,sorter:function(a,b,c){var d,e,f,g;if(!a)return b;for(g=[],e=0,f=b.length;e<f;e++)d=b[e],d.atwho_order=new String(d[c]).toLowerCase().indexOf(a.toLowerCase()),d.atwho_order>-1&&g.push(d);return g.sort(function(a,b){return a.atwho_order-b.atwho_order})},tpl_eval:function(a,b){var c;try{return a.replace(/\$\{([^\}]*)\}/g,function(a,c,d){return b[c]})}catch(a){return c=a,""}},highlighter:function(a,b){var c;return b?(c=new RegExp(">\\s*(\\w*?)("+b.replace("+","\\+")+")(\\w*)\\s*<","ig"),a.replace(c,function(a,b,c,d){return"> "+b+"<strong>"+c+"</strong>"+d+" <"})):a},before_insert:function(a,b){return a},inserting_wrapper:function(a,b,c){var d;return c=""===c?c:c||" ",a.is("textarea, input")?""+b+c:"true"===a.attr("contentEditable")?(c=" "===c?"&nbsp;":c,/firefox/i.test(navigator.userAgent)?d="<span>"+b+c+"</span>":(c="<span contenteditable='false'>"+c+"</span>",d="<span contenteditable='false'>"+b+c+"</span>"),this.app.document.selection&&(d="<span contenteditable='true'>"+b+"</span>"),d+"<span></span>"):void 0}},b={load:function(a,b){var c;if(c=this.controller(a))return c.model.load(b)},setIframe:function(a,b){return this.setIframe(a,b),null},run:function(){return this.dispatch()},destroy:function(){return this.shutdown(),this.$inputor.data("atwho",null)}},a.fn.atwho=function(d){var e,f;return f=arguments,e=null,this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function(){var g,h;return(h=(g=a(this)).data("atwho"))||g.data("atwho",h=new c(this)),"object"!=typeof d&&d?b[d]&&h?e=b[d].apply(h,Array.prototype.slice.call(f,1)):a.error("Method "+d+" does not exist on jQuery.caret"):h.reg(d.at,d)}),e||this},a.fn.atwho.default={at:void 0,alias:void 0,data:null,tpl:"<li data-value='${atwho-at}${name}'>${name}</li>",insert_tpl:"<span id='${id}'>${atwho-data-value}</span>",callbacks:e,search_key:"name",suffix:void 0,hide_without_suffix:!1,start_with_space:!0,highlight_first:!0,limit:5,max_len:20,display_timeout:300,delay:null}});
bp-core/js/{jquery.atwho.txt → vendor/jquery.atwho.txt} RENAMED
File without changes
bp-core/js/{jquery.caret.js → vendor/jquery.caret.js} RENAMED
File without changes
bp-core/js/{jquery.caret.min.js → vendor/jquery.caret.min.js} RENAMED
@@ -1 +1 @@
1
- !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.returnExportsGlobal=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){"use strict";var b,c,d,e,f,g,h,i,j,k,l;k="caret",b=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.setPos=function(a){return this.domInputor},b.prototype.getIEPosition=function(){return this.getPosition()},b.prototype.getPosition=function(){var a,b;return b=this.getOffset(),a=this.$inputor.offset(),b.left-=a.left,b.top-=a.top,b},b.prototype.getOldIEPos=function(){var a,b;return b=h.selection.createRange(),a=h.body.createTextRange(),a.moveToElementText(this.domInputor),a.setEndPoint("EndToEnd",b),a.text.length},b.prototype.getPos=function(){var a,b,c;return(c=this.range())?(a=c.cloneRange(),a.selectNodeContents(this.domInputor),a.setEnd(c.endContainer,c.endOffset),b=a.toString().length,a.detach(),b):h.selection?this.getOldIEPos():void 0},b.prototype.getOldIEOffset=function(){var a,b;return a=h.selection.createRange().duplicate(),a.moveStart("character",-1),b=a.getBoundingClientRect(),{height:b.bottom-b.top,left:b.left,top:b.top}},b.prototype.getOffset=function(b){var c,d,e,f,g;return j.getSelection&&(e=this.range())?(e.endOffset-1>0&&e.endContainer===!this.domInputor&&(c=e.cloneRange(),c.setStart(e.endContainer,e.endOffset-1),c.setEnd(e.endContainer,e.endOffset),f=c.getBoundingClientRect(),d={height:f.height,left:f.left+f.width,top:f.top},c.detach()),d&&0!==(null!=d?d.height:void 0)||(c=e.cloneRange(),g=a(h.createTextNode("|")),c.insertNode(g[0]),c.selectNode(g[0]),f=c.getBoundingClientRect(),d={height:f.height,left:f.left,top:f.top},g.remove(),c.detach())):h.selection&&(d=this.getOldIEOffset()),d&&(d.top+=a(j).scrollTop(),d.left+=a(j).scrollLeft()),d},b.prototype.range=function(){var a;if(j.getSelection)return a=j.getSelection(),a.rangeCount>0?a.getRangeAt(0):null},b}(),c=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.getIEPos=function(){var a,b,c,d,e,f,g;return b=this.domInputor,f=h.selection.createRange(),e=0,f&&f.parentElement()===b&&(d=b.value.replace(/\r\n/g,"\n"),c=d.length,g=b.createTextRange(),g.moveToBookmark(f.getBookmark()),a=b.createTextRange(),a.collapse(!1),e=g.compareEndPoints("StartToEnd",a)>-1?c:-g.moveStart("character",-c)),e},b.prototype.getPos=function(){return h.selection?this.getIEPos():this.domInputor.selectionStart},b.prototype.setPos=function(a){var b,c;return b=this.domInputor,h.selection?(c=b.createTextRange(),c.move("character",a),c.select()):b.setSelectionRange&&b.setSelectionRange(a,a),b},b.prototype.getIEOffset=function(a){var b,c,d,e;return c=this.domInputor.createTextRange(),a||(a=this.getPos()),c.move("character",a),d=c.boundingLeft,e=c.boundingTop,b=c.boundingHeight,{left:d,top:e,height:b}},b.prototype.getOffset=function(b){var c,d,e;return c=this.$inputor,h.selection?(d=this.getIEOffset(b),d.top+=a(j).scrollTop()+c.scrollTop(),d.left+=a(j).scrollLeft()+c.scrollLeft(),d):(d=c.offset(),e=this.getPosition(b),d={left:d.left+e.left-c.scrollLeft(),top:d.top+e.top-c.scrollTop(),height:e.height})},b.prototype.getPosition=function(a){var b,c,e,f,g,h,i;return b=this.$inputor,f=function(a){return a=a.replace(/<|>|`|"|&/g,"?").replace(/\r\n|\r|\n/g,"<br/>"),/firefox/i.test(navigator.userAgent)&&(a=a.replace(/\s/g,"&nbsp;")),a},void 0===a&&(a=this.getPos()),i=b.val().slice(0,a),e=b.val().slice(a),g="<span style='position: relative; display: inline;'>"+f(i)+"</span>",g+="<span id='caret' style='position: relative; display: inline;'>|</span>",g+="<span style='position: relative; display: inline;'>"+f(e)+"</span>",h=new d(b),c=h.create(g).rect()},b.prototype.getIEPosition=function(a){var b,c,d,e,f;return d=this.getIEOffset(a),c=this.$inputor.offset(),e=d.left-c.left,f=d.top-c.top,b=d.height,{left:e,top:f,height:b}},b}(),d=function(){function b(a){this.$inputor=a}return b.prototype.css_attr=["borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopStyle","borderRightStyle","borderBottomStyle","borderLeftStyle","borderTopWidth","boxSizing","fontFamily","fontSize","fontWeight","height","letterSpacing","lineHeight","marginBottom","marginLeft","marginRight","marginTop","outlineWidth","overflow","overflowX","overflowY","paddingBottom","paddingLeft","paddingRight","paddingTop","textAlign","textOverflow","textTransform","whiteSpace","wordBreak","wordWrap"],b.prototype.mirrorCss=function(){var b,c=this;return b={position:"absolute",left:-9999,top:0,zIndex:-2e4},"TEXTAREA"===this.$inputor.prop("tagName")&&this.css_attr.push("width"),a.each(this.css_attr,function(a,d){return b[d]=c.$inputor.css(d)}),b},b.prototype.create=function(b){return this.$mirror=a("<div></div>"),this.$mirror.css(this.mirrorCss()),this.$mirror.html(b),this.$inputor.after(this.$mirror),this},b.prototype.rect=function(){var a,b,c;return a=this.$mirror.find("#caret"),b=a.position(),c={left:b.left,top:b.top,height:a.height()},this.$mirror.remove(),c},b}(),e={contentEditable:function(a){return!(!a[0].contentEditable||"true"!==a[0].contentEditable)}},g={pos:function(a){return a||0===a?this.setPos(a):this.getPos()},position:function(a){return h.selection?this.getIEPosition(a):this.getPosition(a)},offset:function(a){var b;return b=this.getOffset(a)}},h=null,j=null,i=null,l=function(a){var b;return(b=null!=a?a.iframe:void 0)?(i=b,j=b.contentWindow,h=b.contentDocument||j.document):(i=void 0,j=window,h=document)},f=function(a){var b;h=a[0].ownerDocument,j=h.defaultView||h.parentWindow;try{return i=j.frameElement}catch(c){b=c}},a.fn.caret=function(d,f,h){var i;return g[d]?(a.isPlainObject(f)?(l(f),f=void 0):l(h),i=e.contentEditable(this)?new b(this):new c(this),g[d].apply(i,[f])):a.error("Method "+d+" does not exist on jQuery.caret")},a.fn.caret.EditableCaret=b,a.fn.caret.InputCaret=c,a.fn.caret.Utils=e,a.fn.caret.apis=g});
1
+ !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.returnExportsGlobal=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){"use strict";var b,c,d,e,f,g,h,i,j,k,l;k="caret",b=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.setPos=function(a){return this.domInputor},b.prototype.getIEPosition=function(){return this.getPosition()},b.prototype.getPosition=function(){var a,b;return b=this.getOffset(),a=this.$inputor.offset(),b.left-=a.left,b.top-=a.top,b},b.prototype.getOldIEPos=function(){var a,b;return b=h.selection.createRange(),a=h.body.createTextRange(),a.moveToElementText(this.domInputor),a.setEndPoint("EndToEnd",b),a.text.length},b.prototype.getPos=function(){var a,b,c;return(c=this.range())?(a=c.cloneRange(),a.selectNodeContents(this.domInputor),a.setEnd(c.endContainer,c.endOffset),b=a.toString().length,a.detach(),b):h.selection?this.getOldIEPos():void 0},b.prototype.getOldIEOffset=function(){var a,b;return a=h.selection.createRange().duplicate(),a.moveStart("character",-1),b=a.getBoundingClientRect(),{height:b.bottom-b.top,left:b.left,top:b.top}},b.prototype.getOffset=function(b){var c,d,e,f,g;return j.getSelection&&(e=this.range())?(e.endOffset-1>0&&e.endContainer===!this.domInputor&&(c=e.cloneRange(),c.setStart(e.endContainer,e.endOffset-1),c.setEnd(e.endContainer,e.endOffset),f=c.getBoundingClientRect(),d={height:f.height,left:f.left+f.width,top:f.top},c.detach()),d&&0!==(null!=d?d.height:void 0)||(c=e.cloneRange(),g=a(h.createTextNode("|")),c.insertNode(g[0]),c.selectNode(g[0]),f=c.getBoundingClientRect(),d={height:f.height,left:f.left,top:f.top},g.remove(),c.detach())):h.selection&&(d=this.getOldIEOffset()),d&&(d.top+=a(j).scrollTop(),d.left+=a(j).scrollLeft()),d},b.prototype.range=function(){var a;if(j.getSelection)return a=j.getSelection(),a.rangeCount>0?a.getRangeAt(0):null},b}(),c=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.getIEPos=function(){var a,b,c,d,e,f,g;return b=this.domInputor,f=h.selection.createRange(),e=0,f&&f.parentElement()===b&&(d=b.value.replace(/\r\n/g,"\n"),c=d.length,g=b.createTextRange(),g.moveToBookmark(f.getBookmark()),a=b.createTextRange(),a.collapse(!1),e=g.compareEndPoints("StartToEnd",a)>-1?c:-g.moveStart("character",-c)),e},b.prototype.getPos=function(){return h.selection?this.getIEPos():this.domInputor.selectionStart},b.prototype.setPos=function(a){var b,c;return b=this.domInputor,h.selection?(c=b.createTextRange(),c.move("character",a),c.select()):b.setSelectionRange&&b.setSelectionRange(a,a),b},b.prototype.getIEOffset=function(a){var b,c,d,e;return c=this.domInputor.createTextRange(),a||(a=this.getPos()),c.move("character",a),d=c.boundingLeft,e=c.boundingTop,b=c.boundingHeight,{left:d,top:e,height:b}},b.prototype.getOffset=function(b){var c,d,e;return c=this.$inputor,h.selection?(d=this.getIEOffset(b),d.top+=a(j).scrollTop()+c.scrollTop(),d.left+=a(j).scrollLeft()+c.scrollLeft(),d):(d=c.offset(),e=this.getPosition(b),d={left:d.left+e.left-c.scrollLeft(),top:d.top+e.top-c.scrollTop(),height:e.height})},b.prototype.getPosition=function(a){var b,c,e,f,g,h,i;return b=this.$inputor,f=function(a){return a=a.replace(/<|>|`|"|&/g,"?").replace(/\r\n|\r|\n/g,"<br/>"),/firefox/i.test(navigator.userAgent)&&(a=a.replace(/\s/g,"&nbsp;")),a},void 0===a&&(a=this.getPos()),i=b.val().slice(0,a),e=b.val().slice(a),g="<span style='position: relative; display: inline;'>"+f(i)+"</span>",g+="<span id='caret' style='position: relative; display: inline;'>|</span>",g+="<span style='position: relative; display: inline;'>"+f(e)+"</span>",h=new d(b),c=h.create(g).rect()},b.prototype.getIEPosition=function(a){var b,c,d,e,f;return d=this.getIEOffset(a),c=this.$inputor.offset(),e=d.left-c.left,f=d.top-c.top,b=d.height,{left:e,top:f,height:b}},b}(),d=function(){function b(a){this.$inputor=a}return b.prototype.css_attr=["borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopStyle","borderRightStyle","borderBottomStyle","borderLeftStyle","borderTopWidth","boxSizing","fontFamily","fontSize","fontWeight","height","letterSpacing","lineHeight","marginBottom","marginLeft","marginRight","marginTop","outlineWidth","overflow","overflowX","overflowY","paddingBottom","paddingLeft","paddingRight","paddingTop","textAlign","textOverflow","textTransform","whiteSpace","wordBreak","wordWrap"],b.prototype.mirrorCss=function(){var b,c=this;return b={position:"absolute",left:-9999,top:0,zIndex:-2e4},"TEXTAREA"===this.$inputor.prop("tagName")&&this.css_attr.push("width"),a.each(this.css_attr,function(a,d){return b[d]=c.$inputor.css(d)}),b},b.prototype.create=function(b){return this.$mirror=a("<div></div>"),this.$mirror.css(this.mirrorCss()),this.$mirror.html(b),this.$inputor.after(this.$mirror),this},b.prototype.rect=function(){var a,b,c;return a=this.$mirror.find("#caret"),b=a.position(),c={left:b.left,top:b.top,height:a.height()},this.$mirror.remove(),c},b}(),e={contentEditable:function(a){return!(!a[0].contentEditable||"true"!==a[0].contentEditable)}},g={pos:function(a){return a||0===a?this.setPos(a):this.getPos()},position:function(a){return h.selection?this.getIEPosition(a):this.getPosition(a)},offset:function(a){var b;return b=this.getOffset(a)}},h=null,j=null,i=null,l=function(a){var b;return(b=null!=a?a.iframe:void 0)?(i=b,j=b.contentWindow,h=b.contentDocument||j.document):(i=void 0,j=window,h=document)},f=function(a){var b;h=a[0].ownerDocument,j=h.defaultView||h.parentWindow;try{return i=j.frameElement}catch(a){b=a}},a.fn.caret=function(d,f,h){var i;return g[d]?(a.isPlainObject(f)?(l(f),f=void 0):l(h),i=e.contentEditable(this)?new b(this):new c(this),g[d].apply(i,[f])):a.error("Method "+d+" does not exist on jQuery.caret")},a.fn.caret.EditableCaret=b,a.fn.caret.InputCaret=c,a.fn.caret.Utils=e,a.fn.caret.apis=g});
bp-core/js/{jquery.caret.txt → vendor/jquery.caret.txt} RENAMED
File without changes
bp-core/js/vendor/livestamp.js ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Livestamp.js / v1.1.2 / (c) 2012 Matt Bradley / MIT License
2
+ (function($, moment) {
3
+ var updateInterval = 1e3,
4
+ paused = false,
5
+ $livestamps = $([]),
6
+
7
+ init = function() {
8
+ livestampGlobal.resume();
9
+ },
10
+
11
+ prep = function($el, timestamp) {
12
+ var oldData = $el.data('livestampdata');
13
+ if (typeof timestamp == 'number')
14
+ timestamp *= 1e3;
15
+
16
+ $el.removeAttr('data-livestamp')
17
+ .removeData('livestamp');
18
+
19
+ timestamp = moment(timestamp);
20
+ if (moment.isMoment(timestamp) && !isNaN(+timestamp)) {
21
+ var newData = $.extend({ }, { 'original': $el.contents() }, oldData);
22
+ newData.moment = moment(timestamp);
23
+
24
+ $el.data('livestampdata', newData).empty();
25
+ $livestamps.push($el[0]);
26
+ }
27
+ },
28
+
29
+ run = function() {
30
+ if (paused) return;
31
+ livestampGlobal.update();
32
+ setTimeout(run, updateInterval);
33
+ },
34
+
35
+ livestampGlobal = {
36
+ update: function() {
37
+ $('[data-livestamp]').each(function() {
38
+ var $this = $(this);
39
+ prep($this, $this.data('livestamp'));
40
+ });
41
+
42
+ var toRemove = [];
43
+ $livestamps.each(function() {
44
+ var $this = $(this),
45
+ data = $this.data('livestampdata');
46
+
47
+ if (data === undefined)
48
+ toRemove.push(this);
49
+ else if (moment.isMoment(data.moment)) {
50
+ var from = $this.html(),
51
+ to = data.moment.fromNow();
52
+
53
+ if (from != to) {
54
+ var e = $.Event('change.livestamp');
55
+ $this.trigger(e, [from, to]);
56
+ if (!e.isDefaultPrevented())
57
+ $this.html(to);
58
+ }
59
+ }
60
+ });
61
+
62
+ $livestamps = $livestamps.not(toRemove);
63
+ },
64
+
65
+ pause: function() {
66
+ paused = true;
67
+ },
68
+
69
+ resume: function() {
70
+ paused = false;
71
+ run();
72
+ },
73
+
74
+ interval: function(interval) {
75
+ if (interval === undefined)
76
+ return updateInterval;
77
+ updateInterval = interval;
78
+ }
79
+ },
80
+
81
+ livestampLocal = {
82
+ add: function($el, timestamp) {
83
+ if (typeof timestamp == 'number')
84
+ timestamp *= 1e3;
85
+ timestamp = moment(timestamp);
86
+
87
+ if (moment.isMoment(timestamp) && !isNaN(+timestamp)) {
88
+ $el.each(function() {
89
+ prep($(this), timestamp);
90
+ });
91
+ livestampGlobal.update();
92
+ }
93
+
94
+ return $el;
95
+ },
96
+
97
+ destroy: function($el) {
98
+ $livestamps = $livestamps.not($el);
99
+ $el.each(function() {
100
+ var $this = $(this),
101
+ data = $this.data('livestampdata');
102
+
103
+ if (data === undefined)
104
+ return $el;
105
+
106
+ $this
107
+ .html(data.original ? data.original : '')
108
+ .removeData('livestampdata');
109
+ });
110
+
111
+ return $el;
112
+ },
113
+
114
+ isLivestamp: function($el) {
115
+ return $el.data('livestampdata') !== undefined;
116
+ }
117
+ };
118
+
119
+ $.livestamp = livestampGlobal;
120
+ $(init);
121
+ $.fn.livestamp = function(method, options) {
122
+ if (!livestampLocal[method]) {
123
+ options = method;
124
+ method = 'add';
125
+ }
126
+
127
+ return livestampLocal[method](this, options);
128
+ };
129
+ })(jQuery, moment);
bp-core/js/vendor/livestamp.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(a,b){var c=1e3,d=!1,e=a([]),f=function(){i.resume()},g=function(c,d){var f=c.data("livestampdata");if("number"==typeof d&&(d*=1e3),c.removeAttr("data-livestamp").removeData("livestamp"),d=b(d),b.isMoment(d)&&!isNaN(+d)){var g=a.extend({},{original:c.contents()},f);g.moment=b(d),c.data("livestampdata",g).empty(),e.push(c[0])}},h=function(){d||(i.update(),setTimeout(h,c))},i={update:function(){a("[data-livestamp]").each(function(){var b=a(this);g(b,b.data("livestamp"))});var c=[];e.each(function(){var d=a(this),e=d.data("livestampdata");if(void 0===e)c.push(this);else if(b.isMoment(e.moment)){var f=d.html(),g=e.moment.fromNow();if(f!=g){var h=a.Event("change.livestamp");d.trigger(h,[f,g]),h.isDefaultPrevented()||d.html(g)}}}),e=e.not(c)},pause:function(){d=!0},resume:function(){d=!1,h()},interval:function(a){return void 0===a?c:void(c=a)}},j={add:function(c,d){return"number"==typeof d&&(d*=1e3),d=b(d),b.isMoment(d)&&!isNaN(+d)&&(c.each(function(){g(a(this),d)}),i.update()),c},destroy:function(b){return e=e.not(b),b.each(function(){var c=a(this),d=c.data("livestampdata");return void 0===d?b:void c.html(d.original?d.original:"").removeData("livestampdata")}),b},isLivestamp:function(a){return void 0!==a.data("livestampdata")}};a.livestamp=i,a(f),a.fn.livestamp=function(a,b){return j[a]||(b=a,a="add"),j[a](this,b)}}(jQuery,moment);
bp-core/js/vendor/moment.js ADDED
@@ -0,0 +1,4040 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! moment.js
2
+ //! version : 2.13.0
3
+ //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
+ //! license : MIT
5
+ //! momentjs.com
6
+
7
+ ;(function (global, factory) {
8
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
9
+ typeof define === 'function' && define.amd ? define(factory) :
10
+ global.moment = factory()
11
+ }(this, function () { 'use strict';
12
+
13
+ var hookCallback;
14
+
15
+ function utils_hooks__hooks () {
16
+ return hookCallback.apply(null, arguments);
17
+ }
18
+
19
+ // This is done to register the method called with moment()
20
+ // without creating circular dependencies.
21
+ function setHookCallback (callback) {
22
+ hookCallback = callback;
23
+ }
24
+
25
+ function isArray(input) {
26
+ return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
27
+ }
28
+
29
+ function isDate(input) {
30
+ return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
31
+ }
32
+
33
+ function map(arr, fn) {
34
+ var res = [], i;
35
+ for (i = 0; i < arr.length; ++i) {
36
+ res.push(fn(arr[i], i));
37
+ }
38
+ return res;
39
+ }
40
+
41
+ function hasOwnProp(a, b) {
42
+ return Object.prototype.hasOwnProperty.call(a, b);
43
+ }
44
+
45
+ function extend(a, b) {
46
+ for (var i in b) {
47
+ if (hasOwnProp(b, i)) {
48
+ a[i] = b[i];
49
+ }
50
+ }
51
+
52
+ if (hasOwnProp(b, 'toString')) {
53
+ a.toString = b.toString;
54
+ }
55
+
56
+ if (hasOwnProp(b, 'valueOf')) {
57
+ a.valueOf = b.valueOf;
58
+ }
59
+
60
+ return a;
61
+ }
62
+
63
+ function create_utc__createUTC (input, format, locale, strict) {
64
+ return createLocalOrUTC(input, format, locale, strict, true).utc();
65
+ }
66
+
67
+ function defaultParsingFlags() {
68
+ // We need to deep clone this object.
69
+ return {
70
+ empty : false,
71
+ unusedTokens : [],
72
+ unusedInput : [],
73
+ overflow : -2,
74
+ charsLeftOver : 0,
75
+ nullInput : false,
76
+ invalidMonth : null,
77
+ invalidFormat : false,
78
+ userInvalidated : false,
79
+ iso : false,
80
+ parsedDateParts : [],
81
+ meridiem : null
82
+ };
83
+ }
84
+
85
+ function getParsingFlags(m) {
86
+ if (m._pf == null) {
87
+ m._pf = defaultParsingFlags();
88
+ }
89
+ return m._pf;
90
+ }
91
+
92
+ var some;
93
+ if (Array.prototype.some) {
94
+ some = Array.prototype.some;
95
+ } else {
96
+ some = function (fun) {
97
+ var t = Object(this);
98
+ var len = t.length >>> 0;
99
+
100
+ for (var i = 0; i < len; i++) {
101
+ if (i in t && fun.call(this, t[i], i, t)) {
102
+ return true;
103
+ }
104
+ }
105
+
106
+ return false;
107
+ };
108
+ }
109
+
110
+ function valid__isValid(m) {
111
+ if (m._isValid == null) {
112
+ var flags = getParsingFlags(m);
113
+ var parsedParts = some.call(flags.parsedDateParts, function (i) {
114
+ return i != null;
115
+ });
116
+ m._isValid = !isNaN(m._d.getTime()) &&
117
+ flags.overflow < 0 &&
118
+ !flags.empty &&
119
+ !flags.invalidMonth &&
120
+ !flags.invalidWeekday &&
121
+ !flags.nullInput &&
122
+ !flags.invalidFormat &&
123
+ !flags.userInvalidated &&
124
+ (!flags.meridiem || (flags.meridiem && parsedParts));
125
+
126
+ if (m._strict) {
127
+ m._isValid = m._isValid &&
128
+ flags.charsLeftOver === 0 &&
129
+ flags.unusedTokens.length === 0 &&
130
+ flags.bigHour === undefined;
131
+ }
132
+ }
133
+ return m._isValid;
134
+ }
135
+
136
+ function valid__createInvalid (flags) {
137
+ var m = create_utc__createUTC(NaN);
138
+ if (flags != null) {
139
+ extend(getParsingFlags(m), flags);
140
+ }
141
+ else {
142
+ getParsingFlags(m).userInvalidated = true;
143
+ }
144
+
145
+ return m;
146
+ }
147
+
148
+ function isUndefined(input) {
149
+ return input === void 0;
150
+ }
151
+
152
+ // Plugins that add properties should also add the key here (null value),
153
+ // so we can properly clone ourselves.
154
+ var momentProperties = utils_hooks__hooks.momentProperties = [];
155
+
156
+ function copyConfig(to, from) {
157
+ var i, prop, val;
158
+
159
+ if (!isUndefined(from._isAMomentObject)) {
160
+ to._isAMomentObject = from._isAMomentObject;
161
+ }
162
+ if (!isUndefined(from._i)) {
163
+ to._i = from._i;
164
+ }
165
+ if (!isUndefined(from._f)) {
166
+ to._f = from._f;
167
+ }
168
+ if (!isUndefined(from._l)) {
169
+ to._l = from._l;
170
+ }
171
+ if (!isUndefined(from._strict)) {
172
+ to._strict = from._strict;
173
+ }
174
+ if (!isUndefined(from._tzm)) {
175
+ to._tzm = from._tzm;
176
+ }
177
+ if (!isUndefined(from._isUTC)) {
178
+ to._isUTC = from._isUTC;
179
+ }
180
+ if (!isUndefined(from._offset)) {
181
+ to._offset = from._offset;
182
+ }
183
+ if (!isUndefined(from._pf)) {
184
+ to._pf = getParsingFlags(from);
185
+ }
186
+ if (!isUndefined(from._locale)) {
187
+ to._locale = from._locale;
188
+ }
189
+
190
+ if (momentProperties.length > 0) {
191
+ for (i in momentProperties) {
192
+ prop = momentProperties[i];
193
+ val = from[prop];
194
+ if (!isUndefined(val)) {
195
+ to[prop] = val;
196
+ }
197
+ }
198
+ }
199
+
200
+ return to;
201
+ }
202
+
203
+ var updateInProgress = false;
204
+
205
+ // Moment prototype object
206
+ function Moment(config) {
207
+ copyConfig(this, config);
208
+ this._d = new Date(config._d != null ? config._d.getTime() : NaN);
209
+ // Prevent infinite loop in case updateOffset creates new moment
210
+ // objects.
211
+ if (updateInProgress === false) {
212
+ updateInProgress = true;
213
+ utils_hooks__hooks.updateOffset(this);
214
+ updateInProgress = false;
215
+ }
216
+ }
217
+
218
+ function isMoment (obj) {
219
+ return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
220
+ }
221
+
222
+ function absFloor (number) {
223
+ if (number < 0) {
224
+ return Math.ceil(number);
225
+ } else {
226
+ return Math.floor(number);
227
+ }
228
+ }
229
+
230
+ function toInt(argumentForCoercion) {
231
+ var coercedNumber = +argumentForCoercion,
232
+ value = 0;
233
+
234
+ if (coercedNumber !== 0 && isFinite(coercedNumber)) {
235
+ value = absFloor(coercedNumber);
236
+ }
237
+
238
+ return value;
239
+ }
240
+
241
+ // compare two arrays, return the number of differences
242
+ function compareArrays(array1, array2, dontConvert) {
243
+ var len = Math.min(array1.length, array2.length),
244
+ lengthDiff = Math.abs(array1.length - array2.length),
245
+ diffs = 0,
246
+ i;
247
+ for (i = 0; i < len; i++) {
248
+ if ((dontConvert && array1[i] !== array2[i]) ||
249
+ (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
250
+ diffs++;
251
+ }
252
+ }
253
+ return diffs + lengthDiff;
254
+ }
255
+
256
+ function warn(msg) {
257
+ if (utils_hooks__hooks.suppressDeprecationWarnings === false &&
258
+ (typeof console !== 'undefined') && console.warn) {
259
+ console.warn('Deprecation warning: ' + msg);
260
+ }
261
+ }
262
+
263
+ function deprecate(msg, fn) {
264
+ var firstTime = true;
265
+
266
+ return extend(function () {
267
+ if (utils_hooks__hooks.deprecationHandler != null) {
268
+ utils_hooks__hooks.deprecationHandler(null, msg);
269
+ }
270
+ if (firstTime) {
271
+ warn(msg + '\nArguments: ' + Array.prototype.slice.call(arguments).join(', ') + '\n' + (new Error()).stack);
272
+ firstTime = false;
273
+ }
274
+ return fn.apply(this, arguments);
275
+ }, fn);
276
+ }
277
+
278
+ var deprecations = {};
279
+
280
+ function deprecateSimple(name, msg) {
281
+ if (utils_hooks__hooks.deprecationHandler != null) {
282
+ utils_hooks__hooks.deprecationHandler(name, msg);
283
+ }
284
+ if (!deprecations[name]) {
285
+ warn(msg);
286
+ deprecations[name] = true;
287
+ }
288
+ }
289
+
290
+ utils_hooks__hooks.suppressDeprecationWarnings = false;
291
+ utils_hooks__hooks.deprecationHandler = null;
292
+
293
+ function isFunction(input) {
294
+ return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
295
+ }
296
+
297
+ function isObject(input) {
298
+ return Object.prototype.toString.call(input) === '[object Object]';
299
+ }
300
+
301
+ function locale_set__set (config) {
302
+ var prop, i;
303
+ for (i in config) {
304
+ prop = config[i];
305
+ if (isFunction(prop)) {
306
+ this[i] = prop;
307
+ } else {
308
+ this['_' + i] = prop;
309
+ }
310
+ }
311
+ this._config = config;
312
+ // Lenient ordinal parsing accepts just a number in addition to
313
+ // number + (possibly) stuff coming from _ordinalParseLenient.
314
+ this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source);
315
+ }
316
+
317
+ function mergeConfigs(parentConfig, childConfig) {
318
+ var res = extend({}, parentConfig), prop;
319
+ for (prop in childConfig) {
320
+ if (hasOwnProp(childConfig, prop)) {
321
+ if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
322
+ res[prop] = {};
323
+ extend(res[prop], parentConfig[prop]);
324
+ extend(res[prop], childConfig[prop]);
325
+ } else if (childConfig[prop] != null) {
326
+ res[prop] = childConfig[prop];
327
+ } else {
328
+ delete res[prop];
329
+ }
330
+ }
331
+ }
332
+ return res;
333
+ }
334
+
335
+ function Locale(config) {
336
+ if (config != null) {
337
+ this.set(config);
338
+ }
339
+ }
340
+
341
+ var keys;
342
+
343
+ if (Object.keys) {
344
+ keys = Object.keys;
345
+ } else {
346
+ keys = function (obj) {
347
+ var i, res = [];
348
+ for (i in obj) {
349
+ if (hasOwnProp(obj, i)) {
350
+ res.push(i);
351
+ }
352
+ }
353
+ return res;
354
+ };
355
+ }
356
+
357
+ // internal storage for locale config files
358
+ var locales = {};
359
+ var globalLocale;
360
+
361
+ function normalizeLocale(key) {
362
+ return key ? key.toLowerCase().replace('_', '-') : key;
363
+ }
364
+
365
+ // pick the locale from the array
366
+ // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
367
+ // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
368
+ function chooseLocale(names) {
369
+ var i = 0, j, next, locale, split;
370
+
371
+ while (i < names.length) {
372
+ split = normalizeLocale(names[i]).split('-');
373
+ j = split.length;
374
+ next = normalizeLocale(names[i + 1]);
375
+ next = next ? next.split('-') : null;
376
+ while (j > 0) {
377
+ locale = loadLocale(split.slice(0, j).join('-'));
378
+ if (locale) {
379
+ return locale;
380
+ }
381
+ if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
382
+ //the next array item is better than a shallower substring of this one
383
+ break;
384
+ }
385
+ j--;
386
+ }
387
+ i++;
388
+ }
389
+ return null;
390
+ }
391
+
392
+ function loadLocale(name) {
393
+ var oldLocale = null;
394
+ // TODO: Find a better way to register and load all the locales in Node
395
+ if (!locales[name] && (typeof module !== 'undefined') &&
396
+ module && module.exports) {
397
+ try {
398
+ oldLocale = globalLocale._abbr;
399
+ require('./locale/' + name);
400
+ // because defineLocale currently also sets the global locale, we
401
+ // want to undo that for lazy loaded locales
402
+ locale_locales__getSetGlobalLocale(oldLocale);
403
+ } catch (e) { }
404
+ }
405
+ return locales[name];
406
+ }
407
+
408
+ // This function will load locale and then set the global locale. If
409
+ // no arguments are passed in, it will simply return the current global
410
+ // locale key.
411
+ function locale_locales__getSetGlobalLocale (key, values) {
412
+ var data;
413
+ if (key) {
414
+ if (isUndefined(values)) {
415
+ data = locale_locales__getLocale(key);
416
+ }
417
+ else {
418
+ data = defineLocale(key, values);
419
+ }
420
+
421
+ if (data) {
422
+ // moment.duration._locale = moment._locale = data;
423
+ globalLocale = data;
424
+ }
425
+ }
426
+
427
+ return globalLocale._abbr;
428
+ }
429
+
430
+ function defineLocale (name, config) {
431
+ if (config !== null) {
432
+ config.abbr = name;
433
+ if (locales[name] != null) {
434
+ deprecateSimple('defineLocaleOverride',
435
+ 'use moment.updateLocale(localeName, config) to change ' +
436
+ 'an existing locale. moment.defineLocale(localeName, ' +
437
+ 'config) should only be used for creating a new locale');
438
+ config = mergeConfigs(locales[name]._config, config);
439
+ } else if (config.parentLocale != null) {
440
+ if (locales[config.parentLocale] != null) {
441
+ config = mergeConfigs(locales[config.parentLocale]._config, config);
442
+ } else {
443
+ // treat as if there is no base config
444
+ deprecateSimple('parentLocaleUndefined',
445
+ 'specified parentLocale is not defined yet');
446
+ }
447
+ }
448
+ locales[name] = new Locale(config);
449
+
450
+ // backwards compat for now: also set the locale
451
+ locale_locales__getSetGlobalLocale(name);
452
+
453
+ return locales[name];
454
+ } else {
455
+ // useful for testing
456
+ delete locales[name];
457
+ return null;
458
+ }
459
+ }
460
+
461
+ function updateLocale(name, config) {
462
+ if (config != null) {
463
+ var locale;
464
+ if (locales[name] != null) {
465
+ config = mergeConfigs(locales[name]._config, config);
466
+ }
467
+ locale = new Locale(config);
468
+ locale.parentLocale = locales[name];
469
+ locales[name] = locale;
470
+
471
+ // backwards compat for now: also set the locale
472
+ locale_locales__getSetGlobalLocale(name);
473
+ } else {
474
+ // pass null for config to unupdate, useful for tests
475
+ if (locales[name] != null) {
476
+ if (locales[name].parentLocale != null) {
477
+ locales[name] = locales[name].parentLocale;
478
+ } else if (locales[name] != null) {
479
+ delete locales[name];
480
+ }
481
+ }
482
+ }
483
+ return locales[name];
484
+ }
485
+
486
+ // returns locale data
487
+ function locale_locales__getLocale (key) {
488
+ var locale;
489
+
490
+ if (key && key._locale && key._locale._abbr) {
491
+ key = key._locale._abbr;
492
+ }
493
+
494
+ if (!key) {
495
+ return globalLocale;
496
+ }
497
+
498
+ if (!isArray(key)) {
499
+ //short-circuit everything else
500
+ locale = loadLocale(key);
501
+ if (locale) {
502
+ return locale;
503
+ }
504
+ key = [key];
505
+ }
506
+
507
+ return chooseLocale(key);
508
+ }
509
+
510
+ function locale_locales__listLocales() {
511
+ return keys(locales);
512
+ }
513
+
514
+ var aliases = {};
515
+
516
+ function addUnitAlias (unit, shorthand) {
517
+ var lowerCase = unit.toLowerCase();
518
+ aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
519
+ }
520
+
521
+ function normalizeUnits(units) {
522
+ return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
523
+ }
524
+
525
+ function normalizeObjectUnits(inputObject) {
526
+ var normalizedInput = {},
527
+ normalizedProp,
528
+ prop;
529
+
530
+ for (prop in inputObject) {
531
+ if (hasOwnProp(inputObject, prop)) {
532
+ normalizedProp = normalizeUnits(prop);
533
+ if (normalizedProp) {
534
+ normalizedInput[normalizedProp] = inputObject[prop];
535
+ }
536
+ }
537
+ }
538
+
539
+ return normalizedInput;
540
+ }
541
+
542
+ function makeGetSet (unit, keepTime) {
543
+ return function (value) {
544
+ if (value != null) {
545
+ get_set__set(this, unit, value);
546
+ utils_hooks__hooks.updateOffset(this, keepTime);
547
+ return this;
548
+ } else {
549
+ return get_set__get(this, unit);
550
+ }
551
+ };
552
+ }
553
+
554
+ function get_set__get (mom, unit) {
555
+ return mom.isValid() ?
556
+ mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
557
+ }
558
+
559
+ function get_set__set (mom, unit, value) {
560
+ if (mom.isValid()) {
561
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
562
+ }
563
+ }
564
+
565
+ // MOMENTS
566
+
567
+ function getSet (units, value) {
568
+ var unit;
569
+ if (typeof units === 'object') {
570
+ for (unit in units) {
571
+ this.set(unit, units[unit]);
572
+ }
573
+ } else {
574
+ units = normalizeUnits(units);
575
+ if (isFunction(this[units])) {
576
+ return this[units](value);
577
+ }
578
+ }
579
+ return this;
580
+ }
581
+
582
+ function zeroFill(number, targetLength, forceSign) {
583
+ var absNumber = '' + Math.abs(number),
584
+ zerosToFill = targetLength - absNumber.length,
585
+ sign = number >= 0;
586
+ return (sign ? (forceSign ? '+' : '') : '-') +
587
+ Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
588
+ }
589
+
590
+ var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
591
+
592
+ var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
593
+
594
+ var formatFunctions = {};
595
+
596
+ var formatTokenFunctions = {};
597
+
598
+ // token: 'M'
599
+ // padded: ['MM', 2]
600
+ // ordinal: 'Mo'
601
+ // callback: function () { this.month() + 1 }
602
+ function addFormatToken (token, padded, ordinal, callback) {
603
+ var func = callback;
604
+ if (typeof callback === 'string') {
605
+ func = function () {
606
+ return this[callback]();
607
+ };
608
+ }
609
+ if (token) {
610
+ formatTokenFunctions[token] = func;
611
+ }
612
+ if (padded) {
613
+ formatTokenFunctions[padded[0]] = function () {
614
+ return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
615
+ };
616
+ }
617
+ if (ordinal) {
618
+ formatTokenFunctions[ordinal] = function () {
619
+ return this.localeData().ordinal(func.apply(this, arguments), token);
620
+ };
621
+ }
622
+ }
623
+
624
+ function removeFormattingTokens(input) {
625
+ if (input.match(/\[[\s\S]/)) {
626
+ return input.replace(/^\[|\]$/g, '');
627
+ }
628
+ return input.replace(/\\/g, '');
629
+ }
630
+
631
+ function makeFormatFunction(format) {
632
+ var array = format.match(formattingTokens), i, length;
633
+
634
+ for (i = 0, length = array.length; i < length; i++) {
635
+ if (formatTokenFunctions[array[i]]) {
636
+ array[i] = formatTokenFunctions[array[i]];
637
+ } else {
638
+ array[i] = removeFormattingTokens(array[i]);
639
+ }
640
+ }
641
+
642
+ return function (mom) {
643
+ var output = '', i;
644
+ for (i = 0; i < length; i++) {
645
+ output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
646
+ }
647
+ return output;
648
+ };
649
+ }
650
+
651
+ // format date using native date object
652
+ function formatMoment(m, format) {
653
+ if (!m.isValid()) {
654
+ return m.localeData().invalidDate();
655
+ }
656
+
657
+ format = expandFormat(format, m.localeData());
658
+ formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
659
+
660
+ return formatFunctions[format](m);
661
+ }
662
+
663
+ function expandFormat(format, locale) {
664
+ var i = 5;
665
+
666
+ function replaceLongDateFormatTokens(input) {
667
+ return locale.longDateFormat(input) || input;
668
+ }
669
+
670
+ localFormattingTokens.lastIndex = 0;
671
+ while (i >= 0 && localFormattingTokens.test(format)) {
672
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
673
+ localFormattingTokens.lastIndex = 0;
674
+ i -= 1;
675
+ }
676
+
677
+ return format;
678
+ }
679
+
680
+ var match1 = /\d/; // 0 - 9
681
+ var match2 = /\d\d/; // 00 - 99
682
+ var match3 = /\d{3}/; // 000 - 999
683
+ var match4 = /\d{4}/; // 0000 - 9999
684
+ var match6 = /[+-]?\d{6}/; // -999999 - 999999
685
+ var match1to2 = /\d\d?/; // 0 - 99
686
+ var match3to4 = /\d\d\d\d?/; // 999 - 9999
687
+ var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
688
+ var match1to3 = /\d{1,3}/; // 0 - 999
689
+ var match1to4 = /\d{1,4}/; // 0 - 9999
690
+ var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
691
+
692
+ var matchUnsigned = /\d+/; // 0 - inf
693
+ var matchSigned = /[+-]?\d+/; // -inf - inf
694
+
695
+ var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
696
+ var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
697
+
698
+ var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
699
+
700
+ // any word (or two) characters or numbers including two/three word month in arabic.
701
+ // includes scottish gaelic two word and hyphenated months
702
+ var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
703
+
704
+
705
+ var regexes = {};
706
+
707
+ function addRegexToken (token, regex, strictRegex) {
708
+ regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
709
+ return (isStrict && strictRegex) ? strictRegex : regex;
710
+ };
711
+ }
712
+
713
+ function getParseRegexForToken (token, config) {
714
+ if (!hasOwnProp(regexes, token)) {
715
+ return new RegExp(unescapeFormat(token));
716
+ }
717
+
718
+ return regexes[token](config._strict, config._locale);
719
+ }
720
+
721
+ // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
722
+ function unescapeFormat(s) {
723
+ return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
724
+ return p1 || p2 || p3 || p4;
725
+ }));
726
+ }
727
+
728
+ function regexEscape(s) {
729
+ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
730
+ }
731
+
732
+ var tokens = {};
733
+
734
+ function addParseToken (token, callback) {
735
+ var i, func = callback;
736
+ if (typeof token === 'string') {
737
+ token = [token];
738
+ }
739
+ if (typeof callback === 'number') {
740
+ func = function (input, array) {
741
+ array[callback] = toInt(input);
742
+ };
743
+ }
744
+ for (i = 0; i < token.length; i++) {
745
+ tokens[token[i]] = func;
746
+ }
747
+ }
748
+
749
+ function addWeekParseToken (token, callback) {
750
+ addParseToken(token, function (input, array, config, token) {
751
+ config._w = config._w || {};
752
+ callback(input, config._w, config, token);
753
+ });
754
+ }
755
+
756
+ function addTimeToArrayFromToken(token, input, config) {
757
+ if (input != null && hasOwnProp(tokens, token)) {
758
+ tokens[token](input, config._a, config, token);
759
+ }
760
+ }
761
+
762
+ var YEAR = 0;
763
+ var MONTH = 1;
764
+ var DATE = 2;
765
+ var HOUR = 3;
766
+ var MINUTE = 4;
767
+ var SECOND = 5;
768
+ var MILLISECOND = 6;
769
+ var WEEK = 7;
770
+ var WEEKDAY = 8;
771
+
772
+ var indexOf;
773
+
774
+ if (Array.prototype.indexOf) {
775
+ indexOf = Array.prototype.indexOf;
776
+ } else {
777
+ indexOf = function (o) {
778
+ // I know
779
+ var i;
780
+ for (i = 0; i < this.length; ++i) {
781
+ if (this[i] === o) {
782
+ return i;
783
+ }
784
+ }
785
+ return -1;
786
+ };
787
+ }
788
+
789
+ function daysInMonth(year, month) {
790
+ return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
791
+ }
792
+
793
+ // FORMATTING
794
+
795
+ addFormatToken('M', ['MM', 2], 'Mo', function () {
796
+ return this.month() + 1;
797
+ });
798
+
799
+ addFormatToken('MMM', 0, 0, function (format) {
800
+ return this.localeData().monthsShort(this, format);
801
+ });
802
+
803
+ addFormatToken('MMMM', 0, 0, function (format) {
804
+ return this.localeData().months(this, format);
805
+ });
806
+
807
+ // ALIASES
808
+
809
+ addUnitAlias('month', 'M');
810
+
811
+ // PARSING
812
+
813
+ addRegexToken('M', match1to2);
814
+ addRegexToken('MM', match1to2, match2);
815
+ addRegexToken('MMM', function (isStrict, locale) {
816
+ return locale.monthsShortRegex(isStrict);
817
+ });
818
+ addRegexToken('MMMM', function (isStrict, locale) {
819
+ return locale.monthsRegex(isStrict);
820
+ });
821
+
822
+ addParseToken(['M', 'MM'], function (input, array) {
823
+ array[MONTH] = toInt(input) - 1;
824
+ });
825
+
826
+ addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
827
+ var month = config._locale.monthsParse(input, token, config._strict);
828
+ // if we didn't find a month name, mark the date as invalid.
829
+ if (month != null) {
830
+ array[MONTH] = month;
831
+ } else {
832
+ getParsingFlags(config).invalidMonth = input;
833
+ }
834
+ });
835
+
836
+ // LOCALES
837
+
838
+ var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/;
839
+ var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
840
+ function localeMonths (m, format) {
841
+ return isArray(this._months) ? this._months[m.month()] :
842
+ this._months[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
843
+ }
844
+
845
+ var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
846
+ function localeMonthsShort (m, format) {
847
+ return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
848
+ this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
849
+ }
850
+
851
+ function units_month__handleStrictParse(monthName, format, strict) {
852
+ var i, ii, mom, llc = monthName.toLocaleLowerCase();
853
+ if (!this._monthsParse) {
854
+ // this is not used
855
+ this._monthsParse = [];
856
+ this._longMonthsParse = [];
857
+ this._shortMonthsParse = [];
858
+ for (i = 0; i < 12; ++i) {
859
+ mom = create_utc__createUTC([2000, i]);
860
+ this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
861
+ this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
862
+ }
863
+ }
864
+
865
+ if (strict) {
866
+ if (format === 'MMM') {
867
+ ii = indexOf.call(this._shortMonthsParse, llc);
868
+ return ii !== -1 ? ii : null;
869
+ } else {
870
+ ii = indexOf.call(this._longMonthsParse, llc);
871
+ return ii !== -1 ? ii : null;
872
+ }
873
+ } else {
874
+ if (format === 'MMM') {
875
+ ii = indexOf.call(this._shortMonthsParse, llc);
876
+ if (ii !== -1) {
877
+ return ii;
878
+ }
879
+ ii = indexOf.call(this._longMonthsParse, llc);
880
+ return ii !== -1 ? ii : null;
881
+ } else {
882
+ ii = indexOf.call(this._longMonthsParse, llc);
883
+ if (ii !== -1) {
884
+ return ii;
885
+ }
886
+ ii = indexOf.call(this._shortMonthsParse, llc);
887
+ return ii !== -1 ? ii : null;
888
+ }
889
+ }
890
+ }
891
+
892
+ function localeMonthsParse (monthName, format, strict) {
893
+ var i, mom, regex;
894
+
895
+ if (this._monthsParseExact) {
896
+ return units_month__handleStrictParse.call(this, monthName, format, strict);
897
+ }
898
+
899
+ if (!this._monthsParse) {
900
+ this._monthsParse = [];
901
+ this._longMonthsParse = [];
902
+ this._shortMonthsParse = [];
903
+ }
904
+
905
+ // TODO: add sorting
906
+ // Sorting makes sure if one month (or abbr) is a prefix of another
907
+ // see sorting in computeMonthsParse
908
+ for (i = 0; i < 12; i++) {
909
+ // make the regex if we don't have it already
910
+ mom = create_utc__createUTC([2000, i]);
911
+ if (strict && !this._longMonthsParse[i]) {
912
+ this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
913
+ this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
914
+ }
915
+ if (!strict && !this._monthsParse[i]) {
916
+ regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
917
+ this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
918
+ }
919
+ // test the regex
920
+ if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
921
+ return i;
922
+ } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
923
+ return i;
924
+ } else if (!strict && this._monthsParse[i].test(monthName)) {
925
+ return i;
926
+ }
927
+ }
928
+ }
929
+
930
+ // MOMENTS
931
+
932
+ function setMonth (mom, value) {
933
+ var dayOfMonth;
934
+
935
+ if (!mom.isValid()) {
936
+ // No op
937
+ return mom;
938
+ }
939
+
940
+ if (typeof value === 'string') {
941
+ if (/^\d+$/.test(value)) {
942
+ value = toInt(value);
943
+ } else {
944
+ value = mom.localeData().monthsParse(value);
945
+ // TODO: Another silent failure?
946
+ if (typeof value !== 'number') {
947
+ return mom;
948
+ }
949
+ }
950
+ }
951
+
952
+ dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
953
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
954
+ return mom;
955
+ }
956
+
957
+ function getSetMonth (value) {
958
+ if (value != null) {
959
+ setMonth(this, value);
960
+ utils_hooks__hooks.updateOffset(this, true);
961
+ return this;
962
+ } else {
963
+ return get_set__get(this, 'Month');
964
+ }
965
+ }
966
+
967
+ function getDaysInMonth () {
968
+ return daysInMonth(this.year(), this.month());
969
+ }
970
+
971
+ var defaultMonthsShortRegex = matchWord;
972
+ function monthsShortRegex (isStrict) {
973
+ if (this._monthsParseExact) {
974
+ if (!hasOwnProp(this, '_monthsRegex')) {
975
+ computeMonthsParse.call(this);
976
+ }
977
+ if (isStrict) {
978
+ return this._monthsShortStrictRegex;
979
+ } else {
980
+ return this._monthsShortRegex;
981
+ }
982
+ } else {
983
+ return this._monthsShortStrictRegex && isStrict ?
984
+ this._monthsShortStrictRegex : this._monthsShortRegex;
985
+ }
986
+ }
987
+
988
+ var defaultMonthsRegex = matchWord;
989
+ function monthsRegex (isStrict) {
990
+ if (this._monthsParseExact) {
991
+ if (!hasOwnProp(this, '_monthsRegex')) {
992
+ computeMonthsParse.call(this);
993
+ }
994
+ if (isStrict) {
995
+ return this._monthsStrictRegex;
996
+ } else {
997
+ return this._monthsRegex;
998
+ }
999
+ } else {
1000
+ return this._monthsStrictRegex && isStrict ?
1001
+ this._monthsStrictRegex : this._monthsRegex;
1002
+ }
1003
+ }
1004
+
1005
+ function computeMonthsParse () {
1006
+ function cmpLenRev(a, b) {
1007
+ return b.length - a.length;
1008
+ }
1009
+
1010
+ var shortPieces = [], longPieces = [], mixedPieces = [],
1011
+ i, mom;
1012
+ for (i = 0; i < 12; i++) {
1013
+ // make the regex if we don't have it already
1014
+ mom = create_utc__createUTC([2000, i]);
1015
+ shortPieces.push(this.monthsShort(mom, ''));
1016
+ longPieces.push(this.months(mom, ''));
1017
+ mixedPieces.push(this.months(mom, ''));
1018
+ mixedPieces.push(this.monthsShort(mom, ''));
1019
+ }
1020
+ // Sorting makes sure if one month (or abbr) is a prefix of another it
1021
+ // will match the longer piece.
1022
+ shortPieces.sort(cmpLenRev);
1023
+ longPieces.sort(cmpLenRev);
1024
+ mixedPieces.sort(cmpLenRev);
1025
+ for (i = 0; i < 12; i++) {
1026
+ shortPieces[i] = regexEscape(shortPieces[i]);
1027
+ longPieces[i] = regexEscape(longPieces[i]);
1028
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
1029
+ }
1030
+
1031
+ this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
1032
+ this._monthsShortRegex = this._monthsRegex;
1033
+ this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
1034
+ this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
1035
+ }
1036
+
1037
+ function checkOverflow (m) {
1038
+ var overflow;
1039
+ var a = m._a;
1040
+
1041
+ if (a && getParsingFlags(m).overflow === -2) {
1042
+ overflow =
1043
+ a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
1044
+ a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
1045
+ a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
1046
+ a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
1047
+ a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
1048
+ a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
1049
+ -1;
1050
+
1051
+ if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
1052
+ overflow = DATE;
1053
+ }
1054
+ if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
1055
+ overflow = WEEK;
1056
+ }
1057
+ if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
1058
+ overflow = WEEKDAY;
1059
+ }
1060
+
1061
+ getParsingFlags(m).overflow = overflow;
1062
+ }
1063
+
1064
+ return m;
1065
+ }
1066
+
1067
+ // iso 8601 regex
1068
+ // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
1069
+ var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
1070
+ var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
1071
+
1072
+ var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
1073
+
1074
+ var isoDates = [
1075
+ ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
1076
+ ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
1077
+ ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
1078
+ ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
1079
+ ['YYYY-DDD', /\d{4}-\d{3}/],
1080
+ ['YYYY-MM', /\d{4}-\d\d/, false],
1081
+ ['YYYYYYMMDD', /[+-]\d{10}/],
1082
+ ['YYYYMMDD', /\d{8}/],
1083
+ // YYYYMM is NOT allowed by the standard
1084
+ ['GGGG[W]WWE', /\d{4}W\d{3}/],
1085
+ ['GGGG[W]WW', /\d{4}W\d{2}/, false],
1086
+ ['YYYYDDD', /\d{7}/]
1087
+ ];
1088
+
1089
+ // iso time formats and regexes
1090
+ var isoTimes = [
1091
+ ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
1092
+ ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
1093
+ ['HH:mm:ss', /\d\d:\d\d:\d\d/],
1094
+ ['HH:mm', /\d\d:\d\d/],
1095
+ ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
1096
+ ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
1097
+ ['HHmmss', /\d\d\d\d\d\d/],
1098
+ ['HHmm', /\d\d\d\d/],
1099
+ ['HH', /\d\d/]
1100
+ ];
1101
+
1102
+ var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
1103
+
1104
+ // date from iso format
1105
+ function configFromISO(config) {
1106
+ var i, l,
1107
+ string = config._i,
1108
+ match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
1109
+ allowTime, dateFormat, timeFormat, tzFormat;
1110
+
1111
+ if (match) {
1112
+ getParsingFlags(config).iso = true;
1113
+
1114
+ for (i = 0, l = isoDates.length; i < l; i++) {
1115
+ if (isoDates[i][1].exec(match[1])) {
1116
+ dateFormat = isoDates[i][0];
1117
+ allowTime = isoDates[i][2] !== false;
1118
+ break;
1119
+ }
1120
+ }
1121
+ if (dateFormat == null) {
1122
+ config._isValid = false;
1123
+ return;
1124
+ }
1125
+ if (match[3]) {
1126
+ for (i = 0, l = isoTimes.length; i < l; i++) {
1127
+ if (isoTimes[i][1].exec(match[3])) {
1128
+ // match[2] should be 'T' or space
1129
+ timeFormat = (match[2] || ' ') + isoTimes[i][0];
1130
+ break;
1131
+ }
1132
+ }
1133
+ if (timeFormat == null) {
1134
+ config._isValid = false;
1135
+ return;
1136
+ }
1137
+ }
1138
+ if (!allowTime && timeFormat != null) {
1139
+ config._isValid = false;
1140
+ return;
1141
+ }
1142
+ if (match[4]) {
1143
+ if (tzRegex.exec(match[4])) {
1144
+ tzFormat = 'Z';
1145
+ } else {
1146
+ config._isValid = false;
1147
+ return;
1148
+ }
1149
+ }
1150
+ config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
1151
+ configFromStringAndFormat(config);
1152
+ } else {
1153
+ config._isValid = false;
1154
+ }
1155
+ }
1156
+
1157
+ // date from iso format or fallback
1158
+ function configFromString(config) {
1159
+ var matched = aspNetJsonRegex.exec(config._i);
1160
+
1161
+ if (matched !== null) {
1162
+ config._d = new Date(+matched[1]);
1163
+ return;
1164
+ }
1165
+
1166
+ configFromISO(config);
1167
+ if (config._isValid === false) {
1168
+ delete config._isValid;
1169
+ utils_hooks__hooks.createFromInputFallback(config);
1170
+ }
1171
+ }
1172
+
1173
+ utils_hooks__hooks.createFromInputFallback = deprecate(
1174
+ 'moment construction falls back to js Date. This is ' +
1175
+ 'discouraged and will be removed in upcoming major ' +
1176
+ 'release. Please refer to ' +
1177
+ 'https://github.com/moment/moment/issues/1407 for more info.',
1178
+ function (config) {
1179
+ config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
1180
+ }
1181
+ );
1182
+
1183
+ function createDate (y, m, d, h, M, s, ms) {
1184
+ //can't just apply() to create a date:
1185
+ //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
1186
+ var date = new Date(y, m, d, h, M, s, ms);
1187
+
1188
+ //the date constructor remaps years 0-99 to 1900-1999
1189
+ if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
1190
+ date.setFullYear(y);
1191
+ }
1192
+ return date;
1193
+ }
1194
+
1195
+ function createUTCDate (y) {
1196
+ var date = new Date(Date.UTC.apply(null, arguments));
1197
+
1198
+ //the Date.UTC function remaps years 0-99 to 1900-1999
1199
+ if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
1200
+ date.setUTCFullYear(y);
1201
+ }
1202
+ return date;
1203
+ }
1204
+
1205
+ // FORMATTING
1206
+
1207
+ addFormatToken('Y', 0, 0, function () {
1208
+ var y = this.year();
1209
+ return y <= 9999 ? '' + y : '+' + y;
1210
+ });
1211
+
1212
+ addFormatToken(0, ['YY', 2], 0, function () {
1213
+ return this.year() % 100;
1214
+ });
1215
+
1216
+ addFormatToken(0, ['YYYY', 4], 0, 'year');
1217
+ addFormatToken(0, ['YYYYY', 5], 0, 'year');
1218
+ addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
1219
+
1220
+ // ALIASES
1221
+
1222
+ addUnitAlias('year', 'y');
1223
+
1224
+ // PARSING
1225
+
1226
+ addRegexToken('Y', matchSigned);
1227
+ addRegexToken('YY', match1to2, match2);
1228
+ addRegexToken('YYYY', match1to4, match4);
1229
+ addRegexToken('YYYYY', match1to6, match6);
1230
+ addRegexToken('YYYYYY', match1to6, match6);
1231
+
1232
+ addParseToken(['YYYYY', 'YYYYYY'], YEAR);
1233
+ addParseToken('YYYY', function (input, array) {
1234
+ array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input);
1235
+ });
1236
+ addParseToken('YY', function (input, array) {
1237
+ array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);
1238
+ });
1239
+ addParseToken('Y', function (input, array) {
1240
+ array[YEAR] = parseInt(input, 10);
1241
+ });
1242
+
1243
+ // HELPERS
1244
+
1245
+ function daysInYear(year) {
1246
+ return isLeapYear(year) ? 366 : 365;
1247
+ }
1248
+
1249
+ function isLeapYear(year) {
1250
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
1251
+ }
1252
+
1253
+ // HOOKS
1254
+
1255
+ utils_hooks__hooks.parseTwoDigitYear = function (input) {
1256
+ return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
1257
+ };
1258
+
1259
+ // MOMENTS
1260
+
1261
+ var getSetYear = makeGetSet('FullYear', true);
1262
+
1263
+ function getIsLeapYear () {
1264
+ return isLeapYear(this.year());
1265
+ }
1266
+
1267
+ // start-of-first-week - start-of-year
1268
+ function firstWeekOffset(year, dow, doy) {
1269
+ var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
1270
+ fwd = 7 + dow - doy,
1271
+ // first-week day local weekday -- which local weekday is fwd
1272
+ fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
1273
+
1274
+ return -fwdlw + fwd - 1;
1275
+ }
1276
+
1277
+ //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
1278
+ function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
1279
+ var localWeekday = (7 + weekday - dow) % 7,
1280
+ weekOffset = firstWeekOffset(year, dow, doy),
1281
+ dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
1282
+ resYear, resDayOfYear;
1283
+
1284
+ if (dayOfYear <= 0) {
1285
+ resYear = year - 1;
1286
+ resDayOfYear = daysInYear(resYear) + dayOfYear;
1287
+ } else if (dayOfYear > daysInYear(year)) {
1288
+ resYear = year + 1;
1289
+ resDayOfYear = dayOfYear - daysInYear(year);
1290
+ } else {
1291
+ resYear = year;
1292
+ resDayOfYear = dayOfYear;
1293
+ }
1294
+
1295
+ return {
1296
+ year: resYear,
1297
+ dayOfYear: resDayOfYear
1298
+ };
1299
+ }
1300
+
1301
+ function weekOfYear(mom, dow, doy) {
1302
+ var weekOffset = firstWeekOffset(mom.year(), dow, doy),
1303
+ week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
1304
+ resWeek, resYear;
1305
+
1306
+ if (week < 1) {
1307
+ resYear = mom.year() - 1;
1308
+ resWeek = week + weeksInYear(resYear, dow, doy);
1309
+ } else if (week > weeksInYear(mom.year(), dow, doy)) {
1310
+ resWeek = week - weeksInYear(mom.year(), dow, doy);
1311
+ resYear = mom.year() + 1;
1312
+ } else {
1313
+ resYear = mom.year();
1314
+ resWeek = week;
1315
+ }
1316
+
1317
+ return {
1318
+ week: resWeek,
1319
+ year: resYear
1320
+ };
1321
+ }
1322
+
1323
+ function weeksInYear(year, dow, doy) {
1324
+ var weekOffset = firstWeekOffset(year, dow, doy),
1325
+ weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
1326
+ return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
1327
+ }
1328
+
1329
+ // Pick the first defined of two or three arguments.
1330
+ function defaults(a, b, c) {
1331
+ if (a != null) {
1332
+ return a;
1333
+ }
1334
+ if (b != null) {
1335
+ return b;
1336
+ }
1337
+ return c;
1338
+ }
1339
+
1340
+ function currentDateArray(config) {
1341
+ // hooks is actually the exported moment object
1342
+ var nowValue = new Date(utils_hooks__hooks.now());
1343
+ if (config._useUTC) {
1344
+ return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
1345
+ }
1346
+ return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
1347
+ }
1348
+
1349
+ // convert an array to a date.
1350
+ // the array should mirror the parameters below
1351
+ // note: all values past the year are optional and will default to the lowest possible value.
1352
+ // [year, month, day , hour, minute, second, millisecond]
1353
+ function configFromArray (config) {
1354
+ var i, date, input = [], currentDate, yearToUse;
1355
+
1356
+ if (config._d) {
1357
+ return;
1358
+ }
1359
+
1360
+ currentDate = currentDateArray(config);
1361
+
1362
+ //compute day of the year from weeks and weekdays
1363
+ if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
1364
+ dayOfYearFromWeekInfo(config);
1365
+ }
1366
+
1367
+ //if the day of the year is set, figure out what it is
1368
+ if (config._dayOfYear) {
1369
+ yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
1370
+
1371
+ if (config._dayOfYear > daysInYear(yearToUse)) {
1372
+ getParsingFlags(config)._overflowDayOfYear = true;
1373
+ }
1374
+
1375
+ date = createUTCDate(yearToUse, 0, config._dayOfYear);
1376
+ config._a[MONTH] = date.getUTCMonth();
1377
+ config._a[DATE] = date.getUTCDate();
1378
+ }
1379
+
1380
+ // Default to current date.
1381
+ // * if no year, month, day of month are given, default to today
1382
+ // * if day of month is given, default month and year
1383
+ // * if month is given, default only year
1384
+ // * if year is given, don't default anything
1385
+ for (i = 0; i < 3 && config._a[i] == null; ++i) {
1386
+ config._a[i] = input[i] = currentDate[i];
1387
+ }
1388
+
1389
+ // Zero out whatever was not defaulted, including time
1390
+ for (; i < 7; i++) {
1391
+ config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
1392
+ }
1393
+
1394
+ // Check for 24:00:00.000
1395
+ if (config._a[HOUR] === 24 &&
1396
+ config._a[MINUTE] === 0 &&
1397
+ config._a[SECOND] === 0 &&
1398
+ config._a[MILLISECOND] === 0) {
1399
+ config._nextDay = true;
1400
+ config._a[HOUR] = 0;
1401
+ }
1402
+
1403
+ config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
1404
+ // Apply timezone offset from input. The actual utcOffset can be changed
1405
+ // with parseZone.
1406
+ if (config._tzm != null) {
1407
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
1408
+ }
1409
+
1410
+ if (config._nextDay) {
1411
+ config._a[HOUR] = 24;
1412
+ }
1413
+ }
1414
+
1415
+ function dayOfYearFromWeekInfo(config) {
1416
+ var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
1417
+
1418
+ w = config._w;
1419
+ if (w.GG != null || w.W != null || w.E != null) {
1420
+ dow = 1;
1421
+ doy = 4;
1422
+
1423
+ // TODO: We need to take the current isoWeekYear, but that depends on
1424
+ // how we interpret now (local, utc, fixed offset). So create
1425
+ // a now version of current config (take local/utc/offset flags, and
1426
+ // create now).
1427
+ weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);
1428
+ week = defaults(w.W, 1);
1429
+ weekday = defaults(w.E, 1);
1430
+ if (weekday < 1 || weekday > 7) {
1431
+ weekdayOverflow = true;
1432
+ }
1433
+ } else {
1434
+ dow = config._locale._week.dow;
1435
+ doy = config._locale._week.doy;
1436
+
1437
+ weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);
1438
+ week = defaults(w.w, 1);
1439
+
1440
+ if (w.d != null) {
1441
+ // weekday -- low day numbers are considered next week
1442
+ weekday = w.d;
1443
+ if (weekday < 0 || weekday > 6) {
1444
+ weekdayOverflow = true;
1445
+ }
1446
+ } else if (w.e != null) {
1447
+ // local weekday -- counting starts from begining of week
1448
+ weekday = w.e + dow;
1449
+ if (w.e < 0 || w.e > 6) {
1450
+ weekdayOverflow = true;
1451
+ }
1452
+ } else {
1453
+ // default to begining of week
1454
+ weekday = dow;
1455
+ }
1456
+ }
1457
+ if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
1458
+ getParsingFlags(config)._overflowWeeks = true;
1459
+ } else if (weekdayOverflow != null) {
1460
+ getParsingFlags(config)._overflowWeekday = true;
1461
+ } else {
1462
+ temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
1463
+ config._a[YEAR] = temp.year;
1464
+ config._dayOfYear = temp.dayOfYear;
1465
+ }
1466
+ }
1467
+
1468
+ // constant that refers to the ISO standard
1469
+ utils_hooks__hooks.ISO_8601 = function () {};
1470
+
1471
+ // date from string and format string
1472
+ function configFromStringAndFormat(config) {
1473
+ // TODO: Move this to another part of the creation flow to prevent circular deps
1474
+ if (config._f === utils_hooks__hooks.ISO_8601) {
1475
+ configFromISO(config);
1476
+ return;
1477
+ }
1478
+
1479
+ config._a = [];
1480
+ getParsingFlags(config).empty = true;
1481
+
1482
+ // This array is used to make a Date, either with `new Date` or `Date.UTC`
1483
+ var string = '' + config._i,
1484
+ i, parsedInput, tokens, token, skipped,
1485
+ stringLength = string.length,
1486
+ totalParsedInputLength = 0;
1487
+
1488
+ tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
1489
+
1490
+ for (i = 0; i < tokens.length; i++) {
1491
+ token = tokens[i];
1492
+ parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
1493
+ // console.log('token', token, 'parsedInput', parsedInput,
1494
+ // 'regex', getParseRegexForToken(token, config));
1495
+ if (parsedInput) {
1496
+ skipped = string.substr(0, string.indexOf(parsedInput));
1497
+ if (skipped.length > 0) {
1498
+ getParsingFlags(config).unusedInput.push(skipped);
1499
+ }
1500
+ string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
1501
+ totalParsedInputLength += parsedInput.length;
1502
+ }
1503
+ // don't parse if it's not a known token
1504
+ if (formatTokenFunctions[token]) {
1505
+ if (parsedInput) {
1506
+ getParsingFlags(config).empty = false;
1507
+ }
1508
+ else {
1509
+ getParsingFlags(config).unusedTokens.push(token);
1510
+ }
1511
+ addTimeToArrayFromToken(token, parsedInput, config);
1512
+ }
1513
+ else if (config._strict && !parsedInput) {
1514
+ getParsingFlags(config).unusedTokens.push(token);
1515
+ }
1516
+ }
1517
+
1518
+ // add remaining unparsed input length to the string
1519
+ getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
1520
+ if (string.length > 0) {
1521
+ getParsingFlags(config).unusedInput.push(string);
1522
+ }
1523
+
1524
+ // clear _12h flag if hour is <= 12
1525
+ if (getParsingFlags(config).bigHour === true &&
1526
+ config._a[HOUR] <= 12 &&
1527
+ config._a[HOUR] > 0) {
1528
+ getParsingFlags(config).bigHour = undefined;
1529
+ }
1530
+
1531
+ getParsingFlags(config).parsedDateParts = config._a.slice(0);
1532
+ getParsingFlags(config).meridiem = config._meridiem;
1533
+ // handle meridiem
1534
+ config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
1535
+
1536
+ configFromArray(config);
1537
+ checkOverflow(config);
1538
+ }
1539
+
1540
+
1541
+ function meridiemFixWrap (locale, hour, meridiem) {
1542
+ var isPm;
1543
+
1544
+ if (meridiem == null) {
1545
+ // nothing to do
1546
+ return hour;
1547
+ }
1548
+ if (locale.meridiemHour != null) {
1549
+ return locale.meridiemHour(hour, meridiem);
1550
+ } else if (locale.isPM != null) {
1551
+ // Fallback
1552
+ isPm = locale.isPM(meridiem);
1553
+ if (isPm && hour < 12) {
1554
+ hour += 12;
1555
+ }
1556
+ if (!isPm && hour === 12) {
1557
+ hour = 0;
1558
+ }
1559
+ return hour;
1560
+ } else {
1561
+ // this is not supposed to happen
1562
+ return hour;
1563
+ }
1564
+ }
1565
+
1566
+ // date from string and array of format strings
1567
+ function configFromStringAndArray(config) {
1568
+ var tempConfig,
1569
+ bestMoment,
1570
+
1571
+ scoreToBeat,
1572
+ i,
1573
+ currentScore;
1574
+
1575
+ if (config._f.length === 0) {
1576
+ getParsingFlags(config).invalidFormat = true;
1577
+ config._d = new Date(NaN);
1578
+ return;
1579
+ }
1580
+
1581
+ for (i = 0; i < config._f.length; i++) {
1582
+ currentScore = 0;
1583
+ tempConfig = copyConfig({}, config);
1584
+ if (config._useUTC != null) {
1585
+ tempConfig._useUTC = config._useUTC;
1586
+ }
1587
+ tempConfig._f = config._f[i];
1588
+ configFromStringAndFormat(tempConfig);
1589
+
1590
+ if (!valid__isValid(tempConfig)) {
1591
+ continue;
1592
+ }
1593
+
1594
+ // if there is any input that was not parsed add a penalty for that format
1595
+ currentScore += getParsingFlags(tempConfig).charsLeftOver;
1596
+
1597
+ //or tokens
1598
+ currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
1599
+
1600
+ getParsingFlags(tempConfig).score = currentScore;
1601
+
1602
+ if (scoreToBeat == null || currentScore < scoreToBeat) {
1603
+ scoreToBeat = currentScore;
1604
+ bestMoment = tempConfig;
1605
+ }
1606
+ }
1607
+
1608
+ extend(config, bestMoment || tempConfig);
1609
+ }
1610
+
1611
+ function configFromObject(config) {
1612
+ if (config._d) {
1613
+ return;
1614
+ }
1615
+
1616
+ var i = normalizeObjectUnits(config._i);
1617
+ config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
1618
+ return obj && parseInt(obj, 10);
1619
+ });
1620
+
1621
+ configFromArray(config);
1622
+ }
1623
+
1624
+ function createFromConfig (config) {
1625
+ var res = new Moment(checkOverflow(prepareConfig(config)));
1626
+ if (res._nextDay) {
1627
+ // Adding is smart enough around DST
1628
+ res.add(1, 'd');
1629
+ res._nextDay = undefined;
1630
+ }
1631
+
1632
+ return res;
1633
+ }
1634
+
1635
+ function prepareConfig (config) {
1636
+ var input = config._i,
1637
+ format = config._f;
1638
+
1639
+ config._locale = config._locale || locale_locales__getLocale(config._l);
1640
+
1641
+ if (input === null || (format === undefined && input === '')) {
1642
+ return valid__createInvalid({nullInput: true});
1643
+ }
1644
+
1645
+ if (typeof input === 'string') {
1646
+ config._i = input = config._locale.preparse(input);
1647
+ }
1648
+
1649
+ if (isMoment(input)) {
1650
+ return new Moment(checkOverflow(input));
1651
+ } else if (isArray(format)) {
1652
+ configFromStringAndArray(config);
1653
+ } else if (format) {
1654
+ configFromStringAndFormat(config);
1655
+ } else if (isDate(input)) {
1656
+ config._d = input;
1657
+ } else {
1658
+ configFromInput(config);
1659
+ }
1660
+
1661
+ if (!valid__isValid(config)) {
1662
+ config._d = null;
1663
+ }
1664
+
1665
+ return config;
1666
+ }
1667
+
1668
+ function configFromInput(config) {
1669
+ var input = config._i;
1670
+ if (input === undefined) {
1671
+ config._d = new Date(utils_hooks__hooks.now());
1672
+ } else if (isDate(input)) {
1673
+ config._d = new Date(input.valueOf());
1674
+ } else if (typeof input === 'string') {
1675
+ configFromString(config);
1676
+ } else if (isArray(input)) {
1677
+ config._a = map(input.slice(0), function (obj) {
1678
+ return parseInt(obj, 10);
1679
+ });
1680
+ configFromArray(config);
1681
+ } else if (typeof(input) === 'object') {
1682
+ configFromObject(config);
1683
+ } else if (typeof(input) === 'number') {
1684
+ // from milliseconds
1685
+ config._d = new Date(input);
1686
+ } else {
1687
+ utils_hooks__hooks.createFromInputFallback(config);
1688
+ }
1689
+ }
1690
+
1691
+ function createLocalOrUTC (input, format, locale, strict, isUTC) {
1692
+ var c = {};
1693
+
1694
+ if (typeof(locale) === 'boolean') {
1695
+ strict = locale;
1696
+ locale = undefined;
1697
+ }
1698
+ // object construction must be done this way.
1699
+ // https://github.com/moment/moment/issues/1423
1700
+ c._isAMomentObject = true;
1701
+ c._useUTC = c._isUTC = isUTC;
1702
+ c._l = locale;
1703
+ c._i = input;
1704
+ c._f = format;
1705
+ c._strict = strict;
1706
+
1707
+ return createFromConfig(c);
1708
+ }
1709
+
1710
+ function local__createLocal (input, format, locale, strict) {
1711
+ return createLocalOrUTC(input, format, locale, strict, false);
1712
+ }
1713
+
1714
+ var prototypeMin = deprecate(
1715
+ 'moment().min is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548',
1716
+ function () {
1717
+ var other = local__createLocal.apply(null, arguments);
1718
+ if (this.isValid() && other.isValid()) {
1719
+ return other < this ? this : other;
1720
+ } else {
1721
+ return valid__createInvalid();
1722
+ }
1723
+ }
1724
+ );
1725
+
1726
+ var prototypeMax = deprecate(
1727
+ 'moment().max is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548',
1728
+ function () {
1729
+ var other = local__createLocal.apply(null, arguments);
1730
+ if (this.isValid() && other.isValid()) {
1731
+ return other > this ? this : other;
1732
+ } else {
1733
+ return valid__createInvalid();
1734
+ }
1735
+ }
1736
+ );
1737
+
1738
+ // Pick a moment m from moments so that m[fn](other) is true for all
1739
+ // other. This relies on the function fn to be transitive.
1740
+ //
1741
+ // moments should either be an array of moment objects or an array, whose
1742
+ // first element is an array of moment objects.
1743
+ function pickBy(fn, moments) {
1744
+ var res, i;
1745
+ if (moments.length === 1 && isArray(moments[0])) {
1746
+ moments = moments[0];
1747
+ }
1748
+ if (!moments.length) {
1749
+ return local__createLocal();
1750
+ }
1751
+ res = moments[0];
1752
+ for (i = 1; i < moments.length; ++i) {
1753
+ if (!moments[i].isValid() || moments[i][fn](res)) {
1754
+ res = moments[i];
1755
+ }
1756
+ }
1757
+ return res;
1758
+ }
1759
+
1760
+ // TODO: Use [].sort instead?
1761
+ function min () {
1762
+ var args = [].slice.call(arguments, 0);
1763
+
1764
+ return pickBy('isBefore', args);
1765
+ }
1766
+
1767
+ function max () {
1768
+ var args = [].slice.call(arguments, 0);
1769
+
1770
+ return pickBy('isAfter', args);
1771
+ }
1772
+
1773
+ var now = function () {
1774
+ return Date.now ? Date.now() : +(new Date());
1775
+ };
1776
+
1777
+ function Duration (duration) {
1778
+ var normalizedInput = normalizeObjectUnits(duration),
1779
+ years = normalizedInput.year || 0,
1780
+ quarters = normalizedInput.quarter || 0,
1781
+ months = normalizedInput.month || 0,
1782
+ weeks = normalizedInput.week || 0,
1783
+ days = normalizedInput.day || 0,
1784
+ hours = normalizedInput.hour || 0,
1785
+ minutes = normalizedInput.minute || 0,
1786
+ seconds = normalizedInput.second || 0,
1787
+ milliseconds = normalizedInput.millisecond || 0;
1788
+
1789
+ // representation for dateAddRemove
1790
+ this._milliseconds = +milliseconds +
1791
+ seconds * 1e3 + // 1000
1792
+ minutes * 6e4 + // 1000 * 60
1793
+ hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
1794
+ // Because of dateAddRemove treats 24 hours as different from a
1795
+ // day when working around DST, we need to store them separately
1796
+ this._days = +days +
1797
+ weeks * 7;
1798
+ // It is impossible translate months into days without knowing
1799
+ // which months you are are talking about, so we have to store
1800
+ // it separately.
1801
+ this._months = +months +
1802
+ quarters * 3 +
1803
+ years * 12;
1804
+
1805
+ this._data = {};
1806
+
1807
+ this._locale = locale_locales__getLocale();
1808
+
1809
+ this._bubble();
1810
+ }
1811
+
1812
+ function isDuration (obj) {
1813
+ return obj instanceof Duration;
1814
+ }
1815
+
1816
+ // FORMATTING
1817
+
1818
+ function offset (token, separator) {
1819
+ addFormatToken(token, 0, 0, function () {
1820
+ var offset = this.utcOffset();
1821
+ var sign = '+';
1822
+ if (offset < 0) {
1823
+ offset = -offset;
1824
+ sign = '-';
1825
+ }
1826
+ return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
1827
+ });
1828
+ }
1829
+
1830
+ offset('Z', ':');
1831
+ offset('ZZ', '');
1832
+
1833
+ // PARSING
1834
+
1835
+ addRegexToken('Z', matchShortOffset);
1836
+ addRegexToken('ZZ', matchShortOffset);
1837
+ addParseToken(['Z', 'ZZ'], function (input, array, config) {
1838
+ config._useUTC = true;
1839
+ config._tzm = offsetFromString(matchShortOffset, input);
1840
+ });
1841
+
1842
+ // HELPERS
1843
+
1844
+ // timezone chunker
1845
+ // '+10:00' > ['10', '00']
1846
+ // '-1530' > ['-15', '30']
1847
+ var chunkOffset = /([\+\-]|\d\d)/gi;
1848
+
1849
+ function offsetFromString(matcher, string) {
1850
+ var matches = ((string || '').match(matcher) || []);
1851
+ var chunk = matches[matches.length - 1] || [];
1852
+ var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
1853
+ var minutes = +(parts[1] * 60) + toInt(parts[2]);
1854
+
1855
+ return parts[0] === '+' ? minutes : -minutes;
1856
+ }
1857
+
1858
+ // Return a moment from input, that is local/utc/zone equivalent to model.
1859
+ function cloneWithOffset(input, model) {
1860
+ var res, diff;
1861
+ if (model._isUTC) {
1862
+ res = model.clone();
1863
+ diff = (isMoment(input) || isDate(input) ? input.valueOf() : local__createLocal(input).valueOf()) - res.valueOf();
1864
+ // Use low-level api, because this fn is low-level api.
1865
+ res._d.setTime(res._d.valueOf() + diff);
1866
+ utils_hooks__hooks.updateOffset(res, false);
1867
+ return res;
1868
+ } else {
1869
+ return local__createLocal(input).local();
1870
+ }
1871
+ }
1872
+
1873
+ function getDateOffset (m) {
1874
+ // On Firefox.24 Date#getTimezoneOffset returns a floating point.
1875
+ // https://github.com/moment/moment/pull/1871
1876
+ return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
1877
+ }
1878
+
1879
+ // HOOKS
1880
+
1881
+ // This function will be called whenever a moment is mutated.
1882
+ // It is intended to keep the offset in sync with the timezone.
1883
+ utils_hooks__hooks.updateOffset = function () {};
1884
+
1885
+ // MOMENTS
1886
+
1887
+ // keepLocalTime = true means only change the timezone, without
1888
+ // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
1889
+ // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
1890
+ // +0200, so we adjust the time as needed, to be valid.
1891
+ //
1892
+ // Keeping the time actually adds/subtracts (one hour)
1893
+ // from the actual represented time. That is why we call updateOffset
1894
+ // a second time. In case it wants us to change the offset again
1895
+ // _changeInProgress == true case, then we have to adjust, because
1896
+ // there is no such time in the given timezone.
1897
+ function getSetOffset (input, keepLocalTime) {
1898
+ var offset = this._offset || 0,
1899
+ localAdjust;
1900
+ if (!this.isValid()) {
1901
+ return input != null ? this : NaN;
1902
+ }
1903
+ if (input != null) {
1904
+ if (typeof input === 'string') {
1905
+ input = offsetFromString(matchShortOffset, input);
1906
+ } else if (Math.abs(input) < 16) {
1907
+ input = input * 60;
1908
+ }
1909
+ if (!this._isUTC && keepLocalTime) {
1910
+ localAdjust = getDateOffset(this);
1911
+ }
1912
+ this._offset = input;
1913
+ this._isUTC = true;
1914
+ if (localAdjust != null) {
1915
+ this.add(localAdjust, 'm');
1916
+ }
1917
+ if (offset !== input) {
1918
+ if (!keepLocalTime || this._changeInProgress) {
1919
+ add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false);
1920
+ } else if (!this._changeInProgress) {
1921
+ this._changeInProgress = true;
1922
+ utils_hooks__hooks.updateOffset(this, true);
1923
+ this._changeInProgress = null;
1924
+ }
1925
+ }
1926
+ return this;
1927
+ } else {
1928
+ return this._isUTC ? offset : getDateOffset(this);
1929
+ }
1930
+ }
1931
+
1932
+ function getSetZone (input, keepLocalTime) {
1933
+ if (input != null) {
1934
+ if (typeof input !== 'string') {
1935
+ input = -input;
1936
+ }
1937
+
1938
+ this.utcOffset(input, keepLocalTime);
1939
+
1940
+ return this;
1941
+ } else {
1942
+ return -this.utcOffset();
1943
+ }
1944
+ }
1945
+
1946
+ function setOffsetToUTC (keepLocalTime) {
1947
+ return this.utcOffset(0, keepLocalTime);
1948
+ }
1949
+
1950
+ function setOffsetToLocal (keepLocalTime) {
1951
+ if (this._isUTC) {
1952
+ this.utcOffset(0, keepLocalTime);
1953
+ this._isUTC = false;
1954
+
1955
+ if (keepLocalTime) {
1956
+ this.subtract(getDateOffset(this), 'm');
1957
+ }
1958
+ }
1959
+ return this;
1960
+ }
1961
+
1962
+ function setOffsetToParsedOffset () {
1963
+ if (this._tzm) {
1964
+ this.utcOffset(this._tzm);
1965
+ } else if (typeof this._i === 'string') {
1966
+ this.utcOffset(offsetFromString(matchOffset, this._i));
1967
+ }
1968
+ return this;
1969
+ }
1970
+
1971
+ function hasAlignedHourOffset (input) {
1972
+ if (!this.isValid()) {
1973
+ return false;
1974
+ }
1975
+ input = input ? local__createLocal(input).utcOffset() : 0;
1976
+
1977
+ return (this.utcOffset() - input) % 60 === 0;
1978
+ }
1979
+
1980
+ function isDaylightSavingTime () {
1981
+ return (
1982
+ this.utcOffset() > this.clone().month(0).utcOffset() ||
1983
+ this.utcOffset() > this.clone().month(5).utcOffset()
1984
+ );
1985
+ }
1986
+
1987
+ function isDaylightSavingTimeShifted () {
1988
+ if (!isUndefined(this._isDSTShifted)) {
1989
+ return this._isDSTShifted;
1990
+ }
1991
+
1992
+ var c = {};
1993
+
1994
+ copyConfig(c, this);
1995
+ c = prepareConfig(c);
1996
+
1997
+ if (c._a) {
1998
+ var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a);
1999
+ this._isDSTShifted = this.isValid() &&
2000
+ compareArrays(c._a, other.toArray()) > 0;
2001
+ } else {
2002
+ this._isDSTShifted = false;
2003
+ }
2004
+
2005
+ return this._isDSTShifted;
2006
+ }
2007
+
2008
+ function isLocal () {
2009
+ return this.isValid() ? !this._isUTC : false;
2010
+ }
2011
+
2012
+ function isUtcOffset () {
2013
+ return this.isValid() ? this._isUTC : false;
2014
+ }
2015
+
2016
+ function isUtc () {
2017
+ return this.isValid() ? this._isUTC && this._offset === 0 : false;
2018
+ }
2019
+
2020
+ // ASP.NET json date format regex
2021
+ var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/;
2022
+
2023
+ // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
2024
+ // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
2025
+ // and further modified to allow for strings containing both week and day
2026
+ var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
2027
+
2028
+ function create__createDuration (input, key) {
2029
+ var duration = input,
2030
+ // matching against regexp is expensive, do it on demand
2031
+ match = null,
2032
+ sign,
2033
+ ret,
2034
+ diffRes;
2035
+
2036
+ if (isDuration(input)) {
2037
+ duration = {
2038
+ ms : input._milliseconds,
2039
+ d : input._days,
2040
+ M : input._months
2041
+ };
2042
+ } else if (typeof input === 'number') {
2043
+ duration = {};
2044
+ if (key) {
2045
+ duration[key] = input;
2046
+ } else {
2047
+ duration.milliseconds = input;
2048
+ }
2049
+ } else if (!!(match = aspNetRegex.exec(input))) {
2050
+ sign = (match[1] === '-') ? -1 : 1;
2051
+ duration = {
2052
+ y : 0,
2053
+ d : toInt(match[DATE]) * sign,
2054
+ h : toInt(match[HOUR]) * sign,
2055
+ m : toInt(match[MINUTE]) * sign,
2056
+ s : toInt(match[SECOND]) * sign,
2057
+ ms : toInt(match[MILLISECOND]) * sign
2058
+ };
2059
+ } else if (!!(match = isoRegex.exec(input))) {
2060
+ sign = (match[1] === '-') ? -1 : 1;
2061
+ duration = {
2062
+ y : parseIso(match[2], sign),
2063
+ M : parseIso(match[3], sign),
2064
+ w : parseIso(match[4], sign),
2065
+ d : parseIso(match[5], sign),
2066
+ h : parseIso(match[6], sign),
2067
+ m : parseIso(match[7], sign),
2068
+ s : parseIso(match[8], sign)
2069
+ };
2070
+ } else if (duration == null) {// checks for null or undefined
2071
+ duration = {};
2072
+ } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
2073
+ diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to));
2074
+
2075
+ duration = {};
2076
+ duration.ms = diffRes.milliseconds;
2077
+ duration.M = diffRes.months;
2078
+ }
2079
+
2080
+ ret = new Duration(duration);
2081
+
2082
+ if (isDuration(input) && hasOwnProp(input, '_locale')) {
2083
+ ret._locale = input._locale;
2084
+ }
2085
+
2086
+ return ret;
2087
+ }
2088
+
2089
+ create__createDuration.fn = Duration.prototype;
2090
+
2091
+ function parseIso (inp, sign) {
2092
+ // We'd normally use ~~inp for this, but unfortunately it also
2093
+ // converts floats to ints.
2094
+ // inp may be undefined, so careful calling replace on it.
2095
+ var res = inp && parseFloat(inp.replace(',', '.'));
2096
+ // apply sign while we're at it
2097
+ return (isNaN(res) ? 0 : res) * sign;
2098
+ }
2099
+
2100
+ function positiveMomentsDifference(base, other) {
2101
+ var res = {milliseconds: 0, months: 0};
2102
+
2103
+ res.months = other.month() - base.month() +
2104
+ (other.year() - base.year()) * 12;
2105
+ if (base.clone().add(res.months, 'M').isAfter(other)) {
2106
+ --res.months;
2107
+ }
2108
+
2109
+ res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
2110
+
2111
+ return res;
2112
+ }
2113
+
2114
+ function momentsDifference(base, other) {
2115
+ var res;
2116
+ if (!(base.isValid() && other.isValid())) {
2117
+ return {milliseconds: 0, months: 0};
2118
+ }
2119
+
2120
+ other = cloneWithOffset(other, base);
2121
+ if (base.isBefore(other)) {
2122
+ res = positiveMomentsDifference(base, other);
2123
+ } else {
2124
+ res = positiveMomentsDifference(other, base);
2125
+ res.milliseconds = -res.milliseconds;
2126
+ res.months = -res.months;
2127
+ }
2128
+
2129
+ return res;
2130
+ }
2131
+
2132
+ function absRound (number) {
2133
+ if (number < 0) {
2134
+ return Math.round(-1 * number) * -1;
2135
+ } else {
2136
+ return Math.round(number);
2137
+ }
2138
+ }
2139
+
2140
+ // TODO: remove 'name' arg after deprecation is removed
2141
+ function createAdder(direction, name) {
2142
+ return function (val, period) {
2143
+ var dur, tmp;
2144
+ //invert the arguments, but complain about it
2145
+ if (period !== null && !isNaN(+period)) {
2146
+ deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');
2147
+ tmp = val; val = period; period = tmp;
2148
+ }
2149
+
2150
+ val = typeof val === 'string' ? +val : val;
2151
+ dur = create__createDuration(val, period);
2152
+ add_subtract__addSubtract(this, dur, direction);
2153
+ return this;
2154
+ };
2155
+ }
2156
+
2157
+ function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) {
2158
+ var milliseconds = duration._milliseconds,
2159
+ days = absRound(duration._days),
2160
+ months = absRound(duration._months);
2161
+
2162
+ if (!mom.isValid()) {
2163
+ // No op
2164
+ return;
2165
+ }
2166
+
2167
+ updateOffset = updateOffset == null ? true : updateOffset;
2168
+
2169
+ if (milliseconds) {
2170
+ mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
2171
+ }
2172
+ if (days) {
2173
+ get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding);
2174
+ }
2175
+ if (months) {
2176
+ setMonth(mom, get_set__get(mom, 'Month') + months * isAdding);
2177
+ }
2178
+ if (updateOffset) {
2179
+ utils_hooks__hooks.updateOffset(mom, days || months);
2180
+ }
2181
+ }
2182
+
2183
+ var add_subtract__add = createAdder(1, 'add');
2184
+ var add_subtract__subtract = createAdder(-1, 'subtract');
2185
+
2186
+ function moment_calendar__calendar (time, formats) {
2187
+ // We want to compare the start of today, vs this.
2188
+ // Getting start-of-today depends on whether we're local/utc/offset or not.
2189
+ var now = time || local__createLocal(),
2190
+ sod = cloneWithOffset(now, this).startOf('day'),
2191
+ diff = this.diff(sod, 'days', true),
2192
+ format = diff < -6 ? 'sameElse' :
2193
+ diff < -1 ? 'lastWeek' :
2194
+ diff < 0 ? 'lastDay' :
2195
+ diff < 1 ? 'sameDay' :
2196
+ diff < 2 ? 'nextDay' :
2197
+ diff < 7 ? 'nextWeek' : 'sameElse';
2198
+
2199
+ var output = formats && (isFunction(formats[format]) ? formats[format]() : formats[format]);
2200
+
2201
+ return this.format(output || this.localeData().calendar(format, this, local__createLocal(now)));
2202
+ }
2203
+
2204
+ function clone () {
2205
+ return new Moment(this);
2206
+ }
2207
+
2208
+ function isAfter (input, units) {
2209
+ var localInput = isMoment(input) ? input : local__createLocal(input);
2210
+ if (!(this.isValid() && localInput.isValid())) {
2211
+ return false;
2212
+ }
2213
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
2214
+ if (units === 'millisecond') {
2215
+ return this.valueOf() > localInput.valueOf();
2216
+ } else {
2217
+ return localInput.valueOf() < this.clone().startOf(units).valueOf();
2218
+ }
2219
+ }
2220
+
2221
+ function isBefore (input, units) {
2222
+ var localInput = isMoment(input) ? input : local__createLocal(input);
2223
+ if (!(this.isValid() && localInput.isValid())) {
2224
+ return false;
2225
+ }
2226
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
2227
+ if (units === 'millisecond') {
2228
+ return this.valueOf() < localInput.valueOf();
2229
+ } else {
2230
+ return this.clone().endOf(units).valueOf() < localInput.valueOf();
2231
+ }
2232
+ }
2233
+
2234
+ function isBetween (from, to, units, inclusivity) {
2235
+ inclusivity = inclusivity || '()';
2236
+ return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
2237
+ (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
2238
+ }
2239
+
2240
+ function isSame (input, units) {
2241
+ var localInput = isMoment(input) ? input : local__createLocal(input),
2242
+ inputMs;
2243
+ if (!(this.isValid() && localInput.isValid())) {
2244
+ return false;
2245
+ }
2246
+ units = normalizeUnits(units || 'millisecond');
2247
+ if (units === 'millisecond') {
2248
+ return this.valueOf() === localInput.valueOf();
2249
+ } else {
2250
+ inputMs = localInput.valueOf();
2251
+ return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
2252
+ }
2253
+ }
2254
+
2255
+ function isSameOrAfter (input, units) {
2256
+ return this.isSame(input, units) || this.isAfter(input,units);
2257
+ }
2258
+
2259
+ function isSameOrBefore (input, units) {
2260
+ return this.isSame(input, units) || this.isBefore(input,units);
2261
+ }
2262
+
2263
+ function diff (input, units, asFloat) {
2264
+ var that,
2265
+ zoneDelta,
2266
+ delta, output;
2267
+
2268
+ if (!this.isValid()) {
2269
+ return NaN;
2270
+ }
2271
+
2272
+ that = cloneWithOffset(input, this);
2273
+
2274
+ if (!that.isValid()) {
2275
+ return NaN;
2276
+ }
2277
+
2278
+ zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
2279
+
2280
+ units = normalizeUnits(units);
2281
+
2282
+ if (units === 'year' || units === 'month' || units === 'quarter') {
2283
+ output = monthDiff(this, that);
2284
+ if (units === 'quarter') {
2285
+ output = output / 3;
2286
+ } else if (units === 'year') {
2287
+ output = output / 12;
2288
+ }
2289
+ } else {
2290
+ delta = this - that;
2291
+ output = units === 'second' ? delta / 1e3 : // 1000
2292
+ units === 'minute' ? delta / 6e4 : // 1000 * 60
2293
+ units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
2294
+ units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
2295
+ units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
2296
+ delta;
2297
+ }
2298
+ return asFloat ? output : absFloor(output);
2299
+ }
2300
+
2301
+ function monthDiff (a, b) {
2302
+ // difference in months
2303
+ var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
2304
+ // b is in (anchor - 1 month, anchor + 1 month)
2305
+ anchor = a.clone().add(wholeMonthDiff, 'months'),
2306
+ anchor2, adjust;
2307
+
2308
+ if (b - anchor < 0) {
2309
+ anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
2310
+ // linear across the month
2311
+ adjust = (b - anchor) / (anchor - anchor2);
2312
+ } else {
2313
+ anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
2314
+ // linear across the month
2315
+ adjust = (b - anchor) / (anchor2 - anchor);
2316
+ }
2317
+
2318
+ //check for negative zero, return zero if negative zero
2319
+ return -(wholeMonthDiff + adjust) || 0;
2320
+ }
2321
+
2322
+ utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
2323
+ utils_hooks__hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
2324
+
2325
+ function toString () {
2326
+ return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
2327
+ }
2328
+
2329
+ function moment_format__toISOString () {
2330
+ var m = this.clone().utc();
2331
+ if (0 < m.year() && m.year() <= 9999) {
2332
+ if (isFunction(Date.prototype.toISOString)) {
2333
+ // native implementation is ~50x faster, use it when we can
2334
+ return this.toDate().toISOString();
2335
+ } else {
2336
+ return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
2337
+ }
2338
+ } else {
2339
+ return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
2340
+ }
2341
+ }
2342
+
2343
+ function format (inputString) {
2344
+ if (!inputString) {
2345
+ inputString = this.isUtc() ? utils_hooks__hooks.defaultFormatUtc : utils_hooks__hooks.defaultFormat;
2346
+ }
2347
+ var output = formatMoment(this, inputString);
2348
+ return this.localeData().postformat(output);
2349
+ }
2350
+
2351
+ function from (time, withoutSuffix) {
2352
+ if (this.isValid() &&
2353
+ ((isMoment(time) && time.isValid()) ||
2354
+ local__createLocal(time).isValid())) {
2355
+ return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
2356
+ } else {
2357
+ return this.localeData().invalidDate();
2358
+ }
2359
+ }
2360
+
2361
+ function fromNow (withoutSuffix) {
2362
+ return this.from(local__createLocal(), withoutSuffix);
2363
+ }
2364
+
2365
+ function to (time, withoutSuffix) {
2366
+ if (this.isValid() &&
2367
+ ((isMoment(time) && time.isValid()) ||
2368
+ local__createLocal(time).isValid())) {
2369
+ return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
2370
+ } else {
2371
+ return this.localeData().invalidDate();
2372
+ }
2373
+ }
2374
+
2375
+ function toNow (withoutSuffix) {
2376
+ return this.to(local__createLocal(), withoutSuffix);
2377
+ }
2378
+
2379
+ // If passed a locale key, it will set the locale for this
2380
+ // instance. Otherwise, it will return the locale configuration
2381
+ // variables for this instance.
2382
+ function locale (key) {
2383
+ var newLocaleData;
2384
+
2385
+ if (key === undefined) {
2386
+ return this._locale._abbr;
2387
+ } else {
2388
+ newLocaleData = locale_locales__getLocale(key);
2389
+ if (newLocaleData != null) {
2390
+ this._locale = newLocaleData;
2391
+ }
2392
+ return this;
2393
+ }
2394
+ }
2395
+
2396
+ var lang = deprecate(
2397
+ 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
2398
+ function (key) {
2399
+ if (key === undefined) {
2400
+ return this.localeData();
2401
+ } else {
2402
+ return this.locale(key);
2403
+ }
2404
+ }
2405
+ );
2406
+
2407
+ function localeData () {
2408
+ return this._locale;
2409
+ }
2410
+
2411
+ function startOf (units) {
2412
+ units = normalizeUnits(units);
2413
+ // the following switch intentionally omits break keywords
2414
+ // to utilize falling through the cases.
2415
+ switch (units) {
2416
+ case 'year':
2417
+ this.month(0);
2418
+ /* falls through */
2419
+ case 'quarter':
2420
+ case 'month':
2421
+ this.date(1);
2422
+ /* falls through */
2423
+ case 'week':
2424
+ case 'isoWeek':
2425
+ case 'day':
2426
+ case 'date':
2427
+ this.hours(0);
2428
+ /* falls through */
2429
+ case 'hour':
2430
+ this.minutes(0);
2431
+ /* falls through */
2432
+ case 'minute':
2433
+ this.seconds(0);
2434
+ /* falls through */
2435
+ case 'second':
2436
+ this.milliseconds(0);
2437
+ }
2438
+
2439
+ // weeks are a special case
2440
+ if (units === 'week') {
2441
+ this.weekday(0);
2442
+ }
2443
+ if (units === 'isoWeek') {
2444
+ this.isoWeekday(1);
2445
+ }
2446
+
2447
+ // quarters are also special
2448
+ if (units === 'quarter') {
2449
+ this.month(Math.floor(this.month() / 3) * 3);
2450
+ }
2451
+
2452
+ return this;
2453
+ }
2454
+
2455
+ function endOf (units) {
2456
+ units = normalizeUnits(units);
2457
+ if (units === undefined || units === 'millisecond') {
2458
+ return this;
2459
+ }
2460
+
2461
+ // 'date' is an alias for 'day', so it should be considered as such.
2462
+ if (units === 'date') {
2463
+ units = 'day';
2464
+ }
2465
+
2466
+ return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
2467
+ }
2468
+
2469
+ function to_type__valueOf () {
2470
+ return this._d.valueOf() - ((this._offset || 0) * 60000);
2471
+ }
2472
+
2473
+ function unix () {
2474
+ return Math.floor(this.valueOf() / 1000);
2475
+ }
2476
+
2477
+ function toDate () {
2478
+ return this._offset ? new Date(this.valueOf()) : this._d;
2479
+ }
2480
+
2481
+ function toArray () {
2482
+ var m = this;
2483
+ return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
2484
+ }
2485
+
2486
+ function toObject () {
2487
+ var m = this;
2488
+ return {
2489
+ years: m.year(),
2490
+ months: m.month(),
2491
+ date: m.date(),
2492
+ hours: m.hours(),
2493
+ minutes: m.minutes(),
2494
+ seconds: m.seconds(),
2495
+ milliseconds: m.milliseconds()
2496
+ };
2497
+ }
2498
+
2499
+ function toJSON () {
2500
+ // new Date(NaN).toJSON() === null
2501
+ return this.isValid() ? this.toISOString() : null;
2502
+ }
2503
+
2504
+ function moment_valid__isValid () {
2505
+ return valid__isValid(this);
2506
+ }
2507
+
2508
+ function parsingFlags () {
2509
+ return extend({}, getParsingFlags(this));
2510
+ }
2511
+
2512
+ function invalidAt () {
2513
+ return getParsingFlags(this).overflow;
2514
+ }
2515
+
2516
+ function creationData() {
2517
+ return {
2518
+ input: this._i,
2519
+ format: this._f,
2520
+ locale: this._locale,
2521
+ isUTC: this._isUTC,
2522
+ strict: this._strict
2523
+ };
2524
+ }
2525
+
2526
+ // FORMATTING
2527
+
2528
+ addFormatToken(0, ['gg', 2], 0, function () {
2529
+ return this.weekYear() % 100;
2530
+ });
2531
+
2532
+ addFormatToken(0, ['GG', 2], 0, function () {
2533
+ return this.isoWeekYear() % 100;
2534
+ });
2535
+
2536
+ function addWeekYearFormatToken (token, getter) {
2537
+ addFormatToken(0, [token, token.length], 0, getter);
2538
+ }
2539
+
2540
+ addWeekYearFormatToken('gggg', 'weekYear');
2541
+ addWeekYearFormatToken('ggggg', 'weekYear');
2542
+ addWeekYearFormatToken('GGGG', 'isoWeekYear');
2543
+ addWeekYearFormatToken('GGGGG', 'isoWeekYear');
2544
+
2545
+ // ALIASES
2546
+
2547
+ addUnitAlias('weekYear', 'gg');
2548
+ addUnitAlias('isoWeekYear', 'GG');
2549
+
2550
+ // PARSING
2551
+
2552
+ addRegexToken('G', matchSigned);
2553
+ addRegexToken('g', matchSigned);
2554
+ addRegexToken('GG', match1to2, match2);
2555
+ addRegexToken('gg', match1to2, match2);
2556
+ addRegexToken('GGGG', match1to4, match4);
2557
+ addRegexToken('gggg', match1to4, match4);
2558
+ addRegexToken('GGGGG', match1to6, match6);
2559
+ addRegexToken('ggggg', match1to6, match6);
2560
+
2561
+ addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
2562
+ week[token.substr(0, 2)] = toInt(input);
2563
+ });
2564
+
2565
+ addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
2566
+ week[token] = utils_hooks__hooks.parseTwoDigitYear(input);
2567
+ });
2568
+
2569
+ // MOMENTS
2570
+
2571
+ function getSetWeekYear (input) {
2572
+ return getSetWeekYearHelper.call(this,
2573
+ input,
2574
+ this.week(),
2575
+ this.weekday(),
2576
+ this.localeData()._week.dow,
2577
+ this.localeData()._week.doy);
2578
+ }
2579
+
2580
+ function getSetISOWeekYear (input) {
2581
+ return getSetWeekYearHelper.call(this,
2582
+ input, this.isoWeek(), this.isoWeekday(), 1, 4);
2583
+ }
2584
+
2585
+ function getISOWeeksInYear () {
2586
+ return weeksInYear(this.year(), 1, 4);
2587
+ }
2588
+
2589
+ function getWeeksInYear () {
2590
+ var weekInfo = this.localeData()._week;
2591
+ return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
2592
+ }
2593
+
2594
+ function getSetWeekYearHelper(input, week, weekday, dow, doy) {
2595
+ var weeksTarget;
2596
+ if (input == null) {
2597
+ return weekOfYear(this, dow, doy).year;
2598
+ } else {
2599
+ weeksTarget = weeksInYear(input, dow, doy);
2600
+ if (week > weeksTarget) {
2601
+ week = weeksTarget;
2602
+ }
2603
+ return setWeekAll.call(this, input, week, weekday, dow, doy);
2604
+ }
2605
+ }
2606
+
2607
+ function setWeekAll(weekYear, week, weekday, dow, doy) {
2608
+ var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
2609
+ date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
2610
+
2611
+ this.year(date.getUTCFullYear());
2612
+ this.month(date.getUTCMonth());
2613
+ this.date(date.getUTCDate());
2614
+ return this;
2615
+ }
2616
+
2617
+ // FORMATTING
2618
+
2619
+ addFormatToken('Q', 0, 'Qo', 'quarter');
2620
+
2621
+ // ALIASES
2622
+
2623
+ addUnitAlias('quarter', 'Q');
2624
+
2625
+ // PARSING
2626
+
2627
+ addRegexToken('Q', match1);
2628
+ addParseToken('Q', function (input, array) {
2629
+ array[MONTH] = (toInt(input) - 1) * 3;
2630
+ });
2631
+
2632
+ // MOMENTS
2633
+
2634
+ function getSetQuarter (input) {
2635
+ return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
2636
+ }
2637
+
2638
+ // FORMATTING
2639
+
2640
+ addFormatToken('w', ['ww', 2], 'wo', 'week');
2641
+ addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
2642
+
2643
+ // ALIASES
2644
+
2645
+ addUnitAlias('week', 'w');
2646
+ addUnitAlias('isoWeek', 'W');
2647
+
2648
+ // PARSING
2649
+
2650
+ addRegexToken('w', match1to2);
2651
+ addRegexToken('ww', match1to2, match2);
2652
+ addRegexToken('W', match1to2);
2653
+ addRegexToken('WW', match1to2, match2);
2654
+
2655
+ addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
2656
+ week[token.substr(0, 1)] = toInt(input);
2657
+ });
2658
+
2659
+ // HELPERS
2660
+
2661
+ // LOCALES
2662
+
2663
+ function localeWeek (mom) {
2664
+ return weekOfYear(mom, this._week.dow, this._week.doy).week;
2665
+ }
2666
+
2667
+ var defaultLocaleWeek = {
2668
+ dow : 0, // Sunday is the first day of the week.
2669
+ doy : 6 // The week that contains Jan 1st is the first week of the year.
2670
+ };
2671
+
2672
+ function localeFirstDayOfWeek () {
2673
+ return this._week.dow;
2674
+ }
2675
+
2676
+ function localeFirstDayOfYear () {
2677
+ return this._week.doy;
2678
+ }
2679
+
2680
+ // MOMENTS
2681
+
2682
+ function getSetWeek (input) {
2683
+ var week = this.localeData().week(this);
2684
+ return input == null ? week : this.add((input - week) * 7, 'd');
2685
+ }
2686
+
2687
+ function getSetISOWeek (input) {
2688
+ var week = weekOfYear(this, 1, 4).week;
2689
+ return input == null ? week : this.add((input - week) * 7, 'd');
2690
+ }
2691
+
2692
+ // FORMATTING
2693
+
2694
+ addFormatToken('D', ['DD', 2], 'Do', 'date');
2695
+
2696
+ // ALIASES
2697
+
2698
+ addUnitAlias('date', 'D');
2699
+
2700
+ // PARSING
2701
+
2702
+ addRegexToken('D', match1to2);
2703
+ addRegexToken('DD', match1to2, match2);
2704
+ addRegexToken('Do', function (isStrict, locale) {
2705
+ return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
2706
+ });
2707
+
2708
+ addParseToken(['D', 'DD'], DATE);
2709
+ addParseToken('Do', function (input, array) {
2710
+ array[DATE] = toInt(input.match(match1to2)[0], 10);
2711
+ });
2712
+
2713
+ // MOMENTS
2714
+
2715
+ var getSetDayOfMonth = makeGetSet('Date', true);
2716
+
2717
+ // FORMATTING
2718
+
2719
+ addFormatToken('d', 0, 'do', 'day');
2720
+
2721
+ addFormatToken('dd', 0, 0, function (format) {
2722
+ return this.localeData().weekdaysMin(this, format);
2723
+ });
2724
+
2725
+ addFormatToken('ddd', 0, 0, function (format) {
2726
+ return this.localeData().weekdaysShort(this, format);
2727
+ });
2728
+
2729
+ addFormatToken('dddd', 0, 0, function (format) {
2730
+ return this.localeData().weekdays(this, format);
2731
+ });
2732
+
2733
+ addFormatToken('e', 0, 0, 'weekday');
2734
+ addFormatToken('E', 0, 0, 'isoWeekday');
2735
+
2736
+ // ALIASES
2737
+
2738
+ addUnitAlias('day', 'd');
2739
+ addUnitAlias('weekday', 'e');
2740
+ addUnitAlias('isoWeekday', 'E');
2741
+
2742
+ // PARSING
2743
+
2744
+ addRegexToken('d', match1to2);
2745
+ addRegexToken('e', match1to2);
2746
+ addRegexToken('E', match1to2);
2747
+ addRegexToken('dd', function (isStrict, locale) {
2748
+ return locale.weekdaysMinRegex(isStrict);
2749
+ });
2750
+ addRegexToken('ddd', function (isStrict, locale) {
2751
+ return locale.weekdaysShortRegex(isStrict);
2752
+ });
2753
+ addRegexToken('dddd', function (isStrict, locale) {
2754
+ return locale.weekdaysRegex(isStrict);
2755
+ });
2756
+
2757
+ addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
2758
+ var weekday = config._locale.weekdaysParse(input, token, config._strict);
2759
+ // if we didn't get a weekday name, mark the date as invalid
2760
+ if (weekday != null) {
2761
+ week.d = weekday;
2762
+ } else {
2763
+ getParsingFlags(config).invalidWeekday = input;
2764
+ }
2765
+ });
2766
+
2767
+ addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
2768
+ week[token] = toInt(input);
2769
+ });
2770
+
2771
+ // HELPERS
2772
+
2773
+ function parseWeekday(input, locale) {
2774
+ if (typeof input !== 'string') {
2775
+ return input;
2776
+ }
2777
+
2778
+ if (!isNaN(input)) {
2779
+ return parseInt(input, 10);
2780
+ }
2781
+
2782
+ input = locale.weekdaysParse(input);
2783
+ if (typeof input === 'number') {
2784
+ return input;
2785
+ }
2786
+
2787
+ return null;
2788
+ }
2789
+
2790
+ // LOCALES
2791
+
2792
+ var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
2793
+ function localeWeekdays (m, format) {
2794
+ return isArray(this._weekdays) ? this._weekdays[m.day()] :
2795
+ this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
2796
+ }
2797
+
2798
+ var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
2799
+ function localeWeekdaysShort (m) {
2800
+ return this._weekdaysShort[m.day()];
2801
+ }
2802
+
2803
+ var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
2804
+ function localeWeekdaysMin (m) {
2805
+ return this._weekdaysMin[m.day()];
2806
+ }
2807
+
2808
+ function day_of_week__handleStrictParse(weekdayName, format, strict) {
2809
+ var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
2810
+ if (!this._weekdaysParse) {
2811
+ this._weekdaysParse = [];
2812
+ this._shortWeekdaysParse = [];
2813
+ this._minWeekdaysParse = [];
2814
+
2815
+ for (i = 0; i < 7; ++i) {
2816
+ mom = create_utc__createUTC([2000, 1]).day(i);
2817
+ this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
2818
+ this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
2819
+ this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
2820
+ }
2821
+ }
2822
+
2823
+ if (strict) {
2824
+ if (format === 'dddd') {
2825
+ ii = indexOf.call(this._weekdaysParse, llc);
2826
+ return ii !== -1 ? ii : null;
2827
+ } else if (format === 'ddd') {
2828
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
2829
+ return ii !== -1 ? ii : null;
2830
+ } else {
2831
+ ii = indexOf.call(this._minWeekdaysParse, llc);
2832
+ return ii !== -1 ? ii : null;
2833
+ }
2834
+ } else {
2835
+ if (format === 'dddd') {
2836
+ ii = indexOf.call(this._weekdaysParse, llc);
2837
+ if (ii !== -1) {
2838
+ return ii;
2839
+ }
2840
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
2841
+ if (ii !== -1) {
2842
+ return ii;
2843
+ }
2844
+ ii = indexOf.call(this._minWeekdaysParse, llc);
2845
+ return ii !== -1 ? ii : null;
2846
+ } else if (format === 'ddd') {
2847
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
2848
+ if (ii !== -1) {
2849
+ return ii;
2850
+ }
2851
+ ii = indexOf.call(this._weekdaysParse, llc);
2852
+ if (ii !== -1) {
2853
+ return ii;
2854
+ }
2855
+ ii = indexOf.call(this._minWeekdaysParse, llc);
2856
+ return ii !== -1 ? ii : null;
2857
+ } else {
2858
+ ii = indexOf.call(this._minWeekdaysParse, llc);
2859
+ if (ii !== -1) {
2860
+ return ii;
2861
+ }
2862
+ ii = indexOf.call(this._weekdaysParse, llc);
2863
+ if (ii !== -1) {
2864
+ return ii;
2865
+ }
2866
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
2867
+ return ii !== -1 ? ii : null;
2868
+ }
2869
+ }
2870
+ }
2871
+
2872
+ function localeWeekdaysParse (weekdayName, format, strict) {
2873
+ var i, mom, regex;
2874
+
2875
+ if (this._weekdaysParseExact) {
2876
+ return day_of_week__handleStrictParse.call(this, weekdayName, format, strict);
2877
+ }
2878
+
2879
+ if (!this._weekdaysParse) {
2880
+ this._weekdaysParse = [];
2881
+ this._minWeekdaysParse = [];
2882
+ this._shortWeekdaysParse = [];
2883
+ this._fullWeekdaysParse = [];
2884
+ }
2885
+
2886
+ for (i = 0; i < 7; i++) {
2887
+ // make the regex if we don't have it already
2888
+
2889
+ mom = create_utc__createUTC([2000, 1]).day(i);
2890
+ if (strict && !this._fullWeekdaysParse[i]) {
2891
+ this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
2892
+ this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
2893
+ this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
2894
+ }
2895
+ if (!this._weekdaysParse[i]) {
2896
+ regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
2897
+ this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
2898
+ }
2899
+ // test the regex
2900
+ if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
2901
+ return i;
2902
+ } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
2903
+ return i;
2904
+ } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
2905
+ return i;
2906
+ } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
2907
+ return i;
2908
+ }
2909
+ }
2910
+ }
2911
+
2912
+ // MOMENTS
2913
+
2914
+ function getSetDayOfWeek (input) {
2915
+ if (!this.isValid()) {
2916
+ return input != null ? this : NaN;
2917
+ }
2918
+ var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
2919
+ if (input != null) {
2920
+ input = parseWeekday(input, this.localeData());
2921
+ return this.add(input - day, 'd');
2922
+ } else {
2923
+ return day;
2924
+ }
2925
+ }
2926
+
2927
+ function getSetLocaleDayOfWeek (input) {
2928
+ if (!this.isValid()) {
2929
+ return input != null ? this : NaN;
2930
+ }
2931
+ var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
2932
+ return input == null ? weekday : this.add(input - weekday, 'd');
2933
+ }
2934
+
2935
+ function getSetISODayOfWeek (input) {
2936
+ if (!this.isValid()) {
2937
+ return input != null ? this : NaN;
2938
+ }
2939
+ // behaves the same as moment#day except
2940
+ // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
2941
+ // as a setter, sunday should belong to the previous week.
2942
+ return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
2943
+ }
2944
+
2945
+ var defaultWeekdaysRegex = matchWord;
2946
+ function weekdaysRegex (isStrict) {
2947
+ if (this._weekdaysParseExact) {
2948
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
2949
+ computeWeekdaysParse.call(this);
2950
+ }
2951
+ if (isStrict) {
2952
+ return this._weekdaysStrictRegex;
2953
+ } else {
2954
+ return this._weekdaysRegex;
2955
+ }
2956
+ } else {
2957
+ return this._weekdaysStrictRegex && isStrict ?
2958
+ this._weekdaysStrictRegex : this._weekdaysRegex;
2959
+ }
2960
+ }
2961
+
2962
+ var defaultWeekdaysShortRegex = matchWord;
2963
+ function weekdaysShortRegex (isStrict) {
2964
+ if (this._weekdaysParseExact) {
2965
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
2966
+ computeWeekdaysParse.call(this);
2967
+ }
2968
+ if (isStrict) {
2969
+ return this._weekdaysShortStrictRegex;
2970
+ } else {
2971
+ return this._weekdaysShortRegex;
2972
+ }
2973
+ } else {
2974
+ return this._weekdaysShortStrictRegex && isStrict ?
2975
+ this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
2976
+ }
2977
+ }
2978
+
2979
+ var defaultWeekdaysMinRegex = matchWord;
2980
+ function weekdaysMinRegex (isStrict) {
2981
+ if (this._weekdaysParseExact) {
2982
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
2983
+ computeWeekdaysParse.call(this);
2984
+ }
2985
+ if (isStrict) {
2986
+ return this._weekdaysMinStrictRegex;
2987
+ } else {
2988
+ return this._weekdaysMinRegex;
2989
+ }
2990
+ } else {
2991
+ return this._weekdaysMinStrictRegex && isStrict ?
2992
+ this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
2993
+ }
2994
+ }
2995
+
2996
+
2997
+ function computeWeekdaysParse () {
2998
+ function cmpLenRev(a, b) {
2999
+ return b.length - a.length;
3000
+ }
3001
+
3002
+ var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
3003
+ i, mom, minp, shortp, longp;
3004
+ for (i = 0; i < 7; i++) {
3005
+ // make the regex if we don't have it already
3006
+ mom = create_utc__createUTC([2000, 1]).day(i);
3007
+ minp = this.weekdaysMin(mom, '');
3008
+ shortp = this.weekdaysShort(mom, '');
3009
+ longp = this.weekdays(mom, '');
3010
+ minPieces.push(minp);
3011
+ shortPieces.push(shortp);
3012
+ longPieces.push(longp);
3013
+ mixedPieces.push(minp);
3014
+ mixedPieces.push(shortp);
3015
+ mixedPieces.push(longp);
3016
+ }
3017
+ // Sorting makes sure if one weekday (or abbr) is a prefix of another it
3018
+ // will match the longer piece.
3019
+ minPieces.sort(cmpLenRev);
3020
+ shortPieces.sort(cmpLenRev);
3021
+ longPieces.sort(cmpLenRev);
3022
+ mixedPieces.sort(cmpLenRev);
3023
+ for (i = 0; i < 7; i++) {
3024
+ shortPieces[i] = regexEscape(shortPieces[i]);
3025
+ longPieces[i] = regexEscape(longPieces[i]);
3026
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
3027
+ }
3028
+
3029
+ this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
3030
+ this._weekdaysShortRegex = this._weekdaysRegex;
3031
+ this._weekdaysMinRegex = this._weekdaysRegex;
3032
+
3033
+ this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
3034
+ this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
3035
+ this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
3036
+ }
3037
+
3038
+ // FORMATTING
3039
+
3040
+ addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
3041
+
3042
+ // ALIASES
3043
+
3044
+ addUnitAlias('dayOfYear', 'DDD');
3045
+
3046
+ // PARSING
3047
+
3048
+ addRegexToken('DDD', match1to3);
3049
+ addRegexToken('DDDD', match3);
3050
+ addParseToken(['DDD', 'DDDD'], function (input, array, config) {
3051
+ config._dayOfYear = toInt(input);
3052
+ });
3053
+
3054
+ // HELPERS
3055
+
3056
+ // MOMENTS
3057
+
3058
+ function getSetDayOfYear (input) {
3059
+ var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
3060
+ return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
3061
+ }
3062
+
3063
+ // FORMATTING
3064
+
3065
+ function hFormat() {
3066
+ return this.hours() % 12 || 12;
3067
+ }
3068
+
3069
+ function kFormat() {
3070
+ return this.hours() || 24;
3071
+ }
3072
+
3073
+ addFormatToken('H', ['HH', 2], 0, 'hour');
3074
+ addFormatToken('h', ['hh', 2], 0, hFormat);
3075
+ addFormatToken('k', ['kk', 2], 0, kFormat);
3076
+
3077
+ addFormatToken('hmm', 0, 0, function () {
3078
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
3079
+ });
3080
+
3081
+ addFormatToken('hmmss', 0, 0, function () {
3082
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
3083
+ zeroFill(this.seconds(), 2);
3084
+ });
3085
+
3086
+ addFormatToken('Hmm', 0, 0, function () {
3087
+ return '' + this.hours() + zeroFill(this.minutes(), 2);
3088
+ });
3089
+
3090
+ addFormatToken('Hmmss', 0, 0, function () {
3091
+ return '' + this.hours() + zeroFill(this.minutes(), 2) +
3092
+ zeroFill(this.seconds(), 2);
3093
+ });
3094
+
3095
+ function meridiem (token, lowercase) {
3096
+ addFormatToken(token, 0, 0, function () {
3097
+ return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
3098
+ });
3099
+ }
3100
+
3101
+ meridiem('a', true);
3102
+ meridiem('A', false);
3103
+
3104
+ // ALIASES
3105
+
3106
+ addUnitAlias('hour', 'h');
3107
+
3108
+ // PARSING
3109
+
3110
+ function matchMeridiem (isStrict, locale) {
3111
+ return locale._meridiemParse;
3112
+ }
3113
+
3114
+ addRegexToken('a', matchMeridiem);
3115
+ addRegexToken('A', matchMeridiem);
3116
+ addRegexToken('H', match1to2);
3117
+ addRegexToken('h', match1to2);
3118
+ addRegexToken('HH', match1to2, match2);
3119
+ addRegexToken('hh', match1to2, match2);
3120
+
3121
+ addRegexToken('hmm', match3to4);
3122
+ addRegexToken('hmmss', match5to6);
3123
+ addRegexToken('Hmm', match3to4);
3124
+ addRegexToken('Hmmss', match5to6);
3125
+
3126
+ addParseToken(['H', 'HH'], HOUR);
3127
+ addParseToken(['a', 'A'], function (input, array, config) {
3128
+ config._isPm = config._locale.isPM(input);
3129
+ config._meridiem = input;
3130
+ });
3131
+ addParseToken(['h', 'hh'], function (input, array, config) {
3132
+ array[HOUR] = toInt(input);
3133
+ getParsingFlags(config).bigHour = true;
3134
+ });
3135
+ addParseToken('hmm', function (input, array, config) {
3136
+ var pos = input.length - 2;
3137
+ array[HOUR] = toInt(input.substr(0, pos));
3138
+ array[MINUTE] = toInt(input.substr(pos));
3139
+ getParsingFlags(config).bigHour = true;
3140
+ });
3141
+ addParseToken('hmmss', function (input, array, config) {
3142
+ var pos1 = input.length - 4;
3143
+ var pos2 = input.length - 2;
3144
+ array[HOUR] = toInt(input.substr(0, pos1));
3145
+ array[MINUTE] = toInt(input.substr(pos1, 2));
3146
+ array[SECOND] = toInt(input.substr(pos2));
3147
+ getParsingFlags(config).bigHour = true;
3148
+ });
3149
+ addParseToken('Hmm', function (input, array, config) {
3150
+ var pos = input.length - 2;
3151
+ array[HOUR] = toInt(input.substr(0, pos));
3152
+ array[MINUTE] = toInt(input.substr(pos));
3153
+ });
3154
+ addParseToken('Hmmss', function (input, array, config) {
3155
+ var pos1 = input.length - 4;
3156
+ var pos2 = input.length - 2;
3157
+ array[HOUR] = toInt(input.substr(0, pos1));
3158
+ array[MINUTE] = toInt(input.substr(pos1, 2));
3159
+ array[SECOND] = toInt(input.substr(pos2));
3160
+ });
3161
+
3162
+ // LOCALES
3163
+
3164
+ function localeIsPM (input) {
3165
+ // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
3166
+ // Using charAt should be more compatible.
3167
+ return ((input + '').toLowerCase().charAt(0) === 'p');
3168
+ }
3169
+
3170
+ var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
3171
+ function localeMeridiem (hours, minutes, isLower) {
3172
+ if (hours > 11) {
3173
+ return isLower ? 'pm' : 'PM';
3174
+ } else {
3175
+ return isLower ? 'am' : 'AM';
3176
+ }
3177
+ }
3178
+
3179
+
3180
+ // MOMENTS
3181
+
3182
+ // Setting the hour should keep the time, because the user explicitly
3183
+ // specified which hour he wants. So trying to maintain the same hour (in
3184
+ // a new timezone) makes sense. Adding/subtracting hours does not follow
3185
+ // this rule.
3186
+ var getSetHour = makeGetSet('Hours', true);
3187
+
3188
+ // FORMATTING
3189
+
3190
+ addFormatToken('m', ['mm', 2], 0, 'minute');
3191
+
3192
+ // ALIASES
3193
+
3194
+ addUnitAlias('minute', 'm');
3195
+
3196
+ // PARSING
3197
+
3198
+ addRegexToken('m', match1to2);
3199
+ addRegexToken('mm', match1to2, match2);
3200
+ addParseToken(['m', 'mm'], MINUTE);
3201
+
3202
+ // MOMENTS
3203
+
3204
+ var getSetMinute = makeGetSet('Minutes', false);
3205
+
3206
+ // FORMATTING
3207
+
3208
+ addFormatToken('s', ['ss', 2], 0, 'second');
3209
+
3210
+ // ALIASES
3211
+
3212
+ addUnitAlias('second', 's');
3213
+
3214
+ // PARSING
3215
+
3216
+ addRegexToken('s', match1to2);
3217
+ addRegexToken('ss', match1to2, match2);
3218
+ addParseToken(['s', 'ss'], SECOND);
3219
+
3220
+ // MOMENTS
3221
+
3222
+ var getSetSecond = makeGetSet('Seconds', false);
3223
+
3224
+ // FORMATTING
3225
+
3226
+ addFormatToken('S', 0, 0, function () {
3227
+ return ~~(this.millisecond() / 100);
3228
+ });
3229
+
3230
+ addFormatToken(0, ['SS', 2], 0, function () {
3231
+ return ~~(this.millisecond() / 10);
3232
+ });
3233
+
3234
+ addFormatToken(0, ['SSS', 3], 0, 'millisecond');
3235
+ addFormatToken(0, ['SSSS', 4], 0, function () {
3236
+ return this.millisecond() * 10;
3237
+ });
3238
+ addFormatToken(0, ['SSSSS', 5], 0, function () {
3239
+ return this.millisecond() * 100;
3240
+ });
3241
+ addFormatToken(0, ['SSSSSS', 6], 0, function () {
3242
+ return this.millisecond() * 1000;
3243
+ });
3244
+ addFormatToken(0, ['SSSSSSS', 7], 0, function () {
3245
+ return this.millisecond() * 10000;
3246
+ });
3247
+ addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
3248
+ return this.millisecond() * 100000;
3249
+ });
3250
+ addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
3251
+ return this.millisecond() * 1000000;
3252
+ });
3253
+
3254
+
3255
+ // ALIASES
3256
+
3257
+ addUnitAlias('millisecond', 'ms');
3258
+
3259
+ // PARSING
3260
+
3261
+ addRegexToken('S', match1to3, match1);
3262
+ addRegexToken('SS', match1to3, match2);
3263
+ addRegexToken('SSS', match1to3, match3);
3264
+
3265
+ var token;
3266
+ for (token = 'SSSS'; token.length <= 9; token += 'S') {
3267
+ addRegexToken(token, matchUnsigned);
3268
+ }
3269
+
3270
+ function parseMs(input, array) {
3271
+ array[MILLISECOND] = toInt(('0.' + input) * 1000);
3272
+ }
3273
+
3274
+ for (token = 'S'; token.length <= 9; token += 'S') {
3275
+ addParseToken(token, parseMs);
3276
+ }
3277
+ // MOMENTS
3278
+
3279
+ var getSetMillisecond = makeGetSet('Milliseconds', false);
3280
+
3281
+ // FORMATTING
3282
+
3283
+ addFormatToken('z', 0, 0, 'zoneAbbr');
3284
+ addFormatToken('zz', 0, 0, 'zoneName');
3285
+
3286
+ // MOMENTS
3287
+
3288
+ function getZoneAbbr () {
3289
+ return this._isUTC ? 'UTC' : '';
3290
+ }
3291
+
3292
+ function getZoneName () {
3293
+ return this._isUTC ? 'Coordinated Universal Time' : '';
3294
+ }
3295
+
3296
+ var momentPrototype__proto = Moment.prototype;
3297
+
3298
+ momentPrototype__proto.add = add_subtract__add;
3299
+ momentPrototype__proto.calendar = moment_calendar__calendar;
3300
+ momentPrototype__proto.clone = clone;
3301
+ momentPrototype__proto.diff = diff;
3302
+ momentPrototype__proto.endOf = endOf;
3303
+ momentPrototype__proto.format = format;
3304
+ momentPrototype__proto.from = from;
3305
+ momentPrototype__proto.fromNow = fromNow;
3306
+ momentPrototype__proto.to = to;
3307
+ momentPrototype__proto.toNow = toNow;
3308
+ momentPrototype__proto.get = getSet;
3309
+ momentPrototype__proto.invalidAt = invalidAt;
3310
+ momentPrototype__proto.isAfter = isAfter;
3311
+ momentPrototype__proto.isBefore = isBefore;
3312
+ momentPrototype__proto.isBetween = isBetween;
3313
+ momentPrototype__proto.isSame = isSame;
3314
+ momentPrototype__proto.isSameOrAfter = isSameOrAfter;
3315
+ momentPrototype__proto.isSameOrBefore = isSameOrBefore;
3316
+ momentPrototype__proto.isValid = moment_valid__isValid;
3317
+ momentPrototype__proto.lang = lang;
3318
+ momentPrototype__proto.locale = locale;
3319
+ momentPrototype__proto.localeData = localeData;
3320
+ momentPrototype__proto.max = prototypeMax;
3321
+ momentPrototype__proto.min = prototypeMin;
3322
+ momentPrototype__proto.parsingFlags = parsingFlags;
3323
+ momentPrototype__proto.set = getSet;
3324
+ momentPrototype__proto.startOf = startOf;
3325
+ momentPrototype__proto.subtract = add_subtract__subtract;
3326
+ momentPrototype__proto.toArray = toArray;
3327
+ momentPrototype__proto.toObject = toObject;
3328
+ momentPrototype__proto.toDate = toDate;
3329
+ momentPrototype__proto.toISOString = moment_format__toISOString;
3330
+ momentPrototype__proto.toJSON = toJSON;
3331
+ momentPrototype__proto.toString = toString;
3332
+ momentPrototype__proto.unix = unix;
3333
+ momentPrototype__proto.valueOf = to_type__valueOf;
3334
+ momentPrototype__proto.creationData = creationData;
3335
+
3336
+ // Year
3337
+ momentPrototype__proto.year = getSetYear;
3338
+ momentPrototype__proto.isLeapYear = getIsLeapYear;
3339
+
3340
+ // Week Year
3341
+ momentPrototype__proto.weekYear = getSetWeekYear;
3342
+ momentPrototype__proto.isoWeekYear = getSetISOWeekYear;
3343
+
3344
+ // Quarter
3345
+ momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter;
3346
+
3347
+ // Month
3348
+ momentPrototype__proto.month = getSetMonth;
3349
+ momentPrototype__proto.daysInMonth = getDaysInMonth;
3350
+
3351
+ // Week
3352
+ momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek;
3353
+ momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek;
3354
+ momentPrototype__proto.weeksInYear = getWeeksInYear;
3355
+ momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear;
3356
+
3357
+ // Day
3358
+ momentPrototype__proto.date = getSetDayOfMonth;
3359
+ momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek;
3360
+ momentPrototype__proto.weekday = getSetLocaleDayOfWeek;
3361
+ momentPrototype__proto.isoWeekday = getSetISODayOfWeek;
3362
+ momentPrototype__proto.dayOfYear = getSetDayOfYear;
3363
+
3364
+ // Hour
3365
+ momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour;
3366
+
3367
+ // Minute
3368
+ momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute;
3369
+
3370
+ // Second
3371
+ momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond;
3372
+
3373
+ // Millisecond
3374
+ momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond;
3375
+
3376
+ // Offset
3377
+ momentPrototype__proto.utcOffset = getSetOffset;
3378
+ momentPrototype__proto.utc = setOffsetToUTC;
3379
+ momentPrototype__proto.local = setOffsetToLocal;
3380
+ momentPrototype__proto.parseZone = setOffsetToParsedOffset;
3381
+ momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset;
3382
+ momentPrototype__proto.isDST = isDaylightSavingTime;
3383
+ momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted;
3384
+ momentPrototype__proto.isLocal = isLocal;
3385
+ momentPrototype__proto.isUtcOffset = isUtcOffset;
3386
+ momentPrototype__proto.isUtc = isUtc;
3387
+ momentPrototype__proto.isUTC = isUtc;
3388
+
3389
+ // Timezone
3390
+ momentPrototype__proto.zoneAbbr = getZoneAbbr;
3391
+ momentPrototype__proto.zoneName = getZoneName;
3392
+
3393
+ // Deprecations
3394
+ momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
3395
+ momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
3396
+ momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
3397
+ momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone);
3398
+
3399
+ var momentPrototype = momentPrototype__proto;
3400
+
3401
+ function moment__createUnix (input) {
3402
+ return local__createLocal(input * 1000);
3403
+ }
3404
+
3405
+ function moment__createInZone () {
3406
+ return local__createLocal.apply(null, arguments).parseZone();
3407
+ }
3408
+
3409
+ var defaultCalendar = {
3410
+ sameDay : '[Today at] LT',
3411
+ nextDay : '[Tomorrow at] LT',
3412
+ nextWeek : 'dddd [at] LT',
3413
+ lastDay : '[Yesterday at] LT',
3414
+ lastWeek : '[Last] dddd [at] LT',
3415
+ sameElse : 'L'
3416
+ };
3417
+
3418
+ function locale_calendar__calendar (key, mom, now) {
3419
+ var output = this._calendar[key];
3420
+ return isFunction(output) ? output.call(mom, now) : output;
3421
+ }
3422
+
3423
+ var defaultLongDateFormat = {
3424
+ LTS : 'h:mm:ss A',
3425
+ LT : 'h:mm A',
3426
+ L : 'MM/DD/YYYY',
3427
+ LL : 'MMMM D, YYYY',
3428
+ LLL : 'MMMM D, YYYY h:mm A',
3429
+ LLLL : 'dddd, MMMM D, YYYY h:mm A'
3430
+ };
3431
+
3432
+ function longDateFormat (key) {
3433
+ var format = this._longDateFormat[key],
3434
+ formatUpper = this._longDateFormat[key.toUpperCase()];
3435
+
3436
+ if (format || !formatUpper) {
3437
+ return format;
3438
+ }
3439
+
3440
+ this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
3441
+ return val.slice(1);
3442
+ });
3443
+
3444
+ return this._longDateFormat[key];
3445
+ }
3446
+
3447
+ var defaultInvalidDate = 'Invalid date';
3448
+
3449
+ function invalidDate () {
3450
+ return this._invalidDate;
3451
+ }
3452
+
3453
+ var defaultOrdinal = '%d';
3454
+ var defaultOrdinalParse = /\d{1,2}/;
3455
+
3456
+ function ordinal (number) {
3457
+ return this._ordinal.replace('%d', number);
3458
+ }
3459
+
3460
+ function preParsePostFormat (string) {
3461
+ return string;
3462
+ }
3463
+
3464
+ var defaultRelativeTime = {
3465
+ future : 'in %s',
3466
+ past : '%s ago',
3467
+ s : 'a few seconds',
3468
+ m : 'a minute',
3469
+ mm : '%d minutes',
3470
+ h : 'an hour',
3471
+ hh : '%d hours',
3472
+ d : 'a day',
3473
+ dd : '%d days',
3474
+ M : 'a month',
3475
+ MM : '%d months',
3476
+ y : 'a year',
3477
+ yy : '%d years'
3478
+ };
3479
+
3480
+ function relative__relativeTime (number, withoutSuffix, string, isFuture) {
3481
+ var output = this._relativeTime[string];
3482
+ return (isFunction(output)) ?
3483
+ output(number, withoutSuffix, string, isFuture) :
3484
+ output.replace(/%d/i, number);
3485
+ }
3486
+
3487
+ function pastFuture (diff, output) {
3488
+ var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
3489
+ return isFunction(format) ? format(output) : format.replace(/%s/i, output);
3490
+ }
3491
+
3492
+ var prototype__proto = Locale.prototype;
3493
+
3494
+ prototype__proto._calendar = defaultCalendar;
3495
+ prototype__proto.calendar = locale_calendar__calendar;
3496
+ prototype__proto._longDateFormat = defaultLongDateFormat;
3497
+ prototype__proto.longDateFormat = longDateFormat;
3498
+ prototype__proto._invalidDate = defaultInvalidDate;
3499
+ prototype__proto.invalidDate = invalidDate;
3500
+ prototype__proto._ordinal = defaultOrdinal;
3501
+ prototype__proto.ordinal = ordinal;
3502
+ prototype__proto._ordinalParse = defaultOrdinalParse;
3503
+ prototype__proto.preparse = preParsePostFormat;
3504
+ prototype__proto.postformat = preParsePostFormat;
3505
+ prototype__proto._relativeTime = defaultRelativeTime;
3506
+ prototype__proto.relativeTime = relative__relativeTime;
3507
+ prototype__proto.pastFuture = pastFuture;
3508
+ prototype__proto.set = locale_set__set;
3509
+
3510
+ // Month
3511
+ prototype__proto.months = localeMonths;
3512
+ prototype__proto._months = defaultLocaleMonths;
3513
+ prototype__proto.monthsShort = localeMonthsShort;
3514
+ prototype__proto._monthsShort = defaultLocaleMonthsShort;
3515
+ prototype__proto.monthsParse = localeMonthsParse;
3516
+ prototype__proto._monthsRegex = defaultMonthsRegex;
3517
+ prototype__proto.monthsRegex = monthsRegex;
3518
+ prototype__proto._monthsShortRegex = defaultMonthsShortRegex;
3519
+ prototype__proto.monthsShortRegex = monthsShortRegex;
3520
+
3521
+ // Week
3522
+ prototype__proto.week = localeWeek;
3523
+ prototype__proto._week = defaultLocaleWeek;
3524
+ prototype__proto.firstDayOfYear = localeFirstDayOfYear;
3525
+ prototype__proto.firstDayOfWeek = localeFirstDayOfWeek;
3526
+
3527
+ // Day of Week
3528
+ prototype__proto.weekdays = localeWeekdays;
3529
+ prototype__proto._weekdays = defaultLocaleWeekdays;
3530
+ prototype__proto.weekdaysMin = localeWeekdaysMin;
3531
+ prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin;
3532
+ prototype__proto.weekdaysShort = localeWeekdaysShort;
3533
+ prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort;
3534
+ prototype__proto.weekdaysParse = localeWeekdaysParse;
3535
+
3536
+ prototype__proto._weekdaysRegex = defaultWeekdaysRegex;
3537
+ prototype__proto.weekdaysRegex = weekdaysRegex;
3538
+ prototype__proto._weekdaysShortRegex = defaultWeekdaysShortRegex;
3539
+ prototype__proto.weekdaysShortRegex = weekdaysShortRegex;
3540
+ prototype__proto._weekdaysMinRegex = defaultWeekdaysMinRegex;
3541
+ prototype__proto.weekdaysMinRegex = weekdaysMinRegex;
3542
+
3543
+ // Hours
3544
+ prototype__proto.isPM = localeIsPM;
3545
+ prototype__proto._meridiemParse = defaultLocaleMeridiemParse;
3546
+ prototype__proto.meridiem = localeMeridiem;
3547
+
3548
+ function lists__get (format, index, field, setter) {
3549
+ var locale = locale_locales__getLocale();
3550
+ var utc = create_utc__createUTC().set(setter, index);
3551
+ return locale[field](utc, format);
3552
+ }
3553
+
3554
+ function listMonthsImpl (format, index, field) {
3555
+ if (typeof format === 'number') {
3556
+ index = format;
3557
+ format = undefined;
3558
+ }
3559
+
3560
+ format = format || '';
3561
+
3562
+ if (index != null) {
3563
+ return lists__get(format, index, field, 'month');
3564
+ }
3565
+
3566
+ var i;
3567
+ var out = [];
3568
+ for (i = 0; i < 12; i++) {
3569
+ out[i] = lists__get(format, i, field, 'month');
3570
+ }
3571
+ return out;
3572
+ }
3573
+
3574
+ // ()
3575
+ // (5)
3576
+ // (fmt, 5)
3577
+ // (fmt)
3578
+ // (true)
3579
+ // (true, 5)
3580
+ // (true, fmt, 5)
3581
+ // (true, fmt)
3582
+ function listWeekdaysImpl (localeSorted, format, index, field) {
3583
+ if (typeof localeSorted === 'boolean') {
3584
+ if (typeof format === 'number') {
3585
+ index = format;
3586
+ format = undefined;
3587
+ }
3588
+
3589
+ format = format || '';
3590
+ } else {
3591
+ format = localeSorted;
3592
+ index = format;
3593
+ localeSorted = false;
3594
+
3595
+ if (typeof format === 'number') {
3596
+ index = format;
3597
+ format = undefined;
3598
+ }
3599
+
3600
+ format = format || '';
3601
+ }
3602
+
3603
+ var locale = locale_locales__getLocale(),
3604
+ shift = localeSorted ? locale._week.dow : 0;
3605
+
3606
+ if (index != null) {
3607
+ return lists__get(format, (index + shift) % 7, field, 'day');
3608
+ }
3609
+
3610
+ var i;
3611
+ var out = [];
3612
+ for (i = 0; i < 7; i++) {
3613
+ out[i] = lists__get(format, (i + shift) % 7, field, 'day');
3614
+ }
3615
+ return out;
3616
+ }
3617
+
3618
+ function lists__listMonths (format, index) {
3619
+ return listMonthsImpl(format, index, 'months');
3620
+ }
3621
+
3622
+ function lists__listMonthsShort (format, index) {
3623
+ return listMonthsImpl(format, index, 'monthsShort');
3624
+ }
3625
+
3626
+ function lists__listWeekdays (localeSorted, format, index) {
3627
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
3628
+ }
3629
+
3630
+ function lists__listWeekdaysShort (localeSorted, format, index) {
3631
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
3632
+ }
3633
+
3634
+ function lists__listWeekdaysMin (localeSorted, format, index) {
3635
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
3636
+ }
3637
+
3638
+ locale_locales__getSetGlobalLocale('en', {
3639
+ ordinalParse: /\d{1,2}(th|st|nd|rd)/,
3640
+ ordinal : function (number) {
3641
+ var b = number % 10,
3642
+ output = (toInt(number % 100 / 10) === 1) ? 'th' :
3643
+ (b === 1) ? 'st' :
3644
+ (b === 2) ? 'nd' :
3645
+ (b === 3) ? 'rd' : 'th';
3646
+ return number + output;
3647
+ }
3648
+ });
3649
+
3650
+ // Side effect imports
3651
+ utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale);
3652
+ utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale);
3653
+
3654
+ var mathAbs = Math.abs;
3655
+
3656
+ function duration_abs__abs () {
3657
+ var data = this._data;
3658
+
3659
+ this._milliseconds = mathAbs(this._milliseconds);
3660
+ this._days = mathAbs(this._days);
3661
+ this._months = mathAbs(this._months);
3662
+
3663
+ data.milliseconds = mathAbs(data.milliseconds);
3664
+ data.seconds = mathAbs(data.seconds);
3665
+ data.minutes = mathAbs(data.minutes);
3666
+ data.hours = mathAbs(data.hours);
3667
+ data.months = mathAbs(data.months);
3668
+ data.years = mathAbs(data.years);
3669
+
3670
+ return this;
3671
+ }
3672
+
3673
+ function duration_add_subtract__addSubtract (duration, input, value, direction) {
3674
+ var other = create__createDuration(input, value);
3675
+
3676
+ duration._milliseconds += direction * other._milliseconds;
3677
+ duration._days += direction * other._days;
3678
+ duration._months += direction * other._months;
3679
+
3680
+ return duration._bubble();
3681
+ }
3682
+
3683
+ // supports only 2.0-style add(1, 's') or add(duration)
3684
+ function duration_add_subtract__add (input, value) {
3685
+ return duration_add_subtract__addSubtract(this, input, value, 1);
3686
+ }
3687
+
3688
+ // supports only 2.0-style subtract(1, 's') or subtract(duration)
3689
+ function duration_add_subtract__subtract (input, value) {
3690
+ return duration_add_subtract__addSubtract(this, input, value, -1);
3691
+ }
3692
+
3693
+ function absCeil (number) {
3694
+ if (number < 0) {
3695
+ return Math.floor(number);
3696
+ } else {
3697
+ return Math.ceil(number);
3698
+ }
3699
+ }
3700
+
3701
+ function bubble () {
3702
+ var milliseconds = this._milliseconds;
3703
+ var days = this._days;
3704
+ var months = this._months;
3705
+ var data = this._data;
3706
+ var seconds, minutes, hours, years, monthsFromDays;
3707
+
3708
+ // if we have a mix of positive and negative values, bubble down first
3709
+ // check: https://github.com/moment/moment/issues/2166
3710
+ if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
3711
+ (milliseconds <= 0 && days <= 0 && months <= 0))) {
3712
+ milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
3713
+ days = 0;
3714
+ months = 0;
3715
+ }
3716
+
3717
+ // The following code bubbles up values, see the tests for
3718
+ // examples of what that means.
3719
+ data.milliseconds = milliseconds % 1000;
3720
+
3721
+ seconds = absFloor(milliseconds / 1000);
3722
+ data.seconds = seconds % 60;
3723
+
3724
+ minutes = absFloor(seconds / 60);
3725
+ data.minutes = minutes % 60;
3726
+
3727
+ hours = absFloor(minutes / 60);
3728
+ data.hours = hours % 24;
3729
+
3730
+ days += absFloor(hours / 24);
3731
+
3732
+ // convert days to months
3733
+ monthsFromDays = absFloor(daysToMonths(days));
3734
+ months += monthsFromDays;
3735
+ days -= absCeil(monthsToDays(monthsFromDays));
3736
+
3737
+ // 12 months -> 1 year
3738
+ years = absFloor(months / 12);
3739
+ months %= 12;
3740
+
3741
+ data.days = days;
3742
+ data.months = months;
3743
+ data.years = years;
3744
+
3745
+ return this;
3746
+ }
3747
+
3748
+ function daysToMonths (days) {
3749
+ // 400 years have 146097 days (taking into account leap year rules)
3750
+ // 400 years have 12 months === 4800
3751
+ return days * 4800 / 146097;
3752
+ }
3753
+
3754
+ function monthsToDays (months) {
3755
+ // the reverse of daysToMonths
3756
+ return months * 146097 / 4800;
3757
+ }
3758
+
3759
+ function as (units) {
3760
+ var days;
3761
+ var months;
3762
+ var milliseconds = this._milliseconds;
3763
+
3764
+ units = normalizeUnits(units);
3765
+
3766
+ if (units === 'month' || units === 'year') {
3767
+ days = this._days + milliseconds / 864e5;
3768
+ months = this._months + daysToMonths(days);
3769
+ return units === 'month' ? months : months / 12;
3770
+ } else {
3771
+ // handle milliseconds separately because of floating point math errors (issue #1867)
3772
+ days = this._days + Math.round(monthsToDays(this._months));
3773
+ switch (units) {
3774
+ case 'week' : return days / 7 + milliseconds / 6048e5;
3775
+ case 'day' : return days + milliseconds / 864e5;
3776
+ case 'hour' : return days * 24 + milliseconds / 36e5;
3777
+ case 'minute' : return days * 1440 + milliseconds / 6e4;
3778
+ case 'second' : return days * 86400 + milliseconds / 1000;
3779
+ // Math.floor prevents floating point math errors here
3780
+ case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
3781
+ default: throw new Error('Unknown unit ' + units);
3782
+ }
3783
+ }
3784
+ }
3785
+
3786
+ // TODO: Use this.as('ms')?
3787
+ function duration_as__valueOf () {
3788
+ return (
3789
+ this._milliseconds +
3790
+ this._days * 864e5 +
3791
+ (this._months % 12) * 2592e6 +
3792
+ toInt(this._months / 12) * 31536e6
3793
+ );
3794
+ }
3795
+
3796
+ function makeAs (alias) {
3797
+ return function () {
3798
+ return this.as(alias);
3799
+ };
3800
+ }
3801
+
3802
+ var asMilliseconds = makeAs('ms');
3803
+ var asSeconds = makeAs('s');
3804
+ var asMinutes = makeAs('m');
3805
+ var asHours = makeAs('h');
3806
+ var asDays = makeAs('d');
3807
+ var asWeeks = makeAs('w');
3808
+ var asMonths = makeAs('M');
3809
+ var asYears = makeAs('y');
3810
+
3811
+ function duration_get__get (units) {
3812
+ units = normalizeUnits(units);
3813
+ return this[units + 's']();
3814
+ }
3815
+
3816
+ function makeGetter(name) {
3817
+ return function () {
3818
+ return this._data[name];
3819
+ };
3820
+ }
3821
+
3822
+ var milliseconds = makeGetter('milliseconds');
3823
+ var seconds = makeGetter('seconds');
3824
+ var minutes = makeGetter('minutes');
3825
+ var hours = makeGetter('hours');
3826
+ var days = makeGetter('days');
3827
+ var months = makeGetter('months');
3828
+ var years = makeGetter('years');
3829
+
3830
+ function weeks () {
3831
+ return absFloor(this.days() / 7);
3832
+ }
3833
+
3834
+ var round = Math.round;
3835
+ var thresholds = {
3836
+ s: 45, // seconds to minute
3837
+ m: 45, // minutes to hour
3838
+ h: 22, // hours to day
3839
+ d: 26, // days to month
3840
+ M: 11 // months to year
3841
+ };
3842
+
3843
+ // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
3844
+ function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
3845
+ return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
3846
+ }
3847
+
3848
+ function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) {
3849
+ var duration = create__createDuration(posNegDuration).abs();
3850
+ var seconds = round(duration.as('s'));
3851
+ var minutes = round(duration.as('m'));
3852
+ var hours = round(duration.as('h'));
3853
+ var days = round(duration.as('d'));
3854
+ var months = round(duration.as('M'));
3855
+ var years = round(duration.as('y'));
3856
+
3857
+ var a = seconds < thresholds.s && ['s', seconds] ||
3858
+ minutes <= 1 && ['m'] ||
3859
+ minutes < thresholds.m && ['mm', minutes] ||
3860
+ hours <= 1 && ['h'] ||
3861
+ hours < thresholds.h && ['hh', hours] ||
3862
+ days <= 1 && ['d'] ||
3863
+ days < thresholds.d && ['dd', days] ||
3864
+ months <= 1 && ['M'] ||
3865
+ months < thresholds.M && ['MM', months] ||
3866
+ years <= 1 && ['y'] || ['yy', years];
3867
+
3868
+ a[2] = withoutSuffix;
3869
+ a[3] = +posNegDuration > 0;
3870
+ a[4] = locale;
3871
+ return substituteTimeAgo.apply(null, a);
3872
+ }
3873
+
3874
+ // This function allows you to set a threshold for relative time strings
3875
+ function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) {
3876
+ if (thresholds[threshold] === undefined) {
3877
+ return false;
3878
+ }
3879
+ if (limit === undefined) {
3880
+ return thresholds[threshold];
3881
+ }
3882
+ thresholds[threshold] = limit;
3883
+ return true;
3884
+ }
3885
+
3886
+ function humanize (withSuffix) {
3887
+ var locale = this.localeData();
3888
+ var output = duration_humanize__relativeTime(this, !withSuffix, locale);
3889
+
3890
+ if (withSuffix) {
3891
+ output = locale.pastFuture(+this, output);
3892
+ }
3893
+
3894
+ return locale.postformat(output);
3895
+ }
3896
+
3897
+ var iso_string__abs = Math.abs;
3898
+
3899
+ function iso_string__toISOString() {
3900
+ // for ISO strings we do not use the normal bubbling rules:
3901
+ // * milliseconds bubble up until they become hours
3902
+ // * days do not bubble at all
3903
+ // * months bubble up until they become years
3904
+ // This is because there is no context-free conversion between hours and days
3905
+ // (think of clock changes)
3906
+ // and also not between days and months (28-31 days per month)
3907
+ var seconds = iso_string__abs(this._milliseconds) / 1000;
3908
+ var days = iso_string__abs(this._days);
3909
+ var months = iso_string__abs(this._months);
3910
+ var minutes, hours, years;
3911
+
3912
+ // 3600 seconds -> 60 minutes -> 1 hour
3913
+ minutes = absFloor(seconds / 60);
3914
+ hours = absFloor(minutes / 60);
3915
+ seconds %= 60;
3916
+ minutes %= 60;
3917
+
3918
+ // 12 months -> 1 year
3919
+ years = absFloor(months / 12);
3920
+ months %= 12;
3921
+
3922
+
3923
+ // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
3924
+ var Y = years;
3925
+ var M = months;
3926
+ var D = days;
3927
+ var h = hours;
3928
+ var m = minutes;
3929
+ var s = seconds;
3930
+ var total = this.asSeconds();
3931
+
3932
+ if (!total) {
3933
+ // this is the same as C#'s (Noda) and python (isodate)...
3934
+ // but not other JS (goog.date)
3935
+ return 'P0D';
3936
+ }
3937
+
3938
+ return (total < 0 ? '-' : '') +
3939
+ 'P' +
3940
+ (Y ? Y + 'Y' : '') +
3941
+ (M ? M + 'M' : '') +
3942
+ (D ? D + 'D' : '') +
3943
+ ((h || m || s) ? 'T' : '') +
3944
+ (h ? h + 'H' : '') +
3945
+ (m ? m + 'M' : '') +
3946
+ (s ? s + 'S' : '');
3947
+ }
3948
+
3949
+ var duration_prototype__proto = Duration.prototype;
3950
+
3951
+ duration_prototype__proto.abs = duration_abs__abs;
3952
+ duration_prototype__proto.add = duration_add_subtract__add;
3953
+ duration_prototype__proto.subtract = duration_add_subtract__subtract;
3954
+ duration_prototype__proto.as = as;
3955
+ duration_prototype__proto.asMilliseconds = asMilliseconds;
3956
+ duration_prototype__proto.asSeconds = asSeconds;
3957
+ duration_prototype__proto.asMinutes = asMinutes;
3958
+ duration_prototype__proto.asHours = asHours;
3959
+ duration_prototype__proto.asDays = asDays;
3960
+ duration_prototype__proto.asWeeks = asWeeks;
3961
+ duration_prototype__proto.asMonths = asMonths;
3962
+ duration_prototype__proto.asYears = asYears;
3963
+ duration_prototype__proto.valueOf = duration_as__valueOf;
3964
+ duration_prototype__proto._bubble = bubble;
3965
+ duration_prototype__proto.get = duration_get__get;
3966
+ duration_prototype__proto.milliseconds = milliseconds;
3967
+ duration_prototype__proto.seconds = seconds;
3968
+ duration_prototype__proto.minutes = minutes;
3969
+ duration_prototype__proto.hours = hours;
3970
+ duration_prototype__proto.days = days;
3971
+ duration_prototype__proto.weeks = weeks;
3972
+ duration_prototype__proto.months = months;
3973
+ duration_prototype__proto.years = years;
3974
+ duration_prototype__proto.humanize = humanize;
3975
+ duration_prototype__proto.toISOString = iso_string__toISOString;
3976
+ duration_prototype__proto.toString = iso_string__toISOString;
3977
+ duration_prototype__proto.toJSON = iso_string__toISOString;
3978
+ duration_prototype__proto.locale = locale;
3979
+ duration_prototype__proto.localeData = localeData;
3980
+
3981
+ // Deprecations
3982
+ duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString);
3983
+ duration_prototype__proto.lang = lang;
3984
+
3985
+ // Side effect imports
3986
+
3987
+ // FORMATTING
3988
+
3989
+ addFormatToken('X', 0, 0, 'unix');
3990
+ addFormatToken('x', 0, 0, 'valueOf');
3991
+
3992
+ // PARSING
3993
+
3994
+ addRegexToken('x', matchSigned);
3995
+ addRegexToken('X', matchTimestamp);
3996
+ addParseToken('X', function (input, array, config) {
3997
+ config._d = new Date(parseFloat(input, 10) * 1000);
3998
+ });
3999
+ addParseToken('x', function (input, array, config) {
4000
+ config._d = new Date(toInt(input));
4001
+ });
4002
+
4003
+ // Side effect imports
4004
+
4005
+
4006
+ utils_hooks__hooks.version = '2.13.0';
4007
+
4008
+ setHookCallback(local__createLocal);
4009
+
4010
+ utils_hooks__hooks.fn = momentPrototype;
4011
+ utils_hooks__hooks.min = min;
4012
+ utils_hooks__hooks.max = max;
4013
+ utils_hooks__hooks.now = now;
4014
+ utils_hooks__hooks.utc = create_utc__createUTC;
4015
+ utils_hooks__hooks.unix = moment__createUnix;
4016
+ utils_hooks__hooks.months = lists__listMonths;
4017
+ utils_hooks__hooks.isDate = isDate;
4018
+ utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale;
4019
+ utils_hooks__hooks.invalid = valid__createInvalid;
4020
+ utils_hooks__hooks.duration = create__createDuration;
4021
+ utils_hooks__hooks.isMoment = isMoment;
4022
+ utils_hooks__hooks.weekdays = lists__listWeekdays;
4023
+ utils_hooks__hooks.parseZone = moment__createInZone;
4024
+ utils_hooks__hooks.localeData = locale_locales__getLocale;
4025
+ utils_hooks__hooks.isDuration = isDuration;
4026
+ utils_hooks__hooks.monthsShort = lists__listMonthsShort;
4027
+ utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin;
4028
+ utils_hooks__hooks.defineLocale = defineLocale;
4029
+ utils_hooks__hooks.updateLocale = updateLocale;
4030
+ utils_hooks__hooks.locales = locale_locales__listLocales;
4031
+ utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort;
4032
+ utils_hooks__hooks.normalizeUnits = normalizeUnits;
4033
+ utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold;
4034
+ utils_hooks__hooks.prototype = momentPrototype;
4035
+
4036
+ var _moment = utils_hooks__hooks;
4037
+
4038
+ return _moment;
4039
+
4040
+ }));
bp-core/js/vendor/moment.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ !function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return fd.apply(null,arguments)}function b(a){fd=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function f(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function g(a,b){for(var c in b)f(b,c)&&(a[c]=b[c]);return f(b,"toString")&&(a.toString=b.toString),f(b,"valueOf")&&(a.valueOf=b.valueOf),a}function h(a,b,c,d){return Ja(a,b,c,d,!0).utc()}function i(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function j(a){return null==a._pf&&(a._pf=i()),a._pf}function k(a){if(null==a._isValid){var b=j(a),c=gd.call(b.parsedDateParts,function(a){return null!=a});a._isValid=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c),a._strict&&(a._isValid=a._isValid&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour)}return a._isValid}function l(a){var b=h(NaN);return null!=a?g(j(b),a):j(b).userInvalidated=!0,b}function m(a){return void 0===a}function n(a,b){var c,d,e;if(m(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),m(b._i)||(a._i=b._i),m(b._f)||(a._f=b._f),m(b._l)||(a._l=b._l),m(b._strict)||(a._strict=b._strict),m(b._tzm)||(a._tzm=b._tzm),m(b._isUTC)||(a._isUTC=b._isUTC),m(b._offset)||(a._offset=b._offset),m(b._pf)||(a._pf=j(b)),m(b._locale)||(a._locale=b._locale),hd.length>0)for(c in hd)d=hd[c],e=b[d],m(e)||(a[d]=e);return a}function o(b){n(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),id===!1&&(id=!0,a.updateOffset(this),id=!1)}function p(a){return a instanceof o||null!=a&&null!=a._isAMomentObject}function q(a){return a<0?Math.ceil(a):Math.floor(a)}function r(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=q(b)),c}function s(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d<e;d++)(c&&a[d]!==b[d]||!c&&r(a[d])!==r(b[d]))&&g++;return g+f}function t(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function u(b,c){var d=!0;return g(function(){return null!=a.deprecationHandler&&a.deprecationHandler(null,b),d&&(t(b+"\nArguments: "+Array.prototype.slice.call(arguments).join(", ")+"\n"+(new Error).stack),d=!1),c.apply(this,arguments)},c)}function v(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),jd[b]||(t(c),jd[b]=!0)}function w(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function x(a){return"[object Object]"===Object.prototype.toString.call(a)}function y(a){var b,c;for(c in a)b=a[c],w(b)?this[c]=b:this["_"+c]=b;this._config=a,this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function z(a,b){var c,d=g({},a);for(c in b)f(b,c)&&(x(a[c])&&x(b[c])?(d[c]={},g(d[c],a[c]),g(d[c],b[c])):null!=b[c]?d[c]=b[c]:delete d[c]);return d}function A(a){null!=a&&this.set(a)}function B(a){return a?a.toLowerCase().replace("_","-"):a}function C(a){for(var b,c,d,e,f=0;f<a.length;){for(e=B(a[f]).split("-"),b=e.length,c=B(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=D(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&s(e,c,!0)>=b-1)break;b--}f++}return null}function D(a){var b=null;if(!nd[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=ld._abbr,require("./locale/"+a),E(b)}catch(a){}return nd[a]}function E(a,b){var c;return a&&(c=m(b)?H(a):F(a,b),c&&(ld=c)),ld._abbr}function F(a,b){return null!==b?(b.abbr=a,null!=nd[a]?(v("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale"),b=z(nd[a]._config,b)):null!=b.parentLocale&&(null!=nd[b.parentLocale]?b=z(nd[b.parentLocale]._config,b):v("parentLocaleUndefined","specified parentLocale is not defined yet")),nd[a]=new A(b),E(a),nd[a]):(delete nd[a],null)}function G(a,b){if(null!=b){var c;null!=nd[a]&&(b=z(nd[a]._config,b)),c=new A(b),c.parentLocale=nd[a],nd[a]=c,E(a)}else null!=nd[a]&&(null!=nd[a].parentLocale?nd[a]=nd[a].parentLocale:null!=nd[a]&&delete nd[a]);return nd[a]}function H(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return ld;if(!c(a)){if(b=D(a))return b;a=[a]}return C(a)}function I(){return kd(nd)}function J(a,b){var c=a.toLowerCase();od[c]=od[c+"s"]=od[b]=a}function K(a){return"string"==typeof a?od[a]||od[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)f(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(b,c){return function(d){return null!=d?(O(this,b,d),a.updateOffset(this,c),this):N(this,b)}}function N(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function O(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}function P(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=K(a),w(this[a]))return this[a](b);return this}function Q(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function R(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(sd[a]=e),b&&(sd[b[0]]=function(){return Q(e.apply(this,arguments),b[1],b[2])}),c&&(sd[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function S(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function T(a){var b,c,d=a.match(pd);for(b=0,c=d.length;b<c;b++)sd[d[b]]?d[b]=sd[d[b]]:d[b]=S(d[b]);return function(b){var e,f="";for(e=0;e<c;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}function U(a,b){return a.isValid()?(b=V(b,a.localeData()),rd[b]=rd[b]||T(b),rd[b](a)):a.localeData().invalidDate()}function V(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(qd.lastIndex=0;d>=0&&qd.test(a);)a=a.replace(qd,c),qd.lastIndex=0,d-=1;return a}function W(a,b,c){Kd[a]=w(b)?b:function(a,d){return a&&c?c:b}}function X(a,b){return f(Kd,a)?Kd[a](b._strict,b._locale):new RegExp(Y(a))}function Y(a){return Z(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function Z(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function $(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=r(a)}),c=0;c<a.length;c++)Ld[a[c]]=d}function _(a,b){$(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function aa(a,b,c){null!=b&&f(Ld,a)&&Ld[a](b,c._a,c,a)}function ba(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function ca(a,b){return c(this._months)?this._months[a.month()]:this._months[Vd.test(b)?"format":"standalone"][a.month()]}function da(a,b){return c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[Vd.test(b)?"format":"standalone"][a.month()]}function ea(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;d<12;++d)f=h([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,"").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,"").toLocaleLowerCase();return c?"MMM"===b?(e=md.call(this._shortMonthsParse,g),e!==-1?e:null):(e=md.call(this._longMonthsParse,g),e!==-1?e:null):"MMM"===b?(e=md.call(this._shortMonthsParse,g),e!==-1?e:(e=md.call(this._longMonthsParse,g),e!==-1?e:null)):(e=md.call(this._longMonthsParse,g),e!==-1?e:(e=md.call(this._shortMonthsParse,g),e!==-1?e:null))}function fa(a,b,c){var d,e,f;if(this._monthsParseExact)return ea.call(this,a,b,c);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;d<12;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function ga(a,b){var c;if(!a.isValid())return a;if("string"==typeof b)if(/^\d+$/.test(b))b=r(b);else if(b=a.localeData().monthsParse(b),"number"!=typeof b)return a;return c=Math.min(a.date(),ba(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a}function ha(b){return null!=b?(ga(this,b),a.updateOffset(this,!0),this):N(this,"Month")}function ia(){return ba(this.year(),this.month())}function ja(a){return this._monthsParseExact?(f(this,"_monthsRegex")||la.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex}function ka(a){return this._monthsParseExact?(f(this,"_monthsRegex")||la.call(this),a?this._monthsStrictRegex:this._monthsRegex):this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex}function la(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;b<12;b++)c=h([2e3,b]),d.push(this.monthsShort(c,"")),e.push(this.months(c,"")),f.push(this.months(c,"")),f.push(this.monthsShort(c,""));for(d.sort(a),e.sort(a),f.sort(a),b=0;b<12;b++)d[b]=Z(d[b]),e[b]=Z(e[b]),f[b]=Z(f[b]);this._monthsRegex=new RegExp("^("+f.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+e.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+d.join("|")+")","i")}function ma(a){var b,c=a._a;return c&&j(a).overflow===-2&&(b=c[Nd]<0||c[Nd]>11?Nd:c[Od]<1||c[Od]>ba(c[Md],c[Nd])?Od:c[Pd]<0||c[Pd]>24||24===c[Pd]&&(0!==c[Qd]||0!==c[Rd]||0!==c[Sd])?Pd:c[Qd]<0||c[Qd]>59?Qd:c[Rd]<0||c[Rd]>59?Rd:c[Sd]<0||c[Sd]>999?Sd:-1,j(a)._overflowDayOfYear&&(b<Md||b>Od)&&(b=Od),j(a)._overflowWeeks&&b===-1&&(b=Td),j(a)._overflowWeekday&&b===-1&&(b=Ud),j(a).overflow=b),a}function na(a){var b,c,d,e,f,g,h=a._i,i=$d.exec(h)||_d.exec(h);if(i){for(j(a).iso=!0,b=0,c=be.length;b<c;b++)if(be[b][1].exec(i[1])){e=be[b][0],d=be[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=ce.length;b<c;b++)if(ce[b][1].exec(i[3])){f=(i[2]||" ")+ce[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!ae.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),Ca(a)}else a._isValid=!1}function oa(b){var c=de.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(na(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function pa(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return a<100&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function qa(a){var b=new Date(Date.UTC.apply(null,arguments));return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}function ra(a){return sa(a)?366:365}function sa(a){return a%4===0&&a%100!==0||a%400===0}function ta(){return sa(this.year())}function ua(a,b,c){var d=7+b-c,e=(7+qa(a,0,d).getUTCDay()-b)%7;return-e+d-1}function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=ra(f)+j):j>ra(a)?(f=a+1,g=j-ra(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(ra(a)-d+e)/7}function ya(a,b,c){return null!=a?a:null!=b?b:c}function za(b){var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}function Aa(a){var b,c,d,e,f=[];if(!a._d){for(d=za(a),a._w&&null==a._a[Od]&&null==a._a[Nd]&&Ba(a),a._dayOfYear&&(e=ya(a._a[Md],d[Md]),a._dayOfYear>ra(e)&&(j(a)._overflowDayOfYear=!0),c=qa(e,0,a._dayOfYear),a._a[Nd]=c.getUTCMonth(),a._a[Od]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[Pd]&&0===a._a[Qd]&&0===a._a[Rd]&&0===a._a[Sd]&&(a._nextDay=!0,a._a[Pd]=0),a._d=(a._useUTC?qa:pa).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[Pd]=24)}}function Ba(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=ya(b.GG,a._a[Md],wa(Ka(),1,4).year),d=ya(b.W,1),e=ya(b.E,1),(e<1||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=ya(b.gg,a._a[Md],wa(Ka(),f,g).year),d=ya(b.w,1),null!=b.d?(e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):e=f),d<1||d>xa(c,f,g)?j(a)._overflowWeeks=!0:null!=i?j(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[Md]=h.year,a._dayOfYear=h.dayOfYear)}function Ca(b){if(b._f===a.ISO_8601)return void na(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=V(b._f,b._locale).match(pd)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(X(f,b))||[])[0],d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),sd[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),aa(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[Pd]<=12&&b._a[Pd]>0&&(j(b).bigHour=void 0),j(b).parsedDateParts=b._a.slice(0),j(b).meridiem=b._meridiem,b._a[Pd]=Da(b._locale,b._a[Pd],b._meridiem),Aa(b),ma(b)}function Da(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}function Ea(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=n({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],Ca(b),k(b)&&(f+=j(b).charsLeftOver,f+=10*j(b).unusedTokens.length,j(b).score=f,(null==d||f<d)&&(d=f,c=b));g(a,c||b)}function Fa(a){if(!a._d){var b=L(a._i);a._a=e([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),Aa(a)}}function Ga(a){var b=new o(ma(Ha(a)));return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function Ha(a){var b=a._i,e=a._f;return a._locale=a._locale||H(a._l),null===b||void 0===e&&""===b?l({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),p(b)?new o(ma(b)):(c(e)?Ea(a):e?Ca(a):d(b)?a._d=b:Ia(a),k(a)||(a._d=null),a))}function Ia(b){var f=b._i;void 0===f?b._d=new Date(a.now()):d(f)?b._d=new Date(f.valueOf()):"string"==typeof f?oa(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),Aa(b)):"object"==typeof f?Fa(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function Ja(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,Ga(f)}function Ka(a,b,c,d){return Ja(a,b,c,d,!1)}function La(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Ka();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}function Ma(){var a=[].slice.call(arguments,0);return La("isBefore",a)}function Na(){var a=[].slice.call(arguments,0);return La("isAfter",a)}function Oa(a){var b=L(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+1e3*h*60*60,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=H(),this._bubble()}function Pa(a){return a instanceof Oa}function Qa(a,b){R(a,0,0,function(){var a=this.utcOffset(),c="+";return a<0&&(a=-a,c="-"),c+Q(~~(a/60),2)+b+Q(~~a%60,2)})}function Ra(a,b){var c=(b||"").match(a)||[],d=c[c.length-1]||[],e=(d+"").match(ie)||["-",0,0],f=+(60*e[1])+r(e[2]);return"+"===e[0]?f:-f}function Sa(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(p(b)||d(b)?b.valueOf():Ka(b).valueOf())-e.valueOf(),e._d.setTime(e._d.valueOf()+f),a.updateOffset(e,!1),e):Ka(b).local()}function Ta(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Ua(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?("string"==typeof b?b=Ra(Hd,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ta(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?jb(this,db(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ta(this):null!=b?this:NaN}function Va(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Wa(a){return this.utcOffset(0,a)}function Xa(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ta(this),"m")),this}function Ya(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ra(Gd,this._i)),this}function Za(a){return!!this.isValid()&&(a=a?Ka(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function $a(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function _a(){if(!m(this._isDSTShifted))return this._isDSTShifted;var a={};if(n(a,this),a=Ha(a),a._a){var b=a._isUTC?h(a._a):Ka(a._a);this._isDSTShifted=this.isValid()&&s(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function ab(){return!!this.isValid()&&!this._isUTC}function bb(){return!!this.isValid()&&this._isUTC}function cb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function db(a,b){var c,d,e,g=a,h=null;return Pa(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=je.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:r(h[Od])*c,h:r(h[Pd])*c,m:r(h[Qd])*c,s:r(h[Rd])*c,ms:r(h[Sd])*c}):(h=ke.exec(a))?(c="-"===h[1]?-1:1,g={y:eb(h[2],c),M:eb(h[3],c),w:eb(h[4],c),d:eb(h[5],c),h:eb(h[6],c),m:eb(h[7],c),s:eb(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=gb(Ka(g.from),Ka(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Oa(g),Pa(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function eb(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function fb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function gb(a,b){var c;return a.isValid()&&b.isValid()?(b=Sa(b,a),a.isBefore(b)?c=fb(a,b):(c=fb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}function hb(a){return a<0?Math.round(-1*a)*-1:Math.round(a)}function ib(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(v(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=db(c,d),jb(this,e,a),this}}function jb(b,c,d,e){var f=c._milliseconds,g=hb(c._days),h=hb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&O(b,"Date",N(b,"Date")+g*d),h&&ga(b,N(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function kb(a,b){var c=a||Ka(),d=Sa(c,this).startOf("day"),e=this.diff(d,"days",!0),f=e<-6?"sameElse":e<-1?"lastWeek":e<0?"lastDay":e<1?"sameDay":e<2?"nextDay":e<7?"nextWeek":"sameElse",g=b&&(w(b[f])?b[f]():b[f]);return this.format(g||this.localeData().calendar(f,this,Ka(c)))}function lb(){return new o(this)}function mb(a,b){var c=p(a)?a:Ka(a);return!(!this.isValid()||!c.isValid())&&(b=K(m(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf())}function nb(a,b){var c=p(a)?a:Ka(a);return!(!this.isValid()||!c.isValid())&&(b=K(m(b)?"millisecond":b),"millisecond"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf())}function ob(a,b,c,d){return d=d||"()",("("===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(")"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function pb(a,b){var c,d=p(a)?a:Ka(a);return!(!this.isValid()||!d.isValid())&&(b=K(b||"millisecond"),"millisecond"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf()))}function qb(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function rb(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function sb(a,b,c){var d,e,f,g;return this.isValid()?(d=Sa(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=K(b),"year"===b||"month"===b||"quarter"===b?(g=tb(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:q(g)):NaN):NaN}function tb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return b-f<0?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)||0}function ub(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function vb(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?w(Date.prototype.toISOString)?this.toDate().toISOString():U(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):U(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function wb(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=U(this,b);return this.localeData().postformat(c)}function xb(a,b){return this.isValid()&&(p(a)&&a.isValid()||Ka(a).isValid())?db({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function yb(a){return this.from(Ka(),a)}function zb(a,b){return this.isValid()&&(p(a)&&a.isValid()||Ka(a).isValid())?db({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function Ab(a){return this.to(Ka(),a)}function Bb(a){var b;return void 0===a?this._locale._abbr:(b=H(a),null!=b&&(this._locale=b),this)}function Cb(){return this._locale}function Db(a){switch(a=K(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function Eb(a){return a=K(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function Fb(){return this._d.valueOf()-6e4*(this._offset||0)}function Gb(){return Math.floor(this.valueOf()/1e3)}function Hb(){return this._offset?new Date(this.valueOf()):this._d}function Ib(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function Jb(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function Kb(){return this.isValid()?this.toISOString():null}function Lb(){return k(this)}function Mb(){return g({},j(this))}function Nb(){return j(this).overflow}function Ob(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Pb(a,b){R(0,[a,a.length],0,b)}function Qb(a){return Ub.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Rb(a){return Ub.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Sb(){return xa(this.year(),1,4)}function Tb(){var a=this.localeData()._week;return xa(this.year(),a.dow,a.doy)}function Ub(a,b,c,d,e){var f;return null==a?wa(this,d,e).year:(f=xa(a,d,e),b>f&&(b=f),Vb.call(this,a,b,c,d,e))}function Vb(a,b,c,d,e){var f=va(a,b,c,d,e),g=qa(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}function Wb(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Xb(a){return wa(a,this._week.dow,this._week.doy).week}function Yb(){return this._week.dow}function Zb(){return this._week.doy}function $b(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function _b(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function ac(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function bc(a,b){return c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]}function cc(a){return this._weekdaysShort[a.day()]}function dc(a){return this._weekdaysMin[a.day()]}function ec(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=h([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=md.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=md.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=md.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=md.call(this._weekdaysParse,g),e!==-1?e:(e=md.call(this._shortWeekdaysParse,g),e!==-1?e:(e=md.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=md.call(this._shortWeekdaysParse,g),e!==-1?e:(e=md.call(this._weekdaysParse,g),e!==-1?e:(e=md.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=md.call(this._minWeekdaysParse,g),e!==-1?e:(e=md.call(this._weekdaysParse,g),e!==-1?e:(e=md.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function fc(a,b,c){var d,e,f;if(this._weekdaysParseExact)return ec.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){if(e=h([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}function gc(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=ac(a,this.localeData()),this.add(a-b,"d")):b}function hc(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function ic(a){return this.isValid()?null==a?this.day()||7:this.day(this.day()%7?a:a-7):null!=a?this:NaN}function jc(a){return this._weekdaysParseExact?(f(this,"_weekdaysRegex")||mc.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex}function kc(a){return this._weekdaysParseExact?(f(this,"_weekdaysRegex")||mc.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex}function lc(a){return this._weekdaysParseExact?(f(this,"_weekdaysRegex")||mc.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex}function mc(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],i=[],j=[],k=[];for(b=0;b<7;b++)c=h([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),i.push(e),j.push(f),k.push(d),k.push(e),k.push(f);for(g.sort(a),i.sort(a),j.sort(a),k.sort(a),b=0;b<7;b++)i[b]=Z(i[b]),j[b]=Z(j[b]),k[b]=Z(k[b]);this._weekdaysRegex=new RegExp("^("+k.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}function nc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function oc(){return this.hours()%12||12}function pc(){return this.hours()||24}function qc(a,b){R(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function rc(a,b){return b._meridiemParse}function sc(a){return"p"===(a+"").toLowerCase().charAt(0)}function tc(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function uc(a,b){b[Sd]=r(1e3*("0."+a))}function vc(){return this._isUTC?"UTC":""}function wc(){return this._isUTC?"Coordinated Universal Time":""}function xc(a){return Ka(1e3*a)}function yc(){return Ka.apply(null,arguments).parseZone()}function zc(a,b,c){var d=this._calendar[a];return w(d)?d.call(b,c):d}function Ac(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function Bc(){return this._invalidDate}function Cc(a){return this._ordinal.replace("%d",a)}function Dc(a){return a}function Ec(a,b,c,d){var e=this._relativeTime[c];return w(e)?e(a,b,c,d):e.replace(/%d/i,a)}function Fc(a,b){var c=this._relativeTime[a>0?"future":"past"];return w(c)?c(b):c.replace(/%s/i,b)}function Gc(a,b,c,d){var e=H(),f=h().set(d,b);return e[c](f,a)}function Hc(a,b,c){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return Gc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Gc(a,d,c,"month");return e}function Ic(a,b,c,d){"boolean"==typeof a?("number"==typeof b&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,"number"==typeof b&&(c=b,b=void 0),b=b||"");var e=H(),f=a?e._week.dow:0;if(null!=c)return Gc(b,(c+f)%7,d,"day");var g,h=[];for(g=0;g<7;g++)h[g]=Gc(b,(g+f)%7,d,"day");return h}function Jc(a,b){return Hc(a,b,"months")}function Kc(a,b){return Hc(a,b,"monthsShort")}function Lc(a,b,c){return Ic(a,b,c,"weekdays")}function Mc(a,b,c){return Ic(a,b,c,"weekdaysShort")}function Nc(a,b,c){return Ic(a,b,c,"weekdaysMin")}function Oc(){var a=this._data;return this._milliseconds=Le(this._milliseconds),this._days=Le(this._days),this._months=Le(this._months),a.milliseconds=Le(a.milliseconds),a.seconds=Le(a.seconds),a.minutes=Le(a.minutes),a.hours=Le(a.hours),a.months=Le(a.months),a.years=Le(a.years),this}function Pc(a,b,c,d){var e=db(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function Qc(a,b){return Pc(this,a,b,1)}function Rc(a,b){return Pc(this,a,b,-1)}function Sc(a){return a<0?Math.floor(a):Math.ceil(a)}function Tc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*Sc(Vc(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=q(f/1e3),i.seconds=a%60,b=q(a/60),i.minutes=b%60,c=q(b/60),i.hours=c%24,g+=q(c/24),e=q(Uc(g)),h+=e,g-=Sc(Vc(e)),d=q(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function Uc(a){return 4800*a/146097}function Vc(a){return 146097*a/4800}function Wc(a){var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+Uc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(Vc(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function Xc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*r(this._months/12)}function Yc(a){return function(){return this.as(a)}}function Zc(a){
2
+ return a=K(a),this[a+"s"]()}function $c(a){return function(){return this._data[a]}}function _c(){return q(this.days()/7)}function ad(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function bd(a,b,c){var d=db(a).abs(),e=_e(d.as("s")),f=_e(d.as("m")),g=_e(d.as("h")),h=_e(d.as("d")),i=_e(d.as("M")),j=_e(d.as("y")),k=e<af.s&&["s",e]||f<=1&&["m"]||f<af.m&&["mm",f]||g<=1&&["h"]||g<af.h&&["hh",g]||h<=1&&["d"]||h<af.d&&["dd",h]||i<=1&&["M"]||i<af.M&&["MM",i]||j<=1&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,ad.apply(null,k)}function cd(a,b){return void 0!==af[a]&&(void 0===b?af[a]:(af[a]=b,!0))}function dd(a){var b=this.localeData(),c=bd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function ed(){var a,b,c,d=bf(this._milliseconds)/1e3,e=bf(this._days),f=bf(this._months);a=q(d/60),b=q(a/60),d%=60,a%=60,c=q(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var fd,gd;gd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d<c;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};var hd=a.momentProperties=[],id=!1,jd={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var kd;kd=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)f(a,b)&&c.push(b);return c};var ld,md,nd={},od={},pd=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,qd=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,rd={},sd={},td=/\d/,ud=/\d\d/,vd=/\d{3}/,wd=/\d{4}/,xd=/[+-]?\d{6}/,yd=/\d\d?/,zd=/\d\d\d\d?/,Ad=/\d\d\d\d\d\d?/,Bd=/\d{1,3}/,Cd=/\d{1,4}/,Dd=/[+-]?\d{1,6}/,Ed=/\d+/,Fd=/[+-]?\d+/,Gd=/Z|[+-]\d\d:?\d\d/gi,Hd=/Z|[+-]\d\d(?::?\d\d)?/gi,Id=/[+-]?\d+(\.\d{1,3})?/,Jd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Kd={},Ld={},Md=0,Nd=1,Od=2,Pd=3,Qd=4,Rd=5,Sd=6,Td=7,Ud=8;md=Array.prototype.indexOf?Array.prototype.indexOf:function(a){var b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1},R("M",["MM",2],"Mo",function(){return this.month()+1}),R("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),R("MMMM",0,0,function(a){return this.localeData().months(this,a)}),J("month","M"),W("M",yd),W("MM",yd,ud),W("MMM",function(a,b){return b.monthsShortRegex(a)}),W("MMMM",function(a,b){return b.monthsRegex(a)}),$(["M","MM"],function(a,b){b[Nd]=r(a)-1}),$(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[Nd]=e:j(c).invalidMonth=a});var Vd=/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/,Wd="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),Xd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),Yd=Jd,Zd=Jd,$d=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,_d=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,ae=/Z|[+-]\d\d(?::?\d\d)?/,be=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],ce=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],de=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=u("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),R("Y",0,0,function(){var a=this.year();return a<=9999?""+a:"+"+a}),R(0,["YY",2],0,function(){return this.year()%100}),R(0,["YYYY",4],0,"year"),R(0,["YYYYY",5],0,"year"),R(0,["YYYYYY",6,!0],0,"year"),J("year","y"),W("Y",Fd),W("YY",yd,ud),W("YYYY",Cd,wd),W("YYYYY",Dd,xd),W("YYYYYY",Dd,xd),$(["YYYYY","YYYYYY"],Md),$("YYYY",function(b,c){c[Md]=2===b.length?a.parseTwoDigitYear(b):r(b)}),$("YY",function(b,c){c[Md]=a.parseTwoDigitYear(b)}),$("Y",function(a,b){b[Md]=parseInt(a,10)}),a.parseTwoDigitYear=function(a){return r(a)+(r(a)>68?1900:2e3)};var ee=M("FullYear",!0);a.ISO_8601=function(){};var fe=u("moment().min is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Ka.apply(null,arguments);return this.isValid()&&a.isValid()?a<this?this:a:l()}),ge=u("moment().max is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Ka.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:l()}),he=function(){return Date.now?Date.now():+new Date};Qa("Z",":"),Qa("ZZ",""),W("Z",Hd),W("ZZ",Hd),$(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ra(Hd,a)});var ie=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var je=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/,ke=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;db.fn=Oa.prototype;var le=ib(1,"add"),me=ib(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var ne=u("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});R(0,["gg",2],0,function(){return this.weekYear()%100}),R(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Pb("gggg","weekYear"),Pb("ggggg","weekYear"),Pb("GGGG","isoWeekYear"),Pb("GGGGG","isoWeekYear"),J("weekYear","gg"),J("isoWeekYear","GG"),W("G",Fd),W("g",Fd),W("GG",yd,ud),W("gg",yd,ud),W("GGGG",Cd,wd),W("gggg",Cd,wd),W("GGGGG",Dd,xd),W("ggggg",Dd,xd),_(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=r(a)}),_(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),R("Q",0,"Qo","quarter"),J("quarter","Q"),W("Q",td),$("Q",function(a,b){b[Nd]=3*(r(a)-1)}),R("w",["ww",2],"wo","week"),R("W",["WW",2],"Wo","isoWeek"),J("week","w"),J("isoWeek","W"),W("w",yd),W("ww",yd,ud),W("W",yd),W("WW",yd,ud),_(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=r(a)});var oe={dow:0,doy:6};R("D",["DD",2],"Do","date"),J("date","D"),W("D",yd),W("DD",yd,ud),W("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),$(["D","DD"],Od),$("Do",function(a,b){b[Od]=r(a.match(yd)[0],10)});var pe=M("Date",!0);R("d",0,"do","day"),R("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),R("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),R("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),R("e",0,0,"weekday"),R("E",0,0,"isoWeekday"),J("day","d"),J("weekday","e"),J("isoWeekday","E"),W("d",yd),W("e",yd),W("E",yd),W("dd",function(a,b){return b.weekdaysMinRegex(a)}),W("ddd",function(a,b){return b.weekdaysShortRegex(a)}),W("dddd",function(a,b){return b.weekdaysRegex(a)}),_(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);null!=e?b.d=e:j(c).invalidWeekday=a}),_(["d","e","E"],function(a,b,c,d){b[d]=r(a)});var qe="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),re="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),se="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),te=Jd,ue=Jd,ve=Jd;R("DDD",["DDDD",3],"DDDo","dayOfYear"),J("dayOfYear","DDD"),W("DDD",Bd),W("DDDD",vd),$(["DDD","DDDD"],function(a,b,c){c._dayOfYear=r(a)}),R("H",["HH",2],0,"hour"),R("h",["hh",2],0,oc),R("k",["kk",2],0,pc),R("hmm",0,0,function(){return""+oc.apply(this)+Q(this.minutes(),2)}),R("hmmss",0,0,function(){return""+oc.apply(this)+Q(this.minutes(),2)+Q(this.seconds(),2)}),R("Hmm",0,0,function(){return""+this.hours()+Q(this.minutes(),2)}),R("Hmmss",0,0,function(){return""+this.hours()+Q(this.minutes(),2)+Q(this.seconds(),2)}),qc("a",!0),qc("A",!1),J("hour","h"),W("a",rc),W("A",rc),W("H",yd),W("h",yd),W("HH",yd,ud),W("hh",yd,ud),W("hmm",zd),W("hmmss",Ad),W("Hmm",zd),W("Hmmss",Ad),$(["H","HH"],Pd),$(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),$(["h","hh"],function(a,b,c){b[Pd]=r(a),j(c).bigHour=!0}),$("hmm",function(a,b,c){var d=a.length-2;b[Pd]=r(a.substr(0,d)),b[Qd]=r(a.substr(d)),j(c).bigHour=!0}),$("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[Pd]=r(a.substr(0,d)),b[Qd]=r(a.substr(d,2)),b[Rd]=r(a.substr(e)),j(c).bigHour=!0}),$("Hmm",function(a,b,c){var d=a.length-2;b[Pd]=r(a.substr(0,d)),b[Qd]=r(a.substr(d))}),$("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[Pd]=r(a.substr(0,d)),b[Qd]=r(a.substr(d,2)),b[Rd]=r(a.substr(e))});var we=/[ap]\.?m?\.?/i,xe=M("Hours",!0);R("m",["mm",2],0,"minute"),J("minute","m"),W("m",yd),W("mm",yd,ud),$(["m","mm"],Qd);var ye=M("Minutes",!1);R("s",["ss",2],0,"second"),J("second","s"),W("s",yd),W("ss",yd,ud),$(["s","ss"],Rd);var ze=M("Seconds",!1);R("S",0,0,function(){return~~(this.millisecond()/100)}),R(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),R(0,["SSS",3],0,"millisecond"),R(0,["SSSS",4],0,function(){return 10*this.millisecond()}),R(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),R(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),R(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),R(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),R(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),J("millisecond","ms"),W("S",Bd,td),W("SS",Bd,ud),W("SSS",Bd,vd);var Ae;for(Ae="SSSS";Ae.length<=9;Ae+="S")W(Ae,Ed);for(Ae="S";Ae.length<=9;Ae+="S")$(Ae,uc);var Be=M("Milliseconds",!1);R("z",0,0,"zoneAbbr"),R("zz",0,0,"zoneName");var Ce=o.prototype;Ce.add=le,Ce.calendar=kb,Ce.clone=lb,Ce.diff=sb,Ce.endOf=Eb,Ce.format=wb,Ce.from=xb,Ce.fromNow=yb,Ce.to=zb,Ce.toNow=Ab,Ce.get=P,Ce.invalidAt=Nb,Ce.isAfter=mb,Ce.isBefore=nb,Ce.isBetween=ob,Ce.isSame=pb,Ce.isSameOrAfter=qb,Ce.isSameOrBefore=rb,Ce.isValid=Lb,Ce.lang=ne,Ce.locale=Bb,Ce.localeData=Cb,Ce.max=ge,Ce.min=fe,Ce.parsingFlags=Mb,Ce.set=P,Ce.startOf=Db,Ce.subtract=me,Ce.toArray=Ib,Ce.toObject=Jb,Ce.toDate=Hb,Ce.toISOString=vb,Ce.toJSON=Kb,Ce.toString=ub,Ce.unix=Gb,Ce.valueOf=Fb,Ce.creationData=Ob,Ce.year=ee,Ce.isLeapYear=ta,Ce.weekYear=Qb,Ce.isoWeekYear=Rb,Ce.quarter=Ce.quarters=Wb,Ce.month=ha,Ce.daysInMonth=ia,Ce.week=Ce.weeks=$b,Ce.isoWeek=Ce.isoWeeks=_b,Ce.weeksInYear=Tb,Ce.isoWeeksInYear=Sb,Ce.date=pe,Ce.day=Ce.days=gc,Ce.weekday=hc,Ce.isoWeekday=ic,Ce.dayOfYear=nc,Ce.hour=Ce.hours=xe,Ce.minute=Ce.minutes=ye,Ce.second=Ce.seconds=ze,Ce.millisecond=Ce.milliseconds=Be,Ce.utcOffset=Ua,Ce.utc=Wa,Ce.local=Xa,Ce.parseZone=Ya,Ce.hasAlignedHourOffset=Za,Ce.isDST=$a,Ce.isDSTShifted=_a,Ce.isLocal=ab,Ce.isUtcOffset=bb,Ce.isUtc=cb,Ce.isUTC=cb,Ce.zoneAbbr=vc,Ce.zoneName=wc,Ce.dates=u("dates accessor is deprecated. Use date instead.",pe),Ce.months=u("months accessor is deprecated. Use month instead",ha),Ce.years=u("years accessor is deprecated. Use year instead",ee),Ce.zone=u("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Va);var De=Ce,Ee={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Fe={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Ge="Invalid date",He="%d",Ie=/\d{1,2}/,Je={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Ke=A.prototype;Ke._calendar=Ee,Ke.calendar=zc,Ke._longDateFormat=Fe,Ke.longDateFormat=Ac,Ke._invalidDate=Ge,Ke.invalidDate=Bc,Ke._ordinal=He,Ke.ordinal=Cc,Ke._ordinalParse=Ie,Ke.preparse=Dc,Ke.postformat=Dc,Ke._relativeTime=Je,Ke.relativeTime=Ec,Ke.pastFuture=Fc,Ke.set=y,Ke.months=ca,Ke._months=Wd,Ke.monthsShort=da,Ke._monthsShort=Xd,Ke.monthsParse=fa,Ke._monthsRegex=Zd,Ke.monthsRegex=ka,Ke._monthsShortRegex=Yd,Ke.monthsShortRegex=ja,Ke.week=Xb,Ke._week=oe,Ke.firstDayOfYear=Zb,Ke.firstDayOfWeek=Yb,Ke.weekdays=bc,Ke._weekdays=qe,Ke.weekdaysMin=dc,Ke._weekdaysMin=se,Ke.weekdaysShort=cc,Ke._weekdaysShort=re,Ke.weekdaysParse=fc,Ke._weekdaysRegex=te,Ke.weekdaysRegex=jc,Ke._weekdaysShortRegex=ue,Ke.weekdaysShortRegex=kc,Ke._weekdaysMinRegex=ve,Ke.weekdaysMinRegex=lc,Ke.isPM=sc,Ke._meridiemParse=we,Ke.meridiem=tc,E("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===r(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=u("moment.lang is deprecated. Use moment.locale instead.",E),a.langData=u("moment.langData is deprecated. Use moment.localeData instead.",H);var Le=Math.abs,Me=Yc("ms"),Ne=Yc("s"),Oe=Yc("m"),Pe=Yc("h"),Qe=Yc("d"),Re=Yc("w"),Se=Yc("M"),Te=Yc("y"),Ue=$c("milliseconds"),Ve=$c("seconds"),We=$c("minutes"),Xe=$c("hours"),Ye=$c("days"),Ze=$c("months"),$e=$c("years"),_e=Math.round,af={s:45,m:45,h:22,d:26,M:11},bf=Math.abs,cf=Oa.prototype;cf.abs=Oc,cf.add=Qc,cf.subtract=Rc,cf.as=Wc,cf.asMilliseconds=Me,cf.asSeconds=Ne,cf.asMinutes=Oe,cf.asHours=Pe,cf.asDays=Qe,cf.asWeeks=Re,cf.asMonths=Se,cf.asYears=Te,cf.valueOf=Xc,cf._bubble=Tc,cf.get=Zc,cf.milliseconds=Ue,cf.seconds=Ve,cf.minutes=We,cf.hours=Xe,cf.days=Ye,cf.weeks=_c,cf.months=Ze,cf.years=$e,cf.humanize=dd,cf.toISOString=ed,cf.toString=ed,cf.toJSON=ed,cf.locale=Bb,cf.localeData=Cb,cf.toIsoString=u("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ed),cf.lang=ne,R("X",0,0,"unix"),R("x",0,0,"valueOf"),W("x",Fd),W("X",Id),$("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),$("x",function(a,b,c){c._d=new Date(r(a))}),a.version="2.13.0",b(Ka),a.fn=De,a.min=Ma,a.max=Na,a.now=he,a.utc=h,a.unix=xc,a.months=Jc,a.isDate=d,a.locale=E,a.invalid=l,a.duration=db,a.isMoment=p,a.weekdays=Lc,a.parseZone=yc,a.localeData=H,a.isDuration=Pa,a.monthsShort=Kc,a.weekdaysMin=Nc,a.defineLocale=F,a.updateLocale=G,a.locales=I,a.weekdaysShort=Mc,a.normalizeUnits=K,a.relativeTimeThreshold=cd,a.prototype=De;var df=a;return df});
bp-forums/bp-forums-bbpress-sa.php CHANGED
@@ -283,13 +283,13 @@ if ( ! class_exists( 'BPDB' ) ) :
283
  function init( $args ) {
284
  if ( 4 == func_num_args() ) {
285
  $args = array(
286
- 'user' => $args,
287
- 'password' => func_get_arg( 1 ),
288
- 'name' => func_get_arg( 2 ),
289
- 'host' => func_get_arg( 3 ),
290
- 'charset' => defined( 'BBDB_CHARSET' ) ? BBDB_CHARSET : false,
291
- 'collate' => defined( 'BBDB_COLLATE' ) ? BBDB_COLLATE : false,
292
- );
293
  }
294
 
295
  $defaults = array(
@@ -310,14 +310,11 @@ if ( ! class_exists( 'BPDB' ) ) :
310
  *
311
  * @since 1.1.0
312
  *
313
- * @see WPDB::escape_deep() for description of parameters and
314
- * return values.
315
- *
316
  * @param mixed $data See {@link WPDB::escape_deep()}.
317
  * @return mixed $data See {@link WPDB::escape_deep()}.
318
  */
319
  function escape_deep( $data ) {
320
- return $this->escape( $data );
321
  }
322
  }
323
  endif; // End class_exists( 'BPDB' ).
283
  function init( $args ) {
284
  if ( 4 == func_num_args() ) {
285
  $args = array(
286
+ 'user' => $args,
287
+ 'password' => func_get_arg( 1 ),
288
+ 'name' => func_get_arg( 2 ),
289
+ 'host' => func_get_arg( 3 ),
290
+ 'charset' => defined( 'BBDB_CHARSET' ) ? BBDB_CHARSET : false,
291
+ 'collate' => defined( 'BBDB_COLLATE' ) ? BBDB_COLLATE : false,
292
+ );
293
  }
294
 
295
  $defaults = array(
310
  *
311
  * @since 1.1.0
312
  *
 
 
 
313
  * @param mixed $data See {@link WPDB::escape_deep()}.
314
  * @return mixed $data See {@link WPDB::escape_deep()}.
315
  */
316
  function escape_deep( $data ) {
317
+ return esc_sql( $data );
318
  }
319
  }
320
  endif; // End class_exists( 'BPDB' ).
bp-forums/bp-forums-template.php CHANGED
@@ -1451,21 +1451,16 @@ function bp_the_topic_total_post_count() {
1451
  function bp_get_the_topic_total_post_count() {
1452
  global $forum_template;
1453
 
1454
- if ( $forum_template->topic->topic_posts == 1 ) {
1455
 
1456
- /**
1457
- * Filters a 'x posts' string with the number of posts in the current topic.
1458
- *
1459
- * @since 1.0.0
1460
- *
1461
- * @param string $value 'X posts' string value for the current topic.
1462
- */
1463
- return apply_filters( 'bp_get_the_topic_total_post_count', sprintf( __( '%d post', 'buddypress' ), $forum_template->topic->topic_posts ) );
1464
- } else {
1465
-
1466
- /** This filter is documented in bp-forums/bp-forums-template.php */
1467
- return apply_filters( 'bp_get_the_topic_total_post_count', sprintf( __( '%d posts', 'buddypress' ), $forum_template->topic->topic_posts ) );
1468
- }
1469
  }
1470
 
1471
  /**
1451
  function bp_get_the_topic_total_post_count() {
1452
  global $forum_template;
1453
 
1454
+ $output = _n( '%d post', '%d posts', (int) $forum_template->topic->topic_posts, 'buddypress' );
1455
 
1456
+ /**
1457
+ * Filters a 'x posts' string with the number of posts in the current topic.
1458
+ *
1459
+ * @since 1.0.0
1460
+ *
1461
+ * @param string $value 'X posts' string value for the current topic.
1462
+ */
1463
+ return apply_filters( 'bp_get_the_topic_total_post_count', sprintf( $output, $forum_template->topic->topic_posts ) );
 
 
 
 
 
1464
  }
1465
 
1466
  /**
bp-friends/bp-friends-actions.php CHANGED
@@ -52,7 +52,7 @@ function friends_action_add_friend() {
52
 
53
  return false;
54
  }
55
- add_action( 'bp_init', 'friends_action_add_friend' );
56
 
57
  /**
58
  * Catch and process Remove Friendship requests.
@@ -92,4 +92,4 @@ function friends_action_remove_friend() {
92
 
93
  return false;
94
  }
95
- add_action( 'bp_init', 'friends_action_remove_friend' );
52
 
53
  return false;
54
  }
55
+ add_action( 'bp_actions', 'friends_action_add_friend' );
56
 
57
  /**
58
  * Catch and process Remove Friendship requests.
92
 
93
  return false;
94
  }
95
+ add_action( 'bp_actions', 'friends_action_remove_friend' );
bp-friends/bp-friends-cache.php CHANGED
@@ -34,6 +34,47 @@ function friends_clear_friend_object_cache( $friendship_id ) {
34
  add_action( 'friends_friendship_accepted', 'friends_clear_friend_object_cache' );
35
  add_action( 'friends_friendship_deleted', 'friends_clear_friend_object_cache' );
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  /**
38
  * Clear the friend request cache for the user not initiating the friendship.
39
  *
34
  add_action( 'friends_friendship_accepted', 'friends_clear_friend_object_cache' );
35
  add_action( 'friends_friendship_deleted', 'friends_clear_friend_object_cache' );
36
 
37
+ /**
38
+ * Clear friendship caches on friendship changes.
39
+ *
40
+ * @since 2.7.0
41
+ *
42
+ * @param int $friendship_id ID of the friendship that has changed.
43
+ * @param int $initiator_user_id ID of the first user.
44
+ * @param int $friend_user_id ID of the second user.
45
+ * @return bool
46
+ */
47
+ function bp_friends_clear_bp_friends_friendships_cache( $friendship_id, $initiator_user_id, $friend_user_id ) {
48
+ // Clear friendship ID cache for each user.
49
+ wp_cache_delete( $initiator_user_id, 'bp_friends_friendships_for_user' );
50
+ wp_cache_delete( $friend_user_id, 'bp_friends_friendships_for_user' );
51
+
52
+ // Clear the friendship object cache.
53
+ wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
54
+ }
55
+ add_action( 'friends_friendship_requested', 'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
56
+ add_action( 'friends_friendship_accepted', 'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
57
+ add_action( 'friends_friendship_deleted', 'bp_friends_clear_bp_friends_friendships_cache', 10, 3 );
58
+
59
+ /**
60
+ * Clear friendship caches on friendship changes.
61
+ *
62
+ * @since 2.7.0
63
+ *
64
+ * @param int $friendship_id The friendship ID.
65
+ * @param BP_Friends_Friendship $friendship Friendship object.
66
+ */
67
+ function bp_friends_clear_bp_friends_friendships_cache_remove( $friendship_id, BP_Friends_Friendship $friendship ) {
68
+ // Clear friendship ID cache for each user.
69
+ wp_cache_delete( $friendship->initiator_user_id, 'bp_friends_friendships_for_user' );
70
+ wp_cache_delete( $friendship->friend_user_id, 'bp_friends_friendships_for_user' );
71
+
72
+ // Clear the friendship object cache.
73
+ wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
74
+ }
75
+ add_action( 'friends_friendship_withdrawn', 'bp_friends_clear_bp_friends_friendships_cache_remove', 10, 2 );
76
+ add_action( 'friends_friendship_rejected', 'bp_friends_clear_bp_friends_friendships_cache_remove', 10, 2 );
77
+
78
  /**
79
  * Clear the friend request cache for the user not initiating the friendship.
80
  *
bp-friends/bp-friends-filters.php CHANGED
@@ -28,44 +28,17 @@ function bp_friends_filter_user_query_populate_extras( BP_User_Query $user_query
28
  global $wpdb;
29
 
30
  // Stop if user isn't logged in.
31
- if ( ! is_user_logged_in() ) {
32
  return;
33
  }
34
 
35
- $bp = buddypress();
36
 
37
- // Fetch whether or not the user is a friend of the current user.
38
- $friend_status = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ( {$user_ids_sql} ) ) OR (initiator_user_id IN ( {$user_ids_sql} ) AND friend_user_id = %d )", bp_loggedin_user_id(), bp_loggedin_user_id() ) );
39
-
40
- // Keep track of members that have a friendship status with the current user.
41
- $friend_user_ids = array();
42
-
43
- // The "friend" is the user ID in the pair who is *not* the logged in user.
44
- foreach ( (array) $friend_status as $fs ) {
45
- $friend_id = bp_loggedin_user_id() == $fs->initiator_user_id ? $fs->friend_user_id : $fs->initiator_user_id;
46
- $friend_user_ids[] = $friend_id;
47
-
48
- if ( isset( $user_query->results[ $friend_id ] ) ) {
49
- if ( 0 == $fs->is_confirmed ) {
50
- $status = $fs->initiator_user_id == bp_loggedin_user_id() ? 'pending' : 'awaiting_response';
51
- } else {
52
- $status = 'is_friend';
53
- }
54
-
55
- $user_query->results[ $friend_id ]->is_friend = $fs->is_confirmed;
56
- $user_query->results[ $friend_id ]->friendship_status = $status;
57
- }
58
- }
59
-
60
- // The rest are not friends with the current user, so set status accordingly.
61
- $not_friends = array_diff( $user_query->user_ids, $friend_user_ids );
62
- foreach ( (array) $not_friends as $nf ) {
63
- if ( bp_loggedin_user_id() == $nf ) {
64
- continue;
65
- }
66
-
67
- if ( isset( $user_query->results[ $nf ] ) ) {
68
- $user_query->results[ $nf ]->friendship_status = 'not_friends';
69
  }
70
  }
71
 
28
  global $wpdb;
29
 
30
  // Stop if user isn't logged in.
31
+ if ( ! $user_id = bp_loggedin_user_id() ) {
32
  return;
33
  }
34
 
35
+ $maybe_friend_ids = wp_parse_id_list( $user_ids_sql );
36
 
37
+ foreach ( $maybe_friend_ids as $friend_id ) {
38
+ $status = BP_Friends_Friendship::check_is_friend( $user_id, $friend_id );
39
+ $user_query->results[ $friend_id ]->friendship_status = $status;
40
+ if ( 'is_friend' == $status ) {
41
+ $user_query->results[ $friend_id ]->is_friend = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
43
  }
44
 
bp-friends/bp-friends-functions.php CHANGED
@@ -795,3 +795,78 @@ function bp_friends_prime_mentions_results() {
795
  ) );
796
  }
797
  add_action( 'bp_activity_mentions_prime_results', 'bp_friends_prime_mentions_results' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
795
  ) );
796
  }
797
  add_action( 'bp_activity_mentions_prime_results', 'bp_friends_prime_mentions_results' );
798
+
799
+ /** Emails ********************************************************************/
800
+
801
+ /**
802
+ * Send notifications related to a new friendship request.
803
+ *
804
+ * When a friendship is requested, an email and a BP notification are sent to
805
+ * the user of whom friendship has been requested ($friend_id).
806
+ *
807
+ * @since 1.0.0
808
+ *
809
+ * @param int $friendship_id ID of the friendship object.
810
+ * @param int $initiator_id ID of the user who initiated the request.
811
+ * @param int $friend_id ID of the request recipient.
812
+ */
813
+ function friends_notification_new_request( $friendship_id, $initiator_id, $friend_id ) {
814
+ if ( 'no' == bp_get_user_meta( (int) $friend_id, 'notification_friends_friendship_request', true ) ) {
815
+ return;
816
+ }
817
+
818
+ $unsubscribe_args = array(
819
+ 'user_id' => $friend_id,
820
+ 'notification_type' => 'friends-request',
821
+ );
822
+
823
+ $args = array(
824
+ 'tokens' => array(
825
+ 'friend-requests.url' => esc_url( bp_core_get_user_domain( $friend_id ) . bp_get_friends_slug() . '/requests/' ),
826
+ 'friend.id' => $friend_id,
827
+ 'friendship.id' => $friendship_id,
828
+ 'initiator.id' => $initiator_id,
829
+ 'initiator.url' => esc_url( bp_core_get_user_domain( $initiator_id ) ),
830
+ 'initiator.name' => bp_core_get_user_displayname( $initiator_id ),
831
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
832
+ ),
833
+ );
834
+ bp_send_email( 'friends-request', $friend_id, $args );
835
+ }
836
+ add_action( 'friends_friendship_requested', 'friends_notification_new_request', 10, 3 );
837
+
838
+ /**
839
+ * Send notifications related to the acceptance of a friendship request.
840
+ *
841
+ * When a friendship request is accepted, an email and a BP notification are
842
+ * sent to the user who requested the friendship ($initiator_id).
843
+ *
844
+ * @since 1.0.0
845
+ *
846
+ * @param int $friendship_id ID of the friendship object.
847
+ * @param int $initiator_id ID of the user who initiated the request.
848
+ * @param int $friend_id ID of the request recipient.
849
+ */
850
+ function friends_notification_accepted_request( $friendship_id, $initiator_id, $friend_id ) {
851
+ if ( 'no' == bp_get_user_meta( (int) $initiator_id, 'notification_friends_friendship_accepted', true ) ) {
852
+ return;
853
+ }
854
+
855
+ $unsubscribe_args = array(
856
+ 'user_id' => $initiator_id,
857
+ 'notification_type' => 'friends-request-accepted',
858
+ );
859
+
860
+ $args = array(
861
+ 'tokens' => array(
862
+ 'friend.id' => $friend_id,
863
+ 'friendship.url' => esc_url( bp_core_get_user_domain( $friend_id ) ),
864
+ 'friend.name' => bp_core_get_user_displayname( $friend_id ),
865
+ 'friendship.id' => $friendship_id,
866
+ 'initiator.id' => $initiator_id,
867
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
868
+ ),
869
+ );
870
+ bp_send_email( 'friends-request-accepted', $initiator_id, $args );
871
+ }
872
+ add_action( 'friends_friendship_accepted', 'friends_notification_accepted_request', 10, 3 );
bp-friends/bp-friends-loader.php CHANGED
@@ -17,7 +17,7 @@ if ( ! buddypress()->do_autoload ) {
17
  }
18
 
19
  /**
20
- * Set up the bp-forums component.
21
  *
22
  * @since 1.6.0
23
  */
17
  }
18
 
19
  /**
20
+ * Set up the bp-friends component.
21
  *
22
  * @since 1.6.0
23
  */
bp-friends/bp-friends-notifications.php CHANGED
@@ -13,71 +13,6 @@
13
  // Exit if accessed directly.
14
  defined( 'ABSPATH' ) || exit;
15
 
16
- /** Emails ********************************************************************/
17
-
18
- /**
19
- * Send notifications related to a new friendship request.
20
- *
21
- * When a friendship is requested, an email and a BP notification are sent to
22
- * the user of whom friendship has been requested ($friend_id).
23
- *
24
- * @since 1.0.0
25
- *
26
- * @param int $friendship_id ID of the friendship object.
27
- * @param int $initiator_id ID of the user who initiated the request.
28
- * @param int $friend_id ID of the request recipient.
29
- */
30
- function friends_notification_new_request( $friendship_id, $initiator_id, $friend_id ) {
31
- if ( 'no' == bp_get_user_meta( (int) $friend_id, 'notification_friends_friendship_request', true ) ) {
32
- return;
33
- }
34
-
35
- $args = array(
36
- 'tokens' => array(
37
- 'friend-requests.url' => esc_url( bp_core_get_user_domain( $friend_id ) . bp_get_friends_slug() . '/requests/' ),
38
- 'friend.id' => $friend_id,
39
- 'friendship.id' => $friendship_id,
40
- 'initiator.id' => $initiator_id,
41
- 'initiator.url' => esc_url( bp_core_get_user_domain( $initiator_id ) ),
42
- 'initiator.name' => bp_core_get_user_displayname( $initiator_id ),
43
- ),
44
- );
45
- bp_send_email( 'friends-request', $friend_id, $args );
46
- }
47
- add_action( 'friends_friendship_requested', 'friends_notification_new_request', 10, 3 );
48
-
49
- /**
50
- * Send notifications related to the acceptance of a friendship request.
51
- *
52
- * When a friendship request is accepted, an email and a BP notification are
53
- * sent to the user who requested the friendship ($initiator_id).
54
- *
55
- * @since 1.0.0
56
- *
57
- * @param int $friendship_id ID of the friendship object.
58
- * @param int $initiator_id ID of the user who initiated the request.
59
- * @param int $friend_id ID of the request recipient.
60
- */
61
- function friends_notification_accepted_request( $friendship_id, $initiator_id, $friend_id ) {
62
- if ( 'no' == bp_get_user_meta( (int) $initiator_id, 'notification_friends_friendship_accepted', true ) ) {
63
- return;
64
- }
65
-
66
- $args = array(
67
- 'tokens' => array(
68
- 'friend.id' => $friend_id,
69
- 'friendship.url' => esc_url( bp_core_get_user_domain( $friend_id ) ),
70
- 'friend.name' => bp_core_get_user_displayname( $friend_id ),
71
- 'friendship.id' => $friendship_id,
72
- 'initiator.id' => $initiator_id,
73
- ),
74
- );
75
- bp_send_email( 'friends-request-accepted', $initiator_id, $args );
76
- }
77
- add_action( 'friends_friendship_accepted', 'friends_notification_accepted_request', 10, 3 );
78
-
79
- /** Notifications *************************************************************/
80
-
81
  /**
82
  * Notification formatting callback for bp-friends notifications.
83
  *
@@ -182,7 +117,7 @@ function friends_format_notifications( $action, $item_id, $secondary_item_id, $t
182
  * @since 1.2.0
183
  */
184
  function friends_clear_friend_notifications() {
185
- if ( isset( $_GET['new'] ) && bp_is_active( 'notifications' ) ) {
186
  bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_accepted' );
187
  }
188
  }
@@ -194,7 +129,7 @@ add_action( 'bp_activity_screen_my_activity', 'friends_clear_friend_notification
194
  * @since 1.9.0
195
  */
196
  function bp_friends_mark_friendship_request_notifications_by_type() {
197
- if ( isset( $_GET['new'] ) && bp_is_active( 'notifications' ) ) {
198
  bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_request' );
199
  }
200
  }
@@ -206,9 +141,7 @@ add_action( 'friends_screen_requests', 'bp_friends_mark_friendship_request_notif
206
  * @since 1.9.0
207
  */
208
  function bp_friends_mark_friendship_accepted_notifications_by_type() {
209
- if ( bp_is_active( 'notifications' ) ) {
210
- bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_accepted' );
211
- }
212
  }
213
  add_action( 'friends_screen_my_friends', 'bp_friends_mark_friendship_accepted_notifications_by_type' );
214
 
@@ -222,17 +155,15 @@ add_action( 'friends_screen_my_friends', 'bp_friends_mark_friendship_accepted_no
222
  * @param int $friend_user_id The friendship request receiver user ID.
223
  */
224
  function bp_friends_friendship_requested_notification( $friendship_id, $initiator_user_id, $friend_user_id ) {
225
- if ( bp_is_active( 'notifications' ) ) {
226
- bp_notifications_add_notification( array(
227
- 'user_id' => $friend_user_id,
228
- 'item_id' => $initiator_user_id,
229
- 'secondary_item_id' => $friendship_id,
230
- 'component_name' => buddypress()->friends->id,
231
- 'component_action' => 'friendship_request',
232
- 'date_notified' => bp_core_current_time(),
233
- 'is_new' => 1,
234
- ) );
235
- }
236
  }
237
  add_action( 'friends_friendship_requested', 'bp_friends_friendship_requested_notification', 10, 3 );
238
 
@@ -245,9 +176,7 @@ add_action( 'friends_friendship_requested', 'bp_friends_friendship_requested_not
245
  * @param object $friendship Friendship object.
246
  */
247
  function bp_friends_mark_friendship_rejected_notifications_by_item_id( $friendship_id, $friendship ) {
248
- if ( bp_is_active( 'notifications' ) ) {
249
- bp_notifications_mark_notifications_by_item_id( $friendship->friend_user_id, $friendship->initiator_user_id, buddypress()->friends->id, 'friendship_request' );
250
- }
251
  }
252
  add_action( 'friends_friendship_rejected', 'bp_friends_mark_friendship_rejected_notifications_by_item_id', 10, 2 );
253
 
@@ -261,12 +190,6 @@ add_action( 'friends_friendship_rejected', 'bp_friends_mark_friendship_rejected_
261
  * @param int $friend_user_id The friendship request receiver user ID.
262
  */
263
  function bp_friends_add_friendship_accepted_notification( $friendship_id, $initiator_user_id, $friend_user_id ) {
264
-
265
- // Bail if notifications is not active.
266
- if ( ! bp_is_active( 'notifications' ) ) {
267
- return;
268
- }
269
-
270
  // Remove the friend request notice.
271
  bp_notifications_mark_notifications_by_item_id( $friend_user_id, $initiator_user_id, buddypress()->friends->id, 'friendship_request' );
272
 
@@ -292,9 +215,7 @@ add_action( 'friends_friendship_accepted', 'bp_friends_add_friendship_accepted_n
292
  * @param object $friendship Friendship Object.
293
  */
294
  function bp_friends_mark_friendship_withdrawn_notifications_by_item_id( $friendship_id, $friendship ) {
295
- if ( bp_is_active( 'notifications' ) ) {
296
- bp_notifications_delete_notifications_by_item_id( $friendship->friend_user_id, $friendship->initiator_user_id, buddypress()->friends->id, 'friendship_request' );
297
- }
298
  }
299
  add_action( 'friends_friendship_withdrawn', 'bp_friends_mark_friendship_withdrawn_notifications_by_item_id', 10, 2 );
300
 
@@ -306,8 +227,6 @@ add_action( 'friends_friendship_withdrawn', 'bp_friends_mark_friendship_withdraw
306
  * @param int $user_id ID of the user whose notifications are removed.
307
  */
308
  function bp_friends_remove_notifications_data( $user_id = 0 ) {
309
- if ( bp_is_active( 'notifications' ) ) {
310
- bp_notifications_delete_notifications_from_user( $user_id, buddypress()->friends->id, 'friendship_request' );
311
- }
312
  }
313
  add_action( 'friends_remove_data', 'bp_friends_remove_notifications_data', 10, 1 );
13
  // Exit if accessed directly.
14
  defined( 'ABSPATH' ) || exit;
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  /**
17
  * Notification formatting callback for bp-friends notifications.
18
  *
117
  * @since 1.2.0
118
  */
119
  function friends_clear_friend_notifications() {
120
+ if ( isset( $_GET['new'] ) ) {
121
  bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_accepted' );
122
  }
123
  }
129
  * @since 1.9.0
130
  */
131
  function bp_friends_mark_friendship_request_notifications_by_type() {
132
+ if ( isset( $_GET['new'] ) ) {
133
  bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_request' );
134
  }
135
  }
141
  * @since 1.9.0
142
  */
143
  function bp_friends_mark_friendship_accepted_notifications_by_type() {
144
+ bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_accepted' );
 
 
145
  }
146
  add_action( 'friends_screen_my_friends', 'bp_friends_mark_friendship_accepted_notifications_by_type' );
147
 
155
  * @param int $friend_user_id The friendship request receiver user ID.
156
  */
157
  function bp_friends_friendship_requested_notification( $friendship_id, $initiator_user_id, $friend_user_id ) {
158
+ bp_notifications_add_notification( array(
159
+ 'user_id' => $friend_user_id,
160
+ 'item_id' => $initiator_user_id,
161
+ 'secondary_item_id' => $friendship_id,
162
+ 'component_name' => buddypress()->friends->id,
163
+ 'component_action' => 'friendship_request',
164
+ 'date_notified' => bp_core_current_time(),
165
+ 'is_new' => 1,
166
+ ) );
 
 
167
  }
168
  add_action( 'friends_friendship_requested', 'bp_friends_friendship_requested_notification', 10, 3 );
169
 
176
  * @param object $friendship Friendship object.
177
  */
178
  function bp_friends_mark_friendship_rejected_notifications_by_item_id( $friendship_id, $friendship ) {
179
+ bp_notifications_mark_notifications_by_item_id( $friendship->friend_user_id, $friendship->initiator_user_id, buddypress()->friends->id, 'friendship_request' );
 
 
180
  }
181
  add_action( 'friends_friendship_rejected', 'bp_friends_mark_friendship_rejected_notifications_by_item_id', 10, 2 );
182
 
190
  * @param int $friend_user_id The friendship request receiver user ID.
191
  */
192
  function bp_friends_add_friendship_accepted_notification( $friendship_id, $initiator_user_id, $friend_user_id ) {
 
 
 
 
 
 
193
  // Remove the friend request notice.
194
  bp_notifications_mark_notifications_by_item_id( $friend_user_id, $initiator_user_id, buddypress()->friends->id, 'friendship_request' );
195
 
215
  * @param object $friendship Friendship Object.
216
  */
217
  function bp_friends_mark_friendship_withdrawn_notifications_by_item_id( $friendship_id, $friendship ) {
218
+ bp_notifications_delete_notifications_by_item_id( $friendship->friend_user_id, $friendship->initiator_user_id, buddypress()->friends->id, 'friendship_request' );
 
 
219
  }
220
  add_action( 'friends_friendship_withdrawn', 'bp_friends_mark_friendship_withdrawn_notifications_by_item_id', 10, 2 );
221
 
227
  * @param int $user_id ID of the user whose notifications are removed.
228
  */
229
  function bp_friends_remove_notifications_data( $user_id = 0 ) {
230
+ bp_notifications_delete_notifications_from_user( $user_id, buddypress()->friends->id, 'friendship_request' );
 
 
231
  }
232
  add_action( 'friends_remove_data', 'bp_friends_remove_notifications_data', 10, 1 );
bp-friends/bp-friends-template.php CHANGED
@@ -369,7 +369,6 @@ function bp_add_friend_button( $potential_friend_id = 0, $friend_status = false
369
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
370
  'link_href' => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $potential_friend_id . '/', 'friends_withdraw_friendship' ),
371
  'link_text' => __( 'Cancel Friendship Request', 'buddypress' ),
372
- 'link_title' => __( 'Cancel Friendship Requested', 'buddypress' ),
373
  'link_id' => 'friend-' . $potential_friend_id,
374
  'link_rel' => 'remove',
375
  'link_class' => 'friendship-button pending_friend requested'
@@ -386,7 +385,6 @@ function bp_add_friend_button( $potential_friend_id = 0, $friend_status = false
386
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
387
  'link_href' => bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/',
388
  'link_text' => __( 'Friendship Requested', 'buddypress' ),
389
- 'link_title' => __( 'Friendship Requested', 'buddypress' ),
390
  'link_id' => 'friend-' . $potential_friend_id,
391
  'link_rel' => 'remove',
392
  'link_class' => 'friendship-button awaiting_response_friend requested'
@@ -403,7 +401,6 @@ function bp_add_friend_button( $potential_friend_id = 0, $friend_status = false
403
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
404
  'link_href' => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/remove-friend/' . $potential_friend_id . '/', 'friends_remove_friend' ),
405
  'link_text' => __( 'Cancel Friendship', 'buddypress' ),
406
- 'link_title' => __( 'Cancel Friendship', 'buddypress' ),
407
  'link_id' => 'friend-' . $potential_friend_id,
408
  'link_rel' => 'remove',
409
  'link_class' => 'friendship-button is_friend remove'
@@ -420,7 +417,6 @@ function bp_add_friend_button( $potential_friend_id = 0, $friend_status = false
420
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
421
  'link_href' => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $potential_friend_id . '/', 'friends_add_friend' ),
422
  'link_text' => __( 'Add Friend', 'buddypress' ),
423
- 'link_title' => __( 'Add Friend', 'buddypress' ),
424
  'link_id' => 'friend-' . $potential_friend_id,
425
  'link_rel' => 'add',
426
  'link_class' => 'friendship-button not_friends add'
369
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
370
  'link_href' => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $potential_friend_id . '/', 'friends_withdraw_friendship' ),
371
  'link_text' => __( 'Cancel Friendship Request', 'buddypress' ),
 
372
  'link_id' => 'friend-' . $potential_friend_id,
373
  'link_rel' => 'remove',
374
  'link_class' => 'friendship-button pending_friend requested'
385
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
386
  'link_href' => bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/',
387
  'link_text' => __( 'Friendship Requested', 'buddypress' ),
 
388
  'link_id' => 'friend-' . $potential_friend_id,
389
  'link_rel' => 'remove',
390
  'link_class' => 'friendship-button awaiting_response_friend requested'
401
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
402
  'link_href' => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/remove-friend/' . $potential_friend_id . '/', 'friends_remove_friend' ),
403
  'link_text' => __( 'Cancel Friendship', 'buddypress' ),
 
404
  'link_id' => 'friend-' . $potential_friend_id,
405
  'link_rel' => 'remove',
406
  'link_class' => 'friendship-button is_friend remove'
417
  'wrapper_id' => 'friendship-button-' . $potential_friend_id,
418
  'link_href' => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $potential_friend_id . '/', 'friends_add_friend' ),
419
  'link_text' => __( 'Add Friend', 'buddypress' ),
 
420
  'link_id' => 'friend-' . $potential_friend_id,
421
  'link_rel' => 'add',
422
  'link_class' => 'friendship-button not_friends add'
bp-friends/bp-friends-widgets.php CHANGED
@@ -78,9 +78,9 @@ function bp_core_ajax_widget_friends() {
78
  <div class="item">
79
  <div class="item-title fn"><a href="<?php bp_member_permalink(); ?>" title="<?php bp_member_name(); ?>"><?php bp_member_name(); ?></a></div>
80
  <?php if ( 'active' == $type ) : ?>
81
- <div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
82
  <?php elseif ( 'newest' == $type ) : ?>
83
- <div class="item-meta"><span class="activity"><?php bp_member_registered(); ?></span></div>
84
  <?php elseif ( bp_is_active( 'friends' ) ) : ?>
85
  <div class="item-meta"><span class="activity"><?php bp_member_total_friend_count(); ?></span></div>
86
  <?php endif; ?>
78
  <div class="item">
79
  <div class="item-title fn"><a href="<?php bp_member_permalink(); ?>" title="<?php bp_member_name(); ?>"><?php bp_member_name(); ?></a></div>
80
  <?php if ( 'active' == $type ) : ?>
81
+ <div class="item-meta"><span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_last_active( array( 'relative' => false ) ) ); ?>"><?php bp_member_last_active(); ?></span></div>
82
  <?php elseif ( 'newest' == $type ) : ?>
83
+ <div class="item-meta"><span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_registered( array( 'relative' => false ) ) ); ?>"><?php bp_member_registered(); ?></span></div>
84
  <?php elseif ( bp_is_active( 'friends' ) ) : ?>
85
  <div class="item-meta"><span class="activity"><?php bp_member_total_friend_count(); ?></span></div>
86
  <?php endif; ?>
bp-friends/classes/class-bp-core-friends-widget.php CHANGED
@@ -117,16 +117,13 @@ class BP_Core_Friends_Widget extends WP_Widget {
117
  <div class="item">
118
  <div class="item-title fn"><a href="<?php bp_member_permalink(); ?>" title="<?php bp_member_name(); ?>"><?php bp_member_name(); ?></a></div>
119
  <div class="item-meta">
120
- <span class="activity">
121
- <?php
122
- if ( 'newest' == $instance['friend_default'] )
123
- bp_member_registered();
124
- if ( 'active' == $instance['friend_default'] )
125
- bp_member_last_active();
126
- if ( 'popular' == $instance['friend_default'] )
127
- bp_member_total_friend_count();
128
- ?>
129
- </span>
130
  </div>
131
  </div>
132
  </li>
117
  <div class="item">
118
  <div class="item-title fn"><a href="<?php bp_member_permalink(); ?>" title="<?php bp_member_name(); ?>"><?php bp_member_name(); ?></a></div>
119
  <div class="item-meta">
120
+ <?php if ( 'newest' == $instance['friend_default'] ) : ?>
121
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_registered( array( 'relative' => false ) ) ); ?>"><?php bp_member_registered(); ?></span>
122
+ <?php elseif ( 'active' == $instance['friend_default'] ) : ?>
123
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_last_active( array( 'relative' => false ) ) ); ?>"><?php bp_member_last_active(); ?></span>
124
+ <?php else : ?>
125
+ <span class="activity"><?php bp_member_total_friend_count(); ?></span>
126
+ <?php endif; ?>
 
 
 
127
  </div>
128
  </div>
129
  </li>
bp-friends/classes/class-bp-friends-component.php CHANGED
@@ -53,10 +53,14 @@ class BP_Friends_Component extends BP_Component {
53
  'activity',
54
  'template',
55
  'functions',
56
- 'notifications',
57
  'widgets',
58
  );
59
 
 
 
 
 
 
60
  if ( ! buddypress()->do_autoload ) {
61
  $includes[] = 'classes';
62
  }
@@ -284,7 +288,9 @@ class BP_Friends_Component extends BP_Component {
284
 
285
  // Global groups.
286
  wp_cache_add_global_groups( array(
287
- 'bp_friends_requests'
 
 
288
  ) );
289
 
290
  parent::setup_cache_groups();
53
  'activity',
54
  'template',
55
  'functions',
 
56
  'widgets',
57
  );
58
 
59
+ // Conditional includes.
60
+ if ( bp_is_active( 'notifications' ) ) {
61
+ $includes[] = 'notifications';
62
+ }
63
+
64
  if ( ! buddypress()->do_autoload ) {
65
  $includes[] = 'classes';
66
  }
288
 
289
  // Global groups.
290
  wp_cache_add_global_groups( array(
291
+ 'bp_friends_requests',
292
+ 'bp_friends_friendships', // Individual friendship objects are cached here by ID.
293
+ 'bp_friends_friendships_for_user' // All friendship IDs for a single user.
294
  ) );
295
 
296
  parent::setup_cache_groups();
bp-friends/classes/class-bp-friends-friendship.php CHANGED
@@ -122,15 +122,29 @@ class BP_Friends_Friendship {
122
 
123
  $bp = buddypress();
124
 
125
- if ( $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) ) ) {
126
- $this->initiator_user_id = (int) $friendship->initiator_user_id;
127
- $this->friend_user_id = (int) $friendship->friend_user_id;
128
- $this->is_confirmed = (int) $friendship->is_confirmed;
129
- $this->is_limited = (int) $friendship->is_limited;
130
- $this->date_created = $friendship->date_created;
 
 
 
 
 
 
 
 
131
  }
132
 
133
- if ( !empty( $this->populate_friend_details ) ) {
 
 
 
 
 
 
134
  if ( $this->friend_user_id == bp_displayed_user_id() ) {
135
  $this->friend = new BP_Core_User( $this->initiator_user_id );
136
  } else {
@@ -205,6 +219,160 @@ class BP_Friends_Friendship {
205
 
206
  /** Static Methods ********************************************************/
207
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  /**
209
  * Get the IDs of a given user's friends.
210
  *
@@ -221,27 +389,29 @@ class BP_Friends_Friendship {
221
  public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
222
  global $wpdb;
223
 
224
- if ( !empty( $friend_requests_only ) ) {
225
- $oc_sql = 'AND is_confirmed = 0';
226
- $friend_sql = $wpdb->prepare( " WHERE friend_user_id = %d", $user_id );
 
 
227
  } else {
228
- $oc_sql = 'AND is_confirmed = 1';
229
- $friend_sql = $wpdb->prepare( " WHERE (initiator_user_id = %d OR friend_user_id = %d)", $user_id, $user_id );
 
230
  }
231
 
232
- $bp = buddypress();
233
- $friends = $wpdb->get_results( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} {$friend_sql} {$oc_sql} ORDER BY date_created DESC" );
234
- $fids = array();
235
 
236
- for ( $i = 0, $count = count( $friends ); $i < $count; ++$i ) {
237
- if ( !empty( $assoc_arr ) ) {
238
- $fids[] = array( 'user_id' => ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id );
 
239
  } else {
240
- $fids[] = ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id;
241
  }
242
  }
243
 
244
- return $fids;
245
  }
246
 
247
  /**
@@ -251,14 +421,29 @@ class BP_Friends_Friendship {
251
  *
252
  * @param int $user_id The ID of the first user.
253
  * @param int $friend_id The ID of the second user.
254
- * @return int|bool The ID of the friendship object if found, otherwise false.
255
  */
256
  public static function get_friendship_id( $user_id, $friend_id ) {
257
- global $wpdb;
258
 
259
- $bp = buddypress();
 
 
 
260
 
261
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->friends->table_name} WHERE ( initiator_user_id = %d AND friend_user_id = %d ) OR ( initiator_user_id = %d AND friend_user_id = %d ) AND is_confirmed = 1", $user_id, $friend_id, $friend_id, $user_id ) );
 
 
 
 
 
 
 
 
 
 
 
 
262
  }
263
 
264
  /**
@@ -274,15 +459,16 @@ class BP_Friends_Friendship {
274
  $friend_requests = wp_cache_get( $user_id, 'bp_friends_requests' );
275
 
276
  if ( false === $friend_requests ) {
277
- global $wpdb;
278
-
279
- $bp = buddypress();
280
-
281
- $friend_requests = $wpdb->get_col( $wpdb->prepare( "SELECT initiator_user_id FROM {$bp->friends->table_name} WHERE friend_user_id = %d AND is_confirmed = 0", $user_id ) );
282
 
283
  wp_cache_set( $user_id, $friend_requests, 'bp_friends_requests' );
284
  }
285
 
 
 
 
 
 
286
  return $friend_requests;
287
  }
288
 
@@ -299,21 +485,25 @@ class BP_Friends_Friendship {
299
  public static function total_friend_count( $user_id = 0 ) {
300
  global $wpdb;
301
 
302
- if ( empty( $user_id ) )
303
  $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
304
-
305
- $bp = buddypress();
306
 
307
  /*
308
  * This is stored in 'total_friend_count' usermeta.
309
  * This function will recalculate, update and return.
310
  */
311
 
312
- $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) AND is_confirmed = 1", $user_id, $user_id ) );
 
 
 
 
313
 
314
  // Do not update meta if user has never had friends.
315
- if ( empty( $count ) && !bp_get_user_meta( $user_id, 'total_friend_count', true ) )
316
  return 0;
 
317
 
318
  bp_update_user_meta( $user_id, 'total_friend_count', (int) $count );
319
 
@@ -381,7 +571,7 @@ class BP_Friends_Friendship {
381
  if ( empty( $filtered_friend_ids ) )
382
  return false;
383
 
384
- return array( 'friends' => $filtered_friend_ids, 'total' => (int) $total_friend_ids );
385
  }
386
 
387
  /**
@@ -408,13 +598,25 @@ class BP_Friends_Friendship {
408
  return false;
409
  }
410
 
411
- $bp = buddypress();
412
-
413
- $result = $wpdb->get_results( $wpdb->prepare( "SELECT id, initiator_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id = %d) OR (initiator_user_id = %d AND friend_user_id = %d)", $initiator_userid, $possible_friend_userid, $possible_friend_userid, $initiator_userid ) );
 
414
 
415
- if ( ! empty( $result ) ) {
416
- if ( 0 == (int) $result[0]->is_confirmed ) {
417
- $status = $initiator_userid == $result[0]->initiator_user_id ? 'pending' : 'awaiting_response';
 
 
 
 
 
 
 
 
 
 
 
418
  } else {
419
  $status = 'is_friend';
420
  }
@@ -691,6 +893,23 @@ class BP_Friends_Friendship {
691
  return $invitable_count;
692
  }
693
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
694
  /**
695
  * Get the friend user IDs for a given friendship.
696
  *
@@ -700,11 +919,18 @@ class BP_Friends_Friendship {
700
  * @return object friend_user_id and initiator_user_id.
701
  */
702
  public static function get_user_ids_for_friendship( $friendship_id ) {
703
- global $wpdb;
704
 
705
- $bp = buddypress();
 
 
 
 
 
 
 
 
706
 
707
- return $wpdb->get_row( $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} WHERE id = %d", $friendship_id ) );
708
  }
709
 
710
  /**
@@ -719,11 +945,22 @@ class BP_Friends_Friendship {
719
 
720
  $bp = buddypress();
721
 
722
- // Get friends of $user_id.
723
- $friend_ids = BP_Friends_Friendship::get_friend_user_ids( $user_id );
 
 
 
 
 
 
 
 
724
 
725
- // Delete all friendships related to $user_id.
726
- $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE friend_user_id = %d OR initiator_user_id = %d", $user_id, $user_id ) );
 
 
 
727
 
728
  // Delete friend request notifications for members who have a
729
  // notification from this user.
@@ -731,9 +968,19 @@ class BP_Friends_Friendship {
731
  $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 ) );
732
  }
733
 
734
- // Loop through friend_ids and update their counts.
 
 
 
 
 
735
  foreach ( (array) $friend_ids as $friend_id ) {
 
 
736
  BP_Friends_Friendship::total_friend_count( $friend_id );
737
  }
 
 
 
738
  }
739
  }
122
 
123
  $bp = buddypress();
124
 
125
+ // Check cache for friendship data.
126
+ $friendship = wp_cache_get( $this->id, 'bp_friends_friendships' );
127
+
128
+ // Cache missed, so query the DB.
129
+ if ( false === $friendship ) {
130
+ $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) );
131
+
132
+ wp_cache_set( $this->id, $friendship, 'bp_friends_friendships' );
133
+ }
134
+
135
+ // No friendship found so set the ID and bail.
136
+ if ( empty( $friendship ) || is_wp_error( $friendship ) ) {
137
+ $this->id = 0;
138
+ return;
139
  }
140
 
141
+ $this->initiator_user_id = (int) $friendship->initiator_user_id;
142
+ $this->friend_user_id = (int) $friendship->friend_user_id;
143
+ $this->is_confirmed = (int) $friendship->is_confirmed;
144
+ $this->is_limited = (int) $friendship->is_limited;
145
+ $this->date_created = $friendship->date_created;
146
+
147
+ if ( ! empty( $this->populate_friend_details ) ) {
148
  if ( $this->friend_user_id == bp_displayed_user_id() ) {
149
  $this->friend = new BP_Core_User( $this->initiator_user_id );
150
  } else {
219
 
220
  /** Static Methods ********************************************************/
221
 
222
+ /**
223
+ * Get the friendships for a given user.
224
+ *
225
+ * @since 2.6.0
226
+ *
227
+ * @param int $user_id ID of the user whose friends are being retrieved.
228
+ * @param array $args {
229
+ * Optional. Filter parameters.
230
+ * @type int $id ID of specific friendship to retrieve.
231
+ * @type int $initiator_user_id ID of friendship initiator.
232
+ * @type int $friend_user_id ID of specific friendship to retrieve.
233
+ * @type int $is_confirmed Whether the friendship has been accepted.
234
+ * @type int $is_limited Whether the friendship is limited.
235
+ * @type string $order_by Column name to order by.
236
+ * @type string $sort_order ASC or DESC. Default DESC.
237
+ * }
238
+ * @param string $operator Optional. Operator to use in `wp_list_filter()`.
239
+ *
240
+ * @return array $friendships Array of friendship objects.
241
+ */
242
+ public static function get_friendships( $user_id, $args = array(), $operator = 'AND' ) {
243
+
244
+ if ( empty( $user_id ) ) {
245
+ $user_id = bp_loggedin_user_id();
246
+ }
247
+
248
+ $r = bp_parse_args( $args, array(
249
+ 'id' => null,
250
+ 'initiator_user_id' => null,
251
+ 'friend_user_id' => null,
252
+ 'is_confirmed' => null,
253
+ 'is_limited' => null,
254
+ 'order_by' => 'date_created',
255
+ 'sort_order' => 'DESC',
256
+ 'page' => null,
257
+ 'per_page' => null
258
+ ), 'bp_get_user_friendships' );
259
+
260
+ // First, we get all friendships that involve the user.
261
+ $friendship_ids = wp_cache_get( $user_id, 'bp_friends_friendships_for_user' );
262
+ if ( false === $friendship_ids ) {
263
+ $friendship_ids = self::get_friendship_ids_for_user( $user_id );
264
+ wp_cache_set( $user_id, $friendship_ids, 'bp_friends_friendships_for_user' );
265
+ }
266
+
267
+ // Prime the membership cache.
268
+ $uncached_friendship_ids = bp_get_non_cached_ids( $friendship_ids, 'bp_friends_friendships' );
269
+ if ( ! empty( $uncached_friendship_ids ) ) {
270
+ $uncached_friendships = self::get_friendships_by_id( $uncached_friendship_ids );
271
+
272
+ foreach ( $uncached_friendships as $uncached_friendship ) {
273
+ wp_cache_set( $uncached_friendship->id, $uncached_friendship, 'bp_friends_friendships' );
274
+ }
275
+ }
276
+
277
+ // Assemble filter array.
278
+ $filters = wp_array_slice_assoc( $r, array( 'id', 'initiator_user_id', 'friend_user_id', 'is_confirmed', 'is_limited' ) );
279
+ foreach ( $filters as $filter_name => $filter_value ) {
280
+ if ( is_null( $filter_value ) ) {
281
+ unset( $filters[ $filter_name ] );
282
+ }
283
+ }
284
+
285
+ // Populate friendship array from cache, and normalize.
286
+ $friendships = array();
287
+ $int_keys = array( 'id', 'initiator_user_id', 'friend_user_id' );
288
+ $bool_keys = array( 'is_confirmed', 'is_limited' );
289
+ foreach ( $friendship_ids as $friendship_id ) {
290
+ // Create a limited BP_Friends_Friendship object (don't fetch the user details).
291
+ $friendship = new BP_Friends_Friendship( $friendship_id, false, false );
292
+
293
+ // Sanity check.
294
+ if ( ! isset( $friendship->id ) ) {
295
+ continue;
296
+ }
297
+
298
+ // Integer values.
299
+ foreach ( $int_keys as $index ) {
300
+ $friendship->{$index} = intval( $friendship->{$index} );
301
+ }
302
+
303
+ // Boolean values.
304
+ foreach ( $bool_keys as $index ) {
305
+ $friendship->{$index} = (bool) $friendship->{$index};
306
+ }
307
+
308
+ // We need to support the same operators as wp_list_filter().
309
+ if ( 'OR' == $operator || 'NOT' == $operator ) {
310
+ $matched = 0;
311
+
312
+ foreach ( $filters as $filter_name => $filter_value ) {
313
+ if ( isset( $friendship->{$filter_name} ) && $filter_value == $friendship->{$filter_name} ) {
314
+ $matched++;
315
+ }
316
+ }
317
+
318
+ if ( ( 'OR' == $operator && $matched > 0 )
319
+ || ( 'NOT' == $operator && 0 == $matched ) ) {
320
+ $friendships[ $friendship->id ] = $friendship;
321
+ }
322
+
323
+ } else {
324
+ /*
325
+ * This is the more typical 'AND' style of filter.
326
+ * If any of the filters miss, we move on.
327
+ */
328
+ foreach ( $filters as $filter_name => $filter_value ) {
329
+ if ( ! isset( $friendship->{$filter_name} ) || $filter_value != $friendship->{$filter_name} ) {
330
+ continue 2;
331
+ }
332
+ }
333
+ $friendships[ $friendship->id ] = $friendship;
334
+ }
335
+
336
+ }
337
+
338
+ // Sort the results on a column name.
339
+ if ( in_array( $r['order_by'], array( 'id', 'initiator_user_id', 'friend_user_id' ) ) ) {
340
+ $friendships = bp_sort_by_key( $friendships, $r['order_by'], 'num', true );
341
+ }
342
+
343
+ // Adjust the sort direction of the results.
344
+ if ( 'ASC' === strtoupper( $r['sort_order'] ) ) {
345
+ // `true` to preserve keys.
346
+ $friendships = array_reverse( $friendships, true );
347
+ }
348
+
349
+ // Paginate the results.
350
+ if ( $r['per_page'] && $r['page'] ) {
351
+ $start = ( $r['page'] - 1 ) * ( $r['per_page'] );
352
+ $friendships = array_slice( $friendships, $start, $r['per_page'] );
353
+ }
354
+
355
+ return $friendships;
356
+ }
357
+
358
+ /**
359
+ * Get all friendship IDs for a user.
360
+ *
361
+ * @since 2.7.0
362
+ *
363
+ * @param int $user_id ID of the user.
364
+ * @return array
365
+ */
366
+ public static function get_friendship_ids_for_user( $user_id ) {
367
+ global $wpdb;
368
+
369
+ $bp = buddypress();
370
+
371
+ $friendship_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) ORDER BY date_created DESC", $user_id, $user_id ) );
372
+
373
+ return $friendship_ids;
374
+ }
375
+
376
  /**
377
  * Get the IDs of a given user's friends.
378
  *
389
  public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
390
  global $wpdb;
391
 
392
+ if ( ! empty( $friend_requests_only ) ) {
393
+ $args = array(
394
+ 'is_confirmed' => 0,
395
+ 'friend_user_id' => $user_id
396
+ );
397
  } else {
398
+ $args = array(
399
+ 'is_confirmed' => 1,
400
+ );
401
  }
402
 
403
+ $friendships = self::get_friendships( $user_id, $args );
 
 
404
 
405
+ $fids = array();
406
+ foreach ( $friendships as $friendship ) {
407
+ if ( ! empty( $assoc_arr ) ) {
408
+ $fids[] = array( 'user_id' => ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id );
409
  } else {
410
+ $fids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
411
  }
412
  }
413
 
414
+ return array_map( 'intval', $fids );
415
  }
416
 
417
  /**
421
  *
422
  * @param int $user_id The ID of the first user.
423
  * @param int $friend_id The ID of the second user.
424
+ * @return int|null The ID of the friendship object if found, otherwise null.
425
  */
426
  public static function get_friendship_id( $user_id, $friend_id ) {
427
+ $friendship_id = null;
428
 
429
+ // Can't friend yourself.
430
+ if ( $user_id == $friend_id ) {
431
+ return $friendship_id;
432
+ }
433
 
434
+ /*
435
+ * Find friendships where the possible_friend_userid is the
436
+ * initiator or friend.
437
+ */
438
+ $args = array(
439
+ 'initiator_user_id' => $friend_id,
440
+ 'friend_user_id' => $friend_id
441
+ );
442
+ $result = self::get_friendships( $user_id, $args, 'OR' );
443
+ if ( $result ) {
444
+ $friendship_id = current( $result )->id;
445
+ }
446
+ return $friendship_id;
447
  }
448
 
449
  /**
459
  $friend_requests = wp_cache_get( $user_id, 'bp_friends_requests' );
460
 
461
  if ( false === $friend_requests ) {
462
+ $friend_requests = self::get_friend_user_ids( $user_id, true );
 
 
 
 
463
 
464
  wp_cache_set( $user_id, $friend_requests, 'bp_friends_requests' );
465
  }
466
 
467
+ // Integer casting.
468
+ if ( ! empty( $friend_requests ) ) {
469
+ $friend_requests = array_map( 'intval', $friend_requests );
470
+ }
471
+
472
  return $friend_requests;
473
  }
474
 
485
  public static function total_friend_count( $user_id = 0 ) {
486
  global $wpdb;
487
 
488
+ if ( empty( $user_id ) ) {
489
  $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
490
+ }
 
491
 
492
  /*
493
  * This is stored in 'total_friend_count' usermeta.
494
  * This function will recalculate, update and return.
495
  */
496
 
497
+ $args = array(
498
+ 'is_confirmed' => 1,
499
+ );
500
+ $friendships = self::get_friendships( $user_id, $args );
501
+ $count = count( $friendships );
502
 
503
  // Do not update meta if user has never had friends.
504
+ if ( ! $count && ! bp_get_user_meta( $user_id, 'total_friend_count', true ) ) {
505
  return 0;
506
+ }
507
 
508
  bp_update_user_meta( $user_id, 'total_friend_count', (int) $count );
509
 
571
  if ( empty( $filtered_friend_ids ) )
572
  return false;
573
 
574
+ return array( 'friends' => array_map( 'intval', $filtered_friend_ids ), 'total' => (int) $total_friend_ids );
575
  }
576
 
577
  /**
598
  return false;
599
  }
600
 
601
+ // Can't friend yourself.
602
+ if ( $initiator_userid == $possible_friend_userid ) {
603
+ return 'not_friends';
604
+ }
605
 
606
+ /*
607
+ * Find friendships where the possible_friend_userid is the
608
+ * initiator or friend.
609
+ */
610
+ $args = array(
611
+ 'initiator_user_id' => $possible_friend_userid,
612
+ 'friend_user_id' => $possible_friend_userid
613
+ );
614
+ $result = self::get_friendships( $initiator_userid, $args, 'OR' );
615
+
616
+ if ( $result ) {
617
+ $friendship = current( $result );
618
+ if ( ! $friendship->is_confirmed ) {
619
+ $status = $initiator_userid == $friendship->initiator_user_id ? 'pending' : 'awaiting_response';
620
  } else {
621
  $status = 'is_friend';
622
  }
893
  return $invitable_count;
894
  }
895
 
896
+ /**
897
+ * Get friendship objects by ID (or an array of IDs).
898
+ *
899
+ * @since 2.7.0
900
+ *
901
+ * @param int|string|array $friendship_ids Single friendship ID or comma-separated/array list of friendship IDs.
902
+ * @return array
903
+ */
904
+ public static function get_friendships_by_id( $friendship_ids ) {
905
+ global $wpdb;
906
+
907
+ $bp = buddypress();
908
+
909
+ $friendship_ids = implode( ',', wp_parse_id_list( $friendship_ids ) );
910
+ return $wpdb->get_results( "SELECT * FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids})" );
911
+ }
912
+
913
  /**
914
  * Get the friend user IDs for a given friendship.
915
  *
919
  * @return object friend_user_id and initiator_user_id.
920
  */
921
  public static function get_user_ids_for_friendship( $friendship_id ) {
 
922
 
923
+ $friendship = new BP_Friends_Friendship( $friendship_id, false, false );
924
+
925
+ if ( empty( $friendship->id ) ) {
926
+ return null;
927
+ }
928
+
929
+ $retval = new StdClass;
930
+ $retval->friend_user_id = $friendship->friend_user_id;
931
+ $retval->initiator_user_id = $friendship->initiator_user_id;
932
 
933
+ return $retval;
934
  }
935
 
936
  /**
945
 
946
  $bp = buddypress();
947
 
948
+ // Get all friendships, of any status, for the user.
949
+ $friendships = self::get_friendships( $user_id );
950
+ $friend_ids = array();
951
+ $friendship_ids = array();
952
+ foreach ( $friendships as $friendship ) {
953
+ $friendship_ids[] = $friendship->id;
954
+ if ( $friendship->is_confirmed ) {
955
+ $friend_ids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
956
+ }
957
+ }
958
 
959
+ // Delete the friendships from the database.
960
+ if ( $friendship_ids ) {
961
+ $friendship_ids_sql = implode( ',', wp_parse_id_list( $friendship_ids ) );
962
+ $wpdb->query( "DELETE FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids_sql})" );
963
+ }
964
 
965
  // Delete friend request notifications for members who have a
966
  // notification from this user.
968
  $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 ) );
969
  }
970
 
971
+ // Clean up the friendships cache.
972
+ foreach ( $friendship_ids as $friendship_id ) {
973
+ wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
974
+ }
975
+
976
+ // Loop through friend_ids to scrub user caches and update total count metas.
977
  foreach ( (array) $friend_ids as $friend_id ) {
978
+ // Delete cached friendships.
979
+ wp_cache_delete( $friend_id, 'bp_friends_friendships_for_user' );
980
  BP_Friends_Friendship::total_friend_count( $friend_id );
981
  }
982
+
983
+ // Delete cached friendships.
984
+ wp_cache_delete( $user_id, 'bp_friends_friendships_for_user' );
985
  }
986
  }
bp-groups/admin/css/admin-rtl.css CHANGED
@@ -28,15 +28,19 @@ body.toplevel_page_bp-groups table.groups th#last_active {
28
  #bp-groups-new-members-list {
29
  margin: 0;
30
  }
31
- #bp_group_settings legend {
32
- margin: 10px 0;
33
- font-weight: bold;
34
- }
35
- #bp_group_settings ul {
36
- margin: 0;
37
- }
38
  .bp-groups-settings-section {
39
  margin-top: 10px;
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
  #bp-groups-permalink-box {
42
  line-height: 24px;
@@ -84,3 +88,9 @@ table.bp-group-members .urole-column {
84
  padding-right: 20px;
85
  padding-left: 20px;
86
  }
 
 
 
 
 
 
28
  #bp-groups-new-members-list {
29
  margin: 0;
30
  }
 
 
 
 
 
 
 
31
  .bp-groups-settings-section {
32
  margin-top: 10px;
33
+ line-height: 2em;
34
+ }
35
+ .bp-groups-settings-section legend {
36
+ margin-top: 10px;
37
+ font-weight: bold;
38
+ }
39
+ .bp-groups-settings-section label {
40
+ clear: right;
41
+ display: block;
42
+ float: right;
43
+ vertical-align: middle;
44
  }
45
  #bp-groups-permalink-box {
46
  line-height: 24px;
88
  padding-right: 20px;
89
  padding-left: 20px;
90
  }
91
+
92
+ @media screen and (max-width: 782px) {
93
+ .bp-groups-settings-section label {
94
+ margin: 0.25em 0;
95
+ }
96
+ }
bp-groups/admin/css/admin-rtl.min.css CHANGED
@@ -1 +1 @@
1
- body.toplevel_page_bp-groups table.groups th#members,body.toplevel_page_bp-groups table.groups th#status{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-form .avatar{float:right;margin-left:10px;margin-top:1px}#bp-groups-edit-form input{outline:0}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%;margin-bottom:6px}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}#bp-groups-new-members-list,#bp_group_settings ul{margin:0}#bp_group_settings legend{margin:10px 0;font-weight:700}.bp-groups-settings-section{margin-top:10px}#bp-groups-permalink-box{line-height:24px;color:#666}.bp-groups-member-type{position:relative}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:left;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-right:15px}table.bp-group-members .uid-column,table.bp-group-members .urole-column{padding-right:20px;padding-left:20px}table.bp-group-members .uname-column{width:70%}
1
+ body.toplevel_page_bp-groups table.groups th#members,body.toplevel_page_bp-groups table.groups th#status{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-form .avatar{float:right;margin-left:10px;margin-top:1px}#bp-groups-edit-form input{outline:0}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%;margin-bottom:6px}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}#bp-groups-new-members-list{margin:0}.bp-groups-settings-section{margin-top:10px;line-height:2em}.bp-groups-settings-section legend{margin-top:10px;font-weight:700}.bp-groups-settings-section label{clear:right;display:block;float:right;vertical-align:middle}#bp-groups-permalink-box{line-height:24px;color:#666}.bp-groups-member-type{position:relative}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:left;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-right:15px}table.bp-group-members .uid-column,table.bp-group-members .urole-column{padding-right:20px;padding-left:20px}table.bp-group-members .uname-column{width:70%}@media screen and (max-width:782px){.bp-groups-settings-section label{margin:.25em 0}}
bp-groups/admin/css/admin.css CHANGED
@@ -28,15 +28,19 @@ body.toplevel_page_bp-groups table.groups th#last_active {
28
  #bp-groups-new-members-list {
29
  margin: 0;
30
  }
31
- #bp_group_settings legend {
32
- margin: 10px 0;
33
- font-weight: bold;
34
- }
35
- #bp_group_settings ul {
36
- margin: 0;
37
- }
38
  .bp-groups-settings-section {
39
  margin-top: 10px;
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
  #bp-groups-permalink-box {
42
  line-height: 24px;
@@ -84,3 +88,9 @@ table.bp-group-members .urole-column {
84
  padding-left: 20px;
85
  padding-right: 20px;
86
  }
 
 
 
 
 
 
28
  #bp-groups-new-members-list {
29
  margin: 0;
30
  }
 
 
 
 
 
 
 
31
  .bp-groups-settings-section {
32
  margin-top: 10px;
33
+ line-height: 2em;
34
+ }
35
+ .bp-groups-settings-section legend {
36
+ margin-top: 10px;
37
+ font-weight: bold;
38
+ }
39
+ .bp-groups-settings-section label {
40
+ clear: left;
41
+ display: block;
42
+ float: left;
43
+ vertical-align: middle;
44
  }
45
  #bp-groups-permalink-box {
46
  line-height: 24px;
88
  padding-left: 20px;
89
  padding-right: 20px;
90
  }
91
+
92
+ @media screen and (max-width: 782px) {
93
+ .bp-groups-settings-section label {
94
+ margin: 0.25em 0;
95
+ }
96
+ }
bp-groups/admin/css/admin.min.css CHANGED
@@ -1 +1 @@
1
- body.toplevel_page_bp-groups table.groups th#members,body.toplevel_page_bp-groups table.groups th#status{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-form .avatar{float:left;margin-right:10px;margin-top:1px}#bp-groups-edit-form input{outline:0}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%;margin-bottom:6px}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}#bp-groups-new-members-list,#bp_group_settings ul{margin:0}#bp_group_settings legend{margin:10px 0;font-weight:700}.bp-groups-settings-section{margin-top:10px}#bp-groups-permalink-box{line-height:24px;color:#666}.bp-groups-member-type{position:relative}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:right;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-left:15px}table.bp-group-members .uid-column,table.bp-group-members .urole-column{padding-left:20px;padding-right:20px}table.bp-group-members .uname-column{width:70%}
1
+ body.toplevel_page_bp-groups table.groups th#members,body.toplevel_page_bp-groups table.groups th#status{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-form .avatar{float:left;margin-right:10px;margin-top:1px}#bp-groups-edit-form input{outline:0}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%;margin-bottom:6px}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}#bp-groups-new-members-list{margin:0}.bp-groups-settings-section{margin-top:10px;line-height:2em}.bp-groups-settings-section legend{margin-top:10px;font-weight:700}.bp-groups-settings-section label{clear:left;display:block;float:left;vertical-align:middle}#bp-groups-permalink-box{line-height:24px;color:#666}.bp-groups-member-type{position:relative}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:right;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-left:15px}table.bp-group-members .uid-column,table.bp-group-members .urole-column{padding-left:20px;padding-right:20px}table.bp-group-members .uname-column{width:70%}@media screen and (max-width:782px){.bp-groups-settings-section label{margin:.25em 0}}
bp-groups/admin/js/admin.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){function b(b,c){a("#bp-groups-new-members-list").append('<li data-login="'+c.item.value+'"><a href="#" class="bp-groups-remove-new-member">x</a> '+c.item.label+"</li>")}var c="undefined"!=typeof group_id?"&group_id="+group_id:"";a(document).ready(function(){window.warn_on_leave=!1,a(".bp-suggest-user").autocomplete({source:ajaxurl+"?action=bp_group_admin_member_autocomplete"+c,delay:500,minLength:2,position:"undefined"!=typeof isRtl&&isRtl?{my:"right top",at:"right bottom",offset:"0, -1"}:{offset:"0, -1"},open:function(){a(this).addClass("open")},close:function(){a(this).removeClass("open"),a(this).val("")},select:function(a,c){b(a,c)}}),a("#bp-groups-new-members").prop("placeholder",BP_Group_Admin.add_member_placeholder),a("#bp_group_add_members").on("click",".bp-groups-remove-new-member",function(b){b.preventDefault(),a(b.target.parentNode).remove()}),a(document).on("change",'input#bp-groups-name, input#bp-groups-description, select.bp-groups-role, #bp-groups-settings-section-status input[type="radio"]',function(){window.warn_on_leave=!0}),a("input#save").on("click",function(){var b=[];a("#bp-groups-new-members-list li").each(function(){b.push(a(this).data("login"))}),b.length&&a("#bp-groups-new-members").val("").val(b.join(", ")),window.warn_on_leave=!1}),window.onbeforeunload=function(){return window.warn_on_leave?BP_Group_Admin.warn_on_leave:void 0}})}(jQuery);
1
+ !function(a){function b(b,c){a("#bp-groups-new-members-list").append('<li data-login="'+c.item.value+'"><a href="#" class="bp-groups-remove-new-member">x</a> '+c.item.label+"</li>")}var c="undefined"!=typeof group_id?"&group_id="+group_id:"";a(document).ready(function(){window.warn_on_leave=!1,a(".bp-suggest-user").autocomplete({source:ajaxurl+"?action=bp_group_admin_member_autocomplete"+c,delay:500,minLength:2,position:"undefined"!=typeof isRtl&&isRtl?{my:"right top",at:"right bottom",offset:"0, -1"}:{offset:"0, -1"},open:function(){a(this).addClass("open")},close:function(){a(this).removeClass("open"),a(this).val("")},select:function(a,c){b(a,c)}}),a("#bp-groups-new-members").prop("placeholder",BP_Group_Admin.add_member_placeholder),a("#bp_group_add_members").on("click",".bp-groups-remove-new-member",function(b){b.preventDefault(),a(b.target.parentNode).remove()}),a(document).on("change",'input#bp-groups-name, input#bp-groups-description, select.bp-groups-role, #bp-groups-settings-section-status input[type="radio"]',function(){window.warn_on_leave=!0}),a("input#save").on("click",function(){var b=[];a("#bp-groups-new-members-list li").each(function(){b.push(a(this).data("login"))}),b.length&&a("#bp-groups-new-members").val("").val(b.join(", ")),window.warn_on_leave=!1}),window.onbeforeunload=function(){if(window.warn_on_leave)return BP_Group_Admin.warn_on_leave}})}(jQuery);
bp-groups/bp-groups-actions.php CHANGED
@@ -27,7 +27,7 @@ function bp_groups_register_group_types() {
27
  */
28
  do_action( 'bp_groups_register_group_types' );
29
  }
30
- add_action( 'bp_init', 'bp_groups_register_group_types', 1 );
31
 
32
  /**
33
  * Protect access to single groups.
@@ -158,7 +158,7 @@ function groups_action_create_group() {
158
  // Set the ID of the new group, if it has already been created in a previous step.
159
  if ( isset( $_COOKIE['bp_new_group_id'] ) ) {
160
  $bp->groups->new_group_id = (int) $_COOKIE['bp_new_group_id'];
161
- $bp->groups->current_group = groups_get_group( array( 'group_id' => $bp->groups->new_group_id ) );
162
 
163
  // Only allow the group creator to continue to edit the new group.
164
  if ( ! bp_is_group_creator( $bp->groups->current_group, bp_loggedin_user_id() ) ) {
@@ -210,6 +210,11 @@ function groups_action_create_group() {
210
  bp_core_redirect( trailingslashit( bp_get_groups_directory_permalink() . 'create/step/' . bp_get_groups_current_create_step() ) );
211
  }
212
 
 
 
 
 
 
213
  /**
214
  * Filters the allowed invite statuses.
215
  *
@@ -566,3 +571,29 @@ function groups_action_group_feed() {
566
  ) );
567
  }
568
  add_action( 'bp_actions', 'groups_action_group_feed' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  */
28
  do_action( 'bp_groups_register_group_types' );
29
  }
30
+ add_action( 'bp_register_taxonomies', 'bp_groups_register_group_types' );
31
 
32
  /**
33
  * Protect access to single groups.
158
  // Set the ID of the new group, if it has already been created in a previous step.
159
  if ( isset( $_COOKIE['bp_new_group_id'] ) ) {
160
  $bp->groups->new_group_id = (int) $_COOKIE['bp_new_group_id'];
161
+ $bp->groups->current_group = groups_get_group( $bp->groups->new_group_id );
162
 
163
  // Only allow the group creator to continue to edit the new group.
164
  if ( ! bp_is_group_creator( $bp->groups->current_group, bp_loggedin_user_id() ) ) {
210
  bp_core_redirect( trailingslashit( bp_get_groups_directory_permalink() . 'create/step/' . bp_get_groups_current_create_step() ) );
211
  }
212
 
213
+ // Save group types.
214
+ if ( ! empty( $_POST['group-types'] ) ) {
215
+ bp_groups_set_group_type( $bp->groups->new_group_id, $_POST['group-types'] );
216
+ }
217
+
218
  /**
219
  * Filters the allowed invite statuses.
220
  *
571
  ) );
572
  }
573
  add_action( 'bp_actions', 'groups_action_group_feed' );
574
+
575
+ /**
576
+ * Update orphaned child groups when the parent is deleted.
577
+ *
578
+ * @since 2.7.0
579
+ *
580
+ * @param BP_Groups_Group $group Instance of the group item being deleted.
581
+ */
582
+ function bp_groups_update_orphaned_groups_on_group_delete( $group ) {
583
+ // Get child groups and set the parent to the deleted parent's parent.
584
+ $grandparent_group_id = $group->parent_id;
585
+ $child_args = array(
586
+ 'parent_id' => $group->id,
587
+ 'show_hidden' => true,
588
+ 'per_page' => false,
589
+ 'update_meta_cache' => false,
590
+ );
591
+ $children = groups_get_groups( $child_args );
592
+ $children = $children['groups'];
593
+
594
+ foreach ( $children as $cgroup ) {
595
+ $cgroup->parent_id = $grandparent_group_id;
596
+ $cgroup->save();
597
+ }
598
+ }
599
+ add_action( 'bp_groups_delete_group', 'bp_groups_update_orphaned_groups_on_group_delete', 10, 2 );
bp-groups/bp-groups-activity.php CHANGED
@@ -98,10 +98,7 @@ add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' )
98
  function bp_groups_format_activity_action_created_group( $action, $activity ) {
99
  $user_link = bp_core_get_userlink( $activity->user_id );
100
 
101
- $group = groups_get_group( array(
102
- 'group_id' => $activity->item_id,
103
- 'populate_extras' => false,
104
- ) );
105
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
106
 
107
  $action = sprintf( __( '%1$s created the group %2$s', 'buddypress'), $user_link, $group_link );
@@ -129,10 +126,7 @@ function bp_groups_format_activity_action_created_group( $action, $activity ) {
129
  function bp_groups_format_activity_action_joined_group( $action, $activity ) {
130
  $user_link = bp_core_get_userlink( $activity->user_id );
131
 
132
- $group = groups_get_group( array(
133
- 'group_id' => $activity->item_id,
134
- 'populate_extras' => false,
135
- ) );
136
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
137
 
138
  $action = sprintf( __( '%1$s joined the group %2$s', 'buddypress' ), $user_link, $group_link );
@@ -171,10 +165,7 @@ function bp_groups_format_activity_action_joined_group( $action, $activity ) {
171
  function bp_groups_format_activity_action_group_details_updated( $action, $activity ) {
172
  $user_link = bp_core_get_userlink( $activity->user_id );
173
 
174
- $group = groups_get_group( array(
175
- 'group_id' => $activity->item_id,
176
- 'populate_extras' => false,
177
- ) );
178
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
179
 
180
  /*
@@ -360,7 +351,7 @@ function groups_record_activity( $args = '' ) {
360
  if ( bp_get_current_group_id() == $args['item_id'] ) {
361
  $group = groups_get_current_group();
362
  } else {
363
- $group = groups_get_group( array( 'group_id' => $args['item_id'] ) );
364
  }
365
 
366
  if ( isset( $group->status ) && 'public' != $group->status ) {
@@ -430,7 +421,7 @@ function bp_groups_membership_accepted_add_activity( $user_id, $group_id ) {
430
  }
431
 
432
  // Get the group so we can get it's name.
433
- $group = groups_get_group( array( 'group_id' => $group_id ) );
434
 
435
  /**
436
  * Filters the 'membership_accepted' activity actions.
98
  function bp_groups_format_activity_action_created_group( $action, $activity ) {
99
  $user_link = bp_core_get_userlink( $activity->user_id );
100
 
101
+ $group = groups_get_group( $activity->item_id );
 
 
 
102
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
103
 
104
  $action = sprintf( __( '%1$s created the group %2$s', 'buddypress'), $user_link, $group_link );
126
  function bp_groups_format_activity_action_joined_group( $action, $activity ) {
127
  $user_link = bp_core_get_userlink( $activity->user_id );
128
 
129
+ $group = groups_get_group( $activity->item_id );
 
 
 
130
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
131
 
132
  $action = sprintf( __( '%1$s joined the group %2$s', 'buddypress' ), $user_link, $group_link );
165
  function bp_groups_format_activity_action_group_details_updated( $action, $activity ) {
166
  $user_link = bp_core_get_userlink( $activity->user_id );
167
 
168
+ $group = groups_get_group( $activity->item_id );
 
 
 
169
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
170
 
171
  /*
351
  if ( bp_get_current_group_id() == $args['item_id'] ) {
352
  $group = groups_get_current_group();
353
  } else {
354
+ $group = groups_get_group( $args['item_id'] );
355
  }
356
 
357
  if ( isset( $group->status ) && 'public' != $group->status ) {
421
  }
422
 
423
  // Get the group so we can get it's name.
424
+ $group = groups_get_group( $group_id );
425
 
426
  /**
427
  * Filters the 'membership_accepted' activity actions.
bp-groups/bp-groups-admin.php CHANGED
@@ -227,7 +227,7 @@ function bp_groups_admin_load() {
227
  check_admin_referer( 'edit-group_' . $group_id );
228
 
229
  // Get the group from the database.
230
- $group = groups_get_group( 'group_id=' . $group_id );
231
 
232
  // If the group doesn't exist, just redirect back to the index.
233
  if ( empty( $group->slug ) ) {
@@ -566,7 +566,7 @@ function bp_groups_admin_edit() {
566
  $is_error = ! empty( $no_admins ) || ! empty( $errors ) || ! empty( $error_new ) || ! empty( $error_modified );
567
 
568
  // Get the group from the database.
569
- $group = groups_get_group( 'group_id=' . (int) $_GET['gid'] );
570
 
571
  $group_name = isset( $group->name ) ? bp_get_group_name( $group ) : '';
572
 
@@ -798,7 +798,7 @@ function bp_groups_admin_edit_metabox_settings( $item ) {
798
 
799
  <?php if ( bp_is_active( 'forums' ) ) : ?>
800
  <div class="bp-groups-settings-section" id="bp-groups-settings-section-forum">
801
- <label for="group-show-forum"><input type="checkbox" name="group-show-forum" id="group-show-forum" <?php checked( $item->enable_forum ) ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ) ?><br />
802
  </div>
803
  <?php endif; ?>
804
 
@@ -806,11 +806,9 @@ function bp_groups_admin_edit_metabox_settings( $item ) {
806
  <fieldset>
807
  <legend><?php _e( 'Privacy', 'buddypress' ); ?></legend>
808
 
809
- <ul>
810
- <li><input type="radio" name="group-status" id="bp-group-status-public" value="public" <?php checked( $item->status, 'public' ) ?> /><label for="bp-group-status-public"><?php _e( 'Public', 'buddypress' ) ?></label></li>
811
- <li><input type="radio" name="group-status" id="bp-group-status-private" value="private" <?php checked( $item->status, 'private' ) ?> /><label for="bp-group-status-private"><?php _e( 'Private', 'buddypress' ) ?></label></li>
812
- <li><input type="radio" name="group-status" id="bp-group-status-hidden" value="hidden" <?php checked( $item->status, 'hidden' ) ?> /><label for="bp-group-status-hidden"><?php _e( 'Hidden', 'buddypress' ) ?></label></li>
813
- </ul>
814
  </fieldset>
815
  </div>
816
 
@@ -818,11 +816,9 @@ function bp_groups_admin_edit_metabox_settings( $item ) {
818
  <fieldset>
819
  <legend><?php _e( 'Who can invite others to this group?', 'buddypress' ); ?></legend>
820
 
821
- <ul>
822
- <li><input type="radio" name="group-invite-status" id="bp-group-invite-status-members" value="members" <?php checked( $invite_status, 'members' ) ?> /><label for="bp-group-invite-status-members"><?php _e( 'All group members', 'buddypress' ) ?></label></li>
823
- <li><input type="radio" name="group-invite-status" id="bp-group-invite-status-mods" value="mods" <?php checked( $invite_status, 'mods' ) ?> /><label for="bp-group-invite-status-mods"><?php _e( 'Group admins and mods only', 'buddypress' ) ?></label></li>
824
- <li><input type="radio" name="group-invite-status" id="bp-group-invite-status-admins" value="admins" <?php checked( $invite_status, 'admins' ) ?> /><label for="bp-group-invite-status-admins"><?php _e( 'Group admins only', 'buddypress' ) ?></label></li>
825
- </ul>
826
  </fieldset>
827
  </div>
828
 
@@ -1228,3 +1224,101 @@ function bp_groups_admin_autocomplete_handler() {
1228
  wp_die( json_encode( $matches ) );
1229
  }
1230
  add_action( 'wp_ajax_bp_group_admin_member_autocomplete', 'bp_groups_admin_autocomplete_handler' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  check_admin_referer( 'edit-group_' . $group_id );
228
 
229
  // Get the group from the database.
230
+ $group = groups_get_group( $group_id );
231
 
232
  // If the group doesn't exist, just redirect back to the index.
233
  if ( empty( $group->slug ) ) {
566
  $is_error = ! empty( $no_admins ) || ! empty( $errors ) || ! empty( $error_new ) || ! empty( $error_modified );
567
 
568
  // Get the group from the database.
569
+ $group = groups_get_group( (int) $_GET['gid'] );
570
 
571
  $group_name = isset( $group->name ) ? bp_get_group_name( $group ) : '';
572
 
798
 
799
  <?php if ( bp_is_active( 'forums' ) ) : ?>
800
  <div class="bp-groups-settings-section" id="bp-groups-settings-section-forum">
801
+ <label for="group-show-forum"><input type="checkbox" name="group-show-forum" id="group-show-forum" <?php checked( $item->enable_forum ) ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ) ?></label>
802
  </div>
803
  <?php endif; ?>
804
 
806
  <fieldset>
807
  <legend><?php _e( 'Privacy', 'buddypress' ); ?></legend>
808
 
809
+ <label for="bp-group-status-public"><input type="radio" name="group-status" id="bp-group-status-public" value="public" <?php checked( $item->status, 'public' ) ?> /><?php _e( 'Public', 'buddypress' ) ?></label>
810
+ <label for="bp-group-status-private"><input type="radio" name="group-status" id="bp-group-status-private" value="private" <?php checked( $item->status, 'private' ) ?> /><?php _e( 'Private', 'buddypress' ) ?></label>
811
+ <label for="bp-group-status-hidden"><input type="radio" name="group-status" id="bp-group-status-hidden" value="hidden" <?php checked( $item->status, 'hidden' ) ?> /><?php _e( 'Hidden', 'buddypress' ) ?></label>
 
 
812
  </fieldset>
813
  </div>
814
 
816
  <fieldset>
817
  <legend><?php _e( 'Who can invite others to this group?', 'buddypress' ); ?></legend>
818
 
819
+ <label for="bp-group-invite-status-members"><input type="radio" name="group-invite-status" id="bp-group-invite-status-members" value="members" <?php checked( $invite_status, 'members' ) ?> /><?php _e( 'All group members', 'buddypress' ) ?></label>
820
+ <label for="bp-group-invite-status-mods"><input type="radio" name="group-invite-status" id="bp-group-invite-status-mods" value="mods" <?php checked( $invite_status, 'mods' ) ?> /><?php _e( 'Group admins and mods only', 'buddypress' ) ?></label>
821
+ <label for="bp-group-invite-status-admins"><input type="radio" name="group-invite-status" id="bp-group-invite-status-admins" value="admins" <?php checked( $invite_status, 'admins' ) ?> /><?php _e( 'Group admins only', 'buddypress' ) ?></label>
 
 
822
  </fieldset>
823
  </div>
824
 
1224
  wp_die( json_encode( $matches ) );
1225
  }
1226
  add_action( 'wp_ajax_bp_group_admin_member_autocomplete', 'bp_groups_admin_autocomplete_handler' );
1227
+
1228
+ /**
1229
+ * Process input from the Group Type bulk change select.
1230
+ *
1231
+ * @since 2.7.0
1232
+ *
1233
+ * @param string $doaction Current $_GET action being performed in admin screen.
1234
+ */
1235
+ function bp_groups_admin_process_group_type_bulk_changes( $doaction ) {
1236
+ // Bail if no groups are specified or if this isn't a relevant action.
1237
+ if ( empty( $_REQUEST['gid'] )
1238
+ || ( empty( $_REQUEST['bp_change_type'] ) && empty( $_REQUEST['bp_change_type2'] ) )
1239
+ || empty( $_REQUEST['bp_change_group_type'] )
1240
+ ) {
1241
+ return;
1242
+ }
1243
+
1244
+ // Bail if nonce check fails.
1245
+ check_admin_referer( 'bp-bulk-groups-change-type-' . bp_loggedin_user_id(), 'bp-bulk-groups-change-type-nonce' );
1246
+
1247
+ if ( ! bp_current_user_can( 'bp_moderate' ) ) {
1248
+ return;
1249
+ }
1250
+
1251
+ $new_type = '';
1252
+ if ( ! empty( $_REQUEST['bp_change_type2'] ) ) {
1253
+ $new_type = sanitize_text_field( $_REQUEST['bp_change_type2'] );
1254
+ } elseif ( ! empty( $_REQUEST['bp_change_type'] ) ) {
1255
+ $new_type = sanitize_text_field( $_REQUEST['bp_change_type'] );
1256
+ }
1257
+
1258
+ // Check that the selected type actually exists.
1259
+ if ( 'remove_group_type' !== $new_type && null === bp_groups_get_group_type_object( $new_type ) ) {
1260
+ $error = true;
1261
+ } else {
1262
+ // Run through group ids.
1263
+ $error = false;
1264
+ foreach ( (array) $_REQUEST['gid'] as $group_id ) {
1265
+ $group_id = (int) $group_id;
1266
+
1267
+ // Get the old group type to check against.
1268
+ $group_type = bp_groups_get_group_type( $group_id );
1269
+
1270
+ if ( 'remove_group_type' === $new_type ) {
1271
+ // Remove the current group type, if there's one to remove.
1272
+ if ( $group_type ) {
1273
+ $removed = bp_groups_remove_group_type( $group_id, $group_type );
1274
+ if ( false === $removed || is_wp_error( $removed ) ) {
1275
+ $error = true;
1276
+ }
1277
+ }
1278
+ } else {
1279
+ // Set the new group type.
1280
+ if ( $new_type !== $group_type ) {
1281
+ $set = bp_groups_set_group_type( $group_id, $new_type );
1282
+ if ( false === $set || is_wp_error( $set ) ) {
1283
+ $error = true;
1284
+ }
1285
+ }
1286
+ }
1287
+ }
1288
+ }
1289
+
1290
+ // If there were any errors, show the error message.
1291
+ if ( $error ) {
1292
+ $redirect = add_query_arg( array( 'updated' => 'group-type-change-error' ), wp_get_referer() );
1293
+ } else {
1294
+ $redirect = add_query_arg( array( 'updated' => 'group-type-change-success' ), wp_get_referer() );
1295
+ }
1296
+
1297
+ wp_redirect( $redirect );
1298
+ exit();
1299
+ }
1300
+ add_action( 'bp_groups_admin_load', 'bp_groups_admin_process_group_type_bulk_changes' );
1301
+
1302
+ /**
1303
+ * Display an admin notice upon group type bulk update.
1304
+ *
1305
+ * @since 2.7.0
1306
+ */
1307
+ function bp_groups_admin_groups_type_change_notice() {
1308
+ $updated = isset( $_REQUEST['updated'] ) ? $_REQUEST['updated'] : false;
1309
+
1310
+ // Display feedback.
1311
+ if ( $updated && in_array( $updated, array( 'group-type-change-error', 'group-type-change-success' ), true ) ) {
1312
+
1313
+ if ( 'group-type-change-error' === $updated ) {
1314
+ $notice = __( 'There was an error while changing group type. Please try again.', 'buddypress' );
1315
+ $type = 'error';
1316
+ } else {
1317
+ $notice = __( 'Group type was changed successfully.', 'buddypress' );
1318
+ $type = 'updated';
1319
+ }
1320
+
1321
+ bp_core_add_admin_notice( $notice, $type );
1322
+ }
1323
+ }
1324
+ add_action( bp_core_admin_hook(), 'bp_groups_admin_groups_type_change_notice' );
bp-groups/bp-groups-cache.php CHANGED
@@ -184,7 +184,7 @@ add_action( 'groups_uninvite_user', 'groups_clear_group_user_object_cache', 10,
184
  add_action( 'groups_remove_member', 'groups_clear_group_user_object_cache', 10, 2 );
185
 
186
  /**
187
- * Clear group administrator cache.
188
  *
189
  * @since 2.1.0
190
  *
@@ -192,15 +192,16 @@ add_action( 'groups_remove_member', 'groups_clear_group_user_object_cache', 10,
192
  */
193
  function groups_clear_group_administrator_cache( $group_id ) {
194
  wp_cache_delete( $group_id, 'bp_group_admins' );
 
195
  }
196
  add_action( 'groups_promote_member', 'groups_clear_group_administrator_cache' );
197
  add_action( 'groups_demote_member', 'groups_clear_group_administrator_cache' );
198
  add_action( 'groups_delete_group', 'groups_clear_group_administrator_cache' );
199
 
200
  /**
201
- * Clear group administrator cache when a group member is saved.
202
  *
203
- * This accounts for situations where group administrators are added manually
204
  * using {@link BP_Groups_Member::save()}. Usually via a plugin.
205
  *
206
  * @since 2.1.0
@@ -253,6 +254,75 @@ add_action( 'bp_groups_member_before_delete', 'bp_groups_clear_user_group_cache_
253
  add_action( 'bp_groups_member_before_delete_invite', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
254
  add_action( 'groups_accept_invite', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
255
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  /* List actions to clear super cached pages on, if super cache is installed */
257
  add_action( 'groups_join_group', 'bp_core_clear_cache' );
258
  add_action( 'groups_leave_group', 'bp_core_clear_cache' );
184
  add_action( 'groups_remove_member', 'groups_clear_group_user_object_cache', 10, 2 );
185
 
186
  /**
187
+ * Clear group administrator and moderator cache.
188
  *
189
  * @since 2.1.0
190
  *
192
  */
193
  function groups_clear_group_administrator_cache( $group_id ) {
194
  wp_cache_delete( $group_id, 'bp_group_admins' );
195
+ wp_cache_delete( $group_id, 'bp_group_mods' );
196
  }
197
  add_action( 'groups_promote_member', 'groups_clear_group_administrator_cache' );
198
  add_action( 'groups_demote_member', 'groups_clear_group_administrator_cache' );
199
  add_action( 'groups_delete_group', 'groups_clear_group_administrator_cache' );
200
 
201
  /**
202
+ * Clear group administrator and moderator cache when a group member is saved.
203
  *
204
+ * This accounts for situations where group admins or mods are added manually
205
  * using {@link BP_Groups_Member::save()}. Usually via a plugin.
206
  *
207
  * @since 2.1.0
254
  add_action( 'bp_groups_member_before_delete_invite', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
255
  add_action( 'groups_accept_invite', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
256
 
257
+ /**
258
+ * Reset cache incrementor for the Groups component.
259
+ *
260
+ * This function invalidates all cached results of group queries,
261
+ * whenever one of the following events takes place:
262
+ * - A group is created or updated.
263
+ * - A group is deleted.
264
+ * - A group's metadata is modified.
265
+ *
266
+ * @since 2.7.0
267
+ *
268
+ * @return bool True on success, false on failure.
269
+ */
270
+ function bp_groups_reset_cache_incrementor() {
271
+ return bp_core_reset_incrementor( 'bp_groups' );
272
+ }
273
+ add_action( 'groups_group_after_save', 'bp_groups_reset_cache_incrementor' );
274
+ add_action( 'bp_groups_delete_group', 'bp_groups_reset_cache_incrementor' );
275
+ add_action( 'updated_group_meta', 'bp_groups_reset_cache_incrementor' );
276
+ add_action( 'deleted_group_meta', 'bp_groups_reset_cache_incrementor' );
277
+ add_action( 'added_group_meta', 'bp_groups_reset_cache_incrementor' );
278
+
279
+ /**
280
+ * Reset cache incrementor for Groups component when a group's taxonomy terms change.
281
+ *
282
+ * We infer that a group is being affected by looking at the objects belonging
283
+ * to the taxonomy being affected.
284
+ *
285
+ * @since 2.7.0
286
+ *
287
+ * @param int $object_id ID of the item whose terms are being modified.
288
+ * @param array $terms Array of object terms.
289
+ * @param array $tt_ids Array of term taxonomy IDs.
290
+ * @param string $taxonomy Taxonomy slug.
291
+ * @return bool True on success, false on failure.
292
+ */
293
+ function bp_groups_reset_cache_incrementor_on_group_term_change( $object_id, $terms, $tt_ids, $taxonomy ) {
294
+ $tax_object = get_taxonomy( $taxonomy );
295
+ if ( $tax_object && in_array( 'bp_group', $tax_object->object_type, true ) ) {
296
+ return bp_groups_reset_cache_incrementor();
297
+ }
298
+
299
+ return false;
300
+ }
301
+ add_action( 'bp_set_object_terms', 'bp_groups_reset_cache_incrementor_on_group_term_change', 10, 4 );
302
+
303
+ /**
304
+ * Reset cache incrementor for Groups component when a group's taxonomy terms are removed.
305
+ *
306
+ * We infer that a group is being affected by looking at the objects belonging
307
+ * to the taxonomy being affected.
308
+ *
309
+ * @since 2.7.0
310
+ *
311
+ * @param int $object_id ID of the item whose terms are being modified.
312
+ * @param array $terms Array of object terms.
313
+ * @param string $taxonomy Taxonomy slug.
314
+ * @return bool True on success, false on failure.
315
+ */
316
+ function bp_groups_reset_cache_incrementor_on_group_term_remove( $object_id, $terms, $taxonomy ) {
317
+ $tax_object = get_taxonomy( $taxonomy );
318
+ if ( $tax_object && in_array( 'bp_group', $tax_object->object_type, true ) ) {
319
+ return bp_groups_reset_cache_incrementor();
320
+ }
321
+
322
+ return false;
323
+ }
324
+ add_action( 'bp_remove_object_terms', 'bp_groups_reset_cache_incrementor_on_group_term_remove', 10, 3 );
325
+
326
  /* List actions to clear super cached pages on, if super cache is installed */
327
  add_action( 'groups_join_group', 'bp_core_clear_cache' );
328
  add_action( 'groups_leave_group', 'bp_core_clear_cache' );
bp-groups/bp-groups-filters.php CHANGED
@@ -315,7 +315,7 @@ function bp_groups_disable_at_mention_notification_for_non_public_groups( $send,
315
  }
316
 
317
  if ( 'groups' === $activity->component ) {
318
- $group = groups_get_group( array( 'group_id' => $activity->item_id ) );
319
  if ( 'public' !== $group->status && ! groups_is_user_member( $user_id, $group->id ) ) {
320
  $send = false;
321
  }
315
  }
316
 
317
  if ( 'groups' === $activity->component ) {
318
+ $group = groups_get_group( $activity->item_id );
319
  if ( 'public' !== $group->status && ! groups_is_user_member( $user_id, $group->id ) ) {
320
  $send = false;
321
  }
bp-groups/bp-groups-forums.php CHANGED
@@ -70,7 +70,7 @@ function groups_new_group_forum( $group_id = 0, $group_name = '', $group_desc =
70
  */
71
  function groups_update_group_forum( $group_id ) {
72
 
73
- $group = groups_get_group( array( 'group_id' => $group_id ) );
74
 
75
  /**
76
  * Bail in the following three situations:
70
  */
71
  function groups_update_group_forum( $group_id ) {
72
 
73
+ $group = groups_get_group( $group_id );
74
 
75
  /**
76
  * Bail in the following three situations:
bp-groups/bp-groups-functions.php CHANGED
@@ -36,29 +36,19 @@ function bp_groups_has_directory() {
36
  * support and pass through the groups_get_group filter.
37
  *
38
  * @since 1.2.0
 
 
39
  *
40
- * @param array|string $args {
41
- * Array of al arguments.
42
- * @type int $group_id ID of the group.
43
- * @type bool $load_users No longer used.
44
- * @type bool $populate_extras Whether to fetch membership data and other
45
- * extra information about the group.
46
- * Default: false.
47
- * }
48
  * @return BP_Groups_Group $group The group object.
49
  */
50
- function groups_get_group( $args = '' ) {
51
- $r = wp_parse_args( $args, array(
52
- 'group_id' => false,
53
- 'load_users' => false,
54
- 'populate_extras' => false,
55
- ) );
56
-
57
- $group_args = array(
58
- 'populate_extras' => $r['populate_extras'],
59
- );
60
 
61
- $group = new BP_Groups_Group( $r['group_id'], $group_args );
62
 
63
  /**
64
  * Filters a single group object.
@@ -87,6 +77,7 @@ function groups_get_group( $args = '' ) {
87
  * @type string $slug The group slug.
88
  * @type string $status The group's status. Accepts 'public', 'private' or
89
  * 'hidden'. Defaults to 'public'.
 
90
  * @type int $enable_forum Optional. Whether the group has a forum enabled.
91
  * If the legacy forums are enabled for this group
92
  * or if a bbPress forum is enabled for the group,
@@ -105,6 +96,7 @@ function groups_create_group( $args = '' ) {
105
  'description' => '',
106
  'slug' => '',
107
  'status' => 'public',
 
108
  'enable_forum' => 0,
109
  'date_created' => bp_core_current_time()
110
  );
@@ -114,7 +106,7 @@ function groups_create_group( $args = '' ) {
114
 
115
  // Pass an existing group ID.
116
  if ( ! empty( $group_id ) ) {
117
- $group = groups_get_group( array( 'group_id' => (int) $group_id ) );
118
  $name = ! empty( $name ) ? $name : $group->name;
119
  $slug = ! empty( $slug ) ? $slug : $group->slug;
120
  $description = ! empty( $description ) ? $description : $group->description;
@@ -151,6 +143,7 @@ function groups_create_group( $args = '' ) {
151
  $group->description = $description;
152
  $group->slug = $slug;
153
  $group->status = $status;
 
154
  $group->enable_forum = (int) $enable_forum;
155
  $group->date_created = $date_created;
156
 
@@ -228,7 +221,7 @@ function groups_edit_base_group_details( $group_id, $group_name, $group_desc, $n
228
  if ( empty( $group_name ) || empty( $group_desc ) )
229
  return false;
230
 
231
- $group = groups_get_group( array( 'group_id' => $group_id ) );
232
  $old_group = clone $group;
233
 
234
  $group->name = $group_name;
@@ -270,9 +263,9 @@ function groups_edit_base_group_details( $group_id, $group_name, $group_desc, $n
270
  * to the group. 'members', 'mods', or 'admins'.
271
  * @return bool True on success, false on failure.
272
  */
273
- function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_status = false ) {
274
 
275
- $group = groups_get_group( array( 'group_id' => $group_id ) );
276
  $group->enable_forum = $enable_forum;
277
 
278
  /**
@@ -285,6 +278,11 @@ function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_
285
  // Now update the status.
286
  $group->status = $status;
287
 
 
 
 
 
 
288
  if ( !$group->save() )
289
  return false;
290
 
@@ -333,7 +331,7 @@ function groups_delete_group( $group_id ) {
333
  do_action( 'groups_before_delete_group', $group_id );
334
 
335
  // Get the group object.
336
- $group = groups_get_group( array( 'group_id' => $group_id ) );
337
 
338
  // Bail if group cannot be deleted.
339
  if ( ! $group->delete() ) {
@@ -405,7 +403,7 @@ function groups_check_slug( $slug ) {
405
  * @return string The group's slug.
406
  */
407
  function groups_get_slug( $group_id ) {
408
- $group = groups_get_group( array( 'group_id' => $group_id ) );
409
  return !empty( $group->slug ) ? $group->slug : '';
410
  }
411
 
@@ -415,10 +413,10 @@ function groups_get_slug( $group_id ) {
415
  * @since 1.6.0
416
  *
417
  * @param string $group_slug The group's slug.
418
- * @return int The ID.
419
  */
420
  function groups_get_id( $group_slug ) {
421
- return (int)BP_Groups_Group::group_exists( $group_slug );
422
  }
423
 
424
  /** User Actions **************************************************************/
@@ -507,7 +505,7 @@ function groups_join_group( $group_id, $user_id = 0 ) {
507
  $bp = buddypress();
508
 
509
  if ( !isset( $bp->groups->current_group ) || !$bp->groups->current_group || $group_id != $bp->groups->current_group->id )
510
- $group = groups_get_group( array( 'group_id' => $group_id ) );
511
  else
512
  $group = $bp->groups->current_group;
513
 
@@ -684,6 +682,7 @@ function groups_get_total_member_count( $group_id ) {
684
  *
685
  * @since 1.2.0
686
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
 
687
  *
688
  * @param array|string $args {
689
  * Array of arguments. Supports all arguments of
@@ -703,6 +702,7 @@ function groups_get_groups( $args = '' ) {
703
  'user_id' => false, // Pass a user_id to limit to only groups that this user is a member of.
704
  'include' => false, // Only include these specific groups (group_ids).
705
  'exclude' => false, // Do not include these specific groups (group_ids).
 
706
  'search_terms' => false, // Limit to groups that match these search terms.
707
  'group_type' => '',
708
  'group_type__in' => '',
@@ -711,8 +711,8 @@ function groups_get_groups( $args = '' ) {
711
  'show_hidden' => false, // Show hidden groups to non-admins.
712
  'per_page' => 20, // The number of results to return per page.
713
  'page' => 1, // The page to return if limiting per page.
714
- 'populate_extras' => true, // Fetch meta such as is_banned and is_member.
715
  'update_meta_cache' => true, // Pre-fetch groupmeta for queried groups.
 
716
  );
717
 
718
  $r = wp_parse_args( $args, $defaults );
@@ -722,6 +722,7 @@ function groups_get_groups( $args = '' ) {
722
  'user_id' => $r['user_id'],
723
  'include' => $r['include'],
724
  'exclude' => $r['exclude'],
 
725
  'search_terms' => $r['search_terms'],
726
  'group_type' => $r['group_type'],
727
  'group_type__in' => $r['group_type__in'],
@@ -730,8 +731,8 @@ function groups_get_groups( $args = '' ) {
730
  'show_hidden' => $r['show_hidden'],
731
  'per_page' => $r['per_page'],
732
  'page' => $r['page'],
733
- 'populate_extras' => $r['populate_extras'],
734
  'update_meta_cache' => $r['update_meta_cache'],
 
735
  'order' => $r['order'],
736
  'orderby' => $r['orderby'],
737
  ) );
@@ -859,8 +860,18 @@ function bp_get_user_groups( $user_id, $args = array() ) {
859
  }
860
  }
861
 
862
- // Populate group membership array from cache.
863
- $groups = array();
 
 
 
 
 
 
 
 
 
 
864
  foreach ( $membership_ids as $membership_id ) {
865
  $membership = wp_cache_get( $membership_id, 'bp_groups_memberships' );
866
 
@@ -869,34 +880,25 @@ function bp_get_user_groups( $user_id, $args = array() ) {
869
  continue;
870
  }
871
 
872
- $group_id = (int) $membership->group_id;
873
-
874
- $groups[ $group_id ] = $membership;
875
- }
876
-
877
- // Normalize group data.
878
- foreach ( $groups as &$group ) {
879
  // Integer values.
880
- foreach ( array( 'id', 'group_id', 'user_id', 'inviter_id' ) as $index ) {
881
- $group->{$index} = intval( $group->{$index} );
882
  }
883
 
884
  // Boolean values.
885
- foreach ( array( 'is_admin', 'is_mod', 'is_confirmed', 'is_banned', 'invite_sent' ) as $index ) {
886
- $group->{$index} = (bool) $group->{$index};
887
  }
888
- }
889
 
890
- // Assemble filter array for use in `wp_list_filter()`.
891
- $filters = wp_array_slice_assoc( $r, array( 'is_confirmed', 'is_banned', 'is_admin', 'is_mod', 'invite_sent' ) );
892
- foreach ( $filters as $filter_name => $filter_value ) {
893
- if ( is_null( $filter_value ) ) {
894
- unset( $filters[ $filter_name ] );
895
  }
896
- }
897
 
898
- if ( ! empty( $filters ) ) {
899
- $groups = wp_list_filter( $groups, $filters );
 
900
  }
901
 
902
  // By default, results are ordered by membership id.
@@ -1200,7 +1202,7 @@ function groups_post_update( $args = '' ) {
1200
  if ( empty( $content ) || !strlen( trim( $content ) ) || empty( $user_id ) || empty( $group_id ) )
1201
  return false;
1202
 
1203
- $bp->groups->current_group = groups_get_group( array( 'group_id' => $group_id ) );
1204
 
1205
  // Be sure the user is a member of the group before posting.
1206
  if ( !bp_current_user_can( 'bp_moderate' ) && !groups_is_user_member( $user_id, $group_id ) )
@@ -1508,7 +1510,7 @@ function groups_send_invites( $user_id, $group_id ) {
1508
 
1509
  // Send friend invites.
1510
  $invited_users = groups_get_invites_for_group( $user_id, $group_id );
1511
- $group = groups_get_group( array( 'group_id' => $group_id ) );
1512
 
1513
  for ( $i = 0, $count = count( $invited_users ); $i < $count; ++$i ) {
1514
  $member = new BP_Groups_Member( $invited_users[$i], $group_id );
@@ -1735,7 +1737,7 @@ function groups_remove_member( $user_id, $group_id ) {
1735
 
1736
  if ( ! bp_is_item_admin() ) {
1737
  return false;
1738
- }
1739
 
1740
  $member = new BP_Groups_Member( $user_id, $group_id );
1741
 
@@ -2113,12 +2115,23 @@ add_action( 'bp_make_spam_user', 'groups_remove_data_for_user' );
2113
  * Register a group type.
2114
  *
2115
  * @since 2.6.0
 
 
2116
  *
2117
  * @param string $group_type Unique string identifier for the group type.
2118
  * @param array $args {
2119
  * Array of arguments describing the group type.
2120
  *
2121
- * @type array $labels {
 
 
 
 
 
 
 
 
 
2122
  * Array of labels to use in various parts of the interface.
2123
  *
2124
  * @type string $name Default name. Should typically be plural.
@@ -2135,7 +2148,11 @@ function bp_groups_register_group_type( $group_type, $args = array() ) {
2135
  }
2136
 
2137
  $r = bp_parse_args( $args, array(
2138
- 'labels' => array(),
 
 
 
 
2139
  ), 'register_group_type' );
2140
 
2141
  $group_type = sanitize_key( $group_type );
@@ -2166,6 +2183,32 @@ function bp_groups_register_group_type( $group_type, $args = array() ) {
2166
  'singular_name' => $default_name,
2167
  ), $r['labels'] );
2168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2169
  $bp->groups->types[ $group_type ] = $type = (object) $r;
2170
 
2171
  /**
@@ -2245,19 +2288,31 @@ function bp_groups_get_group_type_object( $group_type ) {
2245
  * Set type for a group.
2246
  *
2247
  * @since 2.6.0
 
2248
  *
2249
- * @param int $group ID of the group.
2250
- * @param string $group_type Group type.
2251
- * @param bool $append Optional. True to append this to existing types for group,
2252
- * false to replace. Default: false.
2253
  * @return array $retval See bp_set_object_terms().
2254
  */
2255
  function bp_groups_set_group_type( $group_id, $group_type, $append = false ) {
2256
  // Pass an empty group type to remove group's type.
2257
- if ( ! empty( $group_type ) && ! bp_groups_get_group_type_object( $group_type ) ) {
2258
  return false;
2259
  }
2260
 
 
 
 
 
 
 
 
 
 
 
 
2261
  $retval = bp_set_object_terms( $group_id, $group_type, 'bp_group_type', $append );
2262
 
2263
  // Bust the cache if the type has been updated.
@@ -2269,9 +2324,9 @@ function bp_groups_set_group_type( $group_id, $group_type, $append = false ) {
2269
  *
2270
  * @since 2.6.0
2271
  *
2272
- * @param int $group_id ID of the group whose group type has been updated.
2273
- * @param string $group_type Group type.
2274
- * @param bool $append Whether the type is being appended to existing types.
2275
  */
2276
  do_action( 'bp_groups_set_group_type', $group_id, $group_type, $append );
2277
  }
@@ -2294,10 +2349,18 @@ function bp_groups_get_group_type( $group_id, $single = true ) {
2294
  $types = wp_cache_get( $group_id, 'bp_groups_group_type' );
2295
 
2296
  if ( false === $types ) {
2297
- $types = bp_get_object_terms( $group_id, 'bp_group_type' );
 
 
 
 
 
 
 
 
 
 
2298
 
2299
- if ( ! is_wp_error( $types ) ) {
2300
- $types = wp_list_pluck( $types, 'name' );
2301
  wp_cache_set( $group_id, $types, 'bp_groups_group_type' );
2302
  }
2303
  }
@@ -2381,6 +2444,25 @@ function bp_groups_has_group_type( $group_id, $group_type ) {
2381
  return in_array( $group_type, $types );
2382
  }
2383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2384
  /**
2385
  * Delete a group's type when the group is deleted.
2386
  *
36
  * support and pass through the groups_get_group filter.
37
  *
38
  * @since 1.2.0
39
+ * @since 2.7.0 The function signature was changed to accept a group ID only,
40
+ * instead of an array containing the group ID.
41
  *
42
+ * @param int $group_id ID of the group.
 
 
 
 
 
 
 
43
  * @return BP_Groups_Group $group The group object.
44
  */
45
+ function groups_get_group( $group_id ) {
46
+ // Backward compatibilty.
47
+ if ( is_array( $group_id ) && isset( $group_id['group_id'] ) ) {
48
+ $group_id = $group_id['group_id'];
49
+ }
 
 
 
 
 
50
 
51
+ $group = new BP_Groups_Group( $group_id );
52
 
53
  /**
54
  * Filters a single group object.
77
  * @type string $slug The group slug.
78
  * @type string $status The group's status. Accepts 'public', 'private' or
79
  * 'hidden'. Defaults to 'public'.
80
+ * @type int $parent_id The ID of the parent group. Default: 0.
81
  * @type int $enable_forum Optional. Whether the group has a forum enabled.
82
  * If the legacy forums are enabled for this group
83
  * or if a bbPress forum is enabled for the group,
96
  'description' => '',
97
  'slug' => '',
98
  'status' => 'public',
99
+ 'parent_id' => 0,
100
  'enable_forum' => 0,
101
  'date_created' => bp_core_current_time()
102
  );
106
 
107
  // Pass an existing group ID.
108
  if ( ! empty( $group_id ) ) {
109
+ $group = groups_get_group( $group_id );
110
  $name = ! empty( $name ) ? $name : $group->name;
111
  $slug = ! empty( $slug ) ? $slug : $group->slug;
112
  $description = ! empty( $description ) ? $description : $group->description;
143
  $group->description = $description;
144
  $group->slug = $slug;
145
  $group->status = $status;
146
+ $group->parent_id = $parent_id;
147
  $group->enable_forum = (int) $enable_forum;
148
  $group->date_created = $date_created;
149
 
221
  if ( empty( $group_name ) || empty( $group_desc ) )
222
  return false;
223
 
224
+ $group = groups_get_group( $group_id );
225
  $old_group = clone $group;
226
 
227
  $group->name = $group_name;
263
  * to the group. 'members', 'mods', or 'admins'.
264
  * @return bool True on success, false on failure.
265
  */
266
+ function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_status = false, $parent_id = false ) {
267
 
268
+ $group = groups_get_group( $group_id );
269
  $group->enable_forum = $enable_forum;
270
 
271
  /**
278
  // Now update the status.
279
  $group->status = $status;
280
 
281
+ // Update the parent ID if necessary.
282
+ if ( false !== $parent_id ) {
283
+ $group->parent_id = $parent_id;
284
+ }
285
+
286
  if ( !$group->save() )
287
  return false;
288
 
331
  do_action( 'groups_before_delete_group', $group_id );
332
 
333
  // Get the group object.
334
+ $group = groups_get_group( $group_id );
335
 
336
  // Bail if group cannot be deleted.
337
  if ( ! $group->delete() ) {
403
  * @return string The group's slug.
404
  */
405
  function groups_get_slug( $group_id ) {
406
+ $group = groups_get_group( $group_id );
407
  return !empty( $group->slug ) ? $group->slug : '';
408
  }
409
 
413
  * @since 1.6.0
414
  *
415
  * @param string $group_slug The group's slug.
416
+ * @return int|null The group ID on success; null on failure.
417
  */
418
  function groups_get_id( $group_slug ) {
419
+ return BP_Groups_Group::group_exists( $group_slug );
420
  }
421
 
422
  /** User Actions **************************************************************/
505
  $bp = buddypress();
506
 
507
  if ( !isset( $bp->groups->current_group ) || !$bp->groups->current_group || $group_id != $bp->groups->current_group->id )
508
+ $group = groups_get_group( $group_id );
509
  else
510
  $group = $bp->groups->current_group;
511
 
682
  *
683
  * @since 1.2.0
684
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
685
+ * @since 2.7.0 Added `$update_admin_cache` and `$parent_id` parameters.
686
  *
687
  * @param array|string $args {
688
  * Array of arguments. Supports all arguments of
702
  'user_id' => false, // Pass a user_id to limit to only groups that this user is a member of.
703
  'include' => false, // Only include these specific groups (group_ids).
704
  'exclude' => false, // Do not include these specific groups (group_ids).
705
+ 'parent_id' => null, // Get groups that are children of the specified group(s).
706
  'search_terms' => false, // Limit to groups that match these search terms.
707
  'group_type' => '',
708
  'group_type__in' => '',
711
  'show_hidden' => false, // Show hidden groups to non-admins.
712
  'per_page' => 20, // The number of results to return per page.
713
  'page' => 1, // The page to return if limiting per page.
 
714
  'update_meta_cache' => true, // Pre-fetch groupmeta for queried groups.
715
+ 'update_admin_cache' => false,
716
  );
717
 
718
  $r = wp_parse_args( $args, $defaults );
722
  'user_id' => $r['user_id'],
723
  'include' => $r['include'],
724
  'exclude' => $r['exclude'],
725
+ 'parent_id' => $r['parent_id'],
726
  'search_terms' => $r['search_terms'],
727
  'group_type' => $r['group_type'],
728
  'group_type__in' => $r['group_type__in'],
731
  'show_hidden' => $r['show_hidden'],
732
  'per_page' => $r['per_page'],
733
  'page' => $r['page'],
 
734
  'update_meta_cache' => $r['update_meta_cache'],
735
+ 'update_admin_cache' => $r['update_admin_cache'],
736
  'order' => $r['order'],
737
  'orderby' => $r['orderby'],
738
  ) );
860
  }
861
  }
862
 
863
+ // Assemble filter array for use in `wp_list_filter()`.
864
+ $filters = wp_array_slice_assoc( $r, array( 'is_confirmed', 'is_banned', 'is_admin', 'is_mod', 'invite_sent' ) );
865
+ foreach ( $filters as $filter_name => $filter_value ) {
866
+ if ( is_null( $filter_value ) ) {
867
+ unset( $filters[ $filter_name ] );
868
+ }
869
+ }
870
+
871
+ // Populate group membership array from cache, and normalize.
872
+ $groups = array();
873
+ $int_keys = array( 'id', 'group_id', 'user_id', 'inviter_id' );
874
+ $bool_keys = array( 'is_admin', 'is_mod', 'is_confirmed', 'is_banned', 'invite_sent' );
875
  foreach ( $membership_ids as $membership_id ) {
876
  $membership = wp_cache_get( $membership_id, 'bp_groups_memberships' );
877
 
880
  continue;
881
  }
882
 
 
 
 
 
 
 
 
883
  // Integer values.
884
+ foreach ( $int_keys as $index ) {
885
+ $membership->{$index} = intval( $membership->{$index} );
886
  }
887
 
888
  // Boolean values.
889
+ foreach ( $bool_keys as $index ) {
890
+ $membership->{$index} = (bool) $membership->{$index};
891
  }
 
892
 
893
+ foreach ( $filters as $filter_name => $filter_value ) {
894
+ if ( ! isset( $membership->{$filter_name} ) || $filter_value != $membership->{$filter_name} ) {
895
+ continue 2;
896
+ }
 
897
  }
 
898
 
899
+ $group_id = (int) $membership->group_id;
900
+
901
+ $groups[ $group_id ] = $membership;
902
  }
903
 
904
  // By default, results are ordered by membership id.
1202
  if ( empty( $content ) || !strlen( trim( $content ) ) || empty( $user_id ) || empty( $group_id ) )
1203
  return false;
1204
 
1205
+ $bp->groups->current_group = groups_get_group( $group_id );
1206
 
1207
  // Be sure the user is a member of the group before posting.
1208
  if ( !bp_current_user_can( 'bp_moderate' ) && !groups_is_user_member( $user_id, $group_id ) )
1510
 
1511
  // Send friend invites.
1512
  $invited_users = groups_get_invites_for_group( $user_id, $group_id );
1513
+ $group = groups_get_group( $group_id );
1514
 
1515
  for ( $i = 0, $count = count( $invited_users ); $i < $count; ++$i ) {
1516
  $member = new BP_Groups_Member( $invited_users[$i], $group_id );
1737
 
1738
  if ( ! bp_is_item_admin() ) {
1739
  return false;
1740
+ }
1741
 
1742
  $member = new BP_Groups_Member( $user_id, $group_id );
1743
 
2115
  * Register a group type.
2116
  *
2117
  * @since 2.6.0
2118
+ * @since 2.7.0 Introduce $has_directory, $show_in_create_screen, $show_in_list, and
2119
+ * $description as $args parameters.
2120
  *
2121
  * @param string $group_type Unique string identifier for the group type.
2122
  * @param array $args {
2123
  * Array of arguments describing the group type.
2124
  *
2125
+ * @type string|bool $has_directory Set the slug to be used for custom group directory page. eg.
2126
+ * example.com/groups/type/MY_SLUG. Default: false.
2127
+ * @type bool $show_in_create_screen Whether this group type is allowed to be selected on the group creation
2128
+ * page. Default: false.
2129
+ * @type bool|null $show_in_list Whether this group type should be shown in lists rendered by
2130
+ * bp_group_type_list(). Default: null. If $show_in_create_screen is true,
2131
+ * this will default to true, unless this is set explicitly to false.
2132
+ * @type string $description A short descriptive summary of what the group type is. Currently shown
2133
+ * on a group's "Manage > Settings" page when selecting group types.
2134
+ * @type array $labels {
2135
  * Array of labels to use in various parts of the interface.
2136
  *
2137
  * @type string $name Default name. Should typically be plural.
2148
  }
2149
 
2150
  $r = bp_parse_args( $args, array(
2151
+ 'has_directory' => false,
2152
+ 'show_in_create_screen' => false,
2153
+ 'show_in_list' => null,
2154
+ 'description' => '',
2155
+ 'labels' => array(),
2156
  ), 'register_group_type' );
2157
 
2158
  $group_type = sanitize_key( $group_type );
2183
  'singular_name' => $default_name,
2184
  ), $r['labels'] );
2185
 
2186
+ // Directory slug.
2187
+ if ( ! empty( $r['has_directory'] ) ) {
2188
+ // A string value is intepreted as the directory slug.
2189
+ if ( is_string( $r['has_directory'] ) ) {
2190
+ $directory_slug = $r['has_directory'];
2191
+
2192
+ // Otherwise fall back on group type.
2193
+ } else {
2194
+ $directory_slug = $group_type;
2195
+ }
2196
+
2197
+ // Sanitize for use in URLs.
2198
+ $r['directory_slug'] = sanitize_title( $directory_slug );
2199
+ $r['has_directory'] = true;
2200
+ } else {
2201
+ $r['directory_slug'] = '';
2202
+ $r['has_directory'] = false;
2203
+ }
2204
+
2205
+ // Type lists.
2206
+ if ( true === $r['show_in_create_screen'] && is_null( $r['show_in_list'] ) ) {
2207
+ $r['show_in_list'] = true;
2208
+ } else {
2209
+ $r['show_in_list'] = (bool) $r['show_in_list'];
2210
+ }
2211
+
2212
  $bp->groups->types[ $group_type ] = $type = (object) $r;
2213
 
2214
  /**
2288
  * Set type for a group.
2289
  *
2290
  * @since 2.6.0
2291
+ * @since 2.7.0 $group_type parameter also accepts an array of group types now.
2292
  *
2293
+ * @param int $group ID of the group.
2294
+ * @param string|array $group_type Group type or array of group types to set.
2295
+ * @param bool $append Optional. True to append this to existing types for group,
2296
+ * false to replace. Default: false.
2297
  * @return array $retval See bp_set_object_terms().
2298
  */
2299
  function bp_groups_set_group_type( $group_id, $group_type, $append = false ) {
2300
  // Pass an empty group type to remove group's type.
2301
+ if ( ! empty( $group_type ) && is_string( $group_type ) && ! bp_groups_get_group_type_object( $group_type ) ) {
2302
  return false;
2303
  }
2304
 
2305
+ // Cast as array.
2306
+ $group_type = (array) $group_type;
2307
+
2308
+ // Validate group types.
2309
+ foreach ( $group_type as $type ) {
2310
+ // Remove any invalid group types.
2311
+ if ( is_null( bp_groups_get_group_type_object( $type ) ) ) {
2312
+ unset( $group_type[ $type ] );
2313
+ }
2314
+ }
2315
+
2316
  $retval = bp_set_object_terms( $group_id, $group_type, 'bp_group_type', $append );
2317
 
2318
  // Bust the cache if the type has been updated.
2324
  *
2325
  * @since 2.6.0
2326
  *
2327
+ * @param int $group_id ID of the group whose group type has been updated.
2328
+ * @param string|array $group_type Group type or array of group types.
2329
+ * @param bool $append Whether the type is being appended to existing types.
2330
  */
2331
  do_action( 'bp_groups_set_group_type', $group_id, $group_type, $append );
2332
  }
2349
  $types = wp_cache_get( $group_id, 'bp_groups_group_type' );
2350
 
2351
  if ( false === $types ) {
2352
+ $raw_types = bp_get_object_terms( $group_id, 'bp_group_type' );
2353
+
2354
+ if ( ! is_wp_error( $raw_types ) ) {
2355
+ $types = array();
2356
+
2357
+ // Only include currently registered group types.
2358
+ foreach ( $raw_types as $gtype ) {
2359
+ if ( bp_groups_get_group_type_object( $gtype->name ) ) {
2360
+ $types[] = $gtype->name;
2361
+ }
2362
+ }
2363
 
 
 
2364
  wp_cache_set( $group_id, $types, 'bp_groups_group_type' );
2365
  }
2366
  }
2444
  return in_array( $group_type, $types );
2445
  }
2446
 
2447
+ /**
2448
+ * Get the "current" group type, if one is provided, in group directories.
2449
+ *
2450
+ * @since 2.7.0
2451
+ *
2452
+ * @return string
2453
+ */
2454
+ function bp_get_current_group_directory_type() {
2455
+
2456
+ /**
2457
+ * Filters the "current" group type, if one is provided, in group directories.
2458
+ *
2459
+ * @since 2.7.0
2460
+ *
2461
+ * @param string $value "Current" group type.
2462
+ */
2463
+ return apply_filters( 'bp_get_current_group_directory_type', buddypress()->groups->current_directory_type );
2464
+ }
2465
+
2466
  /**
2467
  * Delete a group's type when the group is deleted.
2468
  *
bp-groups/bp-groups-loader.php CHANGED
@@ -19,7 +19,7 @@ if ( ! buddypress()->do_autoload ) {
19
  }
20
 
21
  /**
22
- * Bootstrap the Notifications component.
23
  *
24
  * @since 1.5.0
25
  */
19
  }
20
 
21
  /**
22
+ * Set up the bp-groups component.
23
  *
24
  * @since 1.5.0
25
  */
bp-groups/bp-groups-notifications.php CHANGED
@@ -24,7 +24,7 @@ defined( 'ABSPATH' ) || exit;
24
  * @param BP_Groups_Group|null $old_group Group before new details were saved.
25
  */
26
  function groups_notification_group_updated( $group_id = 0, $old_group = null ) {
27
- $group = groups_get_group( array( 'group_id' => $group_id ) );
28
 
29
  if ( $old_group instanceof BP_Groups_Group ) {
30
  $changed = array();
@@ -68,6 +68,11 @@ function groups_notification_group_updated( $group_id = 0, $old_group = null ) {
68
  continue;
69
  }
70
 
 
 
 
 
 
71
  $args = array(
72
  'tokens' => array(
73
  'changed_text' => $changed_text,
@@ -75,6 +80,7 @@ function groups_notification_group_updated( $group_id = 0, $old_group = null ) {
75
  'group.id' => $group_id,
76
  'group.url' => esc_url( bp_get_group_permalink( $group ) ),
77
  'group.name' => $group->name,
 
78
  ),
79
  );
80
  bp_send_email( 'groups-details-updated', (int) $user_id, $args );
@@ -115,7 +121,7 @@ function groups_notification_new_membership_request( $requesting_user_id = 0, $a
115
  'item_id' => $group_id,
116
  'secondary_item_id' => $requesting_user_id,
117
  'component_name' => buddypress()->groups->id,
118
- 'component_action' => 'new_membership_request'
119
  ) );
120
  }
121
 
@@ -124,7 +130,12 @@ function groups_notification_new_membership_request( $requesting_user_id = 0, $a
124
  return;
125
  }
126
 
127
- $group = groups_get_group( array( 'group_id' => $group_id ) );
 
 
 
 
 
128
  $args = array(
129
  'tokens' => array(
130
  'admin.id' => $admin_id,
@@ -136,6 +147,7 @@ function groups_notification_new_membership_request( $requesting_user_id = 0, $a
136
  'profile.url' => esc_url( bp_core_get_user_domain( $requesting_user_id ) ),
137
  'requesting-user.id' => $requesting_user_id,
138
  'requesting-user.name' => bp_core_get_user_displayname( $requesting_user_id ),
 
139
  ),
140
  );
141
  bp_send_email( 'groups-membership-request', (int) $admin_id, $args );
@@ -172,7 +184,7 @@ function groups_notification_membership_request_completed( $requesting_user_id =
172
  return;
173
  }
174
 
175
- $group = groups_get_group( array( 'group_id' => $group_id ) );
176
  $args = array(
177
  'tokens' => array(
178
  'group' => $group,
@@ -184,8 +196,25 @@ function groups_notification_membership_request_completed( $requesting_user_id =
184
  );
185
 
186
  if ( ! empty( $accepted ) ) {
 
 
 
 
 
 
 
 
187
  bp_send_email( 'groups-membership-request-accepted', (int) $requesting_user_id, $args );
 
188
  } else {
 
 
 
 
 
 
 
 
189
  bp_send_email( 'groups-membership-request-rejected', (int) $requesting_user_id, $args );
190
  }
191
  }
@@ -226,7 +255,12 @@ function groups_notification_promoted_member( $user_id = 0, $group_id = 0 ) {
226
  return;
227
  }
228
 
229
- $group = groups_get_group( array( 'group_id' => $group_id ) );
 
 
 
 
 
230
  $args = array(
231
  'tokens' => array(
232
  'group' => $group,
@@ -235,6 +269,7 @@ function groups_notification_promoted_member( $user_id = 0, $group_id = 0 ) {
235
  'group.name' => $group->name,
236
  'promoted_to' => $promoted_to,
237
  'user.id' => $user_id,
 
238
  ),
239
  );
240
  bp_send_email( 'groups-member-promoted', (int) $user_id, $args );
@@ -277,6 +312,12 @@ function groups_notification_group_invites( &$group, &$member, $inviter_user_id
277
  }
278
 
279
  $invited_link = bp_core_get_user_domain( $invited_user_id ) . bp_get_groups_slug();
 
 
 
 
 
 
280
  $args = array(
281
  'tokens' => array(
282
  'group' => $group,
@@ -286,6 +327,7 @@ function groups_notification_group_invites( &$group, &$member, $inviter_user_id
286
  'inviter.url' => bp_core_get_user_domain( $inviter_user_id ),
287
  'inviter.id' => $inviter_user_id,
288
  'invites.url' => esc_url( $invited_link . '/invites/' ),
 
289
  ),
290
  );
291
  bp_send_email( 'groups-invitation', (int) $invited_user_id, $args );
@@ -314,7 +356,7 @@ function groups_format_notifications( $action, $item_id, $secondary_item_id, $to
314
  $group_id = $item_id;
315
  $requesting_user_id = $secondary_item_id;
316
 
317
- $group = groups_get_group( array( 'group_id' => $group_id ) );
318
  $group_link = bp_get_group_permalink( $group );
319
  $amount = 'single';
320
 
@@ -418,7 +460,7 @@ function groups_format_notifications( $action, $item_id, $secondary_item_id, $to
418
  case 'membership_request_accepted':
419
  $group_id = $item_id;
420
 
421
- $group = groups_get_group( array( 'group_id' => $group_id ) );
422
  $group_link = bp_get_group_permalink( $group );
423
  $amount = 'single';
424
 
@@ -507,7 +549,7 @@ function groups_format_notifications( $action, $item_id, $secondary_item_id, $to
507
  case 'membership_request_rejected':
508
  $group_id = $item_id;
509
 
510
- $group = groups_get_group( array( 'group_id' => $group_id ) );
511
  $group_link = bp_get_group_permalink( $group );
512
  $amount = 'single';
513
 
@@ -595,7 +637,7 @@ function groups_format_notifications( $action, $item_id, $secondary_item_id, $to
595
  case 'member_promoted_to_admin':
596
  $group_id = $item_id;
597
 
598
- $group = groups_get_group( array( 'group_id' => $group_id ) );
599
  $group_link = bp_get_group_permalink( $group );
600
  $amount = 'single';
601
 
@@ -677,7 +719,7 @@ function groups_format_notifications( $action, $item_id, $secondary_item_id, $to
677
  case 'member_promoted_to_mod':
678
  $group_id = $item_id;
679
 
680
- $group = groups_get_group( array( 'group_id' => $group_id ) );
681
  $group_link = bp_get_group_permalink( $group );
682
  $amount = 'single';
683
 
@@ -758,7 +800,7 @@ function groups_format_notifications( $action, $item_id, $secondary_item_id, $to
758
 
759
  case 'group_invite':
760
  $group_id = $item_id;
761
- $group = groups_get_group( array( 'group_id' => $group_id ) );
762
  $group_link = bp_get_group_permalink( $group );
763
  $amount = 'single';
764
 
24
  * @param BP_Groups_Group|null $old_group Group before new details were saved.
25
  */
26
  function groups_notification_group_updated( $group_id = 0, $old_group = null ) {
27
+ $group = groups_get_group( $group_id );
28
 
29
  if ( $old_group instanceof BP_Groups_Group ) {
30
  $changed = array();
68
  continue;
69
  }
70
 
71
+ $unsubscribe_args = array(
72
+ 'user_id' => $user_id,
73
+ 'notification_type' => 'groups-details-updated',
74
+ );
75
+
76
  $args = array(
77
  'tokens' => array(
78
  'changed_text' => $changed_text,
80
  'group.id' => $group_id,
81
  'group.url' => esc_url( bp_get_group_permalink( $group ) ),
82
  'group.name' => $group->name,
83
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
84
  ),
85
  );
86
  bp_send_email( 'groups-details-updated', (int) $user_id, $args );
121
  'item_id' => $group_id,
122
  'secondary_item_id' => $requesting_user_id,
123
  'component_name' => buddypress()->groups->id,
124
+ 'component_action' => 'new_membership_request',
125
  ) );
126
  }
127
 
130
  return;
131
  }
132
 
133
+ $unsubscribe_args = array(
134
+ 'user_id' => $admin_id,
135
+ 'notification_type' => 'groups-membership-request',
136
+ );
137
+
138
+ $group = groups_get_group( $group_id );
139
  $args = array(
140
  'tokens' => array(
141
  'admin.id' => $admin_id,
147
  'profile.url' => esc_url( bp_core_get_user_domain( $requesting_user_id ) ),
148
  'requesting-user.id' => $requesting_user_id,
149
  'requesting-user.name' => bp_core_get_user_displayname( $requesting_user_id ),
150
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
151
  ),
152
  );
153
  bp_send_email( 'groups-membership-request', (int) $admin_id, $args );
184
  return;
185
  }
186
 
187
+ $group = groups_get_group( $group_id );
188
  $args = array(
189
  'tokens' => array(
190
  'group' => $group,
196
  );
197
 
198
  if ( ! empty( $accepted ) ) {
199
+
200
+ $unsubscribe_args = array(
201
+ 'user_id' => $requesting_user_id,
202
+ 'notification_type' => 'groups-membership-request-accepted',
203
+ );
204
+
205
+ $args['tokens']['unsubscribe'] = esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) );
206
+
207
  bp_send_email( 'groups-membership-request-accepted', (int) $requesting_user_id, $args );
208
+
209
  } else {
210
+
211
+ $unsubscribe_args = array(
212
+ 'user_id' => $requesting_user_id,
213
+ 'notification_type' => 'groups-membership-request-rejected',
214
+ );
215
+
216
+ $args['tokens']['unsubscribe'] = esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) );
217
+
218
  bp_send_email( 'groups-membership-request-rejected', (int) $requesting_user_id, $args );
219
  }
220
  }
255
  return;
256
  }
257
 
258
+ $unsubscribe_args = array(
259
+ 'user_id' => $user_id,
260
+ 'notification_type' => 'groups-member-promoted',
261
+ );
262
+
263
+ $group = groups_get_group( $group_id );
264
  $args = array(
265
  'tokens' => array(
266
  'group' => $group,
269
  'group.name' => $group->name,
270
  'promoted_to' => $promoted_to,
271
  'user.id' => $user_id,
272
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
273
  ),
274
  );
275
  bp_send_email( 'groups-member-promoted', (int) $user_id, $args );
312
  }
313
 
314
  $invited_link = bp_core_get_user_domain( $invited_user_id ) . bp_get_groups_slug();
315
+
316
+ $unsubscribe_args = array(
317
+ 'user_id' => $invited_user_id,
318
+ 'notification_type' => 'groups-invitation',
319
+ );
320
+
321
  $args = array(
322
  'tokens' => array(
323
  'group' => $group,
327
  'inviter.url' => bp_core_get_user_domain( $inviter_user_id ),
328
  'inviter.id' => $inviter_user_id,
329
  'invites.url' => esc_url( $invited_link . '/invites/' ),
330
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
331
  ),
332
  );
333
  bp_send_email( 'groups-invitation', (int) $invited_user_id, $args );
356
  $group_id = $item_id;
357
  $requesting_user_id = $secondary_item_id;
358
 
359
+ $group = groups_get_group( $group_id );
360
  $group_link = bp_get_group_permalink( $group );
361
  $amount = 'single';
362
 
460
  case 'membership_request_accepted':
461
  $group_id = $item_id;
462
 
463
+ $group = groups_get_group( $group_id );
464
  $group_link = bp_get_group_permalink( $group );
465
  $amount = 'single';
466
 
549
  case 'membership_request_rejected':
550
  $group_id = $item_id;
551
 
552
+ $group = groups_get_group( $group_id );
553
  $group_link = bp_get_group_permalink( $group );
554
  $amount = 'single';
555
 
637
  case 'member_promoted_to_admin':
638
  $group_id = $item_id;
639
 
640
+ $group = groups_get_group( $group_id );
641
  $group_link = bp_get_group_permalink( $group );
642
  $amount = 'single';
643
 
719
  case 'member_promoted_to_mod':
720
  $group_id = $item_id;
721
 
722
+ $group = groups_get_group( $group_id );
723
  $group_link = bp_get_group_permalink( $group );
724
  $amount = 'single';
725
 
800
 
801
  case 'group_invite':
802
  $group_id = $item_id;
803
+ $group = groups_get_group( $group_id );
804
  $group_link = bp_get_group_permalink( $group );
805
  $amount = 'single';
806
 
bp-groups/bp-groups-screens.php CHANGED
@@ -25,6 +25,22 @@ if ( ! buddypress()->do_autoload ) {
25
  */
26
  function groups_directory_groups_setup() {
27
  if ( bp_is_groups_directory() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  bp_update_is_directory( true, 'groups' );
29
 
30
  /**
@@ -89,7 +105,7 @@ function groups_screen_group_invites() {
89
  bp_core_add_message( __('Group invite accepted', 'buddypress') );
90
 
91
  // Record this in activity streams.
92
- $group = groups_get_group( array( 'group_id' => $group_id ) );
93
 
94
  groups_record_activity( array(
95
  'type' => 'joined_group',
@@ -915,6 +931,32 @@ function groups_screen_group_admin_settings() {
915
  if ( !check_admin_referer( 'groups_edit_group_settings' ) )
916
  return false;
917
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
918
  if ( !groups_edit_group_settings( $_POST['group-id'], $enable_forum, $status, $invite_status ) ) {
919
  bp_core_add_message( __( 'There was an error updating group settings. Please try again.', 'buddypress' ), 'error' );
920
  } else {
25
  */
26
  function groups_directory_groups_setup() {
27
  if ( bp_is_groups_directory() ) {
28
+ // Set group type if available.
29
+ if ( bp_is_current_action( bp_get_groups_group_type_base() ) && bp_action_variable() ) {
30
+ $matched_types = bp_groups_get_group_types( array(
31
+ 'has_directory' => true,
32
+ 'directory_slug' => bp_action_variable(),
33
+ ) );
34
+
35
+ // Redirect back to group directory if no match.
36
+ if ( empty( $matched_types ) ) {
37
+ bp_core_redirect( bp_get_groups_directory_permalink() );
38
+ }
39
+
40
+ // Set our global variable.
41
+ buddypress()->groups->current_directory_type = reset( $matched_types );
42
+ }
43
+
44
  bp_update_is_directory( true, 'groups' );
45
 
46
  /**
105
  bp_core_add_message( __('Group invite accepted', 'buddypress') );
106
 
107
  // Record this in activity streams.
108
+ $group = groups_get_group( $group_id );
109
 
110
  groups_record_activity( array(
111
  'type' => 'joined_group',
931
  if ( !check_admin_referer( 'groups_edit_group_settings' ) )
932
  return false;
933
 
934
+ /*
935
+ * Save group types.
936
+ *
937
+ * Ensure we keep types that have 'show_in_create_screen' set to false.
938
+ */
939
+ $current_types = bp_groups_get_group_type( bp_get_current_group_id(), false );
940
+ $current_types = array_intersect( bp_groups_get_group_types( array( 'show_in_create_screen' => false ) ), (array) $current_types );
941
+ if ( isset( $_POST['group-types'] ) ) {
942
+ $current_types = array_merge( $current_types, $_POST['group-types'] );
943
+
944
+ // Set group types.
945
+ bp_groups_set_group_type( bp_get_current_group_id(), $current_types );
946
+
947
+ // No group types checked, so this means we want to wipe out all group types.
948
+ } else {
949
+ /*
950
+ * Passing a blank string will wipe out all types for the group.
951
+ *
952
+ * Ensure we keep types that have 'show_in_create_screen' set to false.
953
+ */
954
+ $current_types = empty( $current_types ) ? '' : $current_types;
955
+
956
+ // Set group types.
957
+ bp_groups_set_group_type( bp_get_current_group_id(), $current_types );
958
+ }
959
+
960
  if ( !groups_edit_group_settings( $_POST['group-id'], $enable_forum, $status, $invite_status ) ) {
961
  bp_core_add_message( __( 'There was an error updating group settings. Please try again.', 'buddypress' ), 'error' );
962
  } else {
bp-groups/bp-groups-template.php CHANGED
@@ -71,6 +71,36 @@ function bp_groups_root_slug() {
71
  return apply_filters( 'bp_get_groups_root_slug', buddypress()->groups->root_slug );
72
  }
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  /**
75
  * Output group directory permalink.
76
  *
@@ -98,11 +128,172 @@ function bp_groups_directory_permalink() {
98
  return apply_filters( 'bp_get_groups_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) );
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * Start the Groups Template Loop.
103
  *
104
  * @since 1.0.0
105
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
 
106
  *
107
  * @param array|string $args {
108
  * Array of parameters. All items are optional.
@@ -133,11 +324,14 @@ function bp_groups_directory_permalink() {
133
  * See {@link WP_Meta_Query::queries} for description.
134
  * @type array|string $include Array or comma-separated list of group IDs. Results will be limited
135
  * to groups within the list. Default: false.
136
- * @type bool $populate_extras Whether to fetch additional information (such as member count)
137
- * about groups. Default: true.
138
  * @type array|string $exclude Array or comma-separated list of group IDs. Results will exclude
139
  * the listed groups. Default: false.
 
 
140
  * @type bool $update_meta_cache Whether to fetch groupmeta for queried groups. Default: true.
 
 
 
141
  * }
142
  * @return bool True if there are groups to display that match the params
143
  */
@@ -169,6 +363,16 @@ function bp_has_groups( $args = '' ) {
169
  $slug = bp_get_current_group_slug();
170
  }
171
 
 
 
 
 
 
 
 
 
 
 
172
  // Default search string (too soon to escape here).
173
  $search_query_arg = bp_core_get_component_search_query_arg( 'groups' );
174
  if ( ! empty( $_REQUEST[ $search_query_arg ] ) ) {
@@ -192,14 +396,15 @@ function bp_has_groups( $args = '' ) {
192
  'user_id' => bp_displayed_user_id(),
193
  'slug' => $slug,
194
  'search_terms' => $search_terms,
195
- 'group_type' => '',
196
  'group_type__in' => '',
197
  'group_type__not_in' => '',
198
  'meta_query' => false,
199
  'include' => false,
200
  'exclude' => false,
201
- 'populate_extras' => true,
202
  'update_meta_cache' => true,
 
203
  ), 'has_groups' );
204
 
205
  // Setup the Groups template global.
@@ -221,8 +426,9 @@ function bp_has_groups( $args = '' ) {
221
  'meta_query' => $r['meta_query'],
222
  'include' => $r['include'],
223
  'exclude' => $r['exclude'],
224
- 'populate_extras' => (bool) $r['populate_extras'],
225
  'update_meta_cache' => (bool) $r['update_meta_cache'],
 
226
  ) );
227
 
228
  /**
@@ -266,10 +472,10 @@ function bp_the_group() {
266
  *
267
  * @since 1.0.0
268
  *
269
- * @param object|bool $group Optional. Group object. Default: current group in loop.
270
  * @return bool
271
  */
272
- function bp_group_is_visible( $group = false ) {
273
  global $groups_template;
274
 
275
  if ( bp_current_user_can( 'bp_moderate' ) ) {
@@ -548,7 +754,7 @@ function bp_group_avatar( $args = '' ) {
548
  * @since 1.0.0
549
  *
550
  * @see bp_core_fetch_avatar() For a description of arguments and return values.
551
-
552
  * @param array|string $args {
553
  * Arguments are listed here with an explanation of their defaults.
554
  * For more information about the arguments, see {@link bp_core_fetch_avatar()}.
@@ -684,41 +890,57 @@ function bp_group_use_cover_image_header() {
684
  * Output the 'last active' string for the current group in the loop.
685
  *
686
  * @since 1.0.0
 
687
  *
688
- * @param object|bool $group Optional. Group object.
689
- * Default: current group in loop.
690
  */
691
- function bp_group_last_active( $group = false ) {
692
- echo bp_get_group_last_active( $group );
693
  }
694
  /**
695
  * Return the 'last active' string for the current group in the loop.
696
  *
697
  * @since 1.0.0
 
698
  *
699
- * @param object|bool $group Optional. Group object.
700
- * Default: current group in loop.
 
 
 
 
 
701
  * @return string
702
  */
703
- function bp_get_group_last_active( $group = false ) {
704
  global $groups_template;
705
 
706
  if ( empty( $group ) ) {
707
  $group =& $groups_template->group;
708
  }
709
 
710
- $last_active = $group->last_activity;
 
 
711
 
712
- if ( !$last_active ) {
 
713
  $last_active = groups_get_groupmeta( $group->id, 'last_activity' );
714
  }
715
 
 
 
 
 
 
 
716
  if ( empty( $last_active ) ) {
717
  return __( 'not yet active', 'buddypress' );
718
  } else {
719
 
720
  /**
721
- * Filters the 'last active' string for the current gorup in the loop.
722
  *
723
  * @since 1.0.0
724
  * @since 2.5.0 Added the `$group` parameter.
@@ -735,10 +957,9 @@ function bp_group_last_active( $group = false ) {
735
  *
736
  * @since 1.0.0
737
  *
738
- * @param object|bool $group Optional. Group object.
739
- * Default: current group in loop.
740
  */
741
- function bp_group_permalink( $group = false ) {
742
  echo bp_get_group_permalink( $group );
743
  }
744
  /**
@@ -746,11 +967,10 @@ function bp_group_permalink( $group = false ) {
746
  *
747
  * @since 1.0.0
748
  *
749
- * @param object|bool $group Optional. Group object.
750
- * Default: current group in loop.
751
  * @return string
752
  */
753
- function bp_get_group_permalink( $group = false ) {
754
  global $groups_template;
755
 
756
  if ( empty( $group ) ) {
@@ -1052,29 +1272,46 @@ function bp_group_is_public( $group = false ) {
1052
  * Output the created date of the current group in the loop.
1053
  *
1054
  * @since 1.0.0
 
1055
  *
1056
- * @param object|bool $group Optional. Group object.
1057
- * Default: current group in loop.
1058
  */
1059
- function bp_group_date_created( $group = false ) {
1060
- echo bp_get_group_date_created( $group );
1061
  }
1062
  /**
1063
  * Return the created date of the current group in the loop.
1064
  *
1065
  * @since 1.0.0
 
1066
  *
1067
- * @param object|bool $group Optional. Group object.
1068
- * Default: current group in loop.
 
 
 
 
 
1069
  * @return string
1070
  */
1071
- function bp_get_group_date_created( $group = false ) {
1072
  global $groups_template;
1073
 
 
 
 
 
1074
  if ( empty( $group ) ) {
1075
  $group =& $groups_template->group;
1076
  }
1077
 
 
 
 
 
 
 
1078
  /**
1079
  * Filters the created date of the current group in the loop.
1080
  *
@@ -1084,7 +1321,7 @@ function bp_group_date_created( $group = false ) {
1084
  * @param string $value Created date for the current group.
1085
  * @param object $group Group object.
1086
  */
1087
- return apply_filters( 'bp_get_group_date_created', bp_core_time_since( strtotime( $group->date_created ) ), $group );
1088
  }
1089
 
1090
  /**
@@ -1209,12 +1446,11 @@ function bp_group_creator_permalink( $group = false ) {
1209
  *
1210
  * @since 1.7.0
1211
  *
1212
- * @param object|bool $group Optional. Group object.
1213
- * Default: current group in loop.
1214
- * @param int $user_id ID of the user.
1215
  * @return bool
1216
  */
1217
- function bp_is_group_creator( $group = false, $user_id = 0 ) {
1218
  global $groups_template;
1219
 
1220
  if ( empty( $group ) ) {
@@ -1337,19 +1573,6 @@ function bp_group_list_admins( $group = false ) {
1337
  $group =& $groups_template->group;
1338
  }
1339
 
1340
- // Fetch group admins if 'populate_extras' flag is false.
1341
- if ( empty( $group->args['populate_extras'] ) ) {
1342
- $query = new BP_Group_Member_Query( array(
1343
- 'group_id' => $group->id,
1344
- 'group_role' => 'admin',
1345
- 'type' => 'first_joined',
1346
- ) );
1347
-
1348
- if ( ! empty( $query->results ) ) {
1349
- $group->admins = $query->results;
1350
- }
1351
- }
1352
-
1353
  if ( ! empty( $group->admins ) ) { ?>
1354
  <ul id="group-admins">
1355
  <?php foreach( (array) $group->admins as $admin ) { ?>
@@ -1379,19 +1602,6 @@ function bp_group_list_mods( $group = false ) {
1379
  $group =& $groups_template->group;
1380
  }
1381
 
1382
- // Fetch group mods if 'populate_extras' flag is false.
1383
- if ( empty( $group->args['populate_extras'] ) ) {
1384
- $query = new BP_Group_Member_Query( array(
1385
- 'group_id' => $group->id,
1386
- 'group_role' => 'mod',
1387
- 'type' => 'first_joined',
1388
- ) );
1389
-
1390
- if ( ! empty( $query->results ) ) {
1391
- $group->mods = $query->results;
1392
- }
1393
- }
1394
-
1395
  if ( ! empty( $group->mods ) ) : ?>
1396
 
1397
  <ul id="group-mods">
@@ -2248,7 +2458,7 @@ function bp_group_mod_memberlist( $admin_list = false, $group = false ) {
2248
  <?php echo bp_core_get_userlink( $mod->user_id ); ?>
2249
 
2250
  <span class="small">
2251
- <a href="<?php bp_group_member_promote_admin_link( array( 'user_id' => $mod->user_id ) ) ?>" class="button confirm mod-promote-to-admin" title="<?php esc_attr_e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
2252
  <a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link($mod->user_id) ?>"><?php _e( 'Demote to Member', 'buddypress' ) ?></a>
2253
  </span>
2254
  </h5>
@@ -3162,7 +3372,6 @@ function bp_group_new_topic_button( $group = false ) {
3162
  'link_class' => 'group-button show-hide-new',
3163
  'link_id' => 'new-topic-button',
3164
  'link_text' => __( 'New Topic', 'buddypress' ),
3165
- 'link_title' => __( 'New Topic', 'buddypress' ),
3166
  );
3167
 
3168
  /**
@@ -3193,7 +3402,7 @@ function bp_group_join_button( $group = false ) {
3193
  * @since 1.0.0
3194
  *
3195
  * @param object|bool $group Single group object.
3196
- * @return mixed
3197
  */
3198
  function bp_get_group_join_button( $group = false ) {
3199
  global $groups_template;
@@ -3232,7 +3441,6 @@ function bp_group_join_button( $group = false ) {
3232
  'wrapper_id' => 'groupbutton-' . $group->id,
3233
  'link_href' => wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ),
3234
  'link_text' => __( 'Leave Group', 'buddypress' ),
3235
- 'link_title' => __( 'Leave Group', 'buddypress' ),
3236
  'link_class' => 'group-button leave-group',
3237
  );
3238
 
@@ -3254,7 +3462,6 @@ function bp_group_join_button( $group = false ) {
3254
  'wrapper_id' => 'groupbutton-' . $group->id,
3255
  'link_href' => wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ),
3256
  'link_text' => __( 'Join Group', 'buddypress' ),
3257
- 'link_title' => __( 'Join Group', 'buddypress' ),
3258
  'link_class' => 'group-button join-group',
3259
  );
3260
  break;
@@ -3273,7 +3480,6 @@ function bp_group_join_button( $group = false ) {
3273
  'wrapper_id' => 'groupbutton-' . $group->id,
3274
  'link_href' => add_query_arg( 'redirect_to', bp_get_group_permalink( $group ), bp_get_group_accept_invite_link( $group ) ),
3275
  'link_text' => __( 'Accept Invitation', 'buddypress' ),
3276
- 'link_title' => __( 'Accept Invitation', 'buddypress' ),
3277
  'link_class' => 'group-button accept-invite',
3278
  );
3279
 
@@ -3289,7 +3495,6 @@ function bp_group_join_button( $group = false ) {
3289
  'wrapper_id' => 'groupbutton-' . $group->id,
3290
  'link_href' => bp_get_group_permalink( $group ),
3291
  'link_text' => __( 'Request Sent', 'buddypress' ),
3292
- 'link_title' => __( 'Request Sent', 'buddypress' ),
3293
  'link_class' => 'group-button pending membership-requested',
3294
  );
3295
 
@@ -3305,7 +3510,6 @@ function bp_group_join_button( $group = false ) {
3305
  'wrapper_id' => 'groupbutton-' . $group->id,
3306
  'link_href' => wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_request_membership' ),
3307
  'link_text' => __( 'Request Membership', 'buddypress' ),
3308
- 'link_title' => __( 'Request Membership', 'buddypress' ),
3309
  'link_class' => 'group-button request-membership',
3310
  );
3311
  }
@@ -3354,7 +3558,6 @@ function bp_group_create_button() {
3354
  'id' => 'create_group',
3355
  'component' => 'groups',
3356
  'link_text' => __( 'Create a Group', 'buddypress' ),
3357
- 'link_title' => __( 'Create a Group', 'buddypress' ),
3358
  'link_class' => 'group-create no-ajax',
3359
  'link_href' => trailingslashit( bp_get_groups_directory_permalink() . 'create' ),
3360
  'wrapper' => false,
@@ -3977,20 +4180,44 @@ function bp_group_member_css_class() {
3977
  }
3978
 
3979
  /**
 
 
3980
  * @since 1.0.0
 
 
 
 
3981
  */
3982
- function bp_group_member_joined_since() {
3983
- echo bp_get_group_member_joined_since();
3984
  }
3985
-
3986
  /**
 
 
3987
  * @since 1.0.0
 
3988
  *
3989
- * @return mixed|void
 
 
 
 
 
 
3990
  */
3991
- function bp_get_group_member_joined_since() {
3992
  global $members_template;
3993
 
 
 
 
 
 
 
 
 
 
 
3994
  /**
3995
  * Filters the joined since time for the current member in the loop.
3996
  *
@@ -4242,7 +4469,7 @@ function bp_groups_get_front_template( $group = null ) {
4242
  */
4243
  function bp_groups_members_template_part() {
4244
  ?>
4245
- <div class="item-list-tabs" id="subnav" role="navigation">
4246
  <ul>
4247
  <li class="groups-members-search" role="search">
4248
  <?php bp_directory_members_search_form(); ?>
@@ -4263,6 +4490,8 @@ function bp_groups_members_template_part() {
4263
  </ul>
4264
  </div>
4265
 
 
 
4266
  <div id="members-group-list" class="group_members dir-list">
4267
 
4268
  <?php bp_get_template_part( 'groups/single/members' ); ?>
@@ -4905,7 +5134,7 @@ function bp_new_group_invite_friend_list( $args = array() ) {
4905
  * @since 1.0.0
4906
  *
4907
  * @param array $args Array of arguments for friends list output.
4908
- * @return mixed HTML list of checkboxes, or false
4909
  */
4910
  function bp_get_new_group_invite_friend_list( $args = array() ) {
4911
 
@@ -5049,6 +5278,36 @@ function bp_groups_filter_title() {
5049
  do_action( 'bp_groups_filter_title' );
5050
  }
5051
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5052
  /**
5053
  * Is the current page a specific group admin screen?
5054
  *
@@ -5384,7 +5643,7 @@ function bp_group_request_time_since_requested() {
5384
  *
5385
  * @param string $value Formatted time since membership was requested.
5386
  */
5387
- echo apply_filters( 'bp_group_request_time_since_requested', sprintf( __( 'requested %s', 'buddypress' ), bp_core_time_since( strtotime( $requests_template->request->date_modified ) ) ) );
5388
  }
5389
 
5390
  /**
71
  return apply_filters( 'bp_get_groups_root_slug', buddypress()->groups->root_slug );
72
  }
73
 
74
+ /**
75
+ * Output the group type base slug.
76
+ *
77
+ * @since 2.7.0
78
+ */
79
+ function bp_groups_group_type_base() {
80
+ echo esc_url( bp_get_groups_group_type_base() );
81
+ }
82
+ /**
83
+ * Get the group type base slug.
84
+ *
85
+ * The base slug is the string used as the base prefix when generating group
86
+ * type directory URLs. For example, in example.com/groups/type/foo/, 'foo' is
87
+ * the group type and 'type' is the base slug.
88
+ *
89
+ * @since 2.7.0
90
+ *
91
+ * @return string
92
+ */
93
+ function bp_get_groups_group_type_base() {
94
+ /**
95
+ * Filters the group type URL base.
96
+ *
97
+ * @since 2.7.0
98
+ *
99
+ * @param string $base
100
+ */
101
+ return apply_filters( 'bp_groups_group_type_base', _x( 'type', 'group type URL base', 'buddypress' ) );
102
+ }
103
+
104
  /**
105
  * Output group directory permalink.
106
  *
128
  return apply_filters( 'bp_get_groups_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) );
129
  }
130
 
131
+ /**
132
+ * Output group type directory permalink.
133
+ *
134
+ * @since 2.7.0
135
+ *
136
+ * @param string $group_type Optional. Group type.
137
+ */
138
+ function bp_group_type_directory_permalink( $group_type = '' ) {
139
+ echo esc_url( bp_get_group_type_directory_permalink( $group_type ) );
140
+ }
141
+ /**
142
+ * Return group type directory permalink.
143
+ *
144
+ * @since 2.7.0
145
+ *
146
+ * @param string $group_type Optional. Group type. Defaults to current group type.
147
+ * @return string Group type directory URL on success, an empty string on failure.
148
+ */
149
+ function bp_get_group_type_directory_permalink( $group_type = '' ) {
150
+
151
+ if ( $group_type ) {
152
+ $_group_type = $group_type;
153
+ } else {
154
+ // Fall back on the current group type.
155
+ $_group_type = bp_get_current_group_directory_type();
156
+ }
157
+
158
+ $type = bp_groups_get_group_type_object( $_group_type );
159
+
160
+ // Bail when member type is not found or has no directory.
161
+ if ( ! $type || ! $type->has_directory ) {
162
+ return '';
163
+ }
164
+
165
+ /**
166
+ * Filters the group type directory permalink.
167
+ *
168
+ * @since 2.7.0
169
+ *
170
+ * @param string $value Group type directory permalink.
171
+ * @param object $type Group type object.
172
+ * @param string $member_type Group type name, as passed to the function.
173
+ */
174
+ return apply_filters( 'bp_get_group_type_directory_permalink', trailingslashit( bp_get_groups_directory_permalink() . bp_get_groups_group_type_base() . '/' . $type->directory_slug ), $type, $group_type );
175
+ }
176
+
177
+ /**
178
+ * Output group type directory link.
179
+ *
180
+ * @since 2.7.0
181
+ *
182
+ * @param string $group_type Unique group type identifier as used in bp_groups_register_group_type().
183
+ */
184
+ function bp_group_type_directory_link( $group_type = '' ) {
185
+ echo bp_get_group_type_directory_link( $group_type );
186
+ }
187
+ /**
188
+ * Return group type directory link.
189
+ *
190
+ * @since 2.7.0
191
+ *
192
+ * @param string $group_type Unique group type identifier as used in bp_groups_register_group_type().
193
+ * @return string
194
+ */
195
+ function bp_get_group_type_directory_link( $group_type = '' ) {
196
+ if ( empty( $group_type ) ) {
197
+ return '';
198
+ }
199
+
200
+ return sprintf( '<a href="%s">%s</a>', esc_url( bp_get_group_type_directory_permalink( $group_type ) ), bp_groups_get_group_type_object( $group_type )->labels['name'] );
201
+ }
202
+
203
+ /**
204
+ * Output a comma-delimited list of group types.
205
+ *
206
+ * @since 2.7.0
207
+ * @see bp_get_group_type_list() for parameter documentation.
208
+ */
209
+ function bp_group_type_list( $group_id = 0, $r = array() ) {
210
+ echo bp_get_group_type_list( $group_id, $r );
211
+ }
212
+ /**
213
+ * Return a comma-delimited list of group types.
214
+ *
215
+ * @since 2.7.0
216
+ *
217
+ * @param int $group_id Group ID. Defaults to current group ID if on a group page.
218
+ * @param array|string $args {
219
+ * Array of parameters. All items are optional.
220
+ * @type string $parent_element Element to wrap around the list. Defaults to 'p'.
221
+ * @type array $parent_attr Element attributes for parent element. Defaults to
222
+ * array( 'class' => 'bp-group-type-list' ).
223
+ * @type string $label Label to add before the list. Defaults to 'Group Types:'.
224
+ * @type string $label_element Element to wrap around the label. Defaults to 'strong'.
225
+ * @type array $label_attr Element attributes for label element. Defaults to array().
226
+ * }
227
+ * @return string
228
+ */
229
+ function bp_get_group_type_list( $group_id = 0, $r = array() ) {
230
+ if ( empty( $group_id ) ) {
231
+ $group_id = bp_get_current_group_id();
232
+ }
233
+
234
+ $r = bp_parse_args( $r, array(
235
+ 'parent_element' => 'p',
236
+ 'parent_attr' => array(
237
+ 'class' => 'bp-group-type-list',
238
+ ),
239
+ 'label' => __( 'Group Types:', 'buddypress' ),
240
+ 'label_element' => 'strong',
241
+ 'label_attr' => array()
242
+ ), 'group_type_list' );
243
+
244
+ $retval = '';
245
+
246
+ if ( $types = bp_groups_get_group_type( $group_id, false ) ) {
247
+ // Make sure we can show the type in the list.
248
+ $types = array_intersect( bp_groups_get_group_types( array( 'show_in_list' => true ) ), $types );
249
+ if ( empty( $types ) ) {
250
+ return $retval;
251
+ }
252
+
253
+ $before = $after = $label = '';
254
+
255
+ // Render parent element.
256
+ if ( ! empty( $r['parent_element'] ) ) {
257
+ $parent_elem = new BP_Core_HTML_Element( array(
258
+ 'element' => $r['parent_element'],
259
+ 'attr' => $r['parent_attr']
260
+ ) );
261
+
262
+ // Set before and after.
263
+ $before = $parent_elem->get( 'open_tag' );
264
+ $after = $parent_elem->get( 'close_tag' );
265
+ }
266
+
267
+ // Render label element.
268
+ if ( ! empty( $r['label_element'] ) ) {
269
+ $label = new BP_Core_HTML_Element( array(
270
+ 'element' => $r['label_element'],
271
+ 'attr' => $r['label_attr'],
272
+ 'inner_html' => esc_html( $r['label'] )
273
+ ) );
274
+ $label = $label->contents() . ' ';
275
+
276
+ // No element, just the label.
277
+ } else {
278
+ $label = esc_html( $r['label'] );
279
+ }
280
+
281
+ // Comma-delimit each type into the group type directory link.
282
+ $label .= implode( ', ', array_map( 'bp_get_group_type_directory_link', $types ) );
283
+
284
+ // Retval time!
285
+ $retval = $before . $label . $after;
286
+ }
287
+
288
+ return $retval;
289
+ }
290
+
291
  /**
292
  * Start the Groups Template Loop.
293
  *
294
  * @since 1.0.0
295
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
296
+ * @since 2.7.0 Added `$update_admin_cache` parameter.
297
  *
298
  * @param array|string $args {
299
  * Array of parameters. All items are optional.
324
  * See {@link WP_Meta_Query::queries} for description.
325
  * @type array|string $include Array or comma-separated list of group IDs. Results will be limited
326
  * to groups within the list. Default: false.
 
 
327
  * @type array|string $exclude Array or comma-separated list of group IDs. Results will exclude
328
  * the listed groups. Default: false.
329
+ * @type array|string $parent_id Array or comma-separated list of group IDs. Results will include only
330
+ * child groups of the listed groups. Default: null.
331
  * @type bool $update_meta_cache Whether to fetch groupmeta for queried groups. Default: true.
332
+ * @type bool $update_admin_cache Whether to pre-fetch group admins for queried groups.
333
+ * Defaults to true when on a group directory, where this
334
+ * information is needed in the loop. Otherwise false.
335
  * }
336
  * @return bool True if there are groups to display that match the params
337
  */
363
  $slug = bp_get_current_group_slug();
364
  }
365
 
366
+ $group_type = bp_get_current_group_directory_type();
367
+ if ( ! $group_type && ! empty( $_GET['group_type'] ) ) {
368
+ if ( is_array( $_GET['group_type'] ) ) {
369
+ $group_type = $_GET['group_type'];
370
+ } else {
371
+ // Can be a comma-separated list.
372
+ $group_type = explode( ',', $_GET['group_type'] );
373
+ }
374
+ }
375
+
376
  // Default search string (too soon to escape here).
377
  $search_query_arg = bp_core_get_component_search_query_arg( 'groups' );
378
  if ( ! empty( $_REQUEST[ $search_query_arg ] ) ) {
396
  'user_id' => bp_displayed_user_id(),
397
  'slug' => $slug,
398
  'search_terms' => $search_terms,
399
+ 'group_type' => $group_type,
400
  'group_type__in' => '',
401
  'group_type__not_in' => '',
402
  'meta_query' => false,
403
  'include' => false,
404
  'exclude' => false,
405
+ 'parent_id' => null,
406
  'update_meta_cache' => true,
407
+ 'update_admin_cache' => bp_is_groups_directory() || bp_is_user_groups(),
408
  ), 'has_groups' );
409
 
410
  // Setup the Groups template global.
426
  'meta_query' => $r['meta_query'],
427
  'include' => $r['include'],
428
  'exclude' => $r['exclude'],
429
+ 'parent_id' => $r['parent_id'],
430
  'update_meta_cache' => (bool) $r['update_meta_cache'],
431
+ 'update_admin_cache' => (bool) $r['update_admin_cache'],
432
  ) );
433
 
434
  /**
472
  *
473
  * @since 1.0.0
474
  *
475
+ * @param BP_Groups_Group $group Optional. Group object. Default: current group in loop.
476
  * @return bool
477
  */
478
+ function bp_group_is_visible( $group = null ) {
479
  global $groups_template;
480
 
481
  if ( bp_current_user_can( 'bp_moderate' ) ) {
754
  * @since 1.0.0
755
  *
756
  * @see bp_core_fetch_avatar() For a description of arguments and return values.
757
+ *
758
  * @param array|string $args {
759
  * Arguments are listed here with an explanation of their defaults.
760
  * For more information about the arguments, see {@link bp_core_fetch_avatar()}.
890
  * Output the 'last active' string for the current group in the loop.
891
  *
892
  * @since 1.0.0
893
+ * @since 2.7.0 Added $args as a parameter.
894
  *
895
+ * @param object|bool $group Optional. Group object. Default: current group in loop.
896
+ * @param array|string $args Optional. {@see bp_get_group_last_active()}.
897
  */
898
+ function bp_group_last_active( $group = false, $args = array() ) {
899
+ echo bp_get_group_last_active( $group, $args );
900
  }
901
  /**
902
  * Return the 'last active' string for the current group in the loop.
903
  *
904
  * @since 1.0.0
905
+ * @since 2.7.0 Added $args as a parameter.
906
  *
907
+ * @param object|bool $group Optional. Group object. Default: current group in loop.
908
+ * @param array|string $args {
909
+ * Array of optional parameters.
910
+ *
911
+ * @type bool $relative Optional. If true, returns relative activity date. eg. active 5 months ago.
912
+ * If false, returns active date value from database. Default: true.
913
+ * }
914
  * @return string
915
  */
916
+ function bp_get_group_last_active( $group = false, $args = array() ) {
917
  global $groups_template;
918
 
919
  if ( empty( $group ) ) {
920
  $group =& $groups_template->group;
921
  }
922
 
923
+ $r = wp_parse_args( $args, array(
924
+ 'relative' => true,
925
+ ) );
926
 
927
+ $last_active = $group->last_activity;
928
+ if ( ! $last_active ) {
929
  $last_active = groups_get_groupmeta( $group->id, 'last_activity' );
930
  }
931
 
932
+ // We do not want relative time, so return now.
933
+ // @todo Should the 'bp_get_group_last_active' filter be applied here?
934
+ if ( ! $r['relative'] ) {
935
+ return esc_attr( $last_active );
936
+ }
937
+
938
  if ( empty( $last_active ) ) {
939
  return __( 'not yet active', 'buddypress' );
940
  } else {
941
 
942
  /**
943
+ * Filters the 'last active' string for the current group in the loop.
944
  *
945
  * @since 1.0.0
946
  * @since 2.5.0 Added the `$group` parameter.
957
  *
958
  * @since 1.0.0
959
  *
960
+ * @param BP_Groups_Group $group Optional. Group object. Default: current group in loop.
 
961
  */
962
+ function bp_group_permalink( $group = null ) {
963
  echo bp_get_group_permalink( $group );
964
  }
965
  /**
967
  *
968
  * @since 1.0.0
969
  *
970
+ * @param BP_Groups_Group $group Optional. Group object. Default: current group in loop.
 
971
  * @return string
972
  */
973
+ function bp_get_group_permalink( $group = null ) {
974
  global $groups_template;
975
 
976
  if ( empty( $group ) ) {
1272
  * Output the created date of the current group in the loop.
1273
  *
1274
  * @since 1.0.0
1275
+ * @since 2.7.0 Added $args as a parameter.
1276
  *
1277
+ * @param object|bool $group Optional. Group object. Default: current group in loop.
1278
+ * @param array|string $args {@see bp_get_group_date_created()}.
1279
  */
1280
+ function bp_group_date_created( $group = false, $args = array() ) {
1281
+ echo bp_get_group_date_created( $group, $args );
1282
  }
1283
  /**
1284
  * Return the created date of the current group in the loop.
1285
  *
1286
  * @since 1.0.0
1287
+ * @since 2.7.0 Added $args as a parameter.
1288
  *
1289
+ * @param object|bool $group Optional. Group object. Default: current group in loop.
1290
+ * @param array|string $args {
1291
+ * Array of optional parameters.
1292
+ *
1293
+ * @type bool $relative Optional. If true, returns relative created date. eg. active 5 months ago.
1294
+ * If false, returns created date value from database. Default: true.
1295
+ * }
1296
  * @return string
1297
  */
1298
+ function bp_get_group_date_created( $group = false, $args = array() ) {
1299
  global $groups_template;
1300
 
1301
+ $r = wp_parse_args( $args, array(
1302
+ 'relative' => true,
1303
+ ) );
1304
+
1305
  if ( empty( $group ) ) {
1306
  $group =& $groups_template->group;
1307
  }
1308
 
1309
+ // We do not want relative time, so return now.
1310
+ // @todo Should the 'bp_get_group_date_created' filter be applied here?
1311
+ if ( ! $r['relative'] ) {
1312
+ return esc_attr( $group->date_created );
1313
+ }
1314
+
1315
  /**
1316
  * Filters the created date of the current group in the loop.
1317
  *
1321
  * @param string $value Created date for the current group.
1322
  * @param object $group Group object.
1323
  */
1324
+ return apply_filters( 'bp_get_group_date_created', bp_core_time_since( $group->date_created ), $group );
1325
  }
1326
 
1327
  /**
1446
  *
1447
  * @since 1.7.0
1448
  *
1449
+ * @param BP_Groups_Group $group Optional. Group object. Default: current group in loop.
1450
+ * @param int $user_id ID of the user.
 
1451
  * @return bool
1452
  */
1453
+ function bp_is_group_creator( $group = null, $user_id = 0 ) {
1454
  global $groups_template;
1455
 
1456
  if ( empty( $group ) ) {
1573
  $group =& $groups_template->group;
1574
  }
1575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1576
  if ( ! empty( $group->admins ) ) { ?>
1577
  <ul id="group-admins">
1578
  <?php foreach( (array) $group->admins as $admin ) { ?>
1602
  $group =& $groups_template->group;
1603
  }
1604
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1605
  if ( ! empty( $group->mods ) ) : ?>
1606
 
1607
  <ul id="group-mods">
2458
  <?php echo bp_core_get_userlink( $mod->user_id ); ?>
2459
 
2460
  <span class="small">
2461
+ <a href="<?php bp_group_member_promote_admin_link( array( 'user_id' => $mod->user_id ) ) ?>" class="button confirm mod-promote-to-admin"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
2462
  <a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link($mod->user_id) ?>"><?php _e( 'Demote to Member', 'buddypress' ) ?></a>
2463
  </span>
2464
  </h5>
3372
  'link_class' => 'group-button show-hide-new',
3373
  'link_id' => 'new-topic-button',
3374
  'link_text' => __( 'New Topic', 'buddypress' ),
 
3375
  );
3376
 
3377
  /**
3402
  * @since 1.0.0
3403
  *
3404
  * @param object|bool $group Single group object.
3405
+ * @return false|string
3406
  */
3407
  function bp_get_group_join_button( $group = false ) {
3408
  global $groups_template;
3441
  'wrapper_id' => 'groupbutton-' . $group->id,
3442
  'link_href' => wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ),
3443
  'link_text' => __( 'Leave Group', 'buddypress' ),
 
3444
  'link_class' => 'group-button leave-group',
3445
  );
3446
 
3462
  'wrapper_id' => 'groupbutton-' . $group->id,
3463
  'link_href' => wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ),
3464
  'link_text' => __( 'Join Group', 'buddypress' ),
 
3465
  'link_class' => 'group-button join-group',
3466
  );
3467
  break;
3480
  'wrapper_id' => 'groupbutton-' . $group->id,
3481
  'link_href' => add_query_arg( 'redirect_to', bp_get_group_permalink( $group ), bp_get_group_accept_invite_link( $group ) ),
3482
  'link_text' => __( 'Accept Invitation', 'buddypress' ),
 
3483
  'link_class' => 'group-button accept-invite',
3484
  );
3485
 
3495
  'wrapper_id' => 'groupbutton-' . $group->id,
3496
  'link_href' => bp_get_group_permalink( $group ),
3497
  'link_text' => __( 'Request Sent', 'buddypress' ),
 
3498
  'link_class' => 'group-button pending membership-requested',
3499
  );
3500
 
3510
  'wrapper_id' => 'groupbutton-' . $group->id,
3511
  'link_href' => wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_request_membership' ),
3512
  'link_text' => __( 'Request Membership', 'buddypress' ),
 
3513
  'link_class' => 'group-button request-membership',
3514
  );
3515
  }
3558
  'id' => 'create_group',
3559
  'component' => 'groups',
3560
  'link_text' => __( 'Create a Group', 'buddypress' ),
 
3561
  'link_class' => 'group-create no-ajax',
3562
  'link_href' => trailingslashit( bp_get_groups_directory_permalink() . 'create' ),
3563
  'wrapper' => false,
4180
  }
4181
 
4182
  /**
4183
+ * Output the joined date for the current member in the group member loop.
4184
+ *
4185
  * @since 1.0.0
4186
+ * @since 2.7.0 Added $args as a parameter.
4187
+ *
4188
+ * @param array|string $args {@see bp_get_group_member_joined_since()}
4189
+ * @return string
4190
  */
4191
+ function bp_group_member_joined_since( $args = array() ) {
4192
+ echo bp_get_group_member_joined_since( $args );
4193
  }
 
4194
  /**
4195
+ * Return the joined date for the current member in the group member loop.
4196
+ *
4197
  * @since 1.0.0
4198
+ * @since 2.7.0 Added $args as a parameter.
4199
  *
4200
+ * @param array|string $args {
4201
+ * Array of optional parameters.
4202
+ *
4203
+ * @type bool $relative Optional. If true, returns relative joined date. eg. joined 5 months ago.
4204
+ * If false, returns joined date value from database. Default: true.
4205
+ * }
4206
+ * @return string
4207
  */
4208
+ function bp_get_group_member_joined_since( $args = array() ) {
4209
  global $members_template;
4210
 
4211
+ $r = wp_parse_args( $args, array(
4212
+ 'relative' => true,
4213
+ ) );
4214
+
4215
+ // We do not want relative time, so return now.
4216
+ // @todo Should the 'bp_get_group_member_joined_since' filter be applied here?
4217
+ if ( ! $r['relative'] ) {
4218
+ return esc_attr( $members_template->member->date_modified );
4219
+ }
4220
+
4221
  /**
4222
  * Filters the joined since time for the current member in the loop.
4223
  *
4469
  */
4470
  function bp_groups_members_template_part() {
4471
  ?>
4472
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Group secondary navigation', 'buddypress' ); ?>" role="navigation">
4473
  <ul>
4474
  <li class="groups-members-search" role="search">
4475
  <?php bp_directory_members_search_form(); ?>
4490
  </ul>
4491
  </div>
4492
 
4493
+ <h2 class="bp-screen-reader-text"><?php _e( 'Members', 'buddypress' ); ?></h2>
4494
+
4495
  <div id="members-group-list" class="group_members dir-list">
4496
 
4497
  <?php bp_get_template_part( 'groups/single/members' ); ?>
5134
  * @since 1.0.0
5135
  *
5136
  * @param array $args Array of arguments for friends list output.
5137
+ * @return false|string HTML list of checkboxes, or false
5138
  */
5139
  function bp_get_new_group_invite_friend_list( $args = array() ) {
5140
 
5278
  do_action( 'bp_groups_filter_title' );
5279
  }
5280
 
5281
+ /**
5282
+ * Echo the current group type message.
5283
+ *
5284
+ * @since 2.7.0
5285
+ */
5286
+ function bp_current_group_directory_type_message() {
5287
+ echo bp_get_current_group_directory_type_message();
5288
+ }
5289
+ /**
5290
+ * Generate the current group type message.
5291
+ *
5292
+ * @since 2.7.0
5293
+ *
5294
+ * @return string
5295
+ */
5296
+ function bp_get_current_group_directory_type_message() {
5297
+ $type_object = bp_groups_get_group_type_object( bp_get_current_group_directory_type() );
5298
+
5299
+ $message = sprintf( __( 'Viewing groups of the type: %s', 'buddypress' ), '<strong>' . $type_object->labels['singular_name'] . '</strong>' );
5300
+
5301
+ /**
5302
+ * Filters the current group type message.
5303
+ *
5304
+ * @since 2.7.0
5305
+ *
5306
+ * @param string $message Message to filter.
5307
+ */
5308
+ return apply_filters( 'bp_get_current_group_type_message', $message );
5309
+ }
5310
+
5311
  /**
5312
  * Is the current page a specific group admin screen?
5313
  *
5643
  *
5644
  * @param string $value Formatted time since membership was requested.
5645
  */
5646
+ echo apply_filters( 'bp_group_request_time_since_requested', sprintf( __( 'requested %s', 'buddypress' ), bp_core_time_since( $requests_template->request->date_modified ) ) );
5647
  }
5648
 
5649
  /**
bp-groups/bp-groups-widgets.php CHANGED
@@ -65,17 +65,13 @@ function groups_ajax_widget_groups_list() {
65
  <div class="item">
66
  <div class="item-title"><a href="<?php bp_group_permalink() ?>" title="<?php bp_group_name() ?>"><?php bp_group_name() ?></a></div>
67
  <div class="item-meta">
68
- <span class="activity">
69
- <?php
70
- if ( 'newest-groups' == $_POST['filter'] ) {
71
- printf( __( 'created %s', 'buddypress' ), bp_get_group_date_created() );
72
- } elseif ( 'recently-active-groups' == $_POST['filter'] ) {
73
- printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() );
74
- } elseif ( 'popular-groups' == $_POST['filter'] ) {
75
- bp_group_member_count();
76
- }
77
- ?>
78
- </span>
79
  </div>
80
  </div>
81
  </li>
65
  <div class="item">
66
  <div class="item-title"><a href="<?php bp_group_permalink() ?>" title="<?php bp_group_name() ?>"><?php bp_group_name() ?></a></div>
67
  <div class="item-meta">
68
+ <?php if ( 'newest-groups' === $_POST['filter'] ) : ?>
69
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_group_date_created( 0, array( 'relative' => false ) ) ); ?>"><?php printf( __( 'created %s', 'buddypress' ), bp_get_group_date_created() ); ?></span>
70
+ <?php elseif ( 'recently-active-groups' === $_POST['filter'] ) : ?>
71
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_group_last_active( 0, array( 'relative' => false ) ) ); ?>"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
72
+ <?php else : ?>
73
+ <span class="activity"><?php bp_group_member_count(); ?></span>
74
+ <?php endif; ?>
 
 
 
 
75
  </div>
76
  </div>
77
  </li>
bp-groups/classes/class-bp-group-extension.php CHANGED
@@ -583,9 +583,7 @@ class BP_Group_Extension {
583
  if ( false === $this->enable_nav_item ) {
584
  $this->params['access'] = 'noone';
585
  } else {
586
- $group = groups_get_group( array(
587
- 'group_id' => $this->group_id,
588
- ) );
589
 
590
  if ( ! empty( $group->status ) && 'public' === $group->status ) {
591
  // Tabs in public groups are accessible to anyone by default.
@@ -668,9 +666,7 @@ class BP_Group_Extension {
668
  * @return bool
669
  */
670
  protected function user_meets_access_condition( $access_condition ) {
671
- $group = groups_get_group( array(
672
- 'group_id' => $this->group_id,
673
- ) );
674
 
675
  switch ( $access_condition ) {
676
  case 'admin' :
@@ -763,7 +759,7 @@ class BP_Group_Extension {
763
  }
764
 
765
  // Hook the group home widget.
766
- if ( ! bp_current_action() && bp_is_current_action( 'home' ) ) {
767
  add_action( $this->display_hook, array( &$this, 'widget_display' ) );
768
  }
769
  }
@@ -850,9 +846,7 @@ class BP_Group_Extension {
850
  $user_can_visit = $this->user_can_visit();
851
 
852
  if ( ! $user_can_visit && is_user_logged_in() ) {
853
- $current_group = groups_get_group( array(
854
- 'group_id' => $this->group_id,
855
- ) );
856
 
857
  $no_access_args['message'] = __( 'You do not have access to this content.', 'buddypress' );
858
  $no_access_args['root'] = bp_get_group_permalink( $current_group ) . 'home/';
583
  if ( false === $this->enable_nav_item ) {
584
  $this->params['access'] = 'noone';
585
  } else {
586
+ $group = groups_get_group( $this->group_id );
 
 
587
 
588
  if ( ! empty( $group->status ) && 'public' === $group->status ) {
589
  // Tabs in public groups are accessible to anyone by default.
666
  * @return bool
667
  */
668
  protected function user_meets_access_condition( $access_condition ) {
669
+ $group = groups_get_group( $this->group_id );
 
 
670
 
671
  switch ( $access_condition ) {
672
  case 'admin' :
759
  }
760
 
761
  // Hook the group home widget.
762
+ if ( bp_is_group_home() ) {
763
  add_action( $this->display_hook, array( &$this, 'widget_display' ) );
764
  }
765
  }
846
  $user_can_visit = $this->user_can_visit();
847
 
848
  if ( ! $user_can_visit && is_user_logged_in() ) {
849
+ $current_group = groups_get_group( $this->group_id );
 
 
850
 
851
  $no_access_args['message'] = __( 'You do not have access to this content.', 'buddypress' );
852
  $no_access_args['root'] = bp_get_group_permalink( $current_group ) . 'home/';
bp-groups/classes/class-bp-groups-component.php CHANGED
@@ -84,6 +84,16 @@ class BP_Groups_Component extends BP_Component {
84
  */
85
  public $types = array();
86
 
 
 
 
 
 
 
 
 
 
 
87
  /**
88
  * Start the groups component creation process.
89
  *
@@ -168,13 +178,17 @@ class BP_Groups_Component extends BP_Component {
168
  'group' => $bp->table_prefix . 'bp_groups_groupmeta',
169
  );
170
 
 
 
 
 
171
  // All globals for groups component.
172
  // Note that global_tables is included in this array.
173
  $args = array(
174
  'slug' => BP_GROUPS_SLUG,
175
  'root_slug' => isset( $bp->pages->groups->slug ) ? $bp->pages->groups->slug : BP_GROUPS_SLUG,
176
  'has_directory' => true,
177
- 'directory_title' => _x( 'Groups', 'component directory title', 'buddypress' ),
178
  'notification_callback' => 'groups_format_notifications',
179
  'search_string' => _x( 'Search Groups...', 'Component directory search', 'buddypress' ),
180
  'global_tables' => $global_tables,
@@ -200,10 +214,7 @@ class BP_Groups_Component extends BP_Component {
200
  $current_group_class = apply_filters( 'bp_groups_current_group_class', 'BP_Groups_Group' );
201
 
202
  if ( $current_group_class == 'BP_Groups_Group' ) {
203
- $this->current_group = groups_get_group( array(
204
- 'group_id' => $group_id,
205
- 'populate_extras' => true,
206
- ) );
207
 
208
  } else {
209
 
@@ -249,17 +260,6 @@ class BP_Groups_Component extends BP_Component {
249
  $this->current_group->is_visible = false;
250
  }
251
 
252
- // If this is a private or hidden group, does the user have access?
253
- if ( 'private' == $this->current_group->status || 'hidden' == $this->current_group->status ) {
254
- if ( $this->current_group->is_user_member && is_user_logged_in() || bp_current_user_can( 'bp_moderate' ) ) {
255
- $this->current_group->user_has_access = true;
256
- } else {
257
- $this->current_group->user_has_access = false;
258
- }
259
- } else {
260
- $this->current_group->user_has_access = true;
261
- }
262
-
263
  // Check once if the current group has a custom front template.
264
  $this->current_group->front_template = bp_groups_get_front_template( $this->current_group );
265
 
84
  */
85
  public $types = array();
86
 
87
+ /**
88
+ * Current directory group type.
89
+ *
90
+ * @see groups_directory_groups_setup()
91
+ *
92
+ * @since 2.7.0
93
+ * @var string
94
+ */
95
+ public $current_directory_type = '';
96
+
97
  /**
98
  * Start the groups component creation process.
99
  *
178
  'group' => $bp->table_prefix . 'bp_groups_groupmeta',
179
  );
180
 
181
+ // Fetch the default directory title.
182
+ $default_directory_titles = bp_core_get_directory_page_default_titles();
183
+ $default_directory_title = $default_directory_titles[$this->id];
184
+
185
  // All globals for groups component.
186
  // Note that global_tables is included in this array.
187
  $args = array(
188
  'slug' => BP_GROUPS_SLUG,
189
  'root_slug' => isset( $bp->pages->groups->slug ) ? $bp->pages->groups->slug : BP_GROUPS_SLUG,
190
  'has_directory' => true,
191
+ 'directory_title' => isset( $bp->pages->groups->title ) ? $bp->pages->groups->title : $default_directory_title,
192
  'notification_callback' => 'groups_format_notifications',
193
  'search_string' => _x( 'Search Groups...', 'Component directory search', 'buddypress' ),
194
  'global_tables' => $global_tables,
214
  $current_group_class = apply_filters( 'bp_groups_current_group_class', 'BP_Groups_Group' );
215
 
216
  if ( $current_group_class == 'BP_Groups_Group' ) {
217
+ $this->current_group = groups_get_group( $group_id );
 
 
 
218
 
219
  } else {
220
 
260
  $this->current_group->is_visible = false;
261
  }
262
 
 
 
 
 
 
 
 
 
 
 
 
263
  // Check once if the current group has a custom front template.
264
  $this->current_group->front_template = bp_groups_get_front_template( $this->current_group );
265
 
bp-groups/classes/class-bp-groups-group-members-template.php CHANGED
@@ -136,7 +136,7 @@ class BP_Groups_Group_Members_Template {
136
  */
137
  $current_group = groups_get_current_group();
138
  if ( empty( $current_group ) || ( $current_group && $current_group->id !== bp_get_current_group_id() ) ) {
139
- $current_group = groups_get_group( array( 'group_id' => $r['group_id'] ) );
140
  }
141
 
142
  // Assemble the base URL for pagination.
@@ -239,10 +239,11 @@ class BP_Groups_Group_Members_Template {
239
  *
240
  * @since 1.0.0
241
  * @since 2.3.0 `$this` parameter added.
 
242
  *
243
  * @param BP_Groups_Group_Members_Template $this Instance of the current Members template.
244
  */
245
- do_action( 'loop_end', $this );
246
 
247
  // Do some cleaning up after the loop.
248
  $this->rewind_members();
@@ -269,10 +270,11 @@ class BP_Groups_Group_Members_Template {
269
  *
270
  * @since 1.0.0
271
  * @since 2.3.0 `$this` parameter added.
 
272
  *
273
  * @param BP_Groups_Group_Members_Template $this Instance of the current Members template.
274
  */
275
- do_action( 'loop_start', $this );
276
  }
277
  }
278
  }
136
  */
137
  $current_group = groups_get_current_group();
138
  if ( empty( $current_group ) || ( $current_group && $current_group->id !== bp_get_current_group_id() ) ) {
139
+ $current_group = groups_get_group( $r['group_id'] );
140
  }
141
 
142
  // Assemble the base URL for pagination.
239
  *
240
  * @since 1.0.0
241
  * @since 2.3.0 `$this` parameter added.
242
+ * @since 2.7.0 Action renamed from `loop_end`.
243
  *
244
  * @param BP_Groups_Group_Members_Template $this Instance of the current Members template.
245
  */
246
+ do_action( 'group_members_loop_end', $this );
247
 
248
  // Do some cleaning up after the loop.
249
  $this->rewind_members();
270
  *
271
  * @since 1.0.0
272
  * @since 2.3.0 `$this` parameter added.
273
+ * @since 2.7.0 Action renamed from `loop_start`.
274
  *
275
  * @param BP_Groups_Group_Members_Template $this Instance of the current Members template.
276
  */
277
+ do_action( 'group_members_loop_start', $this );
278
  }
279
  }
280
  }
bp-groups/classes/class-bp-groups-group.php CHANGED
@@ -67,6 +67,16 @@ class BP_Groups_Group {
67
  */
68
  public $status;
69
 
 
 
 
 
 
 
 
 
 
 
70
  /**
71
  * Should (legacy) bbPress forums be enabled for this group?
72
  *
@@ -89,7 +99,7 @@ class BP_Groups_Group {
89
  * @since 1.6.0
90
  * @var array
91
  */
92
- public $admins;
93
 
94
  /**
95
  * Data about the group's moderators.
@@ -97,7 +107,7 @@ class BP_Groups_Group {
97
  * @since 1.6.0
98
  * @var array
99
  */
100
- public $mods;
101
 
102
  /**
103
  * Total count of group members.
@@ -105,7 +115,7 @@ class BP_Groups_Group {
105
  * @since 1.6.0
106
  * @var int
107
  */
108
- public $total_member_count;
109
 
110
  /**
111
  * Is the current user a member of this group?
@@ -113,7 +123,7 @@ class BP_Groups_Group {
113
  * @since 1.2.0
114
  * @var bool
115
  */
116
- public $is_member;
117
 
118
  /**
119
  * Does the current user have an outstanding invitation to this group?
@@ -121,7 +131,7 @@ class BP_Groups_Group {
121
  * @since 1.9.0
122
  * @var bool
123
  */
124
- public $is_invited;
125
 
126
  /**
127
  * Does the current user have a pending membership request to this group?
@@ -129,7 +139,7 @@ class BP_Groups_Group {
129
  * @since 1.9.0
130
  * @var bool
131
  */
132
- public $is_pending;
133
 
134
  /**
135
  * Timestamp of the last activity that happened in this group.
@@ -137,7 +147,7 @@ class BP_Groups_Group {
137
  * @since 1.2.0
138
  * @var string
139
  */
140
- public $last_activity;
141
 
142
  /**
143
  * If this is a private or hidden group, does the current user have access?
@@ -145,7 +155,7 @@ class BP_Groups_Group {
145
  * @since 1.6.0
146
  * @var bool
147
  */
148
- public $user_has_access;
149
 
150
  /**
151
  * Raw arguments passed to the constructor.
@@ -164,18 +174,12 @@ class BP_Groups_Group {
164
  * the object will be pre-populated with info about that group.
165
  * @param array $args {
166
  * Array of optional arguments.
167
- * @type bool $populate_extras Whether to fetch "extra" data about the group
168
- * (group admins/mods, access for the current user).
169
- * Default: false.
170
  * }
171
  */
172
  public function __construct( $id = null, $args = array() ) {
173
- $this->args = wp_parse_args( $args, array(
174
- 'populate_extras' => false,
175
- ) );
176
-
177
  if ( !empty( $id ) ) {
178
- $this->id = $id;
179
  $this->populate();
180
  }
181
  }
@@ -208,61 +212,15 @@ class BP_Groups_Group {
208
  }
209
 
210
  // Group found so setup the object variables.
211
- $this->id = $group->id;
212
- $this->creator_id = $group->creator_id;
213
  $this->name = stripslashes( $group->name );
214
  $this->slug = $group->slug;
215
  $this->description = stripslashes( $group->description );
216
  $this->status = $group->status;
217
- $this->enable_forum = $group->enable_forum;
 
218
  $this->date_created = $group->date_created;
219
-
220
- // Are we getting extra group data?
221
- if ( ! empty( $this->args['populate_extras'] ) ) {
222
-
223
- /**
224
- * Filters the SQL prepared statement used to fetch group admins and mods.
225
- *
226
- * @since 1.5.0
227
- *
228
- * @param string $value SQL select statement used to fetch admins and mods.
229
- */
230
- $admin_mods = $wpdb->get_results( apply_filters( 'bp_group_admin_mods_user_join_filter', $wpdb->prepare( "SELECT u.ID as user_id, u.user_login, u.user_email, u.user_nicename, m.is_admin, m.is_mod FROM {$wpdb->users} u, {$bp->groups->table_name_members} m WHERE u.ID = m.user_id AND m.group_id = %d AND ( m.is_admin = 1 OR m.is_mod = 1 )", $this->id ) ) );
231
-
232
- // Add admins and moderators to their respective arrays.
233
- foreach ( (array) $admin_mods as $user ) {
234
- if ( !empty( $user->is_admin ) ) {
235
- $this->admins[] = $user;
236
- } else {
237
- $this->mods[] = $user;
238
- }
239
- }
240
-
241
- // Set up some specific group vars from meta. Excluded
242
- // from the bp_groups cache because it's cached independently.
243
- $this->last_activity = groups_get_groupmeta( $this->id, 'last_activity' );
244
- $this->total_member_count = groups_get_groupmeta( $this->id, 'total_member_count' );
245
-
246
- // Set user-specific data.
247
- $user_id = bp_loggedin_user_id();
248
- $this->is_member = groups_is_user_member( $user_id, $this->id );
249
- $this->is_invited = groups_check_user_has_invite( $user_id, $this->id );
250
- $this->is_pending = groups_check_for_membership_request( $user_id, $this->id );
251
-
252
- // If this is a private or hidden group, does the current user have access?
253
- if ( ( 'private' === $this->status ) || ( 'hidden' === $this->status ) ) {
254
-
255
- // Assume user does not have access to hidden/private groups.
256
- $this->user_has_access = false;
257
-
258
- // Group members or community moderators have access.
259
- if ( ( $this->is_member && is_user_logged_in() ) || bp_current_user_can( 'bp_moderate' ) ) {
260
- $this->user_has_access = true;
261
- }
262
- } else {
263
- $this->user_has_access = true;
264
- }
265
- }
266
  }
267
 
268
  /**
@@ -282,6 +240,7 @@ class BP_Groups_Group {
282
  $this->slug = apply_filters( 'groups_group_slug_before_save', $this->slug, $this->id );
283
  $this->description = apply_filters( 'groups_group_description_before_save', $this->description, $this->id );
284
  $this->status = apply_filters( 'groups_group_status_before_save', $this->status, $this->id );
 
285
  $this->enable_forum = apply_filters( 'groups_group_enable_forum_before_save', $this->enable_forum, $this->id );
286
  $this->date_created = apply_filters( 'groups_group_date_created_before_save', $this->date_created, $this->id );
287
 
@@ -324,6 +283,7 @@ class BP_Groups_Group {
324
  slug = %s,
325
  description = %s,
326
  status = %s,
 
327
  enable_forum = %d,
328
  date_created = %s
329
  WHERE
@@ -334,6 +294,7 @@ class BP_Groups_Group {
334
  $this->slug,
335
  $this->description,
336
  $this->status,
 
337
  $this->enable_forum,
338
  $this->date_created,
339
  $this->id
@@ -346,16 +307,18 @@ class BP_Groups_Group {
346
  slug,
347
  description,
348
  status,
 
349
  enable_forum,
350
  date_created
351
  ) VALUES (
352
- %d, %s, %s, %s, %s, %d, %s
353
  )",
354
  $this->creator_id,
355
  $this->name,
356
  $this->slug,
357
  $this->description,
358
  $this->status,
 
359
  $this->enable_forum,
360
  $this->date_created
361
  );
@@ -425,6 +388,213 @@ class BP_Groups_Group {
425
  return true;
426
  }
427
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
  /** Static Methods ****************************************************/
429
 
430
  /**
@@ -435,7 +605,7 @@ class BP_Groups_Group {
435
  * @param string $slug Slug to check.
436
  * @param string|bool $table_name Optional. Name of the table to check
437
  * against. Default: $bp->groups->table_name.
438
- * @return string|null ID of the group, if one is found, else null.
439
  */
440
  public static function group_exists( $slug, $table_name = false ) {
441
  global $wpdb;
@@ -446,7 +616,9 @@ class BP_Groups_Group {
446
  if ( empty( $slug ) )
447
  return false;
448
 
449
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$table_name} WHERE slug = %s", strtolower( $slug ) ) );
 
 
450
  }
451
 
452
  /**
@@ -506,7 +678,7 @@ class BP_Groups_Group {
506
  if ( empty( $user_id ) )
507
  $user_id = bp_displayed_user_id();
508
 
509
- $search_terms_like = bp_esc_like( $filter ) . '%';
510
 
511
  $pag_sql = $order_sql = $hidden_sql = '';
512
 
@@ -684,6 +856,7 @@ class BP_Groups_Group {
684
  *
685
  * @since 1.6.0
686
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
 
687
  *
688
  * @param array $args {
689
  * Array of parameters. All items are optional.
@@ -710,12 +883,14 @@ class BP_Groups_Group {
710
  * See {@link WP_Meta_Query::queries} for description.
711
  * @type array|string $value Optional. Array or comma-separated list of group IDs. Results
712
  * will be limited to groups within the list. Default: false.
713
- * @type bool $populate_extras Whether to fetch additional information
714
- * (such as member count) about groups. Default: true.
715
  * @type array|string $exclude Optional. Array or comma-separated list of group IDs.
716
  * Results will exclude the listed groups. Default: false.
717
  * @type bool $update_meta_cache Whether to pre-fetch groupmeta for the returned groups.
718
  * Default: true.
 
 
719
  * @type bool $show_hidden Whether to include hidden groups in results. Default: false.
720
  * }
721
  * @return array {
@@ -761,8 +936,9 @@ class BP_Groups_Group {
761
  'group_type__not_in' => '',
762
  'meta_query' => false,
763
  'include' => false,
764
- 'populate_extras' => true,
765
  'update_meta_cache' => true,
 
766
  'exclude' => false,
767
  'show_hidden' => false,
768
  );
@@ -771,31 +947,27 @@ class BP_Groups_Group {
771
 
772
  $bp = buddypress();
773
 
774
- $sql = array();
775
- $total_sql = array();
776
-
777
- $sql['select'] = "SELECT DISTINCT g.id, g.*, gm1.meta_value AS total_member_count, gm2.meta_value AS last_activity";
778
- $sql['from'] = " FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2,";
779
-
780
- if ( ! empty( $r['user_id'] ) ) {
781
- $sql['members_from'] = " {$bp->groups->table_name_members} m,";
782
- }
783
-
784
- $sql['group_from'] = " {$bp->groups->table_name} g WHERE";
785
 
786
  if ( ! empty( $r['user_id'] ) ) {
787
- $sql['user_where'] = " g.id = m.group_id AND";
788
  }
789
 
790
- $sql['where'] = " g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count'";
791
 
792
  if ( empty( $r['show_hidden'] ) ) {
793
- $sql['hidden'] = " AND g.status != 'hidden'";
794
  }
795
 
796
  if ( ! empty( $r['search_terms'] ) ) {
797
  $search_terms_like = '%' . bp_esc_like( $r['search_terms'] ) . '%';
798
- $sql['search'] = $wpdb->prepare( " AND ( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like );
799
  }
800
 
801
  $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
@@ -805,7 +977,7 @@ class BP_Groups_Group {
805
  }
806
 
807
  if ( ! empty( $meta_query_sql['where'] ) ) {
808
- $sql['meta'] = $meta_query_sql['where'];
809
  }
810
 
811
  // Only use 'group_type__in', if 'group_type' is not set.
@@ -823,21 +995,27 @@ class BP_Groups_Group {
823
  }
824
 
825
  if ( ! empty( $group_type_clause ) ) {
826
- $sql['group_type'] = $group_type_clause;
827
  }
828
 
829
  if ( ! empty( $r['user_id'] ) ) {
830
- $sql['user'] = $wpdb->prepare( " AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
831
  }
832
 
833
  if ( ! empty( $r['include'] ) ) {
834
  $include = implode( ',', wp_parse_id_list( $r['include'] ) );
835
- $sql['include'] = " AND g.id IN ({$include})";
 
 
 
 
 
 
836
  }
837
 
838
  if ( ! empty( $r['exclude'] ) ) {
839
  $exclude = implode( ',', wp_parse_id_list( $r['exclude'] ) );
840
- $sql['exclude'] = " AND g.id NOT IN ({$exclude})";
841
  }
842
 
843
  /* Order/orderby ********************************************/
@@ -871,6 +1049,16 @@ class BP_Groups_Group {
871
  }
872
  }
873
 
 
 
 
 
 
 
 
 
 
 
874
  // Sanitize 'order'.
875
  $order = bp_esc_sql_order( $order );
876
 
@@ -887,15 +1075,23 @@ class BP_Groups_Group {
887
 
888
  // Random order is a special case.
889
  if ( 'rand()' === $orderby ) {
890
- $sql[] = "ORDER BY rand()";
891
  } else {
892
- $sql[] = "ORDER BY {$orderby} {$order}";
893
  }
894
 
895
  if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) && $r['per_page'] != -1 ) {
896
  $sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
897
  }
898
 
 
 
 
 
 
 
 
 
899
  /**
900
  * Filters the pagination SQL statement.
901
  *
@@ -905,61 +1101,31 @@ class BP_Groups_Group {
905
  * @param array $sql Array of SQL parts before concatenation.
906
  * @param array $r Array of parsed arguments for the get method.
907
  */
908
- $paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', join( ' ', (array) $sql ), $sql, $r );
909
- $paged_groups = $wpdb->get_results( $paged_groups_sql );
910
-
911
- $total_sql['select'] = "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name} g, {$bp->groups->table_name_groupmeta} gm";
912
-
913
- if ( ! empty( $r['user_id'] ) ) {
914
- $total_sql['select'] .= ", {$bp->groups->table_name_members} m";
915
- }
916
-
917
- if ( ! empty( $sql['hidden'] ) ) {
918
- $total_sql['where'][] = "g.status != 'hidden'";
919
- }
920
-
921
- if ( ! empty( $sql['search'] ) ) {
922
- $total_sql['where'][] = $wpdb->prepare( "( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like );
923
- }
924
-
925
- if ( ! empty( $r['user_id'] ) ) {
926
- $total_sql['where'][] = $wpdb->prepare( "m.group_id = g.id AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
927
- }
928
-
929
- // Temporary implementation of meta_query for total count
930
- // See #5099.
931
- if ( ! empty( $meta_query_sql['where'] ) ) {
932
- // Join the groupmeta table.
933
- $total_sql['select'] .= ", ". substr( $meta_query_sql['join'], 0, -2 );
934
-
935
- // Modify the meta_query clause from paged_sql for our syntax.
936
- $meta_query_clause = preg_replace( '/^\s*AND/', '', $meta_query_sql['where'] );
937
- $total_sql['where'][] = $meta_query_clause;
938
- }
939
 
940
- // Trim leading 'AND' to match `$total_sql` query style.
941
- if ( ! empty( $group_type_clause ) ) {
942
- $total_sql['where'][] = preg_replace( '/^\s*AND\s*/', '', $group_type_clause );
 
 
 
943
  }
944
 
945
- // Already escaped in the paginated results block.
946
- if ( ! empty( $include ) ) {
947
- $total_sql['where'][] = "g.id IN ({$include})";
 
 
 
 
948
  }
949
 
950
- // Already escaped in the paginated results block.
951
- if ( ! empty( $exclude ) ) {
952
- $total_sql['where'][] = "g.id NOT IN ({$exclude})";
953
  }
954
 
955
- $total_sql['where'][] = "g.id = gm.group_id";
956
- $total_sql['where'][] = "gm.meta_key = 'last_activity'";
957
-
958
- $t_sql = $total_sql['select'];
959
-
960
- if ( ! empty( $total_sql['where'] ) ) {
961
- $t_sql .= " WHERE " . join( ' AND ', (array) $total_sql['where'] );
962
- }
963
 
964
  /**
965
  * Filters the SQL used to retrieve total group results.
@@ -970,24 +1136,43 @@ class BP_Groups_Group {
970
  * @param array $total_sql Array of SQL parts for the query.
971
  * @param array $r Array of parsed arguments for the get method.
972
  */
973
- $total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', $t_sql, $total_sql, $r );
974
- $total_groups = $wpdb->get_var( $total_groups_sql );
 
 
 
 
 
 
 
975
 
976
  $group_ids = array();
977
  foreach ( (array) $paged_groups as $group ) {
978
  $group_ids[] = $group->id;
979
  }
980
 
981
- // Populate some extra information instead of querying each time in the loop.
982
- if ( !empty( $r['populate_extras'] ) ) {
983
- $paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, $r['type'] );
984
- }
985
-
986
  // Grab all groupmeta.
987
  if ( ! empty( $r['update_meta_cache'] ) ) {
988
  bp_groups_update_meta_cache( $group_ids );
989
  }
990
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
991
  unset( $sql, $total_sql );
992
 
993
  return array( 'groups' => $paged_groups, 'total' => $total_groups );
@@ -997,10 +1182,7 @@ class BP_Groups_Group {
997
  * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get()
998
  *
999
  * We use WP_Meta_Query to do the heavy lifting of parsing the
1000
- * meta_query array and creating the necessary SQL clauses. However,
1001
- * since BP_Activity_Activity::get() builds its SQL differently than
1002
- * WP_Query, we have to alter the return value (stripping the leading
1003
- * AND keyword from the 'where' clause).
1004
  *
1005
  * @since 1.8.0
1006
  *
@@ -1024,22 +1206,8 @@ class BP_Groups_Group {
1024
  $wpdb->groupmeta = buddypress()->groups->table_name_groupmeta;
1025
 
1026
  $meta_sql = $groups_meta_query->get_sql( 'group', 'g', 'id' );
1027
-
1028
- // BP_Groups_Group::get uses the comma syntax for table
1029
- // joins, which means that we have to do some regex to
1030
- // convert the INNER JOIN and move the ON clause to a
1031
- // WHERE condition
1032
- //
1033
- // @todo It may be better in the long run to refactor
1034
- // the more general query syntax to accord better with
1035
- // BP/WP convention.
1036
- preg_match_all( '/JOIN (.+?) ON/', $meta_sql['join'], $matches_a );
1037
- preg_match_all( '/ON \((.+?)\)/', $meta_sql['join'], $matches_b );
1038
-
1039
- if ( ! empty( $matches_a[1] ) && ! empty( $matches_b[1] ) ) {
1040
- $sql_array['join'] = implode( ',', $matches_a[1] ) . ', ';
1041
- $sql_array['where'] = $meta_sql['where'] . ' AND ' . implode( ' AND ', $matches_b[1] );
1042
- }
1043
  }
1044
 
1045
  return $sql_array;
@@ -1179,11 +1347,11 @@ class BP_Groups_Group {
1179
  break;
1180
 
1181
  case 'last_activity' :
1182
- $order_by_term = 'last_activity';
1183
  break;
1184
 
1185
  case 'total_member_count' :
1186
- $order_by_term = 'CONVERT(gm1.meta_value, SIGNED)';
1187
  break;
1188
 
1189
  case 'name' :
@@ -1425,9 +1593,9 @@ class BP_Groups_Group {
1425
  $user_id = bp_loggedin_user_id();
1426
 
1427
  foreach ( $paged_groups as &$group ) {
1428
- $group->is_member = groups_is_user_member( $user_id, $group->id ) ? '1' : '0';
1429
- $group->is_invited = groups_is_user_invited( $user_id, $group->id ) ? '1' : '0';
1430
- $group->is_pending = groups_is_user_pending( $user_id, $group->id ) ? '1' : '0';
1431
  $group->is_banned = (bool) groups_is_user_banned( $user_id, $group->id );
1432
  }
1433
 
@@ -1648,15 +1816,15 @@ class BP_Groups_Group {
1648
 
1649
  // The no_results clauses are the same between IN and NOT IN.
1650
  if ( false !== strpos( $sql_clauses['where'], '0 = 1' ) ) {
1651
- $clause = $sql_clauses['where'];
1652
 
1653
  // The tax_query clause generated for NOT IN can be used almost as-is.
1654
  } elseif ( 'NOT IN' === $operator ) {
1655
- $clause = $sql_clauses['where'];
1656
 
1657
  // IN clauses must be converted to a subquery.
1658
  } elseif ( preg_match( '/' . $wpdb->term_relationships . '\.term_taxonomy_id IN \([0-9, ]+\)/', $sql_clauses['where'], $matches ) ) {
1659
- $clause = " AND g.id IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )";
1660
  }
1661
 
1662
  if ( $switched ) {
@@ -1665,4 +1833,19 @@ class BP_Groups_Group {
1665
 
1666
  return $clause;
1667
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1668
  }
67
  */
68
  public $status;
69
 
70
+ /**
71
+ * Parent ID.
72
+ *
73
+ * ID of parent group, if applicable.
74
+ *
75
+ * @since 2.7.0
76
+ * @var int
77
+ */
78
+ public $parent_id;
79
+
80
  /**
81
  * Should (legacy) bbPress forums be enabled for this group?
82
  *
99
  * @since 1.6.0
100
  * @var array
101
  */
102
+ protected $admins;
103
 
104
  /**
105
  * Data about the group's moderators.
107
  * @since 1.6.0
108
  * @var array
109
  */
110
+ protected $mods;
111
 
112
  /**
113
  * Total count of group members.
115
  * @since 1.6.0
116
  * @var int
117
  */
118
+ protected $total_member_count;
119
 
120
  /**
121
  * Is the current user a member of this group?
123
  * @since 1.2.0
124
  * @var bool
125
  */
126
+ protected $is_member;
127
 
128
  /**
129
  * Does the current user have an outstanding invitation to this group?
131
  * @since 1.9.0
132
  * @var bool
133
  */
134
+ protected $is_invited;
135
 
136
  /**
137
  * Does the current user have a pending membership request to this group?
139
  * @since 1.9.0
140
  * @var bool
141
  */
142
+ protected $is_pending;
143
 
144
  /**
145
  * Timestamp of the last activity that happened in this group.
147
  * @since 1.2.0
148
  * @var string
149
  */
150
+ protected $last_activity;
151
 
152
  /**
153
  * If this is a private or hidden group, does the current user have access?
155
  * @since 1.6.0
156
  * @var bool
157
  */
158
+ protected $user_has_access;
159
 
160
  /**
161
  * Raw arguments passed to the constructor.
174
  * the object will be pre-populated with info about that group.
175
  * @param array $args {
176
  * Array of optional arguments.
177
+ * @type bool $populate_extras Deprecated.
 
 
178
  * }
179
  */
180
  public function __construct( $id = null, $args = array() ) {
 
 
 
 
181
  if ( !empty( $id ) ) {
182
+ $this->id = (int) $id;
183
  $this->populate();
184
  }
185
  }
212
  }
213
 
214
  // Group found so setup the object variables.
215
+ $this->id = (int) $group->id;
216
+ $this->creator_id = (int) $group->creator_id;
217
  $this->name = stripslashes( $group->name );
218
  $this->slug = $group->slug;
219
  $this->description = stripslashes( $group->description );
220
  $this->status = $group->status;
221
+ $this->parent_id = (int) $group->parent_id;
222
+ $this->enable_forum = (int) $group->enable_forum;
223
  $this->date_created = $group->date_created;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
225
 
226
  /**
240
  $this->slug = apply_filters( 'groups_group_slug_before_save', $this->slug, $this->id );
241
  $this->description = apply_filters( 'groups_group_description_before_save', $this->description, $this->id );
242
  $this->status = apply_filters( 'groups_group_status_before_save', $this->status, $this->id );
243
+ $this->parent_id = apply_filters( 'groups_group_parent_id_before_save', $this->parent_id, $this->id );
244
  $this->enable_forum = apply_filters( 'groups_group_enable_forum_before_save', $this->enable_forum, $this->id );
245
  $this->date_created = apply_filters( 'groups_group_date_created_before_save', $this->date_created, $this->id );
246
 
283
  slug = %s,
284
  description = %s,
285
  status = %s,
286
+ parent_id = %d,
287
  enable_forum = %d,
288
  date_created = %s
289
  WHERE
294
  $this->slug,
295
  $this->description,
296
  $this->status,
297
+ $this->parent_id,
298
  $this->enable_forum,
299
  $this->date_created,
300
  $this->id
307
  slug,
308
  description,
309
  status,
310
+ parent_id,
311
  enable_forum,
312
  date_created
313
  ) VALUES (
314
+ %d, %s, %s, %s, %s, %d, %d, %s
315
  )",
316
  $this->creator_id,
317
  $this->name,
318
  $this->slug,
319
  $this->description,
320
  $this->status,
321
+ $this->parent_id,
322
  $this->enable_forum,
323
  $this->date_created
324
  );
388
  return true;
389
  }
390
 
391
+ /**
392
+ * Magic getter.
393
+ *
394
+ * @since 2.7.0
395
+ *
396
+ * @param string $key Property name.
397
+ * @return mixed
398
+ */
399
+ public function __get( $key ) {
400
+ switch ( $key ) {
401
+ case 'last_activity' :
402
+ return groups_get_groupmeta( $this->id, 'last_activity' );
403
+
404
+ case 'total_member_count' :
405
+ return (int) groups_get_groupmeta( $this->id, 'total_member_count' );
406
+
407
+ case 'admins' :
408
+ return $this->get_admins();
409
+
410
+ case 'mods' :
411
+ return $this->get_mods();
412
+
413
+ case 'is_member' :
414
+ return $this->get_is_member();
415
+
416
+ case 'is_invited' :
417
+ return groups_check_user_has_invite( bp_loggedin_user_id(), $this->id );
418
+
419
+ case 'is_pending' :
420
+ return groups_check_for_membership_request( bp_loggedin_user_id(), $this->id );
421
+
422
+ case 'user_has_access' :
423
+ return $this->get_user_has_access();
424
+
425
+ default :
426
+ break;
427
+ }
428
+ }
429
+
430
+ /**
431
+ * Magic issetter.
432
+ *
433
+ * Used to maintain backward compatibility for properties that are now
434
+ * accessible only via magic method.
435
+ *
436
+ * @since 2.7.0
437
+ *
438
+ * @param string $key Property name.
439
+ * @return bool
440
+ */
441
+ public function __isset( $key ) {
442
+ switch ( $key ) {
443
+ case 'admins' :
444
+ case 'is_invited' :
445
+ case 'is_member' :
446
+ case 'is_pending' :
447
+ case 'last_activity' :
448
+ case 'mods' :
449
+ case 'total_member_count' :
450
+ case 'user_has_access' :
451
+ return true;
452
+
453
+ default :
454
+ return false;
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Magic setter.
460
+ *
461
+ * Used to maintain backward compatibility for properties that are now
462
+ * accessible only via magic method.
463
+ *
464
+ * @since 2.7.0
465
+ *
466
+ * @param string $key Property name.
467
+ */
468
+ public function __set( $key, $value ) {
469
+ switch ( $key ) {
470
+ case 'user_has_access' :
471
+ return $this->user_has_access = (bool) $value;
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Get a list of the group's admins.
477
+ *
478
+ * Used to provide cache-friendly access to the 'admins' property of
479
+ * the group object.
480
+ *
481
+ * @since 2.7.0
482
+ *
483
+ * @return array
484
+ */
485
+ protected function get_admins() {
486
+ if ( isset( $this->admins ) ) {
487
+ return $this->admins;
488
+ }
489
+
490
+ $this->set_up_admins_and_mods();
491
+ return $this->admins;
492
+ }
493
+
494
+ /**
495
+ * Get a list of the group's mods.
496
+ *
497
+ * Used to provide cache-friendly access to the 'mods' property of
498
+ * the group object.
499
+ *
500
+ * @since 2.7.0
501
+ *
502
+ * @return array
503
+ */
504
+ protected function get_mods() {
505
+ if ( isset( $this->mods ) ) {
506
+ return $this->mods;
507
+ }
508
+
509
+ $this->set_up_admins_and_mods();
510
+ return $this->mods;
511
+ }
512
+
513
+ /**
514
+ * Set up admins and mods for the current group object.
515
+ *
516
+ * Called only when the 'admins' or 'mods' property is accessed.
517
+ *
518
+ * @since 2.7.0
519
+ */
520
+ protected function set_up_admins_and_mods() {
521
+ $admin_ids = BP_Groups_Member::get_group_administrator_ids( $this->id );
522
+ $admin_ids_plucked = wp_list_pluck( $admin_ids, 'user_id' );
523
+
524
+ $mod_ids = BP_Groups_Member::get_group_moderator_ids( $this->id );
525
+ $mod_ids_plucked = wp_list_pluck( $mod_ids, 'user_id' );
526
+
527
+ $admin_mod_users = get_users( array(
528
+ 'include' => array_merge( $admin_ids_plucked, $mod_ids_plucked ),
529
+ ) );
530
+
531
+ $admin_objects = $mod_objects = array();
532
+ foreach ( $admin_mod_users as $admin_mod_user ) {
533
+ $obj = new stdClass();
534
+ $obj->user_id = $admin_mod_user->ID;
535
+ $obj->user_login = $admin_mod_user->user_login;
536
+ $obj->user_email = $admin_mod_user->user_email;
537
+ $obj->user_nicename = $admin_mod_user->user_nicename;
538
+
539
+ if ( in_array( $admin_mod_user->ID, $admin_ids_plucked, true ) ) {
540
+ $obj->is_admin = 1;
541
+ $obj->is_mod = 0;
542
+ $admin_objects[] = $obj;
543
+ } else {
544
+ $obj->is_admin = 0;
545
+ $obj->is_mod = 1;
546
+ $mod_objects[] = $obj;
547
+ }
548
+ }
549
+
550
+ $this->admins = $admin_objects;
551
+ $this->mods = $mod_objects;
552
+ }
553
+
554
+ /**
555
+ * Checks whether the logged-in user is a member of the group.
556
+ *
557
+ * @since 2.7.0
558
+ *
559
+ * @return bool
560
+ */
561
+ protected function get_is_member() {
562
+ if ( isset( $this->is_member ) ) {
563
+ return $this->is_member;
564
+ }
565
+
566
+ $this->is_member = groups_is_user_member( bp_loggedin_user_id(), $this->id );
567
+ return $this->is_member;
568
+ }
569
+
570
+ /**
571
+ * Checks whether the logged-in user has access to the group.
572
+ *
573
+ * @since 2.7.0
574
+ *
575
+ * @return bool
576
+ */
577
+ protected function get_user_has_access() {
578
+ if ( isset( $this->user_has_access ) ) {
579
+ return $this->user_has_access;
580
+ }
581
+
582
+ if ( ( 'private' === $this->status ) || ( 'hidden' === $this->status ) ) {
583
+
584
+ // Assume user does not have access to hidden/private groups.
585
+ $this->user_has_access = false;
586
+
587
+ // Group members or community moderators have access.
588
+ if ( ( is_user_logged_in() && $this->get_is_member() ) || bp_current_user_can( 'bp_moderate' ) ) {
589
+ $this->user_has_access = true;
590
+ }
591
+ } else {
592
+ $this->user_has_access = true;
593
+ }
594
+
595
+ return $this->user_has_access;
596
+ }
597
+
598
  /** Static Methods ****************************************************/
599
 
600
  /**
605
  * @param string $slug Slug to check.
606
  * @param string|bool $table_name Optional. Name of the table to check
607
  * against. Default: $bp->groups->table_name.
608
+ * @return int|null Group ID if found; null if not.
609
  */
610
  public static function group_exists( $slug, $table_name = false ) {
611
  global $wpdb;
616
  if ( empty( $slug ) )
617
  return false;
618
 
619
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$table_name} WHERE slug = %s", strtolower( $slug ) ) );
620
+
621
+ return is_numeric( $query ) ? (int) $query : $query;
622
  }
623
 
624
  /**
678
  if ( empty( $user_id ) )
679
  $user_id = bp_displayed_user_id();
680
 
681
+ $search_terms_like = '%' . bp_esc_like( $filter ) . '%';
682
 
683
  $pag_sql = $order_sql = $hidden_sql = '';
684
 
856
  *
857
  * @since 1.6.0
858
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
859
+ * @since 2.7.0 Added `$update_admin_cache` and `$parent_id` parameters.
860
  *
861
  * @param array $args {
862
  * Array of parameters. All items are optional.
883
  * See {@link WP_Meta_Query::queries} for description.
884
  * @type array|string $value Optional. Array or comma-separated list of group IDs. Results
885
  * will be limited to groups within the list. Default: false.
886
+ * @type array|string $parent_id Optional. Array or comma-separated list of group IDs. Results
887
+ * will be limited to children of the specified groups. Default: null.
888
  * @type array|string $exclude Optional. Array or comma-separated list of group IDs.
889
  * Results will exclude the listed groups. Default: false.
890
  * @type bool $update_meta_cache Whether to pre-fetch groupmeta for the returned groups.
891
  * Default: true.
892
+ * @type bool $update_admin_cache Whether to pre-fetch administrator IDs for the returned
893
+ * groups. Default: false.
894
  * @type bool $show_hidden Whether to include hidden groups in results. Default: false.
895
  * }
896
  * @return array {
936
  'group_type__not_in' => '',
937
  'meta_query' => false,
938
  'include' => false,
939
+ 'parent_id' => null,
940
  'update_meta_cache' => true,
941
+ 'update_admin_cache' => false,
942
  'exclude' => false,
943
  'show_hidden' => false,
944
  );
947
 
948
  $bp = buddypress();
949
 
950
+ $sql = array(
951
+ 'select' => "SELECT DISTINCT g.id",
952
+ 'from' => "{$bp->groups->table_name} g",
953
+ 'where' => '',
954
+ 'orderby' => '',
955
+ 'pagination' => '',
956
+ );
 
 
 
 
957
 
958
  if ( ! empty( $r['user_id'] ) ) {
959
+ $sql['from'] .= " JOIN {$bp->groups->table_name_members} m ON ( g.id = m.group_id )";
960
  }
961
 
962
+ $where_conditions = array();
963
 
964
  if ( empty( $r['show_hidden'] ) ) {
965
+ $where_conditions['hidden'] = "g.status != 'hidden'";
966
  }
967
 
968
  if ( ! empty( $r['search_terms'] ) ) {
969
  $search_terms_like = '%' . bp_esc_like( $r['search_terms'] ) . '%';
970
+ $where_conditions['search'] = $wpdb->prepare( "( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like );
971
  }
972
 
973
  $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
977
  }
978
 
979
  if ( ! empty( $meta_query_sql['where'] ) ) {
980
+ $where_conditions['meta'] = $meta_query_sql['where'];
981
  }
982
 
983
  // Only use 'group_type__in', if 'group_type' is not set.
995
  }
996
 
997
  if ( ! empty( $group_type_clause ) ) {
998
+ $where_conditions['group_type'] = $group_type_clause;
999
  }
1000
 
1001
  if ( ! empty( $r['user_id'] ) ) {
1002
+ $where_conditions['user'] = $wpdb->prepare( "m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
1003
  }
1004
 
1005
  if ( ! empty( $r['include'] ) ) {
1006
  $include = implode( ',', wp_parse_id_list( $r['include'] ) );
1007
+ $where_conditions['include'] = "g.id IN ({$include})";
1008
+ }
1009
+
1010
+ if ( ! is_null( $r['parent_id'] ) ) {
1011
+ // Note that `wp_parse_id_list()` converts `false` to 0.
1012
+ $parent_id = implode( ',', wp_parse_id_list( $r['parent_id'] ) );
1013
+ $where_conditions['parent_id'] = "g.parent_id IN ({$parent_id})";
1014
  }
1015
 
1016
  if ( ! empty( $r['exclude'] ) ) {
1017
  $exclude = implode( ',', wp_parse_id_list( $r['exclude'] ) );
1018
+ $where_conditions['exclude'] = "g.id NOT IN ({$exclude})";
1019
  }
1020
 
1021
  /* Order/orderby ********************************************/
1049
  }
1050
  }
1051
 
1052
+ // 'total_member_count' and 'last_activity' sorts require additional table joins.
1053
+ if ( 'total_member_count' === $orderby ) {
1054
+ $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_total_member_count ON ( g.id = gm_total_member_count.group_id )";
1055
+ $where_conditions['total_member_count'] = "gm_total_member_count.meta_key = 'total_member_count'";
1056
+ } elseif ( 'last_activity' === $orderby ) {
1057
+
1058
+ $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_last_activity on ( g.id = gm_last_activity.group_id )";
1059
+ $where_conditions['last_activity'] = "gm_last_activity.meta_key = 'last_activity'";
1060
+ }
1061
+
1062
  // Sanitize 'order'.
1063
  $order = bp_esc_sql_order( $order );
1064
 
1075
 
1076
  // Random order is a special case.
1077
  if ( 'rand()' === $orderby ) {
1078
+ $sql['orderby'] = "ORDER BY rand()";
1079
  } else {
1080
+ $sql['orderby'] = "ORDER BY {$orderby} {$order}";
1081
  }
1082
 
1083
  if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) && $r['per_page'] != -1 ) {
1084
  $sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
1085
  }
1086
 
1087
+ $where = '';
1088
+ if ( ! empty( $where_conditions ) ) {
1089
+ $sql['where'] = implode( ' AND ', $where_conditions );
1090
+ $where = "WHERE {$sql['where']}";
1091
+ }
1092
+
1093
+ $paged_groups_sql = "{$sql['select']} FROM {$sql['from']} {$where} {$sql['orderby']} {$sql['pagination']}";
1094
+
1095
  /**
1096
  * Filters the pagination SQL statement.
1097
  *
1101
  * @param array $sql Array of SQL parts before concatenation.
1102
  * @param array $r Array of parsed arguments for the get method.
1103
  */
1104
+ $paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', $paged_groups_sql, $sql, $r );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1105
 
1106
+ $cached = bp_core_get_incremented_cache( $paged_groups_sql, 'bp_groups' );
1107
+ if ( false === $cached ) {
1108
+ $paged_group_ids = $wpdb->get_col( $paged_groups_sql );
1109
+ bp_core_set_incremented_cache( $paged_groups_sql, 'bp_groups', $paged_group_ids );
1110
+ } else {
1111
+ $paged_group_ids = $cached;
1112
  }
1113
 
1114
+ $uncached_group_ids = bp_get_non_cached_ids( $paged_group_ids, 'bp_groups' );
1115
+ if ( $uncached_group_ids ) {
1116
+ $group_ids_sql = implode( ',', array_map( 'intval', $uncached_group_ids ) );
1117
+ $group_data_objects = $wpdb->get_results( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id IN ({$group_ids_sql})" );
1118
+ foreach ( $group_data_objects as $group_data_object ) {
1119
+ wp_cache_set( $group_data_object->id, $group_data_object, 'bp_groups' );
1120
+ }
1121
  }
1122
 
1123
+ $paged_groups = array();
1124
+ foreach ( $paged_group_ids as $paged_group_id ) {
1125
+ $paged_groups[] = new BP_Groups_Group( $paged_group_id );
1126
  }
1127
 
1128
+ $total_groups_sql = "SELECT COUNT(DISTINCT g.id) FROM {$sql['from']} $where";
 
 
 
 
 
 
 
1129
 
1130
  /**
1131
  * Filters the SQL used to retrieve total group results.
1136
  * @param array $total_sql Array of SQL parts for the query.
1137
  * @param array $r Array of parsed arguments for the get method.
1138
  */
1139
+ $total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', $total_groups_sql, $sql, $r );
1140
+
1141
+ $cached = bp_core_get_incremented_cache( $total_groups_sql, 'bp_groups' );
1142
+ if ( false === $cached ) {
1143
+ $total_groups = (int) $wpdb->get_var( $total_groups_sql );
1144
+ bp_core_set_incremented_cache( $total_groups_sql, 'bp_groups', $total_groups );
1145
+ } else {
1146
+ $total_groups = (int) $cached;
1147
+ }
1148
 
1149
  $group_ids = array();
1150
  foreach ( (array) $paged_groups as $group ) {
1151
  $group_ids[] = $group->id;
1152
  }
1153
 
 
 
 
 
 
1154
  // Grab all groupmeta.
1155
  if ( ! empty( $r['update_meta_cache'] ) ) {
1156
  bp_groups_update_meta_cache( $group_ids );
1157
  }
1158
 
1159
+ // Prefetch all administrator IDs, if requested.
1160
+ if ( $r['update_admin_cache'] ) {
1161
+ BP_Groups_Member::prime_group_admins_mods_cache( $group_ids );
1162
+ }
1163
+
1164
+ // Set up integer properties needing casting.
1165
+ $int_props = array(
1166
+ 'id', 'creator_id', 'enable_forum'
1167
+ );
1168
+
1169
+ // Integer casting.
1170
+ foreach ( $paged_groups as $key => $g ) {
1171
+ foreach ( $int_props as $int_prop ) {
1172
+ $paged_groups[ $key ]->{$int_prop} = (int) $paged_groups[ $key ]->{$int_prop};
1173
+ }
1174
+ }
1175
+
1176
  unset( $sql, $total_sql );
1177
 
1178
  return array( 'groups' => $paged_groups, 'total' => $total_groups );
1182
  * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get()
1183
  *
1184
  * We use WP_Meta_Query to do the heavy lifting of parsing the
1185
+ * meta_query array and creating the necessary SQL clauses.
 
 
 
1186
  *
1187
  * @since 1.8.0
1188
  *
1206
  $wpdb->groupmeta = buddypress()->groups->table_name_groupmeta;
1207
 
1208
  $meta_sql = $groups_meta_query->get_sql( 'group', 'g', 'id' );
1209
+ $sql_array['join'] = $meta_sql['join'];
1210
+ $sql_array['where'] = self::strip_leading_and( $meta_sql['where'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1211
  }
1212
 
1213
  return $sql_array;
1347
  break;
1348
 
1349
  case 'last_activity' :
1350
+ $order_by_term = 'gm_last_activity.meta_value';
1351
  break;
1352
 
1353
  case 'total_member_count' :
1354
+ $order_by_term = 'CONVERT(gm_total_member_count.meta_value, SIGNED)';
1355
  break;
1356
 
1357
  case 'name' :
1593
  $user_id = bp_loggedin_user_id();
1594
 
1595
  foreach ( $paged_groups as &$group ) {
1596
+ $group->is_member = groups_is_user_member( $user_id, $group->id ) ? 1 : 0;
1597
+ $group->is_invited = groups_is_user_invited( $user_id, $group->id ) ? 1 : 0;
1598
+ $group->is_pending = groups_is_user_pending( $user_id, $group->id ) ? 1 : 0;
1599
  $group->is_banned = (bool) groups_is_user_banned( $user_id, $group->id );
1600
  }
1601
 
1816
 
1817
  // The no_results clauses are the same between IN and NOT IN.
1818
  if ( false !== strpos( $sql_clauses['where'], '0 = 1' ) ) {
1819
+ $clause = self::strip_leading_and( $sql_clauses['where'] );
1820
 
1821
  // The tax_query clause generated for NOT IN can be used almost as-is.
1822
  } elseif ( 'NOT IN' === $operator ) {
1823
+ $clause = self::strip_leading_and( $sql_clauses['where'] );
1824
 
1825
  // IN clauses must be converted to a subquery.
1826
  } elseif ( preg_match( '/' . $wpdb->term_relationships . '\.term_taxonomy_id IN \([0-9, ]+\)/', $sql_clauses['where'], $matches ) ) {
1827
+ $clause = " g.id IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )";
1828
  }
1829
 
1830
  if ( $switched ) {
1833
 
1834
  return $clause;
1835
  }
1836
+
1837
+ /**
1838
+ * Strips the leading AND and any surrounding whitespace from a string.
1839
+ *
1840
+ * Used here to normalize SQL fragments generated by `WP_Meta_Query` and
1841
+ * other utility classes.
1842
+ *
1843
+ * @since 2.7.0
1844
+ *
1845
+ * @param string $s String.
1846
+ * @return string
1847
+ */
1848
+ protected static function strip_leading_and( $s ) {
1849
+ return preg_replace( '/^\s*AND\s*/', '', $s );
1850
+ }
1851
  }
bp-groups/classes/class-bp-groups-invite-template.php CHANGED
@@ -197,10 +197,11 @@ class BP_Groups_Invite_Template {
197
  *
198
  * @since 1.1.0
199
  * @since 2.3.0 `$this` parameter added.
 
200
  *
201
  * @param BP_Groups_Invite_Template $this Instance of the current Invites template.
202
  */
203
- do_action( 'loop_end', $this );
204
 
205
  // Do some cleaning up after the loop
206
  $this->rewind_invites();
@@ -261,10 +262,11 @@ class BP_Groups_Invite_Template {
261
  *
262
  * @since 1.1.0
263
  * @since 2.3.0 `$this` parameter added.
 
264
  *
265
  * @param BP_Groups_Invite_Template $this Instance of the current Invites template.
266
  */
267
- do_action( 'loop_start', $this );
268
  }
269
  }
270
  }
197
  *
198
  * @since 1.1.0
199
  * @since 2.3.0 `$this` parameter added.
200
+ * @since 2.7.0 Action renamed from `loop_start`.
201
  *
202
  * @param BP_Groups_Invite_Template $this Instance of the current Invites template.
203
  */
204
+ do_action( 'group_invitation_loop_end', $this );
205
 
206
  // Do some cleaning up after the loop
207
  $this->rewind_invites();
262
  *
263
  * @since 1.1.0
264
  * @since 2.3.0 `$this` parameter added.
265
+ * @since 2.7.0 Action renamed from `loop_start`.
266
  *
267
  * @param BP_Groups_Invite_Template $this Instance of the current Invites template.
268
  */
269
+ do_action( 'group_invitation_loop_start', $this );
270
  }
271
  }
272
  }
bp-groups/classes/class-bp-groups-list-table.php CHANGED
@@ -39,7 +39,7 @@ class BP_Groups_List_Table extends WP_List_Table {
39
  public $group_counts = 0;
40
 
41
  /**
42
- * Multidimensional array of group visibility types and their groups.
43
  *
44
  * @link https://buddypress.trac.wordpress.org/ticket/6277
45
  * @var array
@@ -59,6 +59,15 @@ class BP_Groups_List_Table extends WP_List_Table {
59
  'plural' => 'groups',
60
  'singular' => 'group',
61
  ) );
 
 
 
 
 
 
 
 
 
62
  }
63
 
64
  /**
@@ -122,7 +131,7 @@ class BP_Groups_List_Table extends WP_List_Table {
122
  $this->view = $_GET['group_status'];
123
  }
124
 
125
- // We'll use the ids of group types for the 'include' param.
126
  $this->group_type_ids = BP_Groups_Group::get_group_type_ids();
127
 
128
  // Pass a dummy array if there are no groups of this type.
@@ -137,9 +146,15 @@ class BP_Groups_List_Table extends WP_List_Table {
137
  $this->group_counts[ $group_type ] = count( $group_ids );
138
  }
139
 
 
 
 
 
 
 
140
  // If we're viewing a specific group, flatten all activities into a single array.
141
  if ( $include_id ) {
142
- $groups = array( (array) groups_get_group( 'group_id=' . $include_id ) );
143
  } else {
144
  $groups_args = array(
145
  'include' => $include,
@@ -149,6 +164,10 @@ class BP_Groups_List_Table extends WP_List_Table {
149
  'order' => $order
150
  );
151
 
 
 
 
 
152
  $groups = array();
153
  if ( bp_has_groups( $groups_args ) ) {
154
  while ( bp_groups() ) {
@@ -243,6 +262,25 @@ class BP_Groups_List_Table extends WP_List_Table {
243
  $this->display_tablenav( 'bottom' );
244
  }
245
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  /**
247
  * Generate content for a single row of the table.
248
  *
@@ -645,4 +683,95 @@ class BP_Groups_List_Table extends WP_List_Table {
645
  */
646
  return apply_filters( 'bp_groups_admin_get_group_custom_column', '', $column_name, $item );
647
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
  }
39
  public $group_counts = 0;
40
 
41
  /**
42
+ * Multidimensional array of group visibility (status) types and their groups.
43
  *
44
  * @link https://buddypress.trac.wordpress.org/ticket/6277
45
  * @var array
59
  'plural' => 'groups',
60
  'singular' => 'group',
61
  ) );
62
+
63
+ // Add Group Type column and bulk change controls.
64
+ if ( bp_groups_get_group_types() ) {
65
+ // Add Group Type column.
66
+ add_filter( 'bp_groups_list_table_get_columns', array( $this, 'add_type_column' ) );
67
+ add_filter( 'bp_groups_admin_get_group_custom_column', array( $this, 'column_content_group_type' ), 10, 3 );
68
+ // Add the bulk change select.
69
+ add_action( 'bp_groups_list_table_after_bulk_actions', array( $this, 'add_group_type_bulk_change_select' ) );
70
+ }
71
  }
72
 
73
  /**
131
  $this->view = $_GET['group_status'];
132
  }
133
 
134
+ // We'll use the ids of group status types for the 'include' param.
135
  $this->group_type_ids = BP_Groups_Group::get_group_type_ids();
136
 
137
  // Pass a dummy array if there are no groups of this type.
146
  $this->group_counts[ $group_type ] = count( $group_ids );
147
  }
148
 
149
+ // Group types
150
+ $group_type = false;
151
+ if ( isset( $_GET['bp-group-type'] ) && null !== bp_groups_get_group_type_object( $_GET['bp-group-type'] ) ) {
152
+ $group_type = $_GET['bp-group-type'];
153
+ }
154
+
155
  // If we're viewing a specific group, flatten all activities into a single array.
156
  if ( $include_id ) {
157
+ $groups = array( (array) groups_get_group( $include_id ) );
158
  } else {
159
  $groups_args = array(
160
  'include' => $include,
164
  'order' => $order
165
  );
166
 
167
+ if ( $group_type ) {
168
+ $groups_args['group_type'] = $group_type;
169
+ }
170
+
171
  $groups = array();
172
  if ( bp_has_groups( $groups_args ) ) {
173
  while ( bp_groups() ) {
262
  $this->display_tablenav( 'bottom' );
263
  }
264
 
265
+ /**
266
+ * Extra controls to be displayed between bulk actions and pagination
267
+ *
268
+ * @since 2.7.0
269
+ * @access protected
270
+ *
271
+ * @param string $which
272
+ */
273
+ protected function extra_tablenav( $which ) {
274
+ /**
275
+ * Fires just after the bulk action controls in the WP Admin groups list table.
276
+ *
277
+ * @since 2.7.0
278
+ *
279
+ * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
280
+ */
281
+ do_action( 'bp_groups_list_table_after_bulk_actions', $which );
282
+ }
283
+
284
  /**
285
  * Generate content for a single row of the table.
286
  *
683
  */
684
  return apply_filters( 'bp_groups_admin_get_group_custom_column', '', $column_name, $item );
685
  }
686
+
687
+ // Group Types
688
+
689
+ /**
690
+ * Add group type column to the WordPress admin groups list table.
691
+ *
692
+ * @since 2.7.0
693
+ *
694
+ * @param array $columns Groups table columns.
695
+ *
696
+ * @return array $columns
697
+ */
698
+ public function add_type_column( $columns = array() ) {
699
+ $columns['bp_group_type'] = _x( 'Group Type', 'Label for the WP groups table group type column', 'buddypress' );
700
+
701
+ return $columns;
702
+ }
703
+
704
+ /**
705
+ * Markup for the Group Type column.
706
+ *
707
+ * @since 2.7.0
708
+ *
709
+ * @param string $value Empty string.
710
+ * @param string $column_name Name of the column being rendered.
711
+ * @param array $item The current group item in the loop.
712
+ */
713
+ public function column_content_group_type( $retval, $column_name, $item ) {
714
+ if ( 'bp_group_type' !== $column_name ) {
715
+ return $retval;
716
+ }
717
+
718
+ // Get the group type.
719
+ $type = bp_groups_get_group_type( $item['id'] );
720
+
721
+ // Output the
722
+ if ( $type_obj = bp_groups_get_group_type_object( $type ) ) {
723
+ $url = add_query_arg( array( 'bp-group-type' => urlencode( $type ) ) );
724
+ $type_string = '<a href="' . esc_url( $url ) . '">' . esc_html( $type_obj->labels['singular_name'] ) . '</a>';
725
+ }
726
+
727
+ /**
728
+ * Filters the markup for the Group Type column.
729
+ *
730
+ * @since 2.7.0
731
+ *
732
+ * @param string $type_string Markup for the Group Type column.
733
+ * @parma array $item The current group item in the loop.
734
+ */
735
+ echo apply_filters_ref_array( 'bp_groups_admin_get_group_type_column', array( $type_string, $item ) );
736
+ }
737
+
738
+ /**
739
+ * Markup for the Group Type bulk change select.
740
+ *
741
+ * @since 2.7.0
742
+ *
743
+ * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
744
+ */
745
+ public function add_group_type_bulk_change_select( $which ) {
746
+ // `$which` is only passed in WordPress 4.6+. Avoid duplicating controls in earlier versions.
747
+ static $displayed = false;
748
+ if ( version_compare( bp_get_major_wp_version(), '4.6', '<' ) && $displayed ) {
749
+ return;
750
+ }
751
+ $displayed = true;
752
+ $id_name = 'bottom' === $which ? 'bp_change_type2' : 'bp_change_type';
753
+
754
+ $types = bp_groups_get_group_types( array(), 'objects' );
755
+ ?>
756
+ <div class="alignleft actions">
757
+ <label class="screen-reader-text" for="<?php echo $id_name; ?>"><?php _e( 'Change group type to&hellip;', 'buddypress' ) ?></label>
758
+ <select name="<?php echo $id_name; ?>" id="<?php echo $id_name; ?>" style="display:inline-block;float:none;">
759
+ <option value=""><?php _e( 'Change group type to&hellip;', 'buddypress' ) ?></option>
760
+
761
+ <?php foreach( $types as $type ) : ?>
762
+
763
+ <option value="<?php echo esc_attr( $type->name ); ?>"><?php echo esc_html( $type->labels['singular_name'] ); ?></option>
764
+
765
+ <?php endforeach; ?>
766
+
767
+ <option value="remove_group_type"><?php _e( 'No Group Type', 'buddypress' ) ?></option>
768
+
769
+ </select>
770
+ <?php
771
+ wp_nonce_field( 'bp-bulk-groups-change-type-' . bp_loggedin_user_id(), 'bp-bulk-groups-change-type-nonce' );
772
+ submit_button( __( 'Change', 'buddypress' ), 'button', 'bp_change_group_type', false );
773
+ ?>
774
+ </div>
775
+ <?php
776
+ }
777
  }
bp-groups/classes/class-bp-groups-member-suggestions.php CHANGED
@@ -65,10 +65,7 @@ class BP_Groups_Member_Suggestions extends BP_Members_Suggestions {
65
  }
66
 
67
  // Check that the specified group_id exists, and that the current user can access it.
68
- $the_group = groups_get_group( array(
69
- 'group_id' => absint( $this->args['group_id'] ),
70
- 'populate_extras' => true,
71
- ) );
72
 
73
  if ( $the_group->id === 0 || ! $the_group->user_has_access ) {
74
  return new WP_Error( 'access_denied' );
@@ -95,7 +92,6 @@ class BP_Groups_Member_Suggestions extends BP_Members_Suggestions {
95
  public function get_suggestions() {
96
  $user_query = array(
97
  'count_total' => '', // Prevents total count.
98
- 'populate_extras' => false,
99
  'type' => 'alphabetical',
100
 
101
  'group_role' => array( 'admin', 'member', 'mod' ),
@@ -118,7 +114,6 @@ class BP_Groups_Member_Suggestions extends BP_Members_Suggestions {
118
  } else {
119
  $group_query = array(
120
  'count_total' => '', // Prevents total count.
121
- 'populate_extras' => false,
122
  'type' => 'alphabetical',
123
 
124
  'group_id' => absint( $this->args['group_id'] ),
65
  }
66
 
67
  // Check that the specified group_id exists, and that the current user can access it.
68
+ $the_group = groups_get_group( absint( $this->args['group_id'] ) );
 
 
 
69
 
70
  if ( $the_group->id === 0 || ! $the_group->user_has_access ) {
71
  return new WP_Error( 'access_denied' );
92
  public function get_suggestions() {
93
  $user_query = array(
94
  'count_total' => '', // Prevents total count.
 
95
  'type' => 'alphabetical',
96
 
97
  'group_role' => array( 'admin', 'member', 'mod' ),
114
  } else {
115
  $group_query = array(
116
  'count_total' => '', // Prevents total count.
 
117
  'type' => 'alphabetical',
118
 
119
  'group_id' => absint( $this->args['group_id'] ),
bp-groups/classes/class-bp-groups-member.php CHANGED
@@ -185,18 +185,18 @@ class BP_Groups_Member {
185
  $member = $wpdb->get_row($sql);
186
 
187
  if ( !empty( $member ) ) {
188
- $this->id = $member->id;
189
- $this->group_id = $member->group_id;
190
- $this->user_id = $member->user_id;
191
- $this->inviter_id = $member->inviter_id;
192
- $this->is_admin = $member->is_admin;
193
- $this->is_mod = $member->is_mod;
194
- $this->is_banned = $member->is_banned;
195
  $this->user_title = $member->user_title;
196
  $this->date_modified = $member->date_modified;
197
- $this->is_confirmed = $member->is_confirmed;
198
  $this->comments = $member->comments;
199
- $this->invite_sent = $member->invite_sent;
200
 
201
  $this->user = new BP_Core_User( $this->user_id );
202
  }
@@ -678,7 +678,7 @@ class BP_Groups_Member {
678
 
679
  if ( $limit && $page ) {
680
  $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit ), intval( $limit ) );
681
- }
682
 
683
  if ( $filter ) {
684
  $search_terms_like = '%' . bp_esc_like( $filter ) . '%';
@@ -786,7 +786,7 @@ class BP_Groups_Member {
786
  * @param int $group_id ID of the group.
787
  * @param string $type If 'sent', results are limited to those invitations
788
  * that have actually been sent (non-draft). Default: 'sent'.
789
- * @return int|null The ID of the invitation if found, otherwise null.
790
  */
791
  public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) {
792
  global $wpdb;
@@ -800,7 +800,9 @@ class BP_Groups_Member {
800
  if ( 'sent' == $type )
801
  $sql .= " AND invite_sent = 1";
802
 
803
- return $wpdb->get_var( $wpdb->prepare( $sql, $user_id, $group_id ) );
 
 
804
  }
805
 
806
  /**
@@ -931,7 +933,8 @@ class BP_Groups_Member {
931
  *
932
  * @param int $user_id ID of the user.
933
  * @param int $group_id ID of the group.
934
- * @return mixed
 
935
  */
936
  public static function check_is_banned( $user_id, $group_id ) {
937
  global $wpdb;
@@ -941,7 +944,9 @@ class BP_Groups_Member {
941
 
942
  $bp = buddypress();
943
 
944
- return $wpdb->get_var( $wpdb->prepare( "SELECT is_banned FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d", $user_id, $group_id ) );
 
 
945
  }
946
 
947
  /**
@@ -951,8 +956,7 @@ class BP_Groups_Member {
951
  *
952
  * @param int $user_id ID of the user.
953
  * @param int $group_id ID of the group.
954
- * @return int|null ID of the group if the user is the creator,
955
- * otherwise false.
956
  */
957
  public static function check_is_creator( $user_id, $group_id ) {
958
  global $wpdb;
@@ -962,7 +966,9 @@ class BP_Groups_Member {
962
 
963
  $bp = buddypress();
964
 
965
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name} WHERE creator_id = %d AND id = %d", $user_id, $group_id ) );
 
 
966
  }
967
 
968
  /**
@@ -972,7 +978,7 @@ class BP_Groups_Member {
972
  *
973
  * @param int $user_id ID of the user.
974
  * @param int $group_id ID of the group.
975
- * @return int|null ID of the membership if found, otherwise false.
976
  */
977
  public static function check_for_membership_request( $user_id, $group_id ) {
978
  global $wpdb;
@@ -1001,9 +1007,9 @@ class BP_Groups_Member {
1001
 
1002
  // If the user is logged in and viewing their random groups, we can show hidden and private groups.
1003
  if ( bp_is_my_profile() ) {
1004
- return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) );
1005
  } else {
1006
- return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT m.group_id FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) );
1007
  }
1008
  }
1009
 
@@ -1020,7 +1026,7 @@ class BP_Groups_Member {
1020
 
1021
  $bp = buddypress();
1022
 
1023
- return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 1 AND is_banned = 0", $group_id ) );
1024
  }
1025
 
1026
  /**
@@ -1037,15 +1043,62 @@ class BP_Groups_Member {
1037
  $group_admins = wp_cache_get( $group_id, 'bp_group_admins' );
1038
 
1039
  if ( false === $group_admins ) {
1040
- $bp = buddypress();
1041
- $group_admins = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_admin = 1 AND is_banned = 0", $group_id ) );
 
1042
 
1043
- wp_cache_set( $group_id, $group_admins, 'bp_group_admins' );
 
 
1044
  }
1045
 
1046
  return $group_admins;
1047
  }
1048
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1049
  /**
1050
  * Get a list of all a given group's moderators.
1051
  *
@@ -1057,9 +1110,19 @@ class BP_Groups_Member {
1057
  public static function get_group_moderator_ids( $group_id ) {
1058
  global $wpdb;
1059
 
1060
- $bp = buddypress();
 
 
 
 
 
 
 
 
 
 
1061
 
1062
- return $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_mod = 1 AND is_banned = 0", $group_id ) );
1063
  }
1064
 
1065
  /**
@@ -1092,7 +1155,7 @@ class BP_Groups_Member {
1092
 
1093
  $bp = buddypress();
1094
 
1095
- return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) );
1096
  }
1097
 
1098
  /**
185
  $member = $wpdb->get_row($sql);
186
 
187
  if ( !empty( $member ) ) {
188
+ $this->id = (int) $member->id;
189
+ $this->group_id = (int) $member->group_id;
190
+ $this->user_id = (int) $member->user_id;
191
+ $this->inviter_id = (int) $member->inviter_id;
192
+ $this->is_admin = (int) $member->is_admin;
193
+ $this->is_mod = (int) $member->is_mod;
194
+ $this->is_banned = (int) $member->is_banned;
195
  $this->user_title = $member->user_title;
196
  $this->date_modified = $member->date_modified;
197
+ $this->is_confirmed = (int) $member->is_confirmed;
198
  $this->comments = $member->comments;
199
+ $this->invite_sent = (int) $member->invite_sent;
200
 
201
  $this->user = new BP_Core_User( $this->user_id );
202
  }
678
 
679
  if ( $limit && $page ) {
680
  $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit ), intval( $limit ) );
681
+ }
682
 
683
  if ( $filter ) {
684
  $search_terms_like = '%' . bp_esc_like( $filter ) . '%';
786
  * @param int $group_id ID of the group.
787
  * @param string $type If 'sent', results are limited to those invitations
788
  * that have actually been sent (non-draft). Default: 'sent'.
789
+ * @return int|null The ID of the invitation if found; null if not found.
790
  */
791
  public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) {
792
  global $wpdb;
800
  if ( 'sent' == $type )
801
  $sql .= " AND invite_sent = 1";
802
 
803
+ $query = $wpdb->get_var( $wpdb->prepare( $sql, $user_id, $group_id ) );
804
+
805
+ return is_numeric( $query ) ? (int) $query : $query;
806
  }
807
 
808
  /**
933
  *
934
  * @param int $user_id ID of the user.
935
  * @param int $group_id ID of the group.
936
+ * @return int|null int 1 if user is banned; int 0 if user is not banned;
937
+ * null if user is not part of the group or if group doesn't exist.
938
  */
939
  public static function check_is_banned( $user_id, $group_id ) {
940
  global $wpdb;
944
 
945
  $bp = buddypress();
946
 
947
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT is_banned FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d", $user_id, $group_id ) );
948
+
949
+ return is_numeric( $query ) ? (int) $query : $query;
950
  }
951
 
952
  /**
956
  *
957
  * @param int $user_id ID of the user.
958
  * @param int $group_id ID of the group.
959
+ * @return int|null int of group ID if user is the creator; null on failure.
 
960
  */
961
  public static function check_is_creator( $user_id, $group_id ) {
962
  global $wpdb;
966
 
967
  $bp = buddypress();
968
 
969
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name} WHERE creator_id = %d AND id = %d", $user_id, $group_id ) );
970
+
971
+ return is_numeric( $query ) ? (int) $query : $query;
972
  }
973
 
974
  /**
978
  *
979
  * @param int $user_id ID of the user.
980
  * @param int $group_id ID of the group.
981
+ * @return int Database ID of the membership if found; int 0 on failure.
982
  */
983
  public static function check_for_membership_request( $user_id, $group_id ) {
984
  global $wpdb;
1007
 
1008
  // If the user is logged in and viewing their random groups, we can show hidden and private groups.
1009
  if ( bp_is_my_profile() ) {
1010
+ return array_map( 'intval', $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) ) );
1011
  } else {
1012
+ return array_map( 'intval', $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT m.group_id FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) ) );
1013
  }
1014
  }
1015
 
1026
 
1027
  $bp = buddypress();
1028
 
1029
+ return array_map( 'intval', $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 1 AND is_banned = 0", $group_id ) ) );
1030
  }
1031
 
1032
  /**
1043
  $group_admins = wp_cache_get( $group_id, 'bp_group_admins' );
1044
 
1045
  if ( false === $group_admins ) {
1046
+ self::prime_group_admins_mods_cache( array( $group_id ) );
1047
+ $group_admins = wp_cache_get( $group_id, 'bp_group_admins' );
1048
+ }
1049
 
1050
+ // Integer casting.
1051
+ foreach ( (array) $group_admins as $key => $data ) {
1052
+ $group_admins[ $key ]->user_id = (int) $group_admins[ $key ]->user_id;
1053
  }
1054
 
1055
  return $group_admins;
1056
  }
1057
 
1058
+ /**
1059
+ * Prime the bp_group_admins cache for one or more groups.
1060
+ *
1061
+ * @since 2.7.0
1062
+ *
1063
+ * @param array $group_ids IDs of the groups.
1064
+ * @return bool True on success.
1065
+ */
1066
+ public static function prime_group_admins_mods_cache( $group_ids ) {
1067
+ global $wpdb;
1068
+
1069
+ $uncached = bp_get_non_cached_ids( $group_ids, 'bp_group_admins' );
1070
+
1071
+ if ( $uncached ) {
1072
+ $bp = buddypress();
1073
+ $uncached_sql = implode( ',', array_map( 'intval', $uncached ) );
1074
+ $group_admin_mods = $wpdb->get_results( "SELECT user_id, group_id, date_modified, is_admin, is_mod FROM {$bp->groups->table_name_members} WHERE group_id IN ({$uncached_sql}) AND ( is_admin = 1 OR is_mod = 1 ) AND is_banned = 0" );
1075
+
1076
+ $admins = $mods = array();
1077
+ if ( $group_admin_mods ) {
1078
+ foreach ( $group_admin_mods as $group_admin_mod ) {
1079
+ $obj = new stdClass();
1080
+ $obj->user_id = $group_admin_mod->user_id;
1081
+ $obj->date_modified = $group_admin_mod->date_modified;
1082
+
1083
+ if ( $group_admin_mod->is_admin ) {
1084
+ $admins[ $group_admin_mod->group_id ][] = $obj;
1085
+ } else {
1086
+ $mods[ $group_admin_mod->group_id ][] = $obj;
1087
+ }
1088
+ }
1089
+ }
1090
+
1091
+ // Prime cache for all groups, even those with no matches.
1092
+ foreach ( $uncached as $group_id ) {
1093
+ $group_admins = isset( $admins[ $group_id ] ) ? $admins[ $group_id ] : array();
1094
+ wp_cache_set( $group_id, $group_admins, 'bp_group_admins' );
1095
+
1096
+ $group_mods = isset( $mods[ $group_id ] ) ? $mods[ $group_id ] : array();
1097
+ wp_cache_set( $group_id, $group_mods, 'bp_group_mods' );
1098
+ }
1099
+ }
1100
+ }
1101
+
1102
  /**
1103
  * Get a list of all a given group's moderators.
1104
  *
1110
  public static function get_group_moderator_ids( $group_id ) {
1111
  global $wpdb;
1112
 
1113
+ $group_mods = wp_cache_get( $group_id, 'bp_group_mods' );
1114
+
1115
+ if ( false === $group_mods ) {
1116
+ self::prime_group_admins_mods_cache( array( $group_id ) );
1117
+ $group_mods = wp_cache_get( $group_id, 'bp_group_mods' );
1118
+ }
1119
+
1120
+ // Integer casting.
1121
+ foreach ( (array) $group_mods as $key => $data ) {
1122
+ $group_mods[ $key ]->user_id = (int) $group_mods[ $key ]->user_id;
1123
+ }
1124
 
1125
+ return $group_mods;
1126
  }
1127
 
1128
  /**
1155
 
1156
  $bp = buddypress();
1157
 
1158
+ return array_map( 'intval', $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) ) );
1159
  }
1160
 
1161
  /**
bp-groups/classes/class-bp-groups-template.php CHANGED
@@ -165,13 +165,14 @@ class BP_Groups_Template {
165
  'slug' => false,
166
  'include' => false,
167
  'exclude' => false,
 
168
  'search_terms' => '',
169
  'group_type' => '',
170
  'group_type__in' => '',
171
  'group_type__not_in' => '',
172
  'meta_query' => false,
173
- 'populate_extras' => true,
174
  'update_meta_cache' => true,
 
175
  );
176
 
177
  $r = wp_parse_args( $args, $defaults );
@@ -194,10 +195,7 @@ class BP_Groups_Template {
194
  $group = groups_get_current_group();
195
 
196
  } else {
197
- $group = groups_get_group( array(
198
- 'group_id' => BP_Groups_Group::get_id_from_slug( $r['slug'] ),
199
- 'populate_extras' => $r['populate_extras'],
200
- ) );
201
  }
202
 
203
  // Backwards compatibility - the 'group_id' variable is not part of the
@@ -226,8 +224,9 @@ class BP_Groups_Template {
226
  'group_type__not_in' => $group_type__not_in,
227
  'include' => $include,
228
  'exclude' => $exclude,
229
- 'populate_extras' => $populate_extras,
230
  'update_meta_cache' => $update_meta_cache,
 
231
  'show_hidden' => $show_hidden,
232
  ) );
233
  }
165
  'slug' => false,
166
  'include' => false,
167
  'exclude' => false,
168
+ 'parent_id' => null,
169
  'search_terms' => '',
170
  'group_type' => '',
171
  'group_type__in' => '',
172
  'group_type__not_in' => '',
173
  'meta_query' => false,
 
174
  'update_meta_cache' => true,
175
+ 'update_admin_cache' => false,
176
  );
177
 
178
  $r = wp_parse_args( $args, $defaults );
195
  $group = groups_get_current_group();
196
 
197
  } else {
198
+ $group = groups_get_group( BP_Groups_Group::get_id_from_slug( $r['slug'] ) );
 
 
 
199
  }
200
 
201
  // Backwards compatibility - the 'group_id' variable is not part of the
224
  'group_type__not_in' => $group_type__not_in,
225
  'include' => $include,
226
  'exclude' => $exclude,
227
+ 'parent_id' => $parent_id,
228
  'update_meta_cache' => $update_meta_cache,
229
+ 'update_admin_cache' => $update_admin_cache,
230
  'show_hidden' => $show_hidden,
231
  ) );
232
  }
bp-groups/classes/class-bp-groups-theme-compat.php CHANGED
@@ -40,7 +40,7 @@ class BP_Groups_Theme_Compat {
40
  return;
41
 
42
  // Group Directory.
43
- if ( ! bp_current_action() && ! bp_current_item() ) {
44
  bp_update_is_directory( true, 'groups' );
45
 
46
  /**
@@ -83,6 +83,12 @@ class BP_Groups_Theme_Compat {
83
  * @return array $templates Array of custom templates to look for.
84
  */
85
  public function directory_template_hierarchy( $templates ) {
 
 
 
 
 
 
86
 
87
  /**
88
  * Filters the Groups directory page template hierarchy based on priority.
@@ -91,9 +97,7 @@ class BP_Groups_Theme_Compat {
91
  *
92
  * @param array $value Array of default template files to use.
93
  */
94
- $new_templates = apply_filters( 'bp_template_hierarchy_groups_directory', array(
95
- 'groups/index-directory.php'
96
- ) );
97
 
98
  // Merge new templates with existing stack.
99
  // @see bp_get_theme_compat_templates().
40
  return;
41
 
42
  // Group Directory.
43
+ if ( bp_is_groups_directory() ) {
44
  bp_update_is_directory( true, 'groups' );
45
 
46
  /**
83
  * @return array $templates Array of custom templates to look for.
84
  */
85
  public function directory_template_hierarchy( $templates ) {
86
+ // Set up the template hierarchy.
87
+ $new_templates = array();
88
+ if ( '' !== bp_get_current_group_directory_type() ) {
89
+ $new_templates[] = 'groups/index-directory-type-' . sanitize_file_name( bp_get_current_group_directory_type() ) . '.php';
90
+ }
91
+ $new_templates[] = 'groups/index-directory.php';
92
 
93
  /**
94
  * Filters the Groups directory page template hierarchy based on priority.
97
  *
98
  * @param array $value Array of default template files to use.
99
  */
100
+ $new_templates = apply_filters( 'bp_template_hierarchy_groups_directory', $new_templates );
 
 
101
 
102
  // Merge new templates with existing stack.
103
  // @see bp_get_theme_compat_templates().
bp-groups/classes/class-bp-groups-widget.php CHANGED
@@ -125,7 +125,7 @@ class BP_Groups_Widget extends WP_Widget {
125
  <a href="<?php bp_groups_directory_permalink(); ?>" id="popular-groups" <?php if ( $instance['group_default'] == 'popular' ) : ?> class="selected"<?php endif; ?>><?php _e("Popular", 'buddypress') ?></a>
126
  </div>
127
 
128
- <ul id="groups-list" class="item-list">
129
  <?php while ( bp_groups() ) : bp_the_group(); ?>
130
  <li <?php bp_group_class(); ?>>
131
  <div class="item-avatar">
125
  <a href="<?php bp_groups_directory_permalink(); ?>" id="popular-groups" <?php if ( $instance['group_default'] == 'popular' ) : ?> class="selected"<?php endif; ?>><?php _e("Popular", 'buddypress') ?></a>
126
  </div>
127
 
128
+ <ul id="groups-list" class="item-list" aria-live="polite" aria-relevant="all" aria-atomic="true">
129
  <?php while ( bp_groups() ) : bp_the_group(); ?>
130
  <li <?php bp_group_class(); ?>>
131
  <div class="item-avatar">
bp-loader.php CHANGED
@@ -12,10 +12,10 @@
12
  /**
13
  * Plugin Name: BuddyPress
14
  * Plugin URI: https://buddypress.org/
15
- * Description: BuddyPress helps you build any type of community website using WordPress, with member profiles, activity streams, user groups, messaging, and more.
16
  * Author: The BuddyPress Community
17
  * Author URI: https://buddypress.org/
18
- * Version: 2.6.2
19
  * Text Domain: buddypress
20
  * Domain Path: /bp-languages/
21
  * License: GPLv2 or later (license.txt)
@@ -308,7 +308,7 @@ class BuddyPress {
308
 
309
  // Whether to refrain from loading deprecated functions
310
  if ( ! defined( 'BP_IGNORE_DEPRECATED' ) ) {
311
- define( 'BP_IGNORE_DEPRECATED', false );
312
  }
313
 
314
  // The search slug has to be defined nice and early because of the way
@@ -330,15 +330,16 @@ class BuddyPress {
330
 
331
  /** Versions **********************************************************/
332
 
333
- $this->version = '2.6.2';
334
- $this->db_version = 10469;
335
 
336
  /** Loading ***********************************************************/
337
 
338
  /**
339
- * Filters the load_deprecated property value.
340
  *
341
  * @since 2.0.0
 
342
  *
343
  * @const constant BP_IGNORE_DEPRECATED Whether or not to ignore deprecated functionality.
344
  */
@@ -509,7 +510,7 @@ class BuddyPress {
509
  }
510
 
511
  // Skip or load deprecated content
512
- if ( false !== $this->load_deprecated ) {
513
  require( $this->plugin_dir . 'bp-core/deprecated/1.2.php' );
514
  require( $this->plugin_dir . 'bp-core/deprecated/1.5.php' );
515
  require( $this->plugin_dir . 'bp-core/deprecated/1.6.php' );
@@ -522,6 +523,7 @@ class BuddyPress {
522
  require( $this->plugin_dir . 'bp-core/deprecated/2.4.php' );
523
  require( $this->plugin_dir . 'bp-core/deprecated/2.5.php' );
524
  require( $this->plugin_dir . 'bp-core/deprecated/2.6.php' );
 
525
  }
526
  }
527
 
12
  /**
13
  * Plugin Name: BuddyPress
14
  * Plugin URI: https://buddypress.org/
15
+ * Description: BuddyPress helps site builders and WordPress developers add community features to their websites, with user profile fields, activity streams, messaging, and notifications.
16
  * Author: The BuddyPress Community
17
  * Author URI: https://buddypress.org/
18
+ * Version: 2.7-beta1
19
  * Text Domain: buddypress
20
  * Domain Path: /bp-languages/
21
  * License: GPLv2 or later (license.txt)
308
 
309
  // Whether to refrain from loading deprecated functions
310
  if ( ! defined( 'BP_IGNORE_DEPRECATED' ) ) {
311
+ define( 'BP_IGNORE_DEPRECATED', true );
312
  }
313
 
314
  // The search slug has to be defined nice and early because of the way
330
 
331
  /** Versions **********************************************************/
332
 
333
+ $this->version = '2.7-beta1';
334
+ $this->db_version = 11105;
335
 
336
  /** Loading ***********************************************************/
337
 
338
  /**
339
+ * Whether to load deprecated code or not.
340
  *
341
  * @since 2.0.0
342
+ * @since 2.7.0 Defaults to false (do not load deprecated code) for new installs.
343
  *
344
  * @const constant BP_IGNORE_DEPRECATED Whether or not to ignore deprecated functionality.
345
  */
510
  }
511
 
512
  // Skip or load deprecated content
513
+ if ( $this->load_deprecated || ! bp_get_option( '_bp_ignore_deprecated_code' ) ) {
514
  require( $this->plugin_dir . 'bp-core/deprecated/1.2.php' );
515
  require( $this->plugin_dir . 'bp-core/deprecated/1.5.php' );
516
  require( $this->plugin_dir . 'bp-core/deprecated/1.6.php' );
523
  require( $this->plugin_dir . 'bp-core/deprecated/2.4.php' );
524
  require( $this->plugin_dir . 'bp-core/deprecated/2.5.php' );
525
  require( $this->plugin_dir . 'bp-core/deprecated/2.6.php' );
526
+ require( $this->plugin_dir . 'bp-core/deprecated/2.7.php' );
527
  }
528
  }
529
 
bp-members/bp-members-cache.php CHANGED
@@ -20,7 +20,7 @@ defined( 'ABSPATH' ) || exit;
20
  function bp_members_prefetch_member_type( BP_User_Query $bp_user_query ) {
21
  $uncached_member_ids = bp_get_non_cached_ids( $bp_user_query->user_ids, 'bp_member_member_type' );
22
 
23
- $member_types = bp_get_object_terms( $uncached_member_ids, 'bp_member_type', array(
24
  'fields' => 'all_with_object_id',
25
  ) );
26
 
@@ -61,3 +61,15 @@ function bp_members_clear_member_type_cache( $user_id ) {
61
  }
62
  add_action( 'wpmu_delete_user', 'bp_members_clear_member_type_cache' );
63
  add_action( 'delete_user', 'bp_members_clear_member_type_cache' );
 
 
 
 
 
 
 
 
 
 
 
 
20
  function bp_members_prefetch_member_type( BP_User_Query $bp_user_query ) {
21
  $uncached_member_ids = bp_get_non_cached_ids( $bp_user_query->user_ids, 'bp_member_member_type' );
22
 
23
+ $member_types = bp_get_object_terms( $uncached_member_ids, bp_get_member_type_tax_name(), array(
24
  'fields' => 'all_with_object_id',
25
  ) );
26
 
61
  }
62
  add_action( 'wpmu_delete_user', 'bp_members_clear_member_type_cache' );
63
  add_action( 'delete_user', 'bp_members_clear_member_type_cache' );
64
+
65
+ /**
66
+ * Invalidate activity caches when a user's last_activity value is changed.
67
+ *
68
+ * @since 2.7.0
69
+ *
70
+ * @return bool True on success, false on failure.
71
+ */
72
+ function bp_members_reset_activity_cache_incrementor() {
73
+ return bp_core_reset_incrementor( 'bp_activity_with_last_activity' );
74
+ }
75
+ add_action( 'bp_core_user_updated_last_activity', 'bp_members_reset_activity_cache_incrementor' );
bp-members/bp-members-functions.php CHANGED
@@ -2505,6 +2505,33 @@ function bp_get_displayed_user() {
2505
 
2506
  /** Member Types *************************************************************/
2507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2508
  /**
2509
  * Register a member type.
2510
  *
@@ -2676,7 +2703,7 @@ function bp_set_member_type( $user_id, $member_type, $append = false ) {
2676
  return false;
2677
  }
2678
 
2679
- $retval = bp_set_object_terms( $user_id, $member_type, 'bp_member_type', $append );
2680
 
2681
  // Bust the cache if the type has been updated.
2682
  if ( ! is_wp_error( $retval ) ) {
@@ -2712,7 +2739,7 @@ function bp_remove_member_type( $user_id, $member_type ) {
2712
  return false;
2713
  }
2714
 
2715
- $deleted = bp_remove_object_terms( $user_id, $member_type, 'bp_member_type' );
2716
 
2717
  // Bust the cache if the type has been removed.
2718
  if ( ! is_wp_error( $deleted ) ) {
@@ -2747,10 +2774,18 @@ function bp_get_member_type( $user_id, $single = true ) {
2747
  $types = wp_cache_get( $user_id, 'bp_member_member_type' );
2748
 
2749
  if ( false === $types ) {
2750
- $types = bp_get_object_terms( $user_id, 'bp_member_type' );
 
 
 
 
 
 
 
 
 
 
2751
 
2752
- if ( ! is_wp_error( $types ) ) {
2753
- $types = wp_list_pluck( $types, 'name' );
2754
  wp_cache_set( $user_id, $types, 'bp_member_member_type' );
2755
  }
2756
  }
2505
 
2506
  /** Member Types *************************************************************/
2507
 
2508
+ /**
2509
+ * Output the slug of the member type taxonomy.
2510
+ *
2511
+ * @since 2.7.0
2512
+ */
2513
+ function bp_member_type_tax_name() {
2514
+ echo bp_get_member_type_tax_name();
2515
+ }
2516
+
2517
+ /**
2518
+ * Return the slug of the member type taxonomy.
2519
+ *
2520
+ * @since 2.7.0
2521
+ *
2522
+ * @return string The unique member taxonomy slug.
2523
+ */
2524
+ function bp_get_member_type_tax_name() {
2525
+ /**
2526
+ * Filters the slug of the member type taxonomy.
2527
+ *
2528
+ * @since 2.7.0
2529
+ *
2530
+ * @param string $value Member type taxonomy slug.
2531
+ */
2532
+ return apply_filters( 'bp_get_member_type_tax_name', 'bp_member_type' );
2533
+ }
2534
+
2535
  /**
2536
  * Register a member type.
2537
  *
2703
  return false;
2704
  }
2705
 
2706
+ $retval = bp_set_object_terms( $user_id, $member_type, bp_get_member_type_tax_name(), $append );
2707
 
2708
  // Bust the cache if the type has been updated.
2709
  if ( ! is_wp_error( $retval ) ) {
2739
  return false;
2740
  }
2741
 
2742
+ $deleted = bp_remove_object_terms( $user_id, $member_type, bp_get_member_type_tax_name() );
2743
 
2744
  // Bust the cache if the type has been removed.
2745
  if ( ! is_wp_error( $deleted ) ) {
2774
  $types = wp_cache_get( $user_id, 'bp_member_member_type' );
2775
 
2776
  if ( false === $types ) {
2777
+ $raw_types = bp_get_object_terms( $user_id, bp_get_member_type_tax_name() );
2778
+
2779
+ if ( ! is_wp_error( $raw_types ) ) {
2780
+ $types = array();
2781
+
2782
+ // Only include currently registered group types.
2783
+ foreach ( $raw_types as $mtype ) {
2784
+ if ( bp_get_member_type_object( $mtype->name ) ) {
2785
+ $types[] = $mtype->name;
2786
+ }
2787
+ }
2788
 
 
 
2789
  wp_cache_set( $user_id, $types, 'bp_member_member_type' );
2790
  }
2791
  }
bp-members/bp-members-screens.php CHANGED
@@ -110,7 +110,7 @@ function bp_core_screen_signup() {
110
  // If the signup page is submitted, validate and save.
111
  } elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) {
112
 
113
- /**
114
  * Fires before the validation of a new signup.
115
  *
116
  * @since 2.0.0
@@ -181,7 +181,7 @@ function bp_core_screen_signup() {
181
  }
182
  }
183
 
184
- /**
185
  * Fires after the validation of a new signup.
186
  *
187
  * @since 1.1.0
110
  // If the signup page is submitted, validate and save.
111
  } elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) {
112
 
113
+ /**
114
  * Fires before the validation of a new signup.
115
  *
116
  * @since 2.0.0
181
  }
182
  }
183
 
184
+ /**
185
  * Fires after the validation of a new signup.
186
  *
187
  * @since 1.1.0
bp-members/bp-members-template.php CHANGED
@@ -610,7 +610,7 @@ function bp_member_class( $classes = array() ) {
610
  if ( ! empty( $members_template->member->last_activity ) ) {
611
 
612
  // Calculate some times.
613
- $current_time = strtotime( bp_core_current_time() );
614
  $last_activity = strtotime( $members_template->member->last_activity );
615
  $still_online = strtotime( '+5 minutes', $last_activity );
616
 
@@ -829,7 +829,7 @@ function bp_member_avatar( $args = '' ) {
829
  * @since 1.2.0
830
  */
831
  function bp_member_permalink() {
832
- echo bp_get_member_permalink();
833
  }
834
  /**
835
  * Get the permalink for the current member in the loop.
@@ -856,7 +856,7 @@ function bp_member_permalink() {
856
  *
857
  * @since 1.2.0
858
  */
859
- function bp_member_link() { echo bp_get_member_permalink(); }
860
 
861
  /**
862
  * Alias of {@link bp_get_member_permalink()}.
@@ -933,7 +933,7 @@ function bp_member_name() {
933
  *
934
  * @since 1.2.0
935
  *
936
- * @param array $args See {@link bp_get_member_last_active()}.
937
  */
938
  function bp_member_last_active( $args = array() ) {
939
  echo bp_get_member_last_active( $args );
@@ -942,13 +942,14 @@ function bp_member_last_active( $args = array() ) {
942
  * Return the current member's last active time.
943
  *
944
  * @since 1.2.0
 
945
  *
946
  * @param array $args {
947
  * Array of optional arguments.
948
- * @type mixed $active_format If true, formatted "active 5 minutes
949
- * ago". If false, formatted "5 minutes ago".
950
- * If string, should be sprintf'able like
951
- * 'last seen %s ago'.
952
  * }
953
  * @return string
954
  */
@@ -957,7 +958,8 @@ function bp_member_last_active( $args = array() ) {
957
 
958
  // Parse the activity format.
959
  $r = bp_parse_args( $args, array(
960
- 'active_format' => true
 
961
  ) );
962
 
963
  // Backwards compatibility for anyone forcing a 'true' active_format.
@@ -967,13 +969,18 @@ function bp_member_last_active( $args = array() ) {
967
 
968
  // Member has logged in at least one time.
969
  if ( isset( $members_template->member->last_activity ) ) {
 
 
 
 
 
970
 
971
  // Backwards compatibility for pre 1.5 'ago' strings.
972
  $last_activity = ! empty( $r['active_format'] )
973
  ? bp_core_get_last_activity( $members_template->member->last_activity, $r['active_format'] )
974
  : bp_core_time_since( $members_template->member->last_activity );
975
 
976
- // Member has never logged in or been active.
977
  } else {
978
  $last_activity = __( 'Never active', 'buddypress' );
979
  }
@@ -1144,27 +1151,62 @@ function bp_member_profile_data( $args = '' ) {
1144
  * @param string|bool $data Profile data if found, otherwise false.
1145
  * @param array $r Array of parsed arguments.
1146
  */
1147
- return apply_filters( 'bp_get_member_profile_data', $data, $r );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1148
  }
1149
 
1150
  /**
1151
  * Output the 'registered [x days ago]' string for the current member.
1152
  *
1153
  * @since 1.2.0
 
 
 
1154
  */
1155
- function bp_member_registered() {
1156
- echo bp_get_member_registered();
1157
  }
1158
  /**
1159
  * Get the 'registered [x days ago]' string for the current member.
1160
  *
1161
  * @since 1.2.0
 
 
 
 
 
 
 
 
1162
  *
1163
  * @return string
1164
  */
1165
- function bp_get_member_registered() {
1166
  global $members_template;
1167
 
 
 
 
 
 
 
 
 
 
 
1168
  $registered = esc_attr( bp_core_get_last_activity( $members_template->member->user_registered, _x( 'registered %s', 'Records the timestamp that the user registered into the activity stream', 'buddypress' ) ) );
1169
 
1170
  /**
@@ -1715,7 +1757,7 @@ function bp_user_firstname() {
1715
  * @since 1.2.4
1716
  */
1717
  function bp_loggedin_user_link() {
1718
- echo bp_get_loggedin_user_link();
1719
  }
1720
  /**
1721
  * Get the link for the logged-in user's profile.
@@ -1742,7 +1784,7 @@ function bp_loggedin_user_link() {
1742
  * @since 1.2.4
1743
  */
1744
  function bp_displayed_user_link() {
1745
- echo bp_get_displayed_user_link();
1746
  }
1747
  /**
1748
  * Get the link for the displayed user's profile.
@@ -1948,6 +1990,7 @@ function bp_loggedin_user_username() {
1948
  */
1949
  return apply_filters( 'bp_get_loggedin_user_username', $username );
1950
  }
 
1951
  /**
1952
  * Echo the current member type message.
1953
  *
@@ -2464,23 +2507,6 @@ function bp_signup_allowed() {
2464
  * @return bool
2465
  */
2466
  function bp_get_signup_allowed() {
2467
- $bp = buddypress();
2468
-
2469
- $signup_allowed = false;
2470
-
2471
- if ( is_multisite() ) {
2472
- $registration = bp_core_get_root_option( 'registration' );
2473
-
2474
- if ( in_array( $registration, array( 'all', 'user' ) ) ) {
2475
- $signup_allowed = true;
2476
- }
2477
-
2478
- } else {
2479
- if ( bp_get_option( 'users_can_register') ) {
2480
- $signup_allowed = true;
2481
- }
2482
- }
2483
-
2484
  /**
2485
  * Filters whether or not new signups are allowed.
2486
  *
@@ -2488,7 +2514,7 @@ function bp_signup_allowed() {
2488
  *
2489
  * @param bool $signup_allowed Whether or not new signups are allowed.
2490
  */
2491
- return apply_filters( 'bp_get_signup_allowed', $signup_allowed );
2492
  }
2493
 
2494
  /**
610
  if ( ! empty( $members_template->member->last_activity ) ) {
611
 
612
  // Calculate some times.
613
+ $current_time = bp_core_current_time( true, 'timestamp' );
614
  $last_activity = strtotime( $members_template->member->last_activity );
615
  $still_online = strtotime( '+5 minutes', $last_activity );
616
 
829
  * @since 1.2.0
830
  */
831
  function bp_member_permalink() {
832
+ echo esc_url( bp_get_member_permalink() );
833
  }
834
  /**
835
  * Get the permalink for the current member in the loop.
856
  *
857
  * @since 1.2.0
858
  */
859
+ function bp_member_link() { echo esc_url( bp_get_member_permalink() ); }
860
 
861
  /**
862
  * Alias of {@link bp_get_member_permalink()}.
933
  *
934
  * @since 1.2.0
935
  *
936
+ * @param array $args {@see bp_get_member_last_active()}.
937
  */
938
  function bp_member_last_active( $args = array() ) {
939
  echo bp_get_member_last_active( $args );
942
  * Return the current member's last active time.
943
  *
944
  * @since 1.2.0
945
+ * @since 2.7.0 Added 'relative' as a parameter to $args.
946
  *
947
  * @param array $args {
948
  * Array of optional arguments.
949
+ * @type mixed $active_format If true, formatted "active 5 minutes ago". If false, formatted "5 minutes
950
+ * ago". If string, should be sprintf'able like 'last seen %s ago'.
951
+ * @type bool $relative If true, will return relative time "5 minutes ago". If false, will return
952
+ * date from database. Default: true.
953
  * }
954
  * @return string
955
  */
958
 
959
  // Parse the activity format.
960
  $r = bp_parse_args( $args, array(
961
+ 'active_format' => true,
962
+ 'relative' => true,
963
  ) );
964
 
965
  // Backwards compatibility for anyone forcing a 'true' active_format.
969
 
970
  // Member has logged in at least one time.
971
  if ( isset( $members_template->member->last_activity ) ) {
972
+ // We do not want relative time, so return now.
973
+ // @todo Should the 'bp_member_last_active' filter be applied here?
974
+ if ( ! $r['relative'] ) {
975
+ return esc_attr( $members_template->member->last_activity );
976
+ }
977
 
978
  // Backwards compatibility for pre 1.5 'ago' strings.
979
  $last_activity = ! empty( $r['active_format'] )
980
  ? bp_core_get_last_activity( $members_template->member->last_activity, $r['active_format'] )
981
  : bp_core_time_since( $members_template->member->last_activity );
982
 
983
+ // Member has never logged in or been active.
984
  } else {
985
  $last_activity = __( 'Never active', 'buddypress' );
986
  }
1151
  * @param string|bool $data Profile data if found, otherwise false.
1152
  * @param array $r Array of parsed arguments.
1153
  */
1154
+ $data = apply_filters( 'bp_get_member_profile_data', $data, $r );
1155
+
1156
+ /**
1157
+ * Filters the resulting piece of member profile data by field type.
1158
+ *
1159
+ * This is a dynamic filter based on field type of the current field requested.
1160
+ *
1161
+ * @since 2.7.0
1162
+ *
1163
+ * @param string|bool $data Profile data if found, otherwise false.
1164
+ * @param array $r Array of parsed arguments.
1165
+ */
1166
+ $data = apply_filters( 'bp_get_member_profile_data_' . $profile_data[ $r['field'] ]['field_type'], $data, $r );
1167
+
1168
+ return $data;
1169
  }
1170
 
1171
  /**
1172
  * Output the 'registered [x days ago]' string for the current member.
1173
  *
1174
  * @since 1.2.0
1175
+ * @since 2.7.0 Added $args as a parameter.
1176
+ *
1177
+ * @param array $args Optional. {@see bp_get_member_registered()}
1178
  */
1179
+ function bp_member_registered( $args = array() ) {
1180
+ echo bp_get_member_registered( $args );
1181
  }
1182
  /**
1183
  * Get the 'registered [x days ago]' string for the current member.
1184
  *
1185
  * @since 1.2.0
1186
+ * @since 2.7.0 Added $args as a parameter.
1187
+ *
1188
+ * @param array $args {
1189
+ * Array of optional parameters.
1190
+ *
1191
+ * @type bool $relative Optional. If true, returns relative registered date. eg. registered 5 months ago.
1192
+ * If false, returns registered date value from database.
1193
+ * }
1194
  *
1195
  * @return string
1196
  */
1197
+ function bp_get_member_registered( $args = array() ) {
1198
  global $members_template;
1199
 
1200
+ $r = wp_parse_args( $args, array(
1201
+ 'relative' => true,
1202
+ ) );
1203
+
1204
+ // We do not want relative time, so return now.
1205
+ // @todo Should the 'bp_member_registered' filter be applied here?
1206
+ if ( ! $r['relative'] ) {
1207
+ return esc_attr( $members_template->member->user_registered );
1208
+ }
1209
+
1210
  $registered = esc_attr( bp_core_get_last_activity( $members_template->member->user_registered, _x( 'registered %s', 'Records the timestamp that the user registered into the activity stream', 'buddypress' ) ) );
1211
 
1212
  /**
1757
  * @since 1.2.4
1758
  */
1759
  function bp_loggedin_user_link() {
1760
+ echo esc_url( bp_get_loggedin_user_link() );
1761
  }
1762
  /**
1763
  * Get the link for the logged-in user's profile.
1784
  * @since 1.2.4
1785
  */
1786
  function bp_displayed_user_link() {
1787
+ echo esc_url( bp_get_displayed_user_link() );
1788
  }
1789
  /**
1790
  * Get the link for the displayed user's profile.
1990
  */
1991
  return apply_filters( 'bp_get_loggedin_user_username', $username );
1992
  }
1993
+
1994
  /**
1995
  * Echo the current member type message.
1996
  *
2507
  * @return bool
2508
  */
2509
  function bp_get_signup_allowed() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2510
  /**
2511
  * Filters whether or not new signups are allowed.
2512
  *
2514
  *
2515
  * @param bool $signup_allowed Whether or not new signups are allowed.
2516
  */
2517
+ return apply_filters( 'bp_get_signup_allowed', (bool) bp_get_option( 'users_can_register' ) );
2518
  }
2519
 
2520
  /**
bp-members/classes/class-bp-core-members-widget.php CHANGED
@@ -88,10 +88,7 @@ class BP_Core_Members_Widget extends WP_Widget {
88
  $separator = apply_filters( 'bp_members_widget_separator', '|' );
89
 
90
  // Output before widget HTMl, title (and maybe content before & after it).
91
- echo $args['before_widget']
92
- . $args['before_title']
93
- . $title
94
- . $args['after_title'];
95
 
96
  // Setup args for querying members.
97
  $members_args = array(
@@ -123,7 +120,7 @@ class BP_Core_Members_Widget extends WP_Widget {
123
 
124
  </div>
125
 
126
- <ul id="members-list" class="item-list">
127
 
128
  <?php while ( bp_members() ) : bp_the_member(); ?>
129
 
@@ -135,14 +132,13 @@ class BP_Core_Members_Widget extends WP_Widget {
135
  <div class="item">
136
  <div class="item-title fn"><a href="<?php bp_member_permalink(); ?>" title="<?php bp_member_name(); ?>"><?php bp_member_name(); ?></a></div>
137
  <div class="item-meta">
138
- <span class="activity"><?php
139
- if ( 'newest' === $settings['member_default'] ) :
140
- bp_member_registered();
141
- elseif ( 'active' === $settings['member_default'] ) :
142
- bp_member_last_active();
143
- elseif ( 'popular' === $settings['member_default'] ) :
144
- bp_member_total_friend_count();
145
- endif; ?></span>
146
  </div>
147
  </div>
148
  </li>
88
  $separator = apply_filters( 'bp_members_widget_separator', '|' );
89
 
90
  // Output before widget HTMl, title (and maybe content before & after it).
91
+ echo $args['before_widget'] . $args['before_title'] . $title . $args['after_title'];
 
 
 
92
 
93
  // Setup args for querying members.
94
  $members_args = array(
120
 
121
  </div>
122
 
123
+ <ul id="members-list" class="item-list" aria-live="polite" aria-relevant="all" aria-atomic="true">
124
 
125
  <?php while ( bp_members() ) : bp_the_member(); ?>
126
 
132
  <div class="item">
133
  <div class="item-title fn"><a href="<?php bp_member_permalink(); ?>" title="<?php bp_member_name(); ?>"><?php bp_member_name(); ?></a></div>
134
  <div class="item-meta">
135
+ <?php if ( 'newest' == $settings['member_default'] ) : ?>
136
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_registered( array( 'relative' => false ) ) ); ?>"><?php bp_member_registered(); ?></span>
137
+ <?php elseif ( 'active' == $settings['member_default'] ) : ?>
138
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_last_active( array( 'relative' => false ) ) ); ?>"><?php bp_member_last_active(); ?></span>
139
+ <?php else : ?>
140
+ <span class="activity"><?php bp_member_total_friend_count(); ?></span>
141
+ <?php endif; ?>
 
142
  </div>
143
  </div>
144
  </li>
bp-members/classes/class-bp-core-recently-active-widget.php CHANGED
@@ -61,9 +61,7 @@ class BP_Core_Recently_Active_Widget extends WP_Widget {
61
  $title = apply_filters( 'widget_title', $settings['title'], $settings, $this->id_base );
62
 
63
  echo $args['before_widget'];
64
- echo $args['before_title']
65
- . $title
66
- . $args['after_title'];
67
 
68
  // Setup args for querying members.
69
  $members_args = array(
61
  $title = apply_filters( 'widget_title', $settings['title'], $settings, $this->id_base );
62
 
63
  echo $args['before_widget'];
64
+ echo $args['before_title'] . $title . $args['after_title'];
 
 
65
 
66
  // Setup args for querying members.
67
  $members_args = array(
bp-members/classes/class-bp-core-whos-online-widget.php CHANGED
@@ -60,10 +60,7 @@ class BP_Core_Whos_Online_Widget extends WP_Widget {
60
  */
61
  $title = apply_filters( 'widget_title', $settings['title'], $settings, $this->id_base );
62
 
63
- echo $args['before_widget']
64
- . $args['before_title']
65
- . $title
66
- . $args['after_title'];
67
 
68
  // Setup args for querying members.
69
  $members_args = array(
60
  */
61
  $title = apply_filters( 'widget_title', $settings['title'], $settings, $this->id_base );
62
 
63
+ echo $args['before_widget'] . $args['before_title'] . $title . $args['after_title'];
 
 
 
64
 
65
  // Setup args for querying members.
66
  $members_args = array(
bp-members/classes/class-bp-members-admin.php CHANGED
@@ -214,6 +214,62 @@ class BP_Members_Admin {
214
  add_filter( "views_{$user_screen}", array( $this, 'signup_filter_view' ), 10, 1 );
215
  add_filter( 'set-screen-option', array( $this, 'signup_screen_options' ), 10, 3 );
216
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  }
218
  }
219
 
@@ -1905,6 +1961,7 @@ class BP_Members_Admin {
1905
  * @since 2.0.0
1906
  *
1907
  * @param string $action Delete, activate, or resend activation link.
 
1908
  * @return string
1909
  */
1910
  public function signups_admin_manage( $action = '' ) {
@@ -2032,5 +2089,225 @@ class BP_Members_Admin {
2032
 
2033
  <?php
2034
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2035
  }
2036
  endif; // End class_exists check.
214
  add_filter( "views_{$user_screen}", array( $this, 'signup_filter_view' ), 10, 1 );
215
  add_filter( 'set-screen-option', array( $this, 'signup_screen_options' ), 10, 3 );
216
  }
217
+
218
+ // Registration is turned on.
219
+ add_action( 'update_site_option_registration', array( $this, 'multisite_registration_on' ), 10, 2 );
220
+ add_action( 'update_option_users_can_register', array( $this, 'single_site_registration_on' ), 10, 2 );
221
+ }
222
+
223
+ /** Users List - Members Types ***************************************
224
+ */
225
+
226
+ if ( is_admin() && bp_get_member_types() ) {
227
+
228
+ // Add "Change type" <select> to WP admin users list table and process bulk members type changes.
229
+ add_action( 'restrict_manage_users', array( $this, 'users_table_output_type_change_select' ) );
230
+ add_action( 'load-users.php', array( $this, 'users_table_process_bulk_type_change' ) );
231
+
232
+ // Add the member type column to the WP admin users list table.
233
+ add_filter( 'manage_users_columns', array( $this, 'users_table_add_type_column' ) );
234
+ add_filter( 'manage_users_custom_column', array( $this, 'users_table_populate_type_cell' ), 10, 3 );
235
+
236
+ // Filter WP admin users list table to include users of the specified type.
237
+ add_filter( 'pre_get_users', array( $this, 'users_table_filter_by_type' ) );
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Create registration pages when multisite user registration is turned on.
243
+ *
244
+ * @since 2.7.0
245
+ *
246
+ * @param string $option_name Current option name; value is always 'registration'.
247
+ * @param string $value
248
+ */
249
+ public function multisite_registration_on( $option_name, $value ) {
250
+ if ( 'user' === $value || 'all' === $value ) {
251
+ bp_core_add_page_mappings( array(
252
+ 'register' => 1,
253
+ 'activate' => 1
254
+ ) );
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Create registration pages when single site registration is turned on.
260
+ *
261
+ * @since 2.7.0
262
+ *
263
+ * @param string $old_value
264
+ * @param string $value
265
+ */
266
+ public function single_site_registration_on( $old_value, $value ) {
267
+ // Single site.
268
+ if ( ! is_multisite() && ! empty( $value ) ) {
269
+ bp_core_add_page_mappings( array(
270
+ 'register' => 1,
271
+ 'activate' => 1
272
+ ) );
273
  }
274
  }
275
 
1961
  * @since 2.0.0
1962
  *
1963
  * @param string $action Delete, activate, or resend activation link.
1964
+ *
1965
  * @return string
1966
  */
1967
  public function signups_admin_manage( $action = '' ) {
2089
 
2090
  <?php
2091
  }
2092
+
2093
+ /** Users List Management ****************************************************/
2094
+
2095
+ /**
2096
+ * Display a dropdown to bulk change the member type of selected user(s).
2097
+ *
2098
+ * @since 2.7.0
2099
+ *
2100
+ * @param string $which Where this dropdown is displayed - top or bottom.
2101
+ */
2102
+ public function users_table_output_type_change_select( $which = 'top' ) {
2103
+
2104
+ // Bail if current user cannot promote users.
2105
+ if ( ! bp_current_user_can( 'promote_users' ) ) {
2106
+ return;
2107
+ }
2108
+
2109
+ // `$which` is only passed in WordPress 4.6+. Avoid duplicating controls in earlier versions.
2110
+ static $displayed = false;
2111
+ if ( version_compare( bp_get_major_wp_version(), '4.6', '<' ) && $displayed ) {
2112
+ return;
2113
+ }
2114
+ $displayed = true;
2115
+
2116
+ $id_name = 'bottom' === $which ? 'bp_change_type2' : 'bp_change_type';
2117
+
2118
+ $types = bp_get_member_types( array(), 'objects' ); ?>
2119
+
2120
+ <label class="screen-reader-text" for="<?php echo $id_name; ?>"><?php _e( 'Change member type to&hellip;', 'buddypress' ) ?></label>
2121
+ <select name="<?php echo $id_name; ?>" id="<?php echo $id_name; ?>" style="display:inline-block;float:none;">
2122
+ <option value=""><?php _e( 'Change member type to&hellip;', 'buddypress' ) ?></option>
2123
+
2124
+ <?php foreach( $types as $type ) : ?>
2125
+
2126
+ <option value="<?php echo esc_attr( $type->name ); ?>"><?php echo esc_html( $type->labels['singular_name'] ); ?></option>
2127
+
2128
+ <?php endforeach; ?>
2129
+
2130
+ <option value="remove_member_type"><?php _e( 'No Member Type', 'buddypress' ) ?></option>
2131
+
2132
+ </select>
2133
+ <?php
2134
+ wp_nonce_field( 'bp-bulk-users-change-type-' . bp_loggedin_user_id(), 'bp-bulk-users-change-type-nonce' );
2135
+ submit_button( __( 'Change', 'buddypress' ), 'button', 'bp_change_member_type', false );
2136
+ }
2137
+
2138
+ /**
2139
+ * Process bulk member type change submission from the WP admin users list table.
2140
+ *
2141
+ * @since 2.7.0
2142
+ */
2143
+ public function users_table_process_bulk_type_change() {
2144
+ // Output the admin notice.
2145
+ $this->users_type_change_notice();
2146
+
2147
+ // Bail if no users are specified or if this isn't a BuddyPress action.
2148
+ if ( empty( $_REQUEST['users'] )
2149
+ || ( empty( $_REQUEST['bp_change_type'] ) && empty( $_REQUEST['bp_change_type2'] ) )
2150
+ || empty( $_REQUEST['bp_change_member_type'] )
2151
+ ) {
2152
+ return;
2153
+ }
2154
+
2155
+ // Bail if nonce check fails.
2156
+ check_admin_referer( 'bp-bulk-users-change-type-' . bp_loggedin_user_id(), 'bp-bulk-users-change-type-nonce' );
2157
+
2158
+ // Bail if current user cannot promote users.
2159
+ if ( ! bp_current_user_can( 'promote_users' ) ) {
2160
+ return;
2161
+ }
2162
+
2163
+ $new_type = '';
2164
+ if ( ! empty( $_REQUEST['bp_change_type2'] ) ) {
2165
+ $new_type = sanitize_text_field( $_REQUEST['bp_change_type2'] );
2166
+ } elseif ( ! empty( $_REQUEST['bp_change_type'] ) ) {
2167
+ $new_type = sanitize_text_field( $_REQUEST['bp_change_type'] );
2168
+ }
2169
+
2170
+ // Check that the selected type actually exists.
2171
+ if ( 'remove_member_type' != $new_type && null === bp_get_member_type_object( $new_type ) ) {
2172
+ $error = true;
2173
+ } else {
2174
+ // Run through user ids.
2175
+ $error = false;
2176
+ foreach ( (array) $_REQUEST['users'] as $user_id ) {
2177
+ $user_id = (int) $user_id;
2178
+
2179
+ // Get the old member type to check against.
2180
+ $member_type = bp_get_member_type( $user_id );
2181
+
2182
+ if ( 'remove_member_type' === $new_type ) {
2183
+ // Remove the current member type, if there's one to remove.
2184
+ if ( $member_type ) {
2185
+ $removed = bp_remove_member_type( $user_id, $member_type );
2186
+ if ( false === $removed || is_wp_error( $removed ) ) {
2187
+ $error = true;
2188
+ }
2189
+ }
2190
+ } else {
2191
+ // Set the new member type.
2192
+ if ( $new_type !== $member_type ) {
2193
+ $set = bp_set_member_type( $user_id, $new_type );
2194
+ if ( false === $set || is_wp_error( $set ) ) {
2195
+ $error = true;
2196
+ }
2197
+ }
2198
+ }
2199
+ }
2200
+ }
2201
+
2202
+ // If there were any errors, show the error message.
2203
+ if ( $error ) {
2204
+ $redirect = add_query_arg( array( 'updated' => 'member-type-change-error' ), wp_get_referer() );
2205
+ } else {
2206
+ $redirect = add_query_arg( array( 'updated' => 'member-type-change-success' ), wp_get_referer() );
2207
+ }
2208
+
2209
+ wp_redirect( $redirect );
2210
+ exit();
2211
+ }
2212
+
2213
+ /**
2214
+ * Display an admin notice upon member type bulk update.
2215
+ *
2216
+ * @since 2.7.0
2217
+ */
2218
+ public function users_type_change_notice() {
2219
+ $updated = isset( $_REQUEST['updated'] ) ? $_REQUEST['updated'] : false;
2220
+
2221
+ // Display feedback.
2222
+ if ( $updated && in_array( $updated, array( 'member-type-change-error', 'member-type-change-success' ), true ) ) {
2223
+
2224
+ if ( 'member-type-change-error' === $updated ) {
2225
+ $notice = __( 'There was an error while changing member type. Please try again.', 'buddypress' );
2226
+ $type = 'error';
2227
+ } else {
2228
+ $notice = __( 'Member type was changed successfully.', 'buddypress' );
2229
+ $type = 'updated';
2230
+ }
2231
+
2232
+ bp_core_add_admin_notice( $notice, $type );
2233
+ }
2234
+ }
2235
+
2236
+ /**
2237
+ * Add member type column to the WordPress admin users list table.
2238
+ *
2239
+ * @since 2.7.0
2240
+ *
2241
+ * @param array $columns Users table columns.
2242
+ *
2243
+ * @return array $columns
2244
+ */
2245
+ public function users_table_add_type_column( $columns = array() ) {
2246
+ $columns[ bp_get_member_type_tax_name() ] = _x( 'Member Type', 'Label for the WP users table member type column' , 'buddypress' );
2247
+
2248
+ return $columns;
2249
+ }
2250
+
2251
+ /**
2252
+ * Return member's type for display in the WP admin users list table.
2253
+ *
2254
+ * @since 2.7.0
2255
+ *
2256
+ * @param string $retval
2257
+ * @param string $column_name
2258
+ * @param int $user_id
2259
+ *
2260
+ * @return string Member type as a link to filter all users.
2261
+ */
2262
+ public function users_table_populate_type_cell( $retval = '', $column_name = '', $user_id = 0 ) {
2263
+ // Only looking for member type column.
2264
+ if ( bp_get_member_type_tax_name() !== $column_name ) {
2265
+ return $retval;
2266
+ }
2267
+
2268
+ // Get the member type.
2269
+ $type = bp_get_member_type( $user_id );
2270
+
2271
+ // Output the
2272
+ if ( $type_obj = bp_get_member_type_object( $type ) ) {
2273
+ $url = add_query_arg( array( 'bp-member-type' => urlencode( $type ) ) );
2274
+ $retval = '<a href="' . esc_url( $url ) . '">' . esc_html( $type_obj->labels['singular_name'] ) . '</a>';
2275
+ }
2276
+
2277
+ return $retval;
2278
+ }
2279
+
2280
+ /**
2281
+ * Filter WP Admin users list table to include users of the specified type.
2282
+ *
2283
+ * @param WP_Query $query
2284
+ *
2285
+ * @since 2.7.0
2286
+ */
2287
+ public function users_table_filter_by_type( $query ) {
2288
+ global $pagenow;
2289
+
2290
+ if ( is_admin() && 'users.php' === $pagenow && ! empty( $_REQUEST['bp-member-type'] ) ) {
2291
+ $type_slug = sanitize_text_field( $_REQUEST['bp-member-type'] );
2292
+
2293
+ // Check that the type is registered.
2294
+ if ( null == bp_get_member_type_object( $type_slug ) ) {
2295
+ return;
2296
+ }
2297
+
2298
+ // Get the list of users that are assigned to this member type.
2299
+ $type = bp_get_term_by( 'slug', $type_slug, bp_get_member_type_tax_name() );
2300
+
2301
+ if ( empty( $type->term_id ) ) {
2302
+ return;
2303
+ }
2304
+
2305
+ $user_ids = bp_get_objects_in_term( $type->term_id, bp_get_member_type_tax_name() );
2306
+
2307
+ if ( $user_ids && ! is_wp_error( $user_ids ) ) {
2308
+ $query->set( 'include', (array) $user_ids );
2309
+ }
2310
+ }
2311
+ }
2312
  }
2313
  endif; // End class_exists check.
bp-members/classes/class-bp-members-component.php CHANGED
@@ -108,12 +108,16 @@ class BP_Members_Component extends BP_Component {
108
  define( 'BP_MEMBERS_SLUG', $this->id );
109
  }
110
 
 
 
 
 
111
  // Override any passed args.
112
  $args = array(
113
  'slug' => BP_MEMBERS_SLUG,
114
  'root_slug' => isset( $bp->pages->members->slug ) ? $bp->pages->members->slug : BP_MEMBERS_SLUG,
115
  'has_directory' => true,
116
- 'directory_title' => _x( 'Members', 'component directory title', 'buddypress' ),
117
  'search_string' => __( 'Search Members...', 'buddypress' ),
118
  'global_tables' => array(
119
  'table_name_last_activity' => bp_core_get_table_prefix() . 'bp_activity',
108
  define( 'BP_MEMBERS_SLUG', $this->id );
109
  }
110
 
111
+ // Fetch the default directory title.
112
+ $default_directory_titles = bp_core_get_directory_page_default_titles();
113
+ $default_directory_title = $default_directory_titles[$this->id];
114
+
115
  // Override any passed args.
116
  $args = array(
117
  'slug' => BP_MEMBERS_SLUG,
118
  'root_slug' => isset( $bp->pages->members->slug ) ? $bp->pages->members->slug : BP_MEMBERS_SLUG,
119
  'has_directory' => true,
120
+ 'directory_title' => isset( $bp->pages->members->title ) ? $bp->pages->members->title : $default_directory_title,
121
  'search_string' => __( 'Search Members...', 'buddypress' ),
122
  'global_tables' => array(
123
  'table_name_last_activity' => bp_core_get_table_prefix() . 'bp_activity',
bp-messages/bp-messages-functions.php CHANGED
@@ -236,26 +236,41 @@ function messages_send_notice( $subject, $message ) {
236
  }
237
 
238
  /**
239
- * Delete message thread(s).
 
 
 
 
 
 
 
240
  *
241
  * @param int|array $thread_ids Thread ID or array of thread IDs.
 
 
242
  * @return bool True on success, false on failure.
243
  */
244
- function messages_delete_thread( $thread_ids ) {
 
 
 
 
245
 
246
  /**
247
  * Fires before specified thread IDs have been deleted.
248
  *
249
  * @since 1.5.0
 
250
  *
251
- * @param int|array Thread ID or array of thread IDs that were deleted.
 
252
  */
253
- do_action( 'messages_before_delete_thread', $thread_ids );
254
 
255
  if ( is_array( $thread_ids ) ) {
256
  $error = 0;
257
  for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
258
- if ( ! BP_Messages_Thread::delete( $thread_ids[$i] ) ) {
259
  $error = 1;
260
  }
261
  }
@@ -268,19 +283,21 @@ function messages_delete_thread( $thread_ids ) {
268
  * Fires after specified thread IDs have been deleted.
269
  *
270
  * @since 1.0.0
 
271
  *
272
  * @param int|array Thread ID or array of thread IDs that were deleted.
 
273
  */
274
- do_action( 'messages_delete_thread', $thread_ids );
275
 
276
  return true;
277
  } else {
278
- if ( ! BP_Messages_Thread::delete( $thread_ids ) ) {
279
  return false;
280
  }
281
 
282
  /** This action is documented in bp-messages/bp-messages-functions.php */
283
- do_action( 'messages_delete_thread', $thread_ids );
284
 
285
  return true;
286
  }
@@ -524,3 +541,84 @@ function bp_messages_add_meta( $message_id, $meta_key, $meta_value, $unique = fa
524
 
525
  return $retval;
526
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  }
237
 
238
  /**
239
+ * Deletes message thread(s) for a given user.
240
+ *
241
+ * Note that "deleting" a thread for a user means removing it from the user's
242
+ * message boxes. A thread is not deleted from the database until it's been
243
+ * "deleted" by all recipients.
244
+ *
245
+ * @since 2.7.0 The $user_id parameter was added. Previously the current user
246
+ * was always assumed.
247
  *
248
  * @param int|array $thread_ids Thread ID or array of thread IDs.
249
+ * @param int $user_id ID of the user to delete the threads for. Defaults
250
+ * to the current logged-in user.
251
  * @return bool True on success, false on failure.
252
  */
253
+ function messages_delete_thread( $thread_ids, $user_id = 0 ) {
254
+
255
+ if ( empty( $user_id ) ) {
256
+ $user_id = bp_loggedin_user_id();
257
+ }
258
 
259
  /**
260
  * Fires before specified thread IDs have been deleted.
261
  *
262
  * @since 1.5.0
263
+ * @since 2.7.0 The $user_id parameter was added.
264
  *
265
+ * @param int|array $thread_ids Thread ID or array of thread IDs to be deleted.
266
+ * @param int $user_id ID of the user the threads are being deleted for.
267
  */
268
+ do_action( 'messages_before_delete_thread', $thread_ids, $user_id );
269
 
270
  if ( is_array( $thread_ids ) ) {
271
  $error = 0;
272
  for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
273
+ if ( ! BP_Messages_Thread::delete( $thread_ids[$i], $user_id ) ) {
274
  $error = 1;
275
  }
276
  }
283
  * Fires after specified thread IDs have been deleted.
284
  *
285
  * @since 1.0.0
286
+ * @since 2.7.0 The $user_id parameter was added.
287
  *
288
  * @param int|array Thread ID or array of thread IDs that were deleted.
289
+ * @param int ID of the user that the threads were deleted for.
290
  */
291
+ do_action( 'messages_delete_thread', $thread_ids, $user_id );
292
 
293
  return true;
294
  } else {
295
+ if ( ! BP_Messages_Thread::delete( $thread_ids, $user_id ) ) {
296
  return false;
297
  }
298
 
299
  /** This action is documented in bp-messages/bp-messages-functions.php */
300
+ do_action( 'messages_delete_thread', $thread_ids, $user_id );
301
 
302
  return true;
303
  }
541
 
542
  return $retval;
543
  }
544
+
545
+ /** Email *********************************************************************/
546
+
547
+ /**
548
+ * Email message recipients to alert them of a new unread private message.
549
+ *
550
+ * @since 1.0.0
551
+ *
552
+ * @param array|BP_Messages_Message $raw_args {
553
+ * Array of arguments. Also accepts a BP_Messages_Message object.
554
+ * @type array $recipients User IDs of recipients.
555
+ * @type string $email_subject Subject line of message.
556
+ * @type string $email_content Content of message.
557
+ * @type int $sender_id User ID of sender.
558
+ * }
559
+ */
560
+ function messages_notification_new_message( $raw_args = array() ) {
561
+ if ( is_object( $raw_args ) ) {
562
+ $args = (array) $raw_args;
563
+ } else {
564
+ $args = $raw_args;
565
+ }
566
+
567
+ // These should be extracted below.
568
+ $recipients = array();
569
+ $email_subject = $email_content = '';
570
+ $sender_id = 0;
571
+
572
+ // Barf.
573
+ extract( $args );
574
+
575
+ if ( empty( $recipients ) ) {
576
+ return;
577
+ }
578
+
579
+ $sender_name = bp_core_get_user_displayname( $sender_id );
580
+
581
+ // Send an email to each recipient.
582
+ foreach ( $recipients as $recipient ) {
583
+ if ( $sender_id == $recipient->user_id || 'no' == bp_get_user_meta( $recipient->user_id, 'notification_messages_new_message', true ) ) {
584
+ continue;
585
+ }
586
+
587
+ // User data and links.
588
+ $ud = get_userdata( $recipient->user_id );
589
+ if ( empty( $ud ) ) {
590
+ continue;
591
+ }
592
+
593
+ $unsubscribe_args = array(
594
+ 'user_id' => $recipient->user_id,
595
+ 'notification_type' => 'messages-unread',
596
+ );
597
+
598
+ $args = array(
599
+ 'tokens' => array(
600
+ 'usermessage' => wp_strip_all_tags( stripslashes( $message ) ),
601
+ 'message.url' => esc_url( bp_core_get_user_domain( $recipient->user_id ) . bp_get_messages_slug() . '/view/' . $thread_id . '/' ),
602
+ 'sender.name' => $sender_name,
603
+ 'usersubject' => sanitize_text_field( stripslashes( $subject ) ),
604
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
605
+ ),
606
+ );
607
+ bp_send_email( 'messages-unread', $ud, $args );
608
+ }
609
+
610
+ /**
611
+ * Fires after the sending of a new message email notification.
612
+ *
613
+ * @since 1.5.0
614
+ * @deprecated 2.5.0 Use the filters in BP_Email.
615
+ * $email_subject and $email_content arguments unset and deprecated.
616
+ *
617
+ * @param array $recipients User IDs of recipients.
618
+ * @param string $email_subject Deprecated in 2.5; now an empty string.
619
+ * @param string $email_content Deprecated in 2.5; now an empty string.
620
+ * @param array $args Array of originally provided arguments.
621
+ */
622
+ do_action( 'bp_messages_sent_notification_email', $recipients, '', '', $args );
623
+ }
624
+ add_action( 'messages_message_sent', 'messages_notification_new_message', 10 );
bp-messages/bp-messages-loader.php CHANGED
@@ -17,7 +17,9 @@ if ( ! buddypress()->do_autoload ) {
17
  }
18
 
19
  /**
20
- * Bootstrap the Messages component.
 
 
21
  */
22
  function bp_setup_messages() {
23
  buddypress()->messages = new BP_Messages_Component();
17
  }
18
 
19
  /**
20
+ * Set up the bp-messages component.
21
+ *
22
+ * @since 1.5.0
23
  */
24
  function bp_setup_messages() {
25
  buddypress()->messages = new BP_Messages_Component();
bp-messages/bp-messages-notifications.php CHANGED
@@ -10,83 +10,6 @@
10
  // Exit if accessed directly.
11
  defined( 'ABSPATH' ) || exit;
12
 
13
- /** Email *********************************************************************/
14
-
15
- /**
16
- * Email message recipients to alert them of a new unread private message.
17
- *
18
- * @since 1.0.0
19
- *
20
- * @param array|BP_Messages_Message $raw_args {
21
- * Array of arguments. Also accepts a BP_Messages_Message object.
22
- * @type array $recipients User IDs of recipients.
23
- * @type string $email_subject Subject line of message.
24
- * @type string $email_content Content of message.
25
- * @type int $sender_id User ID of sender.
26
- * }
27
- */
28
- function messages_notification_new_message( $raw_args = array() ) {
29
- if ( is_object( $raw_args ) ) {
30
- $args = (array) $raw_args;
31
- } else {
32
- $args = $raw_args;
33
- }
34
-
35
- // These should be extracted below.
36
- $recipients = array();
37
- $email_subject = $email_content = '';
38
- $sender_id = 0;
39
-
40
- // Barf.
41
- extract( $args );
42
-
43
- if ( empty( $recipients ) ) {
44
- return;
45
- }
46
-
47
- $sender_name = bp_core_get_user_displayname( $sender_id );
48
-
49
- // Send an email to each recipient.
50
- foreach ( $recipients as $recipient ) {
51
- if ( $sender_id == $recipient->user_id || 'no' == bp_get_user_meta( $recipient->user_id, 'notification_messages_new_message', true ) ) {
52
- continue;
53
- }
54
-
55
- // User data and links.
56
- $ud = get_userdata( $recipient->user_id );
57
- if ( empty( $ud ) ) {
58
- continue;
59
- }
60
-
61
- $args = array(
62
- 'tokens' => array(
63
- 'usermessage' => wp_strip_all_tags( stripslashes( $message ) ),
64
- 'message.url' => esc_url( bp_core_get_user_domain( $recipient->user_id ) . bp_get_messages_slug() . '/view/' . $thread_id . '/' ),
65
- 'sender.name' => $sender_name,
66
- 'usersubject' => sanitize_text_field( stripslashes( $subject ) ),
67
- ),
68
- );
69
- bp_send_email( 'messages-unread', $ud, $args );
70
- }
71
-
72
- /**
73
- * Fires after the sending of a new message email notification.
74
- *
75
- * @since 1.5.0
76
- * @deprecated 2.5.0 Use the filters in BP_Email.
77
- * $email_subject and $email_content arguments unset and deprecated.
78
- *
79
- * @param array $recipients User IDs of recipients.
80
- * @param string $email_subject Deprecated in 2.5; now an empty string.
81
- * @param string $email_content Deprecated in 2.5; now an empty string.
82
- * @param array $args Array of originally provided arguments.
83
- */
84
- do_action( 'bp_messages_sent_notification_email', $recipients, '', '', $args );
85
- }
86
- add_action( 'messages_message_sent', 'messages_notification_new_message', 10 );
87
-
88
- /** Notifications *************************************************************/
89
-
90
  /**
91
  * Format notifications for the Messages component.
92
  *
@@ -224,7 +147,7 @@ function messages_format_notifications( $action, $item_id, $secondary_item_id, $
224
  * @param BP_Messages_Message $message Message object.
225
  */
226
  function bp_messages_message_sent_add_notification( $message ) {
227
- if ( bp_is_active( 'notifications' ) && ! empty( $message->recipients ) ) {
228
  foreach ( (array) $message->recipients as $recipient ) {
229
  bp_notifications_add_notification( array(
230
  'user_id' => $recipient->user_id,
@@ -246,30 +169,28 @@ add_action( 'messages_message_sent', 'bp_messages_message_sent_add_notification'
246
  * @since 1.9.0
247
  */
248
  function bp_messages_screen_conversation_mark_notifications() {
249
- if ( bp_is_active( 'notifications' ) ) {
250
- global $thread_template;
251
-
252
- // Get unread PM notifications for the user.
253
- $new_pm_notifications = BP_Notifications_Notification::get( array(
254
- 'user_id' => bp_loggedin_user_id(),
255
- 'component_name' => buddypress()->messages->id,
256
- 'component_action' => 'new_message',
257
- 'is_new' => 1,
258
- ) );
259
- $unread_message_ids = wp_list_pluck( $new_pm_notifications, 'item_id' );
260
-
261
- // No unread PMs, so stop!
262
- if ( empty( $unread_message_ids ) ) {
263
- return;
264
- }
265
 
266
- // Get the unread message ids for this thread only.
267
- $message_ids = array_intersect( $unread_message_ids, wp_list_pluck( $thread_template->thread->messages, 'id' ) );
268
 
269
- // Mark each notification for each PM message as read.
270
- foreach ( $message_ids as $message_id ) {
271
- bp_notifications_mark_notifications_by_item_id( bp_loggedin_user_id(), (int) $message_id, buddypress()->messages->id, 'new_message' );
272
- }
273
  }
274
  }
275
  add_action( 'thread_loop_start', 'bp_messages_screen_conversation_mark_notifications', 10 );
@@ -283,10 +204,6 @@ add_action( 'thread_loop_start', 'bp_messages_screen_conversation_mark_notificat
283
  * @param array $message_ids IDs of the messages.
284
  */
285
  function bp_messages_message_delete_notifications( $thread_id, $message_ids ) {
286
- if ( ! bp_is_active( 'notifications' ) ) {
287
- return;
288
- }
289
-
290
  // For each recipient, delete notifications corresponding to each message.
291
  $thread = new BP_Messages_Thread( $thread_id );
292
  foreach ( $thread->get_recipients() as $recipient ) {
10
  // Exit if accessed directly.
11
  defined( 'ABSPATH' ) || exit;
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * Format notifications for the Messages component.
15
  *
147
  * @param BP_Messages_Message $message Message object.
148
  */
149
  function bp_messages_message_sent_add_notification( $message ) {
150
+ if ( ! empty( $message->recipients ) ) {
151
  foreach ( (array) $message->recipients as $recipient ) {
152
  bp_notifications_add_notification( array(
153
  'user_id' => $recipient->user_id,
169
  * @since 1.9.0
170
  */
171
  function bp_messages_screen_conversation_mark_notifications() {
172
+ global $thread_template;
173
+
174
+ // Get unread PM notifications for the user.
175
+ $new_pm_notifications = BP_Notifications_Notification::get( array(
176
+ 'user_id' => bp_loggedin_user_id(),
177
+ 'component_name' => buddypress()->messages->id,
178
+ 'component_action' => 'new_message',
179
+ 'is_new' => 1,
180
+ ) );
181
+ $unread_message_ids = wp_list_pluck( $new_pm_notifications, 'item_id' );
182
+
183
+ // No unread PMs, so stop!
184
+ if ( empty( $unread_message_ids ) ) {
185
+ return;
186
+ }
 
187
 
188
+ // Get the unread message ids for this thread only.
189
+ $message_ids = array_intersect( $unread_message_ids, wp_list_pluck( $thread_template->thread->messages, 'id' ) );
190
 
191
+ // Mark each notification for each PM message as read.
192
+ foreach ( $message_ids as $message_id ) {
193
+ bp_notifications_mark_notifications_by_item_id( bp_loggedin_user_id(), (int) $message_id, buddypress()->messages->id, 'new_message' );
 
194
  }
195
  }
196
  add_action( 'thread_loop_start', 'bp_messages_screen_conversation_mark_notifications', 10 );
204
  * @param array $message_ids IDs of the messages.
205
  */
206
  function bp_messages_message_delete_notifications( $thread_id, $message_ids ) {
 
 
 
 
207
  // For each recipient, delete notifications corresponding to each message.
208
  $thread = new BP_Messages_Thread( $thread_id );
209
  foreach ( $thread->get_recipients() as $recipient ) {
bp-messages/bp-messages-template.php CHANGED
@@ -1345,7 +1345,6 @@ function bp_send_message_button() {
1345
  'block_self' => true,
1346
  'wrapper_id' => 'send-private-message',
1347
  'link_href' => bp_get_send_private_message_link(),
1348
- 'link_title' => __( 'Send a private message to this user.', 'buddypress' ),
1349
  'link_text' => __( 'Private Message', 'buddypress' ),
1350
  'link_class' => 'send-message',
1351
  ) ) )
1345
  'block_self' => true,
1346
  'wrapper_id' => 'send-private-message',
1347
  'link_href' => bp_get_send_private_message_link(),
 
1348
  'link_text' => __( 'Private Message', 'buddypress' ),
1349
  'link_class' => 'send-message',
1350
  ) ) )
bp-messages/classes/class-bp-messages-component.php CHANGED
@@ -63,7 +63,6 @@ class BP_Messages_Component extends BP_Component {
63
  'filters',
64
  'template',
65
  'functions',
66
- 'notifications',
67
  'widgets',
68
  );
69
 
@@ -72,6 +71,9 @@ class BP_Messages_Component extends BP_Component {
72
  }
73
 
74
  // Conditional includes.
 
 
 
75
  if ( bp_is_active( $this->id, 'star' ) ) {
76
  $includes[] = 'star';
77
  }
63
  'filters',
64
  'template',
65
  'functions',
 
66
  'widgets',
67
  );
68
 
71
  }
72
 
73
  // Conditional includes.
74
+ if ( bp_is_active( 'notifications' ) ) {
75
+ $includes[] = 'notifications';
76
+ }
77
  if ( bp_is_active( $this->id, 'star' ) ) {
78
  $includes[] = 'star';
79
  }
bp-messages/classes/class-bp-messages-message.php CHANGED
@@ -88,9 +88,9 @@ class BP_Messages_Message {
88
  $bp = buddypress();
89
 
90
  if ( $message = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_messages} WHERE id = %d", $id ) ) ) {
91
- $this->id = $message->id;
92
- $this->thread_id = $message->thread_id;
93
- $this->sender_id = $message->sender_id;
94
  $this->subject = $message->subject;
95
  $this->message = $message->message;
96
  $this->date_sent = $message->date_sent;
@@ -220,7 +220,9 @@ class BP_Messages_Message {
220
 
221
  $bp = buddypress();
222
 
223
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE sender_id = %d AND thread_id = %d ORDER BY date_sent DESC LIMIT 1", bp_loggedin_user_id(), $thread_id ) );
 
 
224
  }
225
 
226
  /**
@@ -236,7 +238,9 @@ class BP_Messages_Message {
236
 
237
  $bp = buddypress();
238
 
239
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE sender_id = %d AND id = %d", $user_id, $message_id ) );
 
 
240
  }
241
 
242
  /**
@@ -250,6 +254,8 @@ class BP_Messages_Message {
250
 
251
  $bp = buddypress();
252
 
253
- return $wpdb->get_var( $wpdb->prepare( "SELECT sender_id FROM {$bp->messages->table_name_messages} WHERE id = %d", $message_id ) );
 
 
254
  }
255
  }
88
  $bp = buddypress();
89
 
90
  if ( $message = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_messages} WHERE id = %d", $id ) ) ) {
91
+ $this->id = (int) $message->id;
92
+ $this->thread_id = (int) $message->thread_id;
93
+ $this->sender_id = (int) $message->sender_id;
94
  $this->subject = $message->subject;
95
  $this->message = $message->message;
96
  $this->date_sent = $message->date_sent;
220
 
221
  $bp = buddypress();
222
 
223
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE sender_id = %d AND thread_id = %d ORDER BY date_sent DESC LIMIT 1", bp_loggedin_user_id(), $thread_id ) );
224
+
225
+ return is_numeric( $query ) ? (int) $query : $query;
226
  }
227
 
228
  /**
238
 
239
  $bp = buddypress();
240
 
241
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE sender_id = %d AND id = %d", $user_id, $message_id ) );
242
+
243
+ return is_numeric( $query ) ? (int) $query : $query;
244
  }
245
 
246
  /**
254
 
255
  $bp = buddypress();
256
 
257
+ $query = $wpdb->get_var( $wpdb->prepare( "SELECT sender_id FROM {$bp->messages->table_name_messages} WHERE id = %d", $message_id ) );
258
+
259
+ return is_numeric( $query ) ? (int) $query : $query;
260
  }
261
  }
bp-messages/classes/class-bp-messages-notice.php CHANGED
@@ -62,7 +62,7 @@ class BP_Messages_Notice {
62
  */
63
  public function __construct( $id = null ) {
64
  if ( $id ) {
65
- $this->id = $id;
66
  $this->populate();
67
  }
68
  }
@@ -85,7 +85,7 @@ class BP_Messages_Notice {
85
  $this->subject = $notice->subject;
86
  $this->message = $notice->message;
87
  $this->date_sent = $notice->date_sent;
88
- $this->is_active = $notice->is_active;
89
  }
90
  }
91
 
@@ -232,6 +232,12 @@ class BP_Messages_Notice {
232
 
233
  $notices = $wpdb->get_results( "SELECT * FROM {$bp->messages->table_name_notices} ORDER BY date_sent DESC {$limit_sql}" );
234
 
 
 
 
 
 
 
235
  return $notices;
236
  }
237
 
62
  */
63
  public function __construct( $id = null ) {
64
  if ( $id ) {
65
+ $this->id = (int) $id;
66
  $this->populate();
67
  }
68
  }
85
  $this->subject = $notice->subject;
86
  $this->message = $notice->message;
87
  $this->date_sent = $notice->date_sent;
88
+ $this->is_active = (int) $notice->is_active;
89
  }
90
  }
91
 
232
 
233
  $notices = $wpdb->get_results( "SELECT * FROM {$bp->messages->table_name_notices} ORDER BY date_sent DESC {$limit_sql}" );
234
 
235
+ // Integer casting.
236
+ foreach ( (array) $notices as $key => $data ) {
237
+ $notices[ $key ]->id = (int) $notices[ $key ]->id;
238
+ $notices[ $key ]->is_active = (int) $notices[ $key ]->is_active;
239
+ }
240
+
241
  return $notices;
242
  }
243
 
bp-messages/classes/class-bp-messages-thread.php CHANGED
@@ -254,6 +254,11 @@ class BP_Messages_Thread {
254
  wp_cache_set( 'thread_recipients_' . $thread_id, $recipients, 'bp_messages' );
255
  }
256
 
 
 
 
 
 
257
  /**
258
  * Filters the recipients of a message thread.
259
  *
@@ -291,6 +296,13 @@ class BP_Messages_Thread {
291
  wp_cache_set( $thread_id, (array) $messages, 'bp_messages_threads' );
292
  }
293
 
 
 
 
 
 
 
 
294
  return $messages;
295
  }
296
 
@@ -314,31 +326,40 @@ class BP_Messages_Thread {
314
  * has marked the thread as deleted.
315
  *
316
  * @since 1.0.0
 
 
317
  *
318
  * @param int $thread_id The message thread ID.
 
 
 
319
  * @return bool
320
  */
321
- public static function delete( $thread_id = 0 ) {
322
  global $wpdb;
323
 
324
  $thread_id = (int) $thread_id;
 
 
 
 
 
325
 
326
  /**
327
  * Fires before a message thread is marked as deleted.
328
  *
329
  * @since 2.2.0
 
330
  *
331
  * @param int $thread_id ID of the thread being deleted.
 
332
  */
333
- do_action( 'bp_messages_thread_before_mark_delete', $thread_id );
334
 
335
  $bp = buddypress();
336
 
337
  // Mark messages as deleted
338
- //
339
- // @todo the reliance on bp_loggedin_user_id() sucks for plugins
340
- // refactor this method to accept a $user_id parameter.
341
- $wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET is_deleted = 1 WHERE thread_id = %d AND user_id = %d", $thread_id, bp_loggedin_user_id() ) );
342
 
343
  // Get the message ids in order to pass to the action.
344
  $message_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) );
@@ -386,11 +407,13 @@ class BP_Messages_Thread {
386
  * Fires after a message thread is either marked as deleted or deleted.
387
  *
388
  * @since 2.2.0
 
389
  *
390
  * @param int $thread_id ID of the thread being deleted.
391
  * @param array $message_ids IDs of messages being deleted.
 
392
  */
393
- do_action( 'bp_messages_thread_after_delete', $thread_id, $message_ids );
394
 
395
  return true;
396
  }
254
  wp_cache_set( 'thread_recipients_' . $thread_id, $recipients, 'bp_messages' );
255
  }
256
 
257
+ // Cast all items from the messages DB table as integers.
258
+ foreach ( (array) $recipients as $key => $data ) {
259
+ $recipients[ $key ] = (object) array_map( 'intval', (array) $data );
260
+ }
261
+
262
  /**
263
  * Filters the recipients of a message thread.
264
  *
296
  wp_cache_set( $thread_id, (array) $messages, 'bp_messages_threads' );
297
  }
298
 
299
+ // Integer casting.
300
+ foreach ( $messages as $key => $data ) {
301
+ $messages[ $key ]->id = (int) $messages[ $key ]->id;
302
+ $messages[ $key ]->thread_id = (int) $messages[ $key ]->thread_id;
303
+ $messages[ $key ]->sender_id = (int) $messages[ $key ]->sender_id;
304
+ }
305
+
306
  return $messages;
307
  }
308
 
326
  * has marked the thread as deleted.
327
  *
328
  * @since 1.0.0
329
+ * @since 2.7.0 The $user_id parameter was added. Previously the current user
330
+ * was always assumed.
331
  *
332
  * @param int $thread_id The message thread ID.
333
+ * @param int $user_id The ID of the user in the thread to mark messages as
334
+ * deleted for. Defaults to the current logged-in user.
335
+ *
336
  * @return bool
337
  */
338
+ public static function delete( $thread_id = 0, $user_id = 0 ) {
339
  global $wpdb;
340
 
341
  $thread_id = (int) $thread_id;
342
+ $user_id = (int) $user_id;
343
+
344
+ if ( empty( $user_id ) ) {
345
+ $user_id = bp_loggedin_user_id();
346
+ }
347
 
348
  /**
349
  * Fires before a message thread is marked as deleted.
350
  *
351
  * @since 2.2.0
352
+ * @since 2.7.0 The $user_id parameter was added.
353
  *
354
  * @param int $thread_id ID of the thread being deleted.
355
+ * @param int $user_id ID of the user that the thread is being deleted for.
356
  */
357
+ do_action( 'bp_messages_thread_before_mark_delete', $thread_id, $user_id );
358
 
359
  $bp = buddypress();
360
 
361
  // Mark messages as deleted
362
+ $wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET is_deleted = 1 WHERE thread_id = %d AND user_id = %d", $thread_id, $user_id ) );
 
 
 
363
 
364
  // Get the message ids in order to pass to the action.
365
  $message_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) );
407
  * Fires after a message thread is either marked as deleted or deleted.
408
  *
409
  * @since 2.2.0
410
+ * @since 2.7.0 The $user_id parameter was added.
411
  *
412
  * @param int $thread_id ID of the thread being deleted.
413
  * @param array $message_ids IDs of messages being deleted.
414
+ * @param int $user_id ID of the user the threads were deleted for.
415
  */
416
+ do_action( 'bp_messages_thread_after_delete', $thread_id, $message_ids, $user_id );
417
 
418
  return true;
419
  }
bp-messages/js/autocomplete/jquery.autocomplete.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){a.fn.extend({autocompletebp:function(b,c){var d="string"==typeof b;return c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c),c.highlight=c.highlight||function(a){return a},this.each(function(){new a.Autocompleter(this,c)})},result:function(a){return this.bind("result",a)},search:function(a){return this.trigger("search",[a])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(a){return this.trigger("setOptions",[a])},unautocomplete:function(){return this.trigger("unautocomplete")}}),a.Autocompleter=function(b,c){function d(){var a=x.selected();if(!a)return!1;var b=a.result;if(t=b,c.multiple){var d=f(s.val());d.length>1&&(b=d.slice(0,d.length-1).join(c.multipleSeparator)+c.multipleSeparator+b),b+=c.multipleSeparator}return s.val(b),j(),s.trigger("result",[a.data,a.value]),!0}function e(a,b){if(q==r.DEL)return void x.hide();var d=s.val();(b||d!=t)&&(t=d,d=g(d),d.length>=c.minChars?(s.addClass(c.loadingClass),jQuery("#send-to-input").addClass("loading"),c.matchCase||(d=d.toLowerCase()),l(d,k,j)):(n(),x.hide()))}function f(b){if(!b)return[""];var d=b.split(a.trim(c.multipleSeparator)),e=[];return a.each(d,function(b,c){a.trim(c)&&(e[b]=a.trim(c))}),e}function g(a){if(!c.multiple)return a;var b=f(a);return b[b.length-1]}function h(d,e){c.autoFill&&g(s.val()).toLowerCase()==d.toLowerCase()&&8!=q&&(s.val(s.val()+e.substring(g(t).length)),a.Autocompleter.Selection(b,t.length,t.length+e.length))}function i(){clearTimeout(p),p=setTimeout(j,200)}function j(){x.hide(),clearTimeout(p),n(),c.mustMatch&&s.search(function(a){a||s.val("")})}function k(a,b){if(b&&b.length&&v){n(),x.display(b,a);var c=b[0].value.split(";");b.value=c[0],h(a,b.value),x.show()}else j()}function l(d,e,f){c.matchCase||(d=d.toLowerCase());var h=u.load(d);if(h&&h.length)e(d,h);else if("string"==typeof c.url&&c.url.length>0){var i={};a.each(c.extraParams,function(a,b){i[a]="function"==typeof b?b():b}),a.ajax({mode:"abort",port:"autocomplete"+b.name,dataType:c.dataType,url:c.url,data:a.extend({q:g(d),limit:c.max,action:"messages_autocomplete_results",cookie:o()},i),success:function(a){var b=c.parse&&c.parse(a)||m(a);u.add(d,b),e(d,b)}})}else f(d)}function m(b){for(var d=[],e=b.split("\n"),f=0;f<e.length;f++){var g=a.trim(e[f]);g&&(g=g.split("|"),d[d.length]={data:g,value:g[0],result:c.formatResult&&c.formatResult(g,g[0])||g[0]})}return d}function n(){s.removeClass(c.loadingClass),jQuery("#send-to-input").removeClass("loading")}function o(){var a,b,c,d,e,f=document.cookie.split(";"),g={},h="bp-";for(a=0;a<f.length;a++)b=f[a],c=b.indexOf("="),d=jq.trim(unescape(b.slice(0,c))),e=unescape(b.slice(c+1)),0===d.indexOf(h)&&(g[d]=e);return encodeURIComponent(jq.param(g))}var p,q,r={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34},s=a(b).attr("autocomplete","off").addClass(c.inputClass),t="",u=a.Autocompleter.Cache(c),v=0,w={mouseDownOnSelect:!1},x=a.Autocompleter.Select(c,b,d,w);s.keydown(function(b){switch(q=b.keyCode,b.keyCode){case r.UP:b.preventDefault(),x.visible()?x.prev():e(0,!0);break;case r.DOWN:b.preventDefault(),x.visible()?x.next():e(0,!0);break;case r.PAGEUP:b.preventDefault(),x.visible()?x.pageUp():e(0,!0);break;case r.PAGEDOWN:b.preventDefault(),x.visible()?x.pageDown():e(0,!0);break;case c.multiple&&","==a.trim(c.multipleSeparator)&&r.COMMA:case r.TAB:case r.RETURN:d()&&(c.multiple||s.blur(),b.preventDefault(),s.focus());break;case r.ESC:x.hide();break;default:clearTimeout(p),p=setTimeout(e,c.delay)}}).keypress(function(){}).focus(function(){v++}).blur(function(){v=0,w.mouseDownOnSelect||i()}).click(function(){v++>1&&!x.visible()&&e(0,!0)}).bind("search",function(){function b(a,b){var d;if(b&&b.length)for(var e=0;e<b.length;e++)if(b[e].result.toLowerCase()==a.toLowerCase()){d=b[e];break}"function"==typeof c?c(d):s.trigger("result",d&&[d.data,d.value])}var c=arguments.length>1?arguments[1]:null;a.each(f(s.val()),function(a,c){l(c,b,b)})}).bind("flushCache",function(){u.flush()}).bind("setOptions",function(){a.extend(c,arguments[1]),"data"in arguments[1]&&u.populate()}).bind("unautocomplete",function(){x.unbind(),s.unbind()})},a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:!1,matchSubset:!0,matchContains:!1,cacheLength:10,max:100,mustMatch:!1,extraParams:{},selectFirst:!0,formatItem:function(a){return a[0]},autoFill:!1,width:0,multiple:!1,multipleSeparator:", ",highlight:function(a,b){return a.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:!0,scrollHeight:250,attachTo:"body"},a.Autocompleter.Cache=function(b){function c(a,c){b.matchCase||(a=a.toLowerCase());var d=a.indexOf(c);return-1==d?!1:0==d||b.matchContains}function d(a,c){h>b.cacheLength&&f(),g[a]||h++,g[a]=c}function e(){if(!b.data)return!1;var c={},e=0;b.url||(b.cacheLength=1),c[""]=[];for(var f=0,g=b.data.length;g>f;f++){var h=b.data[f];h="string"==typeof h?[h]:h;var i=b.formatItem(h,f+1,b.data.length);if(i!==!1){var j=i.charAt(0).toLowerCase();c[j]||(c[j]=[]);var k={value:i,data:h,result:b.formatResult&&b.formatResult(h)||i};c[j].push(k),e++<b.max&&c[""].push(k)}}a.each(c,function(a,c){b.cacheLength++,d(a,c)})}function f(){g={},h=0}var g={},h=0;return setTimeout(e,25),{flush:f,add:d,populate:e,load:function(d){if(!b.cacheLength||!h)return null;if(!b.url&&b.matchContains){var e=[];for(var f in g)if(f.length>0){var i=g[f];a.each(i,function(a,b){c(b.value,d)&&e.push(b)})}return e}if(g[d])return g[d];if(b.matchSubset)for(var j=d.length-1;j>=b.minChars;j--){var i=g[d.substr(0,j)];if(i){var e=[];return a.each(i,function(a,b){c(b.value,d)&&(e[e.length]=b)}),e}}return null}}},a.Autocompleter.Select=function(b,c,d,e){function f(){s&&(n=a("<div/>").hide().addClass(b.resultsClass).css("position","absolute").appendTo(b.attachTo),o=a("<ul>").appendTo(n).mouseover(function(b){g(b).nodeName&&"LI"==g(b).nodeName.toUpperCase()&&(q=a("li",o).removeClass(p.ACTIVE).index(g(b)),a(g(b)).addClass(p.ACTIVE))}).click(function(b){return a(g(b)).addClass(p.ACTIVE),d(),c.focus(),!1}).mousedown(function(){e.mouseDownOnSelect=!0}).mouseup(function(){e.mouseDownOnSelect=!1}),b.width>0&&n.css("width",b.width),s=!1)}function g(a){for(var b=a.target;b&&"LI"!=b.tagName;)b=b.parentNode;return b?b:[]}function h(a){l.slice(q,q+1).removeClass(),i(a);var c=l.slice(q,q+1).addClass(p.ACTIVE);if(b.scroll){var d=0;l.slice(0,q).each(function(){d+=this.offsetHeight}),d+c[0].offsetHeight-o.scrollTop()>o[0].clientHeight?o.scrollTop(d+c[0].offsetHeight-o.innerHeight()):d<o.scrollTop()&&o.scrollTop(d)}}function i(a){q+=a,0>q?q=l.size()-1:q>=l.size()&&(q=0)}function j(a){return b.max&&b.max<a?b.max:a}function k(){o.empty();for(var c=j(m.length),d=0;c>d;d++)if(m[d]){var e=b.formatItem(m[d].data,d+1,c,m[d].value,r);if(e!==!1){var f=a("<li>").html(b.highlight(e,r)).addClass(d%2==0?"ac_event":"ac_odd").appendTo(o)[0];a.data(f,"ac_data",m[d])}}l=o.find("li"),b.selectFirst&&(l.slice(0,1).addClass(p.ACTIVE),q=0),o.bgiframe()}var l,m,n,o,p={ACTIVE:"ac_over"},q=-1,r="",s=!0;return{display:function(a,b){f(),m=a,r=b,k()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){h(0!=q&&0>q-8?-q:-8)},pageDown:function(){h(q!=l.size()-1&&q+8>l.size()?l.size()-1-q:8)},hide:function(){n&&n.hide(),q=-1},visible:function(){return n&&n.is(":visible")},current:function(){return this.visible()&&(l.filter("."+p.ACTIVE)[0]||b.selectFirst&&l[0])},show:function(){var d=a(c).offset();if(n.css({width:"string"==typeof b.width||b.width>0?b.width:a(c).width(),top:d.top+c.offsetHeight,left:d.left}).show(),b.scroll&&(o.scrollTop(0),o.css({maxHeight:b.scrollHeight,overflow:"auto"}),a.browser.msie&&"undefined"==typeof document.body.style.maxHeight)){var e=0;l.each(function(){e+=this.offsetHeight});var f=e>b.scrollHeight;o.css("height",f?b.scrollHeight:e),f||l.width(o.width()-parseInt(l.css("padding-left"))-parseInt(l.css("padding-right")))}},selected:function(){var b=l&&l.filter("."+p.ACTIVE).removeClass(p.ACTIVE);return b&&b.length&&a.data(b[0],"ac_data")},unbind:function(){n&&n.remove()}}},a.Autocompleter.Selection=function(a,b,c){if(a.createTextRange){var d=a.createTextRange();d.collapse(!0),d.moveStart("character",b),d.moveEnd("character",c),d.select()}else a.setSelectionRange?a.setSelectionRange(b,c):a.selectionStart&&(a.selectionStart=b,a.selectionEnd=c);a.focus()}}(jQuery);
1
+ !function(a){a.fn.extend({autocompletebp:function(b,c){var d="string"==typeof b;return c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c),c.highlight=c.highlight||function(a){return a},this.each(function(){new a.Autocompleter(this,c)})},result:function(a){return this.bind("result",a)},search:function(a){return this.trigger("search",[a])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(a){return this.trigger("setOptions",[a])},unautocomplete:function(){return this.trigger("unautocomplete")}}),a.Autocompleter=function(b,c){function d(){var a=x.selected();if(!a)return!1;var b=a.result;if(t=b,c.multiple){var d=f(s.val());d.length>1&&(b=d.slice(0,d.length-1).join(c.multipleSeparator)+c.multipleSeparator+b),b+=c.multipleSeparator}return s.val(b),j(),s.trigger("result",[a.data,a.value]),!0}function e(a,b){if(q==r.DEL)return void x.hide();var d=s.val();(b||d!=t)&&(t=d,d=g(d),d.length>=c.minChars?(s.addClass(c.loadingClass),jQuery("#send-to-input").addClass("loading"),c.matchCase||(d=d.toLowerCase()),l(d,k,j)):(n(),x.hide()))}function f(b){if(!b)return[""];var d=b.split(a.trim(c.multipleSeparator)),e=[];return a.each(d,function(b,c){a.trim(c)&&(e[b]=a.trim(c))}),e}function g(a){if(!c.multiple)return a;var b=f(a);return b[b.length-1]}function h(d,e){c.autoFill&&g(s.val()).toLowerCase()==d.toLowerCase()&&8!=q&&(s.val(s.val()+e.substring(g(t).length)),a.Autocompleter.Selection(b,t.length,t.length+e.length))}function i(){clearTimeout(p),p=setTimeout(j,200)}function j(){x.hide(),clearTimeout(p),n(),c.mustMatch&&s.search(function(a){a||s.val("")})}function k(a,b){if(b&&b.length&&v){n(),x.display(b,a);var c=b[0].value.split(";");b.value=c[0],h(a,b.value),x.show()}else j()}function l(d,e,f){c.matchCase||(d=d.toLowerCase());var h=u.load(d);if(h&&h.length)e(d,h);else if("string"==typeof c.url&&c.url.length>0){var i={};a.each(c.extraParams,function(a,b){i[a]="function"==typeof b?b():b}),a.ajax({mode:"abort",port:"autocomplete"+b.name,dataType:c.dataType,url:c.url,data:a.extend({q:g(d),limit:c.max,action:"messages_autocomplete_results",cookie:o()},i),success:function(a){var b=c.parse&&c.parse(a)||m(a);u.add(d,b),e(d,b)}})}else f(d)}function m(b){for(var d=[],e=b.split("\n"),f=0;f<e.length;f++){var g=a.trim(e[f]);g&&(g=g.split("|"),d[d.length]={data:g,value:g[0],result:c.formatResult&&c.formatResult(g,g[0])||g[0]})}return d}function n(){s.removeClass(c.loadingClass),jQuery("#send-to-input").removeClass("loading")}function o(){var a,b,c,d,e,f=document.cookie.split(";"),g={},h="bp-";for(a=0;a<f.length;a++)b=f[a],c=b.indexOf("="),d=jq.trim(unescape(b.slice(0,c))),e=unescape(b.slice(c+1)),0===d.indexOf(h)&&(g[d]=e);return encodeURIComponent(jq.param(g))}var p,q,r={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34},s=a(b).attr("autocomplete","off").addClass(c.inputClass),t="",u=a.Autocompleter.Cache(c),v=0,w={mouseDownOnSelect:!1},x=a.Autocompleter.Select(c,b,d,w);s.keydown(function(b){switch(q=b.keyCode,b.keyCode){case r.UP:b.preventDefault(),x.visible()?x.prev():e(0,!0);break;case r.DOWN:b.preventDefault(),x.visible()?x.next():e(0,!0);break;case r.PAGEUP:b.preventDefault(),x.visible()?x.pageUp():e(0,!0);break;case r.PAGEDOWN:b.preventDefault(),x.visible()?x.pageDown():e(0,!0);break;case c.multiple&&","==a.trim(c.multipleSeparator)&&r.COMMA:case r.TAB:case r.RETURN:d()&&(c.multiple||s.blur(),b.preventDefault(),s.focus());break;case r.ESC:x.hide();break;default:clearTimeout(p),p=setTimeout(e,c.delay)}}).keypress(function(){}).focus(function(){v++}).blur(function(){v=0,w.mouseDownOnSelect||i()}).click(function(){v++>1&&!x.visible()&&e(0,!0)}).bind("search",function(){function b(a,b){var d;if(b&&b.length)for(var e=0;e<b.length;e++)if(b[e].result.toLowerCase()==a.toLowerCase()){d=b[e];break}"function"==typeof c?c(d):s.trigger("result",d&&[d.data,d.value])}var c=arguments.length>1?arguments[1]:null;a.each(f(s.val()),function(a,c){l(c,b,b)})}).bind("flushCache",function(){u.flush()}).bind("setOptions",function(){a.extend(c,arguments[1]),"data"in arguments[1]&&u.populate()}).bind("unautocomplete",function(){x.unbind(),s.unbind()})},a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:!1,matchSubset:!0,matchContains:!1,cacheLength:10,max:100,mustMatch:!1,extraParams:{},selectFirst:!0,formatItem:function(a){return a[0]},autoFill:!1,width:0,multiple:!1,multipleSeparator:", ",highlight:function(a,b){return a.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:!0,scrollHeight:250,attachTo:"body"},a.Autocompleter.Cache=function(b){function c(a,c){b.matchCase||(a=a.toLowerCase());var d=a.indexOf(c);return d!=-1&&(0==d||b.matchContains)}function d(a,c){h>b.cacheLength&&f(),g[a]||h++,g[a]=c}function e(){if(!b.data)return!1;var c={},e=0;b.url||(b.cacheLength=1),c[""]=[];for(var f=0,g=b.data.length;f<g;f++){var h=b.data[f];h="string"==typeof h?[h]:h;var i=b.formatItem(h,f+1,b.data.length);if(i!==!1){var j=i.charAt(0).toLowerCase();c[j]||(c[j]=[]);var k={value:i,data:h,result:b.formatResult&&b.formatResult(h)||i};c[j].push(k),e++<b.max&&c[""].push(k)}}a.each(c,function(a,c){b.cacheLength++,d(a,c)})}function f(){g={},h=0}var g={},h=0;return setTimeout(e,25),{flush:f,add:d,populate:e,load:function(d){if(!b.cacheLength||!h)return null;if(!b.url&&b.matchContains){var e=[];for(var f in g)if(f.length>0){var i=g[f];a.each(i,function(a,b){c(b.value,d)&&e.push(b)})}return e}if(g[d])return g[d];if(b.matchSubset)for(var j=d.length-1;j>=b.minChars;j--){var i=g[d.substr(0,j)];if(i){var e=[];return a.each(i,function(a,b){c(b.value,d)&&(e[e.length]=b)}),e}}return null}}},a.Autocompleter.Select=function(b,c,d,e){function f(){s&&(n=a("<div/>").hide().addClass(b.resultsClass).css("position","absolute").appendTo(b.attachTo),o=a("<ul>").appendTo(n).mouseover(function(b){g(b).nodeName&&"LI"==g(b).nodeName.toUpperCase()&&(q=a("li",o).removeClass(p.ACTIVE).index(g(b)),a(g(b)).addClass(p.ACTIVE))}).click(function(b){return a(g(b)).addClass(p.ACTIVE),d(),c.focus(),!1}).mousedown(function(){e.mouseDownOnSelect=!0}).mouseup(function(){e.mouseDownOnSelect=!1}),b.width>0&&n.css("width",b.width),s=!1)}function g(a){for(var b=a.target;b&&"LI"!=b.tagName;)b=b.parentNode;return b?b:[]}function h(a){l.slice(q,q+1).removeClass(),i(a);var c=l.slice(q,q+1).addClass(p.ACTIVE);if(b.scroll){var d=0;l.slice(0,q).each(function(){d+=this.offsetHeight}),d+c[0].offsetHeight-o.scrollTop()>o[0].clientHeight?o.scrollTop(d+c[0].offsetHeight-o.innerHeight()):d<o.scrollTop()&&o.scrollTop(d)}}function i(a){q+=a,q<0?q=l.size()-1:q>=l.size()&&(q=0)}function j(a){return b.max&&b.max<a?b.max:a}function k(){o.empty();for(var c=j(m.length),d=0;d<c;d++)if(m[d]){var e=b.formatItem(m[d].data,d+1,c,m[d].value,r);if(e!==!1){var f=a("<li>").html(b.highlight(e,r)).addClass(d%2==0?"ac_event":"ac_odd").appendTo(o)[0];a.data(f,"ac_data",m[d])}}l=o.find("li"),b.selectFirst&&(l.slice(0,1).addClass(p.ACTIVE),q=0),o.bgiframe()}var l,m,n,o,p={ACTIVE:"ac_over"},q=-1,r="",s=!0;return{display:function(a,b){f(),m=a,r=b,k()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){h(0!=q&&q-8<0?-q:-8)},pageDown:function(){h(q!=l.size()-1&&q+8>l.size()?l.size()-1-q:8)},hide:function(){n&&n.hide(),q=-1},visible:function(){return n&&n.is(":visible")},current:function(){return this.visible()&&(l.filter("."+p.ACTIVE)[0]||b.selectFirst&&l[0])},show:function(){var d=a(c).offset();if(n.css({width:"string"==typeof b.width||b.width>0?b.width:a(c).width(),top:d.top+c.offsetHeight,left:d.left}).show(),b.scroll&&(o.scrollTop(0),o.css({maxHeight:b.scrollHeight,overflow:"auto"}),a.browser.msie&&"undefined"==typeof document.body.style.maxHeight)){var e=0;l.each(function(){e+=this.offsetHeight});var f=e>b.scrollHeight;o.css("height",f?b.scrollHeight:e),f||l.width(o.width()-parseInt(l.css("padding-left"))-parseInt(l.css("padding-right")))}},selected:function(){var b=l&&l.filter("."+p.ACTIVE).removeClass(p.ACTIVE);return b&&b.length&&a.data(b[0],"ac_data")},unbind:function(){n&&n.remove()}}},a.Autocompleter.Selection=function(a,b,c){if(a.createTextRange){var d=a.createTextRange();d.collapse(!0),d.moveStart("character",b),d.moveEnd("character",c),d.select()}else a.setSelectionRange?a.setSelectionRange(b,c):a.selectionStart&&(a.selectionStart=b,a.selectionEnd=c);a.focus()}}(jQuery);
bp-messages/js/autocomplete/jquery.dimensions.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){a.dimensions={version:"@VERSION"},a.each(["Height","Width"],function(c,d){a.fn["inner"+d]=function(){if(this[0]){var a="Height"==d?"Top":"Left",c="Height"==d?"Bottom":"Right";return this[d.toLowerCase()]()+b(this,"padding"+a)+b(this,"padding"+c)}},a.fn["outer"+d]=function(c){if(this[0]){var e="Height"==d?"Top":"Left",f="Height"==d?"Bottom":"Right";return c=a.extend({margin:!1},c||{}),this[d.toLowerCase()]()+b(this,"border"+e+"Width")+b(this,"border"+f+"Width")+b(this,"padding"+e)+b(this,"padding"+f)+(c.margin?b(this,"margin"+e)+b(this,"margin"+f):0)}}}),a.each(["Left","Top"],function(b,c){a.fn["scroll"+c]=function(b){return this[0]?void 0!=b?this.each(function(){this==window||this==document?window.scrollTo("Left"==c?b:a(window).scrollLeft(),"Top"==c?b:a(window).scrollTop()):this["scroll"+c]=b}):this[0]==window||this[0]==document?self["Left"==c?"pageXOffset":"pageYOffset"]||a.boxModel&&document.documentElement["scroll"+c]||document.body["scroll"+c]:this[0]["scroll"+c]:void 0}}),a.fn.extend({position:function(){var a,c,d,e,f=this[0];return f&&(d=this.offsetParent(),a=this.offset(),c=d.offset(),a.top-=b(f,"marginTop"),a.left-=b(f,"marginLeft"),c.top+=b(d,"borderTopWidth"),c.left+=b(d,"borderLeftWidth"),e={top:a.top-c.top,left:a.left-c.left}),e},offsetParent:function(){for(var b=this[0].offsetParent;b&&!/^body|html$/i.test(b.tagName)&&"static"==a.css(b,"position");)b=b.offsetParent;return a(b)}});var b=function(b,c){return parseInt(a.css(b.jquery?b[0]:b,c))||0}}(jQuery);
1
+ !function(a){a.dimensions={version:"@VERSION"},a.each(["Height","Width"],function(c,d){a.fn["inner"+d]=function(){if(this[0]){var a="Height"==d?"Top":"Left",c="Height"==d?"Bottom":"Right";return this[d.toLowerCase()]()+b(this,"padding"+a)+b(this,"padding"+c)}},a.fn["outer"+d]=function(c){if(this[0]){var e="Height"==d?"Top":"Left",f="Height"==d?"Bottom":"Right";return c=a.extend({margin:!1},c||{}),this[d.toLowerCase()]()+b(this,"border"+e+"Width")+b(this,"border"+f+"Width")+b(this,"padding"+e)+b(this,"padding"+f)+(c.margin?b(this,"margin"+e)+b(this,"margin"+f):0)}}}),a.each(["Left","Top"],function(b,c){a.fn["scroll"+c]=function(b){if(this[0])return void 0!=b?this.each(function(){this==window||this==document?window.scrollTo("Left"==c?b:a(window).scrollLeft(),"Top"==c?b:a(window).scrollTop()):this["scroll"+c]=b}):this[0]==window||this[0]==document?self["Left"==c?"pageXOffset":"pageYOffset"]||a.boxModel&&document.documentElement["scroll"+c]||document.body["scroll"+c]:this[0]["scroll"+c]}}),a.fn.extend({position:function(){var a,c,d,e,f=this[0];return f&&(d=this.offsetParent(),a=this.offset(),c=d.offset(),a.top-=b(f,"marginTop"),a.left-=b(f,"marginLeft"),c.top+=b(d,"borderTopWidth"),c.left+=b(d,"borderLeftWidth"),e={top:a.top-c.top,left:a.left-c.left}),e},offsetParent:function(){for(var b=this[0].offsetParent;b&&!/^body|html$/i.test(b.tagName)&&"static"==a.css(b,"position");)b=b.offsetParent;return a(b)}});var b=function(b,c){return parseInt(a.css(b.jquery?b[0]:b,c))||0}}(jQuery);
bp-notifications/bp-notifications-loader.php CHANGED
@@ -17,7 +17,7 @@ if ( ! buddypress()->do_autoload ) {
17
  }
18
 
19
  /**
20
- * Bootstrap the Notifications component.
21
  *
22
  * @since 1.9.0
23
  */
17
  }
18
 
19
  /**
20
+ * Set up the bp-notifications component.
21
  *
22
  * @since 1.9.0
23
  */
bp-notifications/classes/class-bp-notifications-notification.php CHANGED
@@ -97,7 +97,7 @@ class BP_Notifications_Notification {
97
  */
98
  public function __construct( $id = 0 ) {
99
  if ( ! empty( $id ) ) {
100
- $this->id = $id;
101
  $this->populate();
102
  }
103
  }
@@ -112,22 +112,8 @@ class BP_Notifications_Notification {
112
  * @return bool True on success, false on failure.
113
  */
114
  public function save() {
115
-
116
- // Return value.
117
  $retval = false;
118
 
119
- // Default data and format.
120
- $data = array(
121
- 'user_id' => $this->user_id,
122
- 'item_id' => $this->item_id,
123
- 'secondary_item_id' => $this->secondary_item_id,
124
- 'component_name' => $this->component_name,
125
- 'component_action' => $this->component_action,
126
- 'date_notified' => $this->date_notified,
127
- 'is_new' => $this->is_new,
128
- );
129
- $data_format = array( '%d', '%d', '%d', '%s', '%s', '%s', '%d' );
130
-
131
  /**
132
  * Fires before the current notification item gets saved.
133
  *
@@ -139,6 +125,17 @@ class BP_Notifications_Notification {
139
  */
140
  do_action_ref_array( 'bp_notification_before_save', array( &$this ) );
141
 
 
 
 
 
 
 
 
 
 
 
 
142
  // Update.
143
  if ( ! empty( $this->id ) ) {
144
  $result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) );
@@ -188,13 +185,13 @@ class BP_Notifications_Notification {
188
 
189
  // Setup the notification data.
190
  if ( ! empty( $notification ) && ! is_wp_error( $notification ) ) {
191
- $this->item_id = $notification->item_id;
192
- $this->secondary_item_id = $notification->secondary_item_id;
193
- $this->user_id = $notification->user_id;
194
  $this->component_name = $notification->component_name;
195
  $this->component_action = $notification->component_action;
196
  $this->date_notified = $notification->date_notified;
197
- $this->is_new = $notification->is_new;
198
  }
199
  }
200
 
@@ -687,6 +684,15 @@ class BP_Notifications_Notification {
687
 
688
  $results = $wpdb->get_results( $sql );
689
 
 
 
 
 
 
 
 
 
 
690
  // Update meta cache.
691
  if ( true === $r['update_meta_cache'] ) {
692
  bp_notifications_update_meta_cache( wp_list_pluck( $results, 'id' ) );
@@ -743,7 +749,7 @@ class BP_Notifications_Notification {
743
  $sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql}";
744
 
745
  // Return the queried results.
746
- return $wpdb->get_var( $sql );
747
  }
748
 
749
  /**
97
  */
98
  public function __construct( $id = 0 ) {
99
  if ( ! empty( $id ) ) {
100
+ $this->id = (int) $id;
101
  $this->populate();
102
  }
103
  }
112
  * @return bool True on success, false on failure.
113
  */
114
  public function save() {
 
 
115
  $retval = false;
116
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  /**
118
  * Fires before the current notification item gets saved.
119
  *
125
  */
126
  do_action_ref_array( 'bp_notification_before_save', array( &$this ) );
127
 
128
+ $data = array(
129
+ 'user_id' => $this->user_id,
130
+ 'item_id' => $this->item_id,
131
+ 'secondary_item_id' => $this->secondary_item_id,
132
+ 'component_name' => $this->component_name,
133
+ 'component_action' => $this->component_action,
134
+ 'date_notified' => $this->date_notified,
135
+ 'is_new' => $this->is_new,
136
+ );
137
+ $data_format = array( '%d', '%d', '%d', '%s', '%s', '%s', '%d' );
138
+
139
  // Update.
140
  if ( ! empty( $this->id ) ) {
141
  $result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) );
185
 
186
  // Setup the notification data.
187
  if ( ! empty( $notification ) && ! is_wp_error( $notification ) ) {
188
+ $this->item_id = (int) $notification->item_id;
189
+ $this->secondary_item_id = (int) $notification->secondary_item_id;
190
+ $this->user_id = (int) $notification->user_id;
191
  $this->component_name = $notification->component_name;
192
  $this->component_action = $notification->component_action;
193
  $this->date_notified = $notification->date_notified;
194
+ $this->is_new = (int) $notification->is_new;
195
  }
196
  }
197
 
684
 
685
  $results = $wpdb->get_results( $sql );
686
 
687
+ // Integer casting.
688
+ foreach ( $results as $key => $result ) {
689
+ $results[$key]->id = (int) $results[$key]->id;
690
+ $results[$key]->user_id = (int) $results[$key]->user_id;
691
+ $results[$key]->item_id = (int) $results[$key]->item_id;
692
+ $results[$key]->secondary_item_id = (int) $results[$key]->secondary_item_id;
693
+ $results[$key]->is_new = (int) $results[$key]->is_new;
694
+ }
695
+
696
  // Update meta cache.
697
  if ( true === $r['update_meta_cache'] ) {
698
  bp_notifications_update_meta_cache( wp_list_pluck( $results, 'id' ) );
749
  $sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql}";
750
 
751
  // Return the queried results.
752
+ return (int) $wpdb->get_var( $sql );
753
  }
754
 
755
  /**
bp-settings/bp-settings-actions.php CHANGED
@@ -472,7 +472,7 @@ function bp_settings_verify_email_change(){
472
 
473
  // Email change is being dismissed.
474
  } elseif ( ! empty( $_GET['dismiss_email_change'] ) ) {
475
- bp_delete_user_meta( bp_displayed_user_id(), 'pending_email_change' );
476
  bp_core_add_message( __( 'You have successfully dismissed your pending email change.', 'buddypress' ) );
477
 
478
  bp_core_redirect( $redirect_to );
472
 
473
  // Email change is being dismissed.
474
  } elseif ( ! empty( $_GET['dismiss_email_change'] ) ) {
475
+ bp_delete_user_meta( bp_displayed_user_id(), 'pending_email_change' );
476
  bp_core_add_message( __( 'You have successfully dismissed your pending email change.', 'buddypress' ) );
477
 
478
  bp_core_redirect( $redirect_to );
bp-settings/bp-settings-loader.php CHANGED
@@ -15,7 +15,7 @@ if ( ! buddypress()->do_autoload ) {
15
  }
16
 
17
  /**
18
- * Instantiates the settings component.
19
  *
20
  * @since 1.6.0
21
  */
15
  }
16
 
17
  /**
18
+ * Set up the bp-settings component.
19
  *
20
  * @since 1.6.0
21
  */
bp-templates/bp-legacy/buddypress-functions.php CHANGED
@@ -105,10 +105,12 @@ class BP_Legacy extends BP_Theme_Compat {
105
 
106
  // Group buttons.
107
  if ( bp_is_active( 'groups' ) ) {
108
- add_action( 'bp_group_header_actions', 'bp_group_join_button', 5 );
109
- add_action( 'bp_group_header_actions', 'bp_group_new_topic_button', 20 );
110
- add_action( 'bp_directory_groups_actions', 'bp_group_join_button' );
111
- add_action( 'bp_groups_directory_group_filter', 'bp_legacy_theme_group_create_nav', 999 );
 
 
112
  }
113
 
114
  // Blog button.
@@ -605,6 +607,19 @@ function bp_legacy_theme_group_create_nav() {
605
  bp_group_create_nav_item();
606
  }
607
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
  /**
609
  * Add the Create a Site button to the Sites directory title.
610
  *
@@ -1344,7 +1359,7 @@ function bp_legacy_theme_ajax_addremove_friend() {
1344
  if ( ! friends_remove_friend( bp_loggedin_user_id(), $friend_id ) ) {
1345
  echo __( 'Friendship could not be canceled.', 'buddypress' );
1346
  } else {
1347
- echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" title="' . __( 'Add Friend', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
1348
  }
1349
 
1350
  // Trying to request friendship.
@@ -1354,7 +1369,7 @@ function bp_legacy_theme_ajax_addremove_friend() {
1354
  if ( ! friends_add_friend( bp_loggedin_user_id(), $friend_id ) ) {
1355
  echo __(' Friendship could not be requested.', 'buddypress' );
1356
  } else {
1357
- echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="remove" rel="remove" title="' . __( 'Cancel Friendship Request', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $friend_id . '/', 'friends_withdraw_friendship' ) . '" class="requested">' . __( 'Cancel Friendship Request', 'buddypress' ) . '</a>';
1358
  }
1359
 
1360
  // Trying to cancel pending request.
@@ -1362,7 +1377,7 @@ function bp_legacy_theme_ajax_addremove_friend() {
1362
  check_ajax_referer( 'friends_withdraw_friendship' );
1363
 
1364
  if ( friends_withdraw_friendship( bp_loggedin_user_id(), $friend_id ) ) {
1365
- echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" title="' . __( 'Add Friend', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
1366
  } else {
1367
  echo __("Friendship request could not be cancelled.", 'buddypress');
1368
  }
@@ -1433,7 +1448,7 @@ function bp_legacy_theme_ajax_joinleave_group() {
1433
  if ( groups_is_user_banned( bp_loggedin_user_id(), $group_id ) )
1434
  return;
1435
 
1436
- if ( ! $group = groups_get_group( array( 'group_id' => $group_id ) ) )
1437
  return;
1438
 
1439
  if ( ! groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
@@ -1443,7 +1458,7 @@ function bp_legacy_theme_ajax_joinleave_group() {
1443
  if ( ! groups_join_group( $group->id ) ) {
1444
  _e( 'Error joining group', 'buddypress' );
1445
  } else {
1446
- echo '<a id="group-' . esc_attr( $group->id ) . '" class="leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
1447
  }
1448
 
1449
  } elseif ( 'private' == $group->status ) {
@@ -1456,7 +1471,7 @@ function bp_legacy_theme_ajax_joinleave_group() {
1456
  if ( ! groups_accept_invite( bp_loggedin_user_id(), $group->id ) ) {
1457
  _e( 'Error requesting membership', 'buddypress' );
1458
  } else {
1459
- echo '<a id="group-' . esc_attr( $group->id ) . '" class="leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
1460
  }
1461
 
1462
  // Otherwise, it's a Request Membership button.
@@ -1477,9 +1492,9 @@ function bp_legacy_theme_ajax_joinleave_group() {
1477
  if ( ! groups_leave_group( $group->id ) ) {
1478
  _e( 'Error leaving group', 'buddypress' );
1479
  } elseif ( 'public' == $group->status ) {
1480
- echo '<a id="group-' . esc_attr( $group->id ) . '" class="join-group" rel="join" title="' . __( 'Join Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ) . '">' . __( 'Join Group', 'buddypress' ) . '</a>';
1481
  } elseif ( 'private' == $group->status ) {
1482
- echo '<a id="group-' . esc_attr( $group->id ) . '" class="request-membership" rel="join" title="' . __( 'Request Membership', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_request_membership' ) . '">' . __( 'Request Membership', 'buddypress' ) . '</a>';
1483
  }
1484
  }
1485
 
@@ -1899,3 +1914,20 @@ function bp_legacy_theme_cover_image( $params = array() ) {
1899
  }
1900
  ';
1901
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  // Group buttons.
107
  if ( bp_is_active( 'groups' ) ) {
108
+ add_action( 'bp_group_header_actions', 'bp_group_join_button', 5 );
109
+ add_action( 'bp_group_header_actions', 'bp_group_new_topic_button', 20 );
110
+ add_action( 'bp_directory_groups_actions', 'bp_group_join_button' );
111
+ add_action( 'bp_groups_directory_group_filter', 'bp_legacy_theme_group_create_nav', 999 );
112
+ add_action( 'bp_after_group_admin_content', 'bp_legacy_groups_admin_screen_hidden_input' );
113
+ add_action( 'bp_before_group_admin_form', 'bp_legacy_theme_group_manage_members_add_search' );
114
  }
115
 
116
  // Blog button.
607
  bp_group_create_nav_item();
608
  }
609
 
610
+ /**
611
+ * Renders the group ID hidden input on group admin screens.
612
+ *
613
+ * @since 2.7.0
614
+ *
615
+ * @return string html
616
+ */
617
+ function bp_legacy_groups_admin_screen_hidden_input() {
618
+ ?>
619
+ <input type="hidden" name="group-id" id="group-id" value="<?php bp_group_id(); ?>" />
620
+ <?php
621
+ }
622
+
623
  /**
624
  * Add the Create a Site button to the Sites directory title.
625
  *
1359
  if ( ! friends_remove_friend( bp_loggedin_user_id(), $friend_id ) ) {
1360
  echo __( 'Friendship could not be canceled.', 'buddypress' );
1361
  } else {
1362
+ echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
1363
  }
1364
 
1365
  // Trying to request friendship.
1369
  if ( ! friends_add_friend( bp_loggedin_user_id(), $friend_id ) ) {
1370
  echo __(' Friendship could not be requested.', 'buddypress' );
1371
  } else {
1372
+ echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="remove" rel="remove" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $friend_id . '/', 'friends_withdraw_friendship' ) . '" class="requested">' . __( 'Cancel Friendship Request', 'buddypress' ) . '</a>';
1373
  }
1374
 
1375
  // Trying to cancel pending request.
1377
  check_ajax_referer( 'friends_withdraw_friendship' );
1378
 
1379
  if ( friends_withdraw_friendship( bp_loggedin_user_id(), $friend_id ) ) {
1380
+ echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
1381
  } else {
1382
  echo __("Friendship request could not be cancelled.", 'buddypress');
1383
  }
1448
  if ( groups_is_user_banned( bp_loggedin_user_id(), $group_id ) )
1449
  return;
1450
 
1451
+ if ( ! $group = groups_get_group( $group_id ) )
1452
  return;
1453
 
1454
  if ( ! groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
1458
  if ( ! groups_join_group( $group->id ) ) {
1459
  _e( 'Error joining group', 'buddypress' );
1460
  } else {
1461
+ echo '<a id="group-' . esc_attr( $group->id ) . '" class="group-button leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
1462
  }
1463
 
1464
  } elseif ( 'private' == $group->status ) {
1471
  if ( ! groups_accept_invite( bp_loggedin_user_id(), $group->id ) ) {
1472
  _e( 'Error requesting membership', 'buddypress' );
1473
  } else {
1474
+ echo '<a id="group-' . esc_attr( $group->id ) . '" class="group-button leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
1475
  }
1476
 
1477
  // Otherwise, it's a Request Membership button.
1492
  if ( ! groups_leave_group( $group->id ) ) {
1493
  _e( 'Error leaving group', 'buddypress' );
1494
  } elseif ( 'public' == $group->status ) {
1495
+ echo '<a id="group-' . esc_attr( $group->id ) . '" class="group-button join-group" rel="join" title="' . __( 'Join Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ) . '">' . __( 'Join Group', 'buddypress' ) . '</a>';
1496
  } elseif ( 'private' == $group->status ) {
1497
+ echo '<a id="group-' . esc_attr( $group->id ) . '" class="group-button request-membership" rel="join" title="' . __( 'Request Membership', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_request_membership' ) . '">' . __( 'Request Membership', 'buddypress' ) . '</a>';
1498
  }
1499
  }
1500
 
1914
  }
1915
  ';
1916
  }
1917
+
1918
+ /**
1919
+ * Add a search box to a single group's manage members screen.
1920
+ *
1921
+ * @since 2.7.0
1922
+ *
1923
+ * @return string HTML for the search form.
1924
+ */
1925
+ function bp_legacy_theme_group_manage_members_add_search() {
1926
+ if ( bp_is_action_variable( 'manage-members' ) ) :
1927
+ ?>
1928
+ <div id="members-dir-search" class="dir-search no-ajax" role="search">
1929
+ <?php bp_directory_members_search_form(); ?>
1930
+ </div>
1931
+ <?php
1932
+ endif;
1933
+ }
bp-templates/bp-legacy/buddypress/activity/comment.php CHANGED
@@ -25,8 +25,8 @@ do_action( 'bp_before_activity_comment' ); ?>
25
 
26
  <div class="acomment-meta">
27
  <?php
28
- /* translators: 1: user profile link, 2: user name, 3: activity permalink, 4: activity timestamp */
29
- printf( __( '<a href="%1$s">%2$s</a> replied <a href="%3$s" class="activity-time-since"><span class="time-since">%4$s</span></a>', 'buddypress' ), bp_get_activity_comment_user_link(), bp_get_activity_comment_name(), bp_get_activity_comment_permalink(), bp_get_activity_comment_date_recorded() );
30
  ?>
31
  </div>
32
 
25
 
26
  <div class="acomment-meta">
27
  <?php
28
+ /* translators: 1: user profile link, 2: user name, 3: activity permalink, 4: ISO8601 timestamp, 5: activity relative timestamp */
29
+ printf( __( '<a href="%1$s">%2$s</a> replied <a href="%3$s" class="activity-time-since"><span class="time-since" data-livestamp="%4$s">%5$s</span></a>', 'buddypress' ), bp_get_activity_comment_user_link(), bp_get_activity_comment_name(), bp_get_activity_comment_permalink(), bp_core_get_iso8601_date( bp_get_activity_comment_date_recorded() ), bp_get_activity_comment_date_recorded() );
30
  ?>
31
  </div>
32
 
bp-templates/bp-legacy/buddypress/activity/entry.php CHANGED
@@ -72,11 +72,11 @@ do_action( 'bp_before_activity_entry' ); ?>
72
 
73
  <?php if ( !bp_get_activity_is_favorite() ) : ?>
74
 
75
- <a href="<?php bp_activity_favorite_link(); ?>" class="button fav bp-secondary-action" title="<?php esc_attr_e( 'Mark as Favorite', 'buddypress' ); ?>"><?php _e( 'Favorite', 'buddypress' ); ?></a>
76
 
77
  <?php else : ?>
78
 
79
- <a href="<?php bp_activity_unfavorite_link(); ?>" class="button unfav bp-secondary-action" title="<?php esc_attr_e( 'Remove Favorite', 'buddypress' ); ?>"><?php _e( 'Remove Favorite', 'buddypress' ); ?></a>
80
 
81
  <?php endif; ?>
82
 
72
 
73
  <?php if ( !bp_get_activity_is_favorite() ) : ?>
74
 
75
+ <a href="<?php bp_activity_favorite_link(); ?>" class="button fav bp-secondary-action"><?php _e( 'Favorite', 'buddypress' ); ?></a>
76
 
77
  <?php else : ?>
78
 
79
+ <a href="<?php bp_activity_unfavorite_link(); ?>" class="button unfav bp-secondary-action"><?php _e( 'Remove Favorite', 'buddypress' ); ?></a>
80
 
81
  <?php endif; ?>
82
 
bp-templates/bp-legacy/buddypress/activity/index.php CHANGED
@@ -41,7 +41,7 @@ do_action( 'bp_before_directory_activity' ); ?>
41
  */
42
  do_action( 'template_notices' ); ?>
43
 
44
- <div class="item-list-tabs activity-type-tabs" role="navigation">
45
  <ul>
46
  <?php
47
 
@@ -52,7 +52,7 @@ do_action( 'bp_before_directory_activity' ); ?>
52
  */
53
  do_action( 'bp_before_activity_type_tab_all' ); ?>
54
 
55
- <li class="selected" id="activity-all"><a href="<?php bp_activity_directory_permalink(); ?>" title="<?php esc_attr_e( 'The public activity for everyone on this site.', 'buddypress' ); ?>"><?php printf( __( 'All Members %s', 'buddypress' ), '<span>' . bp_get_total_member_count() . '</span>' ); ?></a></li>
56
 
57
  <?php if ( is_user_logged_in() ) : ?>
58
 
@@ -69,7 +69,7 @@ do_action( 'bp_before_directory_activity' ); ?>
69
 
70
  <?php if ( bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
71
 
72
- <li id="activity-friends"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/'; ?>" title="<?php esc_attr_e( 'The activity of my friends only.', 'buddypress' ); ?>"><?php printf( __( 'My Friends %s', 'buddypress' ), '<span>' . bp_get_total_friend_count( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
73
 
74
  <?php endif; ?>
75
 
@@ -88,7 +88,7 @@ do_action( 'bp_before_directory_activity' ); ?>
88
 
89
  <?php if ( bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ) : ?>
90
 
91
- <li id="activity-groups"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/'; ?>" title="<?php esc_attr_e( 'The activity of groups I am a member of.', 'buddypress' ); ?>"><?php printf( __( 'My Groups %s', 'buddypress' ), '<span>' . bp_get_total_group_count_for_user( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
92
 
93
  <?php endif; ?>
94
 
@@ -105,7 +105,7 @@ do_action( 'bp_before_directory_activity' ); ?>
105
 
106
  <?php if ( bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) ) : ?>
107
 
108
- <li id="activity-favorites"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/favorites/'; ?>" title="<?php esc_attr_e( "The activity I've marked as a favorite.", 'buddypress' ); ?>"><?php printf( __( 'My Favorites %s', 'buddypress' ), '<span>' . bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
109
 
110
  <?php endif; ?>
111
 
@@ -120,7 +120,7 @@ do_action( 'bp_before_directory_activity' ); ?>
120
  */
121
  do_action( 'bp_before_activity_type_tab_mentions' ); ?>
122
 
123
- <li id="activity-mentions"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/'; ?>" title="<?php esc_attr_e( 'Activity that I have been mentioned in.', 'buddypress' ); ?>"><?php _e( 'Mentions', 'buddypress' ); ?><?php if ( bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ) : ?> <strong><span><?php printf( _nx( '%s new', '%s new', bp_get_total_mention_count_for_user( bp_loggedin_user_id() ), 'Number of new activity mentions', 'buddypress' ), bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ); ?></span></strong><?php endif; ?></a></li>
124
 
125
  <?php endif; ?>
126
 
@@ -137,7 +137,7 @@ do_action( 'bp_before_directory_activity' ); ?>
137
  </ul>
138
  </div><!-- .item-list-tabs -->
139
 
140
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
141
  <ul>
142
  <li class="feed"><a href="<?php bp_sitewide_activity_feed_link(); ?>" title="<?php esc_attr_e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
143
 
@@ -180,7 +180,7 @@ do_action( 'bp_before_directory_activity' ); ?>
180
  */
181
  do_action( 'bp_before_directory_activity_list' ); ?>
182
 
183
- <div class="activity">
184
 
185
  <?php bp_get_template_part( 'activity/activity-loop' ); ?>
186
 
41
  */
42
  do_action( 'template_notices' ); ?>
43
 
44
+ <div class="item-list-tabs activity-type-tabs" aria-label="<?php esc_attr_e( 'Sitewide activities navigation', 'buddypress' ); ?>" role="navigation">
45
  <ul>
46
  <?php
47
 
52
  */
53
  do_action( 'bp_before_activity_type_tab_all' ); ?>
54
 
55
+ <li class="selected" id="activity-all"><a href="<?php bp_activity_directory_permalink(); ?>"><?php printf( __( 'All Members %s', 'buddypress' ), '<span>' . bp_get_total_member_count() . '</span>' ); ?></a></li>
56
 
57
  <?php if ( is_user_logged_in() ) : ?>
58
 
69
 
70
  <?php if ( bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
71
 
72
+ <li id="activity-friends"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/'; ?>"><?php printf( __( 'My Friends %s', 'buddypress' ), '<span>' . bp_get_total_friend_count( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
73
 
74
  <?php endif; ?>
75
 
88
 
89
  <?php if ( bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ) : ?>
90
 
91
+ <li id="activity-groups"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/'; ?>"><?php printf( __( 'My Groups %s', 'buddypress' ), '<span>' . bp_get_total_group_count_for_user( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
92
 
93
  <?php endif; ?>
94
 
105
 
106
  <?php if ( bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) ) : ?>
107
 
108
+ <li id="activity-favorites"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/favorites/'; ?>"><?php printf( __( 'My Favorites %s', 'buddypress' ), '<span>' . bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
109
 
110
  <?php endif; ?>
111
 
120
  */
121
  do_action( 'bp_before_activity_type_tab_mentions' ); ?>
122
 
123
+ <li id="activity-mentions"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/'; ?>"><?php _e( 'Mentions', 'buddypress' ); ?><?php if ( bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ) : ?> <strong><span><?php printf( _nx( '%s new', '%s new', bp_get_total_mention_count_for_user( bp_loggedin_user_id() ), 'Number of new activity mentions', 'buddypress' ), bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ); ?></span></strong><?php endif; ?></a></li>
124
 
125
  <?php endif; ?>
126
 
137
  </ul>
138
  </div><!-- .item-list-tabs -->
139
 
140
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Activity secondary navigation', 'buddypress' ); ?>" role="navigation">
141
  <ul>
142
  <li class="feed"><a href="<?php bp_sitewide_activity_feed_link(); ?>" title="<?php esc_attr_e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
143
 
180
  */
181
  do_action( 'bp_before_directory_activity_list' ); ?>
182
 
183
+ <div class="activity" aria-live="polite" aria-atomic="true" aria-relevant="all">
184
 
185
  <?php bp_get_template_part( 'activity/activity-loop' ); ?>
186
 
bp-templates/bp-legacy/buddypress/assets/_attachments/avatars/index.php CHANGED
@@ -35,10 +35,10 @@ do_action( 'bp_attachments_avatar_check_template' );
35
  <script id="tmpl-bp-avatar-delete" type="text/html">
36
  <# if ( 'user' === data.object ) { #>
37
  <p><?php _e( "If you'd like to delete your current profile photo but not upload a new one, please use the delete profile photo button.", 'buddypress' ); ?></p>
38
- <p><a class="button edit" id="bp-delete-avatar" href="#" title="<?php esc_attr_e( 'Delete Profile Photo', 'buddypress' ); ?>"><?php esc_html_e( 'Delete My Profile Photo', 'buddypress' ); ?></a></p>
39
  <# } else if ( 'group' === data.object ) { #>
40
  <p><?php _e( "If you'd like to remove the existing group profile photo but not upload a new one, please use the delete group profile photo button.", 'buddypress' ); ?></p>
41
- <p><a class="button edit" id="bp-delete-avatar" href="#" title="<?php esc_attr_e( 'Delete Group Profile Photo', 'buddypress' ); ?>"><?php esc_html_e( 'Delete Group Profile Photo', 'buddypress' ); ?></a></p>
42
  <# } else { #>
43
  <?php do_action( 'bp_attachments_avatar_delete_template' ); ?>
44
  <# } #>
35
  <script id="tmpl-bp-avatar-delete" type="text/html">
36
  <# if ( 'user' === data.object ) { #>
37
  <p><?php _e( "If you'd like to delete your current profile photo but not upload a new one, please use the delete profile photo button.", 'buddypress' ); ?></p>
38
+ <p><a class="button edit" id="bp-delete-avatar" href="#"><?php esc_html_e( 'Delete My Profile Photo', 'buddypress' ); ?></a></p>
39
  <# } else if ( 'group' === data.object ) { #>
40
  <p><?php _e( "If you'd like to remove the existing group profile photo but not upload a new one, please use the delete group profile photo button.", 'buddypress' ); ?></p>
41
+ <p><a class="button edit" id="bp-delete-avatar" href="#"><?php esc_html_e( 'Delete Group Profile Photo', 'buddypress' ); ?></a></p>
42
  <# } else { #>
43
  <?php do_action( 'bp_attachments_avatar_delete_template' ); ?>
44
  <# } #>
bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php CHANGED
@@ -1,36 +1,36 @@
1
- <?php
2
- /**
3
- * BuddyPress Cover Images main template.
4
- *
5
- * This template is used to inject the BuddyPress Backbone views
6
- * dealing with cover images.
7
- *
8
- * It's also used to create the common Backbone views.
9
- *
10
- * @since 2.4.0
11
- *
12
- * @package BuddyPress
13
- * @subpackage bp-attachments
14
- */
15
-
16
- ?>
17
-
18
- <div class="bp-cover-image"></div>
19
- <div class="bp-cover-image-status"></div>
20
- <div class="bp-cover-image-manage"></div>
21
-
22
- <?php bp_attachments_get_template_part( 'uploader' ); ?>
23
-
24
- <script id="tmpl-bp-cover-image-delete" type="text/html">
25
- <# if ( 'user' === data.object ) { #>
26
- <p><?php _e( "If you'd like to delete your current cover image but not upload a new one, please use the delete Cover Image button.", 'buddypress' ); ?></p>
27
- <p><a class="button edit" id="bp-delete-cover-image" href="#" title="<?php esc_attr_e( 'Delete Cover Image', 'buddypress' ); ?>"><?php esc_html_e( 'Delete My Cover Image', 'buddypress' ); ?></a></p>
28
- <# } else if ( 'group' === data.object ) { #>
29
- <p><?php _e( "If you'd like to remove the existing group cover image but not upload a new one, please use the delete group cover image button.", 'buddypress' ); ?></p>
30
- <p><a class="button edit" id="bp-delete-cover-image" href="#" title="<?php esc_attr_e( 'Delete Cover Image', 'buddypress' ); ?>"><?php esc_html_e( 'Delete Group Cover Image', 'buddypress' ); ?></a></p>
31
- <# } else { #>
32
- <?php do_action( 'bp_attachments_cover_image_delete_template' ); ?>
33
- <# } #>
34
- </script>
35
-
36
- <?php do_action( 'bp_attachments_cover_image_main_template' ); ?>
1
+ <?php
2
+ /**
3
+ * BuddyPress Cover Images main template.
4
+ *
5
+ * This template is used to inject the BuddyPress Backbone views
6
+ * dealing with cover images.
7
+ *
8
+ * It's also used to create the common Backbone views.
9
+ *
10
+ * @since 2.4.0
11
+ *
12
+ * @package BuddyPress
13
+ * @subpackage bp-attachments
14
+ */
15
+
16
+ ?>
17
+
18
+ <div class="bp-cover-image"></div>
19
+ <div class="bp-cover-image-status"></div>
20
+ <div class="bp-cover-image-manage"></div>
21
+
22
+ <?php bp_attachments_get_template_part( 'uploader' ); ?>
23
+
24
+ <script id="tmpl-bp-cover-image-delete" type="text/html">
25
+ <# if ( 'user' === data.object ) { #>
26
+ <p><?php _e( "If you'd like to delete your current cover image but not upload a new one, please use the delete Cover Image button.", 'buddypress' ); ?></p>
27
+ <p><a class="button edit" id="bp-delete-cover-image" href="#"><?php esc_html_e( 'Delete My Cover Image', 'buddypress' ); ?></a></p>
28
+ <# } else if ( 'group' === data.object ) { #>
29
+ <p><?php _e( "If you'd like to remove the existing group cover image but not upload a new one, please use the delete group cover image button.", 'buddypress' ); ?></p>
30
+ <p><a class="button edit" id="bp-delete-cover-image" href="#"><?php esc_html_e( 'Delete Group Cover Image', 'buddypress' ); ?></a></p>
31
+ <# } else { #>
32
+ <?php do_action( 'bp_attachments_cover_image_delete_template' ); ?>
33
+ <# } #>
34
+ </script>
35
+
36
+ <?php do_action( 'bp_attachments_cover_image_main_template' ); ?>
bp-templates/bp-legacy/buddypress/blogs/index.php CHANGED
@@ -33,9 +33,18 @@ do_action( 'bp_before_directory_blogs_page' ); ?>
33
  */
34
  do_action( 'bp_before_directory_blogs_content' ); ?>
35
 
36
- <div id="blog-dir-search" class="dir-search" role="search">
37
- <?php bp_directory_blogs_search_form(); ?>
38
- </div><!-- #blog-dir-search -->
 
 
 
 
 
 
 
 
 
39
 
40
  <?php
41
 
@@ -48,7 +57,7 @@ do_action( 'bp_before_directory_blogs_page' ); ?>
48
 
49
  <form action="" method="post" id="blogs-directory-form" class="dir-form">
50
 
51
- <div class="item-list-tabs" role="navigation">
52
  <ul>
53
  <li class="selected" id="blogs-all"><a href="<?php bp_root_domain(); ?>/<?php bp_blogs_root_slug(); ?>"><?php printf( __( 'All Sites %s', 'buddypress' ), '<span>' . bp_get_total_blog_count() . '</span>' ); ?></a></li>
54
 
@@ -70,7 +79,7 @@ do_action( 'bp_before_directory_blogs_page' ); ?>
70
  </ul>
71
  </div><!-- .item-list-tabs -->
72
 
73
- <div class="item-list-tabs" id="subnav" role="navigation">
74
  <ul>
75
 
76
  <?php
@@ -104,6 +113,8 @@ do_action( 'bp_before_directory_blogs_page' ); ?>
104
  </ul>
105
  </div>
106
 
 
 
107
  <div id="blogs-dir-list" class="blogs dir-list">
108
 
109
  <?php bp_get_template_part( 'blogs/blogs-loop' ); ?>
33
  */
34
  do_action( 'bp_before_directory_blogs_content' ); ?>
35
 
36
+ <?php /* Backward compatibility for inline search form. Use template part instead. */ ?>
37
+ <?php if ( has_filter( 'bp_directory_blogs_search_form' ) ) : ?>
38
+
39
+ <div id="blog-dir-search" class="dir-search" role="search">
40
+ <?php bp_directory_blogs_search_form(); ?>
41
+ </div><!-- #blog-dir-search -->
42
+
43
+ <?php else : ?>
44
+
45
+ <?php bp_get_template_part( 'common/search/dir-search-form' ); ?>
46
+
47
+ <?php endif; ?>
48
 
49
  <?php
50
 
57
 
58
  <form action="" method="post" id="blogs-directory-form" class="dir-form">
59
 
60
+ <div class="item-list-tabs" aria-label="<?php esc_attr_e( 'Sites directory main navigation', 'buddypress' ); ?>" role="navigation">
61
  <ul>
62
  <li class="selected" id="blogs-all"><a href="<?php bp_root_domain(); ?>/<?php bp_blogs_root_slug(); ?>"><?php printf( __( 'All Sites %s', 'buddypress' ), '<span>' . bp_get_total_blog_count() . '</span>' ); ?></a></li>
63
 
79
  </ul>
80
  </div><!-- .item-list-tabs -->
81
 
82
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Sites directory secondary navigation', 'buddypress' ); ?>" role="navigation">
83
  <ul>
84
 
85
  <?php
113
  </ul>
114
  </div>
115
 
116
+ <h2 class="bp-screen-reader-text"><?php _e( 'Sites directory', 'buddypress' ); ?></h2>
117
+
118
  <div id="blogs-dir-list" class="blogs dir-list">
119
 
120
  <?php bp_get_template_part( 'blogs/blogs-loop' ); ?>
bp-templates/bp-legacy/buddypress/common/search/dir-search-form.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Output the search form markup.
4
+ *
5
+ * @since 2.7.0
6
+ */
7
+ ?>
8
+
9
+ <div id="<?php echo esc_attr( bp_current_component() ); ?>-dir-search" class="dir-search" role="search">
10
+ <form action="" method="get" id="search-<?php echo esc_attr( bp_current_component() ); ?>-form">
11
+ <label for="<?php bp_search_input_name(); ?>" class="bp-screen-reader-text"><?php bp_search_placeholder(); ?></label>
12
+ <input type="text" name="<?php echo esc_attr( bp_core_get_component_search_query_arg() ); ?>" id="<?php bp_search_input_name(); ?>" placeholder="<?php bp_search_placeholder(); ?>" />
13
+
14
+ <input type="submit" id="<?php echo esc_attr( bp_get_search_input_name() ); ?>_submit" name="<?php bp_search_input_name(); ?>_submit" value="<?php echo esc_html( 'Search', 'buddypress' ); ?>" />
15
+ </form>
16
+ </div><!-- #<?php echo esc_attr( bp_current_component() ); ?>-dir-search -->
bp-templates/bp-legacy/buddypress/forums/index.php CHANGED
@@ -29,11 +29,19 @@
29
  */
30
  do_action( 'bp_before_directory_forums_content' ); ?>
31
 
32
- <div id="forums-dir-search" class="dir-search" role="search">
 
33
 
34
- <?php bp_directory_forums_search_form(); ?>
 
 
 
 
 
 
 
 
35
 
36
- </div>
37
  </form>
38
 
39
  <?php
@@ -47,7 +55,7 @@
47
 
48
  <form action="" method="post" id="forums-directory-form" class="dir-form">
49
 
50
- <div class="item-list-tabs" role="navigation">
51
  <ul>
52
  <li class="selected" id="forums-all"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() ); ?>"><?php printf( __( 'All Topics %s', 'buddypress' ), '<span>' . bp_get_forum_topic_count() . '</span>' ); ?></a></li>
53
 
@@ -69,7 +77,7 @@
69
  </ul>
70
  </div>
71
 
72
- <div class="item-list-tabs" id="subnav" role="navigation">
73
  <ul>
74
 
75
  <?php
29
  */
30
  do_action( 'bp_before_directory_forums_content' ); ?>
31
 
32
+ <?php /* Backward compatibility for inline search form. Use template part instead. */ ?>
33
+ <?php if ( has_filter( 'bp_directory_forums_search_form' ) ) : ?>
34
 
35
+ <div id="forums-dir-search" class="dir-search" role="search">
36
+ <?php bp_directory_forums_search_form(); ?>
37
+ </div>
38
+
39
+ <?php else: ?>
40
+
41
+ <?php bp_get_template_part( 'common/search/dir-search-form' ); ?>
42
+
43
+ <?php endif; ?>
44
 
 
45
  </form>
46
 
47
  <?php
55
 
56
  <form action="" method="post" id="forums-directory-form" class="dir-form">
57
 
58
+ <div class="item-list-tabs" aria-label="<?php esc_attr_e( 'Forums directory main navigation', 'buddypress' ); ?>" role="navigation">
59
  <ul>
60
  <li class="selected" id="forums-all"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() ); ?>"><?php printf( __( 'All Topics %s', 'buddypress' ), '<span>' . bp_get_forum_topic_count() . '</span>' ); ?></a></li>
61
 
77
  </ul>
78
  </div>
79
 
80
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Forums secondary navigation', 'buddypress' ); ?>" role="navigation">
81
  <ul>
82
 
83
  <?php
bp-templates/bp-legacy/buddypress/groups/create.php CHANGED
@@ -35,7 +35,7 @@ do_action( 'bp_before_create_group_page' ); ?>
35
  */
36
  do_action( 'bp_before_create_group' ); ?>
37
 
38
- <div class="item-list-tabs no-ajax" id="group-create-tabs" role="navigation">
39
  <ul>
40
 
41
  <?php bp_group_creation_tabs(); ?>
@@ -53,6 +53,8 @@ do_action( 'bp_before_create_group_page' ); ?>
53
  <?php /* Group creation step 1: Basic group details */ ?>
54
  <?php if ( bp_is_group_creation_step( 'group-details' ) ) : ?>
55
 
 
 
56
  <?php
57
 
58
  /**
@@ -89,6 +91,8 @@ do_action( 'bp_before_create_group_page' ); ?>
89
  <?php /* Group creation step 2: Group settings */ ?>
90
  <?php if ( bp_is_group_creation_step( 'group-settings' ) ) : ?>
91
 
 
 
92
  <?php
93
 
94
  /**
@@ -98,51 +102,82 @@ do_action( 'bp_before_create_group_page' ); ?>
98
  */
99
  do_action( 'bp_before_group_settings_creation_step' ); ?>
100
 
101
- <h4><?php _e( 'Privacy Options', 'buddypress' ); ?></h4>
102
 
103
- <div class="radio">
104
 
105
- <label for="group-status-public"><input type="radio" name="group-status" id="group-status-public" value="public"<?php if ( 'public' == bp_get_new_group_status() || !bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="public-group-description" /> <?php _e( 'This is a public group', 'buddypress' ); ?></label>
106
 
107
- <ul id="public-group-description">
108
- <li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
109
- <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
110
- <li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
111
- </ul>
112
 
 
 
 
 
 
113
 
114
- <label for="group-status-private"><input type="radio" name="group-status" id="group-status-private" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="private-group-description" /> <?php _e( 'This is a private group', 'buddypress' ); ?></label>
115
 
116
- <ul id="private-group-description">
117
- <li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
118
- <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
119
- <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
120
- </ul>
121
 
 
122
 
123
- <label for="group-status-hidden"><input type="radio" name="group-status" id="group-status-hidden" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="hidden-group-description" /> <?php _e('This is a hidden group', 'buddypress' ); ?></label>
 
 
 
 
124
 
125
- <ul id="hidden-group-description">
126
- <li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
127
- <li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
128
- <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
129
- </ul>
130
 
131
- </div>
132
 
133
- <h4><?php _e( 'Group Invitations', 'buddypress' ); ?></h4>
 
134
 
135
- <p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
 
136
 
137
- <div class="radio">
138
 
139
- <label for="group-invite-status-members"><input type="radio" name="group-invite-status" id="group-invite-status-members" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> /> <?php _e( 'All group members', 'buddypress' ); ?></label>
 
 
 
 
 
 
 
 
 
140
 
141
- <label for="group-invite-status-mods"><input type="radio" name="group-invite-status" id="group-invite-status-mods" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> /> <?php _e( 'Group admins and mods only', 'buddypress' ); ?></label>
142
 
143
- <label for="group-invite-status-admins"><input type="radio" name="group-invite-status" id="group-invite-status-admins" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> /> <?php _e( 'Group admins only', 'buddypress' ); ?></label>
144
 
145
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  <?php if ( bp_is_active( 'forums' ) ) : ?>
148
 
@@ -179,6 +214,8 @@ do_action( 'bp_before_create_group_page' ); ?>
179
  <?php /* Group creation step 3: Avatar Uploads */ ?>
180
  <?php if ( bp_is_group_creation_step( 'group-avatar' ) ) : ?>
181
 
 
 
182
  <?php
183
 
184
  /**
@@ -259,6 +296,8 @@ do_action( 'bp_before_create_group_page' ); ?>
259
  <?php /* Group creation step 4: Cover image */ ?>
260
  <?php if ( bp_is_group_creation_step( 'group-cover-image' ) ) : ?>
261
 
 
 
262
  <?php
263
 
264
  /**
@@ -290,6 +329,8 @@ do_action( 'bp_before_create_group_page' ); ?>
290
  <?php /* Group creation step 5: Invite friends to group */ ?>
291
  <?php if ( bp_is_group_creation_step( 'group-invites' ) ) : ?>
292
 
 
 
293
  <?php
294
 
295
  /**
35
  */
36
  do_action( 'bp_before_create_group' ); ?>
37
 
38
+ <div class="item-list-tabs no-ajax" id="group-create-tabs">
39
  <ul>
40
 
41
  <?php bp_group_creation_tabs(); ?>
53
  <?php /* Group creation step 1: Basic group details */ ?>
54
  <?php if ( bp_is_group_creation_step( 'group-details' ) ) : ?>
55
 
56
+ <h2 class="bp-screen-reader-text"><?php _e( 'Group Details', 'buddypress' ); ?></h2>
57
+
58
  <?php
59
 
60
  /**
91
  <?php /* Group creation step 2: Group settings */ ?>
92
  <?php if ( bp_is_group_creation_step( 'group-settings' ) ) : ?>
93
 
94
+ <h2 class="bp-screen-reader-text"><?php _e( 'Group Settings', 'buddypress' ); ?></h2>
95
+
96
  <?php
97
 
98
  /**
102
  */
103
  do_action( 'bp_before_group_settings_creation_step' ); ?>
104
 
105
+ <fieldset class="group-create-privacy">
106
 
107
+ <legend><?php _e( 'Privacy Options', 'buddypress' ); ?></legend>
108
 
109
+ <div class="radio">
110
 
111
+ <label for="group-status-public"><input type="radio" name="group-status" id="group-status-public" value="public"<?php if ( 'public' == bp_get_new_group_status() || !bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="public-group-description" /> <?php _e( 'This is a public group', 'buddypress' ); ?></label>
 
 
 
 
112
 
113
+ <ul id="public-group-description">
114
+ <li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
115
+ <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
116
+ <li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
117
+ </ul>
118
 
119
+ <label for="group-status-private"><input type="radio" name="group-status" id="group-status-private" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="private-group-description" /> <?php _e( 'This is a private group', 'buddypress' ); ?></label>
120
 
121
+ <ul id="private-group-description">
122
+ <li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
123
+ <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
124
+ <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
125
+ </ul>
126
 
127
+ <label for="group-status-hidden"><input type="radio" name="group-status" id="group-status-hidden" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="hidden-group-description" /> <?php _e('This is a hidden group', 'buddypress' ); ?></label>
128
 
129
+ <ul id="hidden-group-description">
130
+ <li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
131
+ <li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
132
+ <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
133
+ </ul>
134
 
135
+ </div>
 
 
 
 
136
 
137
+ </fieldset>
138
 
139
+ <?php // Group type selection ?>
140
+ <?php if ( $group_types = bp_groups_get_group_types( array( 'show_in_create_screen' => true ), 'objects' ) ): ?>
141
 
142
+ <fieldset class="group-create-types">
143
+ <legend><?php _e( 'Group Types', 'buddypress' ); ?></legend>
144
 
145
+ <p><?php _e( 'Select the types this group should be a part of.', 'buddypress' ); ?></p>
146
 
147
+ <?php foreach ( $group_types as $type ) : ?>
148
+ <div class="checkbox">
149
+ <label for="<?php printf( 'group-type-%s', $type->name ); ?>"><input type="checkbox" name="group-types[]" id="<?php printf( 'group-type-%s', $type->name ); ?>" value="<?php echo esc_attr( $type->name ); ?>" /> <?php echo esc_html( $type->labels['name'] ); ?>
150
+ <?php
151
+ if ( isset( $type->description ) ) {
152
+ printf( __( '&ndash; %s', 'buddypress' ), '<span class="bp-group-type-desc">' . $type->description . '</span>' );
153
+ }
154
+ ?>
155
+ </label>
156
+ </div>
157
 
158
+ <?php endforeach; ?>
159
 
160
+ </fieldset>
161
 
162
+ <?php endif; ?>
163
+
164
+ <fieldset class="group-create-invitations">
165
+
166
+ <legend><?php _e( 'Group Invitations', 'buddypress' ); ?></legend>
167
+
168
+ <p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
169
+
170
+ <div class="radio">
171
+
172
+ <label for="group-invite-status-members"><input type="radio" name="group-invite-status" id="group-invite-status-members" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> /> <?php _e( 'All group members', 'buddypress' ); ?></label>
173
+
174
+ <label for="group-invite-status-mods"><input type="radio" name="group-invite-status" id="group-invite-status-mods" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> /> <?php _e( 'Group admins and mods only', 'buddypress' ); ?></label>
175
+
176
+ <label for="group-invite-status-admins"><input type="radio" name="group-invite-status" id="group-invite-status-admins" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> /> <?php _e( 'Group admins only', 'buddypress' ); ?></label>
177
+
178
+ </div>
179
+
180
+ </fieldset>
181
 
182
  <?php if ( bp_is_active( 'forums' ) ) : ?>
183
 
214
  <?php /* Group creation step 3: Avatar Uploads */ ?>
215
  <?php if ( bp_is_group_creation_step( 'group-avatar' ) ) : ?>
216
 
217
+ <h2 class="bp-screen-reader-text"><?php _e( 'Group Avatar', 'buddypress' ); ?></h2>
218
+
219
  <?php
220
 
221
  /**
296
  <?php /* Group creation step 4: Cover image */ ?>
297
  <?php if ( bp_is_group_creation_step( 'group-cover-image' ) ) : ?>
298
 
299
+ <h2 class="bp-screen-reader-text"><?php _e( 'Cover Image', 'buddypress' ); ?></h2>
300
+
301
  <?php
302
 
303
  /**
329
  <?php /* Group creation step 5: Invite friends to group */ ?>
330
  <?php if ( bp_is_group_creation_step( 'group-invites' ) ) : ?>
331
 
332
+ <h2 class="bp-screen-reader-text"><?php _e( 'Group Invites', 'buddypress' ); ?></h2>
333
+
334
  <?php
335
 
336
  /**
bp-templates/bp-legacy/buddypress/groups/groups-loop.php CHANGED
@@ -19,6 +19,10 @@
19
  */
20
  do_action( 'bp_before_groups_loop' ); ?>
21
 
 
 
 
 
22
  <?php if ( bp_has_groups( bp_ajax_querystring( 'groups' ) ) ) : ?>
23
 
24
  <div id="pag-top" class="pagination">
@@ -59,7 +63,7 @@ do_action( 'bp_before_groups_loop' ); ?>
59
 
60
  <div class="item">
61
  <div class="item-title"><a href="<?php bp_group_permalink(); ?>"><?php bp_group_name(); ?></a></div>
62
- <div class="item-meta"><span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span></div>
63
 
64
  <div class="item-desc"><?php bp_group_description_excerpt(); ?></div>
65
 
19
  */
20
  do_action( 'bp_before_groups_loop' ); ?>
21
 
22
+ <?php if ( bp_get_current_group_directory_type() ) : ?>
23
+ <p class="current-group-type"><?php bp_current_group_directory_type_message() ?></p>
24
+ <?php endif; ?>
25
+
26
  <?php if ( bp_has_groups( bp_ajax_querystring( 'groups' ) ) ) : ?>
27
 
28
  <div id="pag-top" class="pagination">
63
 
64
  <div class="item">
65
  <div class="item-title"><a href="<?php bp_group_permalink(); ?>"><?php bp_group_name(); ?></a></div>
66
+ <div class="item-meta"><span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_group_last_active( 0, array( 'relative' => false ) ) ); ?>"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span></div>
67
 
68
  <div class="item-desc"><?php bp_group_description_excerpt(); ?></div>
69
 
bp-templates/bp-legacy/buddypress/groups/index.php CHANGED
@@ -33,9 +33,18 @@ do_action( 'bp_before_directory_groups_page' ); ?>
33
  */
34
  do_action( 'bp_before_directory_groups_content' ); ?>
35
 
36
- <div id="group-dir-search" class="dir-search" role="search">
37
- <?php bp_directory_groups_search_form(); ?>
38
- </div><!-- #group-dir-search -->
 
 
 
 
 
 
 
 
 
39
 
40
  <form action="" method="post" id="groups-directory-form" class="dir-form">
41
 
@@ -44,7 +53,7 @@ do_action( 'bp_before_directory_groups_page' ); ?>
44
  /** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
45
  do_action( 'template_notices' ); ?>
46
 
47
- <div class="item-list-tabs" role="navigation">
48
  <ul>
49
  <li class="selected" id="groups-all"><a href="<?php bp_groups_directory_permalink(); ?>"><?php printf( __( 'All Groups %s', 'buddypress' ), '<span>' . bp_get_total_group_count() . '</span>' ); ?></a></li>
50
 
@@ -64,7 +73,7 @@ do_action( 'bp_before_directory_groups_page' ); ?>
64
  </ul>
65
  </div><!-- .item-list-tabs -->
66
 
67
- <div class="item-list-tabs" id="subnav" role="navigation">
68
  <ul>
69
  <?php
70
 
@@ -98,6 +107,8 @@ do_action( 'bp_before_directory_groups_page' ); ?>
98
  </ul>
99
  </div>
100
 
 
 
101
  <div id="groups-dir-list" class="groups dir-list">
102
  <?php bp_get_template_part( 'groups/groups-loop' ); ?>
103
  </div><!-- #groups-dir-list -->
33
  */
34
  do_action( 'bp_before_directory_groups_content' ); ?>
35
 
36
+ <?php /* Backward compatibility for inline search form. Use template part instead. */ ?>
37
+ <?php if ( has_filter( 'bp_directory_groups_search_form' ) ) : ?>
38
+
39
+ <div id="group-dir-search" class="dir-search" role="search">
40
+ <?php bp_directory_groups_search_form(); ?>
41
+ </div><!-- #group-dir-search -->
42
+
43
+ <?php else: ?>
44
+
45
+ <?php bp_get_template_part( 'common/search/dir-search-form' ); ?>
46
+
47
+ <?php endif; ?>
48
 
49
  <form action="" method="post" id="groups-directory-form" class="dir-form">
50
 
53
  /** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
54
  do_action( 'template_notices' ); ?>
55
 
56
+ <div class="item-list-tabs" aria-label="<?php esc_attr_e( 'Groups directory main navigation', 'buddypress' ); ?>">
57
  <ul>
58
  <li class="selected" id="groups-all"><a href="<?php bp_groups_directory_permalink(); ?>"><?php printf( __( 'All Groups %s', 'buddypress' ), '<span>' . bp_get_total_group_count() . '</span>' ); ?></a></li>
59
 
73
  </ul>
74
  </div><!-- .item-list-tabs -->
75
 
76
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Groups directory secondary navigation', 'buddypress' ); ?>" role="navigation">
77
  <ul>
78
  <?php
79
 
107
  </ul>
108
  </div>
109
 
110
+ <h2 class="bp-screen-reader-text"><?php _e( 'Groups directory', 'buddypress' ); ?></h2>
111
+
112
  <div id="groups-dir-list" class="groups dir-list">
113
  <?php bp_get_template_part( 'groups/groups-loop' ); ?>
114
  </div><!-- #groups-dir-list -->
bp-templates/bp-legacy/buddypress/groups/single/activity.php CHANGED
@@ -7,7 +7,7 @@
7
  */
8
 
9
  ?>
10
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
11
  <ul>
12
  <li class="feed"><a href="<?php bp_group_activity_feed_link(); ?>" title="<?php esc_attr_e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
13
 
@@ -72,7 +72,7 @@ do_action( 'bp_after_group_activity_post_form' ); ?>
72
  */
73
  do_action( 'bp_before_group_activity_content' ); ?>
74
 
75
- <div class="activity single-group">
76
 
77
  <?php bp_get_template_part( 'activity/activity-loop' ); ?>
78
 
7
  */
8
 
9
  ?>
10
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Group secondary navigation', 'buddypress' ); ?>" role="navigation">
11
  <ul>
12
  <li class="feed"><a href="<?php bp_group_activity_feed_link(); ?>" title="<?php esc_attr_e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
13
 
72
  */
73
  do_action( 'bp_before_group_activity_content' ); ?>
74
 
75
+ <div class="activity single-group" aria-live="polite" aria-atomic="true" aria-relevant="all">
76
 
77
  <?php bp_get_template_part( 'activity/activity-loop' ); ?>
78
 
bp-templates/bp-legacy/buddypress/groups/single/admin.php CHANGED
@@ -7,501 +7,64 @@
7
  */
8
 
9
  ?>
10
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
11
  <ul>
12
  <?php bp_group_admin_tabs(); ?>
13
  </ul>
14
  </div><!-- .item-list-tabs -->
15
 
16
- <form action="<?php bp_group_admin_form_action(); ?>" name="group-settings-form" id="group-settings-form" class="standard-form" method="post" enctype="multipart/form-data">
17
-
18
  <?php
19
-
20
  /**
21
- * Fires inside the group admin form and before the content.
22
  *
23
- * @since 1.1.0
24
  */
25
- do_action( 'bp_before_group_admin_content' ); ?>
26
-
27
- <?php /* Edit Group Details */ ?>
28
- <?php if ( bp_is_group_admin_screen( 'edit-details' ) ) : ?>
29
-
30
- <?php
31
-
32
- /**
33
- * Fires before the display of group admin details.
34
- *
35
- * @since 1.1.0
36
- */
37
- do_action( 'bp_before_group_details_admin' ); ?>
38
-
39
- <label for="group-name"><?php _e( 'Group Name (required)', 'buddypress' ); ?></label>
40
- <input type="text" name="group-name" id="group-name" value="<?php bp_group_name(); ?>" aria-required="true" />
41
-
42
- <label for="group-desc"><?php _e( 'Group Description (required)', 'buddypress' ); ?></label>
43
- <textarea name="group-desc" id="group-desc" aria-required="true"><?php bp_group_description_editable(); ?></textarea>
44
-
45
- <?php
46
-
47
- /**
48
- * Fires after the group description admin details.
49
- *
50
- * @since 1.0.0
51
- */
52
- do_action( 'groups_custom_group_fields_editable' ); ?>
53
-
54
- <p>
55
- <label for="group-notify-members">
56
- <input type="checkbox" name="group-notify-members" id="group-notify-members" value="1" /> <?php _e( 'Notify group members of these changes via email', 'buddypress' ); ?>
57
- </label>
58
- </p>
59
-
60
- <?php
61
-
62
- /**
63
- * Fires after the display of group admin details.
64
- *
65
- * @since 1.1.0
66
- */
67
- do_action( 'bp_after_group_details_admin' ); ?>
68
-
69
- <p><input type="submit" value="<?php esc_attr_e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
70
- <?php wp_nonce_field( 'groups_edit_group_details' ); ?>
71
-
72
- <?php endif; ?>
73
-
74
- <?php /* Manage Group Settings */ ?>
75
- <?php if ( bp_is_group_admin_screen( 'group-settings' ) ) : ?>
76
-
77
- <?php
78
-
79
- /**
80
- * Fires before the group settings admin display.
81
- *
82
- * @since 1.1.0
83
- */
84
- do_action( 'bp_before_group_settings_admin' ); ?>
85
-
86
- <?php if ( bp_is_active( 'forums' ) ) : ?>
87
-
88
- <?php if ( bp_forums_is_installed_correctly() ) : ?>
89
-
90
- <div class="checkbox">
91
- <label for="group-show-forum"><input type="checkbox" name="group-show-forum" id="group-show-forum" value="1"<?php bp_group_show_forum_setting(); ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ); ?></label>
92
- </div>
93
-
94
- <hr />
95
-
96
- <?php endif; ?>
97
-
98
- <?php endif; ?>
99
-
100
- <h4><?php _e( 'Privacy Options', 'buddypress' ); ?></h4>
101
-
102
- <div class="radio">
103
-
104
- <label for="group-status-public"><input type="radio" name="group-status" id="group-status-public" value="public"<?php if ( 'public' == bp_get_new_group_status() || !bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="public-group-description" /> <?php _e( 'This is a public group', 'buddypress' ); ?></label>
105
-
106
- <ul id="public-group-description">
107
- <li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
108
- <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
109
- <li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
110
- </ul>
111
-
112
- <label for="group-status-private"><input type="radio" name="group-status" id="group-status-private" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="private-group-description" /> <?php _e( 'This is a private group', 'buddypress' ); ?></label>
113
-
114
- <ul id="private-group-description">
115
- <li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
116
- <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
117
- <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
118
- </ul>
119
 
120
- <label for="group-status-hidden"><input type="radio" name="group-status" id="group-status-hidden" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="hidden-group-description" /> <?php _e('This is a hidden group', 'buddypress' ); ?></label>
121
-
122
- <ul id="hidden-group-description">
123
- <li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
124
- <li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
125
- <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
126
- </ul>
127
-
128
- </div>
129
-
130
- <hr />
131
-
132
- <h4><?php _e( 'Group Invitations', 'buddypress' ); ?></h4>
133
-
134
- <p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
135
-
136
- <div class="radio">
137
-
138
- <label for="group-invite-status-members"><input type="radio" name="group-invite-status" id="group-invite-status-members" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> /> <?php _e( 'All group members', 'buddypress' ); ?></label>
139
-
140
- <label for="group-invite-status-mods"><input type="radio" name="group-invite-status" id="group-invite-status-mods" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> /> <?php _e( 'Group admins and mods only', 'buddypress' ); ?></label>
141
-
142
- <label for="group-invite-status-admins"><input type="radio" name="group-invite-status" id="group-invite-status-admins" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> /> <?php _e( 'Group admins only', 'buddypress' ); ?></label>
143
-
144
- </div>
145
-
146
- <hr />
147
 
148
  <?php
149
-
150
  /**
151
- * Fires after the group settings admin display.
152
  *
153
  * @since 1.1.0
154
  */
155
- do_action( 'bp_after_group_settings_admin' ); ?>
156
 
157
- <p><input type="submit" value="<?php esc_attr_e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
158
- <?php wp_nonce_field( 'groups_edit_group_settings' ); ?>
159
 
160
- <?php endif; ?>
161
 
162
- <?php /* Group Avatar Settings */ ?>
163
- <?php if ( bp_is_group_admin_screen( 'group-avatar' ) ) : ?>
164
-
165
- <?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
166
-
167
- <p><?php _e("Upload an image to use as a profile photo for this group. The image will be shown on the main group page, and in search results.", 'buddypress' ); ?></p>
168
-
169
- <p>
170
- <label for="file" class="bp-screen-reader-text"><?php
171
- /* translators: accessibility text */
172
- _e( 'Select an image', 'buddypress' );
173
- ?></label>
174
- <input type="file" name="file" id="file" />
175
- <input type="submit" name="upload" id="upload" value="<?php esc_attr_e( 'Upload Image', 'buddypress' ); ?>" />
176
- <input type="hidden" name="action" id="action" value="bp_avatar_upload" />
177
- </p>
178
-
179
- <?php if ( bp_get_group_has_avatar() ) : ?>
180
-
181
- <p><?php _e( "If you'd like to remove the existing group profile photo but not upload a new one, please use the delete group profile photo button.", 'buddypress' ); ?></p>
182
-
183
- <?php bp_button( array( 'id' => 'delete_group_avatar', 'component' => 'groups', 'wrapper_id' => 'delete-group-avatar-button', 'link_class' => 'edit', 'link_href' => bp_get_group_avatar_delete_link(), 'link_title' => __( 'Delete Group Profile Photo', 'buddypress' ), 'link_text' => __( 'Delete Group Profile Photo', 'buddypress' ) ) ); ?>
184
-
185
- <?php endif; ?>
186
-
187
- <?php
188
- /**
189
- * Load the Avatar UI templates
190
- *
191
- * @since 2.3.0
192
- */
193
- bp_avatar_get_templates(); ?>
194
-
195
- <?php wp_nonce_field( 'bp_avatar_upload' ); ?>
196
 
197
  <?php endif; ?>
198
 
199
- <?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
200
-
201
- <h4><?php _e( 'Crop Profile Photo', 'buddypress' ); ?></h4>
202
-
203
- <img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php esc_attr_e( 'Profile photo to crop', 'buddypress' ); ?>" />
204
-
205
- <div id="avatar-crop-pane">
206
- <img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php esc_attr_e( 'Profile photo preview', 'buddypress' ); ?>" />
207
- </div>
208
-
209
- <input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php esc_attr_e( 'Crop Image', 'buddypress' ); ?>" />
210
-
211
- <input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
212
- <input type="hidden" id="x" name="x" />
213
- <input type="hidden" id="y" name="y" />
214
- <input type="hidden" id="w" name="w" />
215
- <input type="hidden" id="h" name="h" />
216
-
217
- <?php wp_nonce_field( 'bp_avatar_cropstore' ); ?>
218
-
219
- <?php endif; ?>
220
-
221
- <?php endif; ?>
222
-
223
- <?php /* Group Cover image Settings */ ?>
224
- <?php if ( bp_is_group_admin_screen( 'group-cover-image' ) ) : ?>
225
-
226
- <h4><?php _e( 'Change Cover Image', 'buddypress' ); ?></h4>
227
-
228
- <?php
229
-
230
- /**
231
- * Fires before the display of profile cover image upload content.
232
- *
233
- * @since 2.4.0
234
- */
235
- do_action( 'bp_before_group_settings_cover_image' ); ?>
236
-
237
- <p><?php _e( 'The Cover Image will be used to customize the header of your group.', 'buddypress' ); ?></p>
238
-
239
- <?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
240
-
241
  <?php
242
 
243
  /**
244
- * Fires after the display of group cover image upload content.
245
  *
246
- * @since 2.4.0
247
- */
248
- do_action( 'bp_after_group_settings_cover_image' ); ?>
249
-
250
- <?php endif; ?>
251
-
252
- <?php /* Manage Group Members */ ?>
253
- <?php if ( bp_is_group_admin_screen( 'manage-members' ) ) : ?>
254
-
255
- <?php
256
-
257
- /**
258
- * Fires before the group manage members admin display.
259
  *
260
  * @since 1.1.0
261
  */
262
- do_action( 'bp_before_group_manage_members_admin' ); ?>
263
-
264
- <div class="bp-widget">
265
- <h4><?php _e( 'Administrators', 'buddypress' ); ?></h4>
266
-
267
- <?php if ( bp_has_members( '&include='. bp_group_admin_ids() ) ) : ?>
268
-
269
- <ul id="admins-list" class="item-list single-line">
270
-
271
- <?php while ( bp_members() ) : bp_the_member(); ?>
272
- <li>
273
- <?php echo bp_core_fetch_avatar( array( 'item_id' => bp_get_member_user_id(), 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_member_name() ) ) ); ?>
274
- <h5>
275
- <a href="<?php bp_member_permalink(); ?>"> <?php bp_member_name(); ?></a>
276
- <?php if ( count( bp_group_admin_ids( false, 'array' ) ) > 1 ) : ?>
277
- <span class="small">
278
- <a class="button confirm admin-demote-to-member" href="<?php bp_group_member_demote_link( bp_get_member_user_id() ); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
279
- </span>
280
- <?php endif; ?>
281
- </h5>
282
- </li>
283
- <?php endwhile; ?>
284
-
285
- </ul>
286
-
287
- <?php endif; ?>
288
-
289
- </div>
290
-
291
- <?php if ( bp_group_has_moderators() ) : ?>
292
- <div class="bp-widget">
293
- <h4><?php _e( 'Moderators', 'buddypress' ); ?></h4>
294
-
295
- <?php if ( bp_has_members( '&include=' . bp_group_mod_ids() ) ) : ?>
296
- <ul id="mods-list" class="item-list single-line">
297
-
298
- <?php while ( bp_members() ) : bp_the_member(); ?>
299
- <li>
300
- <?php echo bp_core_fetch_avatar( array( 'item_id' => bp_get_member_user_id(), 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_member_name() ) ) ); ?>
301
- <h5>
302
- <a href="<?php bp_member_permalink(); ?>"> <?php bp_member_name(); ?></a>
303
- <span class="small">
304
- <a href="<?php bp_group_member_promote_admin_link( array( 'user_id' => bp_get_member_user_id() ) ); ?>" class="button confirm mod-promote-to-admin" title="<?php esc_attr_e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
305
- <a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link( bp_get_member_user_id() ); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
306
- </span>
307
- </h5>
308
- </li>
309
- <?php endwhile; ?>
310
-
311
- </ul>
312
-
313
- <?php endif; ?>
314
- </div>
315
- <?php endif ?>
316
-
317
-
318
- <div class="bp-widget">
319
- <h4><?php _e( "Members", 'buddypress' ); ?></h4>
320
-
321
- <?php if ( bp_group_has_members( 'per_page=15&exclude_banned=0' ) ) : ?>
322
-
323
- <?php if ( bp_group_member_needs_pagination() ) : ?>
324
-
325
- <div class="pagination no-ajax">
326
-
327
- <div id="member-count" class="pag-count">
328
- <?php bp_group_member_pagination_count(); ?>
329
- </div>
330
-
331
- <div id="member-admin-pagination" class="pagination-links">
332
- <?php bp_group_member_admin_pagination(); ?>
333
- </div>
334
-
335
- </div>
336
-
337
- <?php endif; ?>
338
-
339
- <ul id="members-list" class="item-list single-line">
340
- <?php while ( bp_group_members() ) : bp_group_the_member(); ?>
341
-
342
- <li class="<?php bp_group_member_css_class(); ?>">
343
- <?php bp_group_member_avatar_mini(); ?>
344
-
345
- <h5>
346
- <?php bp_group_member_link(); ?>
347
-
348
- <?php if ( bp_get_group_member_is_banned() ) _e( '(banned)', 'buddypress' ); ?>
349
-
350
- <span class="small">
351
-
352
- <?php if ( bp_get_group_member_is_banned() ) : ?>
353
-
354
- <a href="<?php bp_group_member_unban_link(); ?>" class="button confirm member-unban" title="<?php esc_attr_e( 'Unban this member', 'buddypress' ); ?>"><?php _e( 'Remove Ban', 'buddypress' ); ?></a>
355
-
356
- <?php else : ?>
357
-
358
- <a href="<?php bp_group_member_ban_link(); ?>" class="button confirm member-ban" title="<?php esc_attr_e( 'Kick and ban this member', 'buddypress' ); ?>"><?php _e( 'Kick &amp; Ban', 'buddypress' ); ?></a>
359
- <a href="<?php bp_group_member_promote_mod_link(); ?>" class="button confirm member-promote-to-mod" title="<?php esc_attr_e( 'Promote to Mod', 'buddypress' ); ?>"><?php _e( 'Promote to Mod', 'buddypress' ); ?></a>
360
- <a href="<?php bp_group_member_promote_admin_link(); ?>" class="button confirm member-promote-to-admin" title="<?php esc_attr_e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
361
-
362
- <?php endif; ?>
363
-
364
- <a href="<?php bp_group_member_remove_link(); ?>" class="button confirm" title="<?php esc_attr_e( 'Remove this member', 'buddypress' ); ?>"><?php _e( 'Remove from group', 'buddypress' ); ?></a>
365
-
366
- <?php
367
-
368
- /**
369
- * Fires inside the display of a member admin item in group management area.
370
- *
371
- * @since 1.1.0
372
- */
373
- do_action( 'bp_group_manage_members_admin_item' ); ?>
374
-
375
- </span>
376
- </h5>
377
- </li>
378
-
379
- <?php endwhile; ?>
380
- </ul>
381
-
382
- <?php if ( bp_group_member_needs_pagination() ) : ?>
383
-
384
- <div class="pagination no-ajax">
385
-
386
- <div id="member-count" class="pag-count">
387
- <?php bp_group_member_pagination_count(); ?>
388
- </div>
389
-
390
- <div id="member-admin-pagination" class="pagination-links">
391
- <?php bp_group_member_admin_pagination(); ?>
392
- </div>
393
-
394
- </div>
395
-
396
- <?php endif; ?>
397
-
398
- <?php else: ?>
399
-
400
- <div id="message" class="info">
401
- <p><?php _e( 'This group has no members.', 'buddypress' ); ?></p>
402
- </div>
403
-
404
- <?php endif; ?>
405
-
406
- </div>
407
-
408
- <?php
409
-
410
- /**
411
- * Fires after the group manage members admin display.
412
- *
413
- * @since 1.1.0
414
- */
415
- do_action( 'bp_after_group_manage_members_admin' ); ?>
416
-
417
- <?php endif; ?>
418
-
419
- <?php /* Manage Membership Requests */ ?>
420
- <?php if ( bp_is_group_admin_screen( 'membership-requests' ) ) : ?>
421
 
422
  <?php
423
 
424
  /**
425
- * Fires before the display of group membership requests admin.
426
  *
427
  * @since 1.1.0
428
  */
429
- do_action( 'bp_before_group_membership_requests_admin' ); ?>
430
-
431
- <div class="requests">
432
-
433
- <?php bp_get_template_part( 'groups/single/requests-loop' ); ?>
434
-
435
- </div>
436
-
437
- <?php
438
-
439
- /**
440
- * Fires after the display of group membership requests admin.
441
- *
442
- * @since 1.1.0
443
- */
444
- do_action( 'bp_after_group_membership_requests_admin' ); ?>
445
-
446
- <?php endif; ?>
447
-
448
- <?php
449
-
450
- /**
451
- * Fires inside the group admin template.
452
- *
453
- * Allows plugins to add custom group edit screens.
454
- *
455
- * @since 1.1.0
456
- */
457
- do_action( 'groups_custom_edit_steps' ); ?>
458
-
459
- <?php /* Delete Group Option */ ?>
460
- <?php if ( bp_is_group_admin_screen( 'delete-group' ) ) : ?>
461
 
462
- <?php
463
-
464
- /**
465
- * Fires before the display of group delete admin.
466
- *
467
- * @since 1.1.0
468
- */
469
- do_action( 'bp_before_group_delete_admin' ); ?>
470
-
471
- <div id="message" class="info">
472
- <p><?php _e( 'WARNING: Deleting this group will completely remove ALL content associated with it. There is no way back, please be careful with this option.', 'buddypress' ); ?></p>
473
- </div>
474
-
475
- <label for="delete-group-understand"><input type="checkbox" name="delete-group-understand" id="delete-group-understand" value="1" onclick="if(this.checked) { document.getElementById('delete-group-button').disabled = ''; } else { document.getElementById('delete-group-button').disabled = 'disabled'; }" /> <?php _e( 'I understand the consequences of deleting this group.', 'buddypress' ); ?></label>
476
-
477
- <?php
478
-
479
- /**
480
- * Fires after the display of group delete admin.
481
- *
482
- * @since 1.1.0
483
- */
484
- do_action( 'bp_after_group_delete_admin' ); ?>
485
-
486
- <div class="submit">
487
- <input type="submit" disabled="disabled" value="<?php esc_attr_e( 'Delete Group', 'buddypress' ); ?>" id="delete-group-button" name="delete-group-button" />
488
- </div>
489
-
490
- <?php wp_nonce_field( 'groups_delete_group' ); ?>
491
-
492
- <?php endif; ?>
493
-
494
- <?php /* This is important, don't forget it */ ?>
495
- <input type="hidden" name="group-id" id="group-id" value="<?php bp_group_id(); ?>" />
496
 
497
  <?php
498
-
499
  /**
500
- * Fires inside the group admin form and after the content.
501
  *
502
- * @since 1.1.0
503
  */
504
- do_action( 'bp_after_group_admin_content' ); ?>
505
-
506
- </form><!-- #group-settings-form -->
507
-
7
  */
8
 
9
  ?>
10
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Group secondary navigation', 'buddypress' ); ?>" role="navigation">
11
  <ul>
12
  <?php bp_group_admin_tabs(); ?>
13
  </ul>
14
  </div><!-- .item-list-tabs -->
15
 
 
 
16
  <?php
 
17
  /**
18
+ * Fires before the group admin form and content.
19
  *
20
+ * @since 2.7.0
21
  */
22
+ do_action( 'bp_before_group_admin_form' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ <form action="<?php bp_group_admin_form_action(); ?>" name="group-settings-form" id="group-settings-form" class="standard-form" method="post" enctype="multipart/form-data">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  <?php
 
27
  /**
28
+ * Fires inside the group admin form and before the content.
29
  *
30
  * @since 1.1.0
31
  */
32
+ do_action( 'bp_before_group_admin_content' ); ?>
33
 
34
+ <?php /* Fetch the template for the current admin screen being viewed */ ?>
 
35
 
36
+ <?php if ( bp_is_group_admin_screen( bp_action_variable() ) ) : ?>
37
 
38
+ <?php bp_get_template_part( 'groups/single/admin/' . bp_action_variable() ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  <?php endif; ?>
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  <?php
43
 
44
  /**
45
+ * Fires inside the group admin template.
46
  *
47
+ * Allows plugins to add custom group edit screens.
 
 
 
 
 
 
 
 
 
 
 
 
48
  *
49
  * @since 1.1.0
50
  */
51
+ do_action( 'groups_custom_edit_steps' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  <?php
54
 
55
  /**
56
+ * Fires inside the group admin form and after the content.
57
  *
58
  * @since 1.1.0
59
  */
60
+ do_action( 'bp_after_group_admin_content' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ </form><!-- #group-settings-form -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  <?php
 
65
  /**
66
+ * Fires after the group admin form and content.
67
  *
68
+ * @since 2.7.0
69
  */
70
+ do_action( 'bp_after_group_admin_form' ); ?>
 
 
 
bp-templates/bp-legacy/buddypress/groups/single/admin/delete-group.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Delete Group
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2 class="bp-screen-reader-text"><?php _e( 'Delete Group', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the display of group delete admin.
17
+ *
18
+ * @since 1.1.0
19
+ */
20
+ do_action( 'bp_before_group_delete_admin' ); ?>
21
+
22
+ <div id="message" class="info">
23
+ <p><?php _e( 'WARNING: Deleting this group will completely remove ALL content associated with it. There is no way back, please be careful with this option.', 'buddypress' ); ?></p>
24
+ </div>
25
+
26
+ <label for="delete-group-understand"><input type="checkbox" name="delete-group-understand" id="delete-group-understand" value="1" onclick="if(this.checked) { document.getElementById('delete-group-button').disabled = ''; } else { document.getElementById('delete-group-button').disabled = 'disabled'; }" /> <?php _e( 'I understand the consequences of deleting this group.', 'buddypress' ); ?></label>
27
+
28
+ <?php
29
+
30
+ /**
31
+ * Fires after the display of group delete admin.
32
+ *
33
+ * @since 1.1.0
34
+ */
35
+ do_action( 'bp_after_group_delete_admin' ); ?>
36
+
37
+ <div class="submit">
38
+ <input type="submit" disabled="disabled" value="<?php esc_attr_e( 'Delete Group', 'buddypress' ); ?>" id="delete-group-button" name="delete-group-button" />
39
+ </div>
40
+
41
+ <?php wp_nonce_field( 'groups_delete_group' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/admin/edit-details.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Edit Details
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2 class="bp-screen-reader-text"><?php _e( 'Manage Group Details', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the display of group admin details.
17
+ *
18
+ * @since 1.1.0
19
+ */
20
+ do_action( 'bp_before_group_details_admin' ); ?>
21
+
22
+ <label for="group-name"><?php _e( 'Group Name (required)', 'buddypress' ); ?></label>
23
+ <input type="text" name="group-name" id="group-name" value="<?php bp_group_name(); ?>" aria-required="true" />
24
+
25
+ <label for="group-desc"><?php _e( 'Group Description (required)', 'buddypress' ); ?></label>
26
+ <textarea name="group-desc" id="group-desc" aria-required="true"><?php bp_group_description_editable(); ?></textarea>
27
+
28
+ <?php
29
+
30
+ /**
31
+ * Fires after the group description admin details.
32
+ *
33
+ * @since 1.0.0
34
+ */
35
+ do_action( 'groups_custom_group_fields_editable' ); ?>
36
+
37
+ <p>
38
+ <label for="group-notify-members">
39
+ <input type="checkbox" name="group-notify-members" id="group-notify-members" value="1" /> <?php _e( 'Notify group members of these changes via email', 'buddypress' ); ?>
40
+ </label>
41
+ </p>
42
+
43
+ <?php
44
+
45
+ /**
46
+ * Fires after the display of group admin details.
47
+ *
48
+ * @since 1.1.0
49
+ */
50
+ do_action( 'bp_after_group_details_admin' ); ?>
51
+
52
+ <p><input type="submit" value="<?php esc_attr_e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
53
+ <?php wp_nonce_field( 'groups_edit_group_details' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/admin/group-avatar.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Group Avatar
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2 class="bp-screen-reader-text"><?php _e( 'Group Avatar', 'buddypress' ); ?></h2>
12
+
13
+ <?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
14
+
15
+ <p><?php _e("Upload an image to use as a profile photo for this group. The image will be shown on the main group page, and in search results.", 'buddypress' ); ?></p>
16
+
17
+ <p>
18
+ <label for="file" class="bp-screen-reader-text"><?php
19
+ /* translators: accessibility text */
20
+ _e( 'Select an image', 'buddypress' );
21
+ ?></label>
22
+ <input type="file" name="file" id="file" />
23
+ <input type="submit" name="upload" id="upload" value="<?php esc_attr_e( 'Upload Image', 'buddypress' ); ?>" />
24
+ <input type="hidden" name="action" id="action" value="bp_avatar_upload" />
25
+ </p>
26
+
27
+ <?php if ( bp_get_group_has_avatar() ) : ?>
28
+
29
+ <p><?php _e( "If you'd like to remove the existing group profile photo but not upload a new one, please use the delete group profile photo button.", 'buddypress' ); ?></p>
30
+
31
+ <?php bp_button( array( 'id' => 'delete_group_avatar', 'component' => 'groups', 'wrapper_id' => 'delete-group-avatar-button', 'link_class' => 'edit', 'link_href' => bp_get_group_avatar_delete_link(), 'link_text' => __( 'Delete Group Profile Photo', 'buddypress' ) ) ); ?>
32
+
33
+ <?php endif; ?>
34
+
35
+ <?php
36
+ /**
37
+ * Load the Avatar UI templates
38
+ *
39
+ * @since 2.3.0
40
+ */
41
+ bp_avatar_get_templates(); ?>
42
+
43
+ <?php wp_nonce_field( 'bp_avatar_upload' ); ?>
44
+
45
+ <?php endif; ?>
46
+
47
+ <?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
48
+
49
+ <h4><?php _e( 'Crop Profile Photo', 'buddypress' ); ?></h4>
50
+
51
+ <img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php esc_attr_e( 'Profile photo to crop', 'buddypress' ); ?>" />
52
+
53
+ <div id="avatar-crop-pane">
54
+ <img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php esc_attr_e( 'Profile photo preview', 'buddypress' ); ?>" />
55
+ </div>
56
+
57
+ <input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php esc_attr_e( 'Crop Image', 'buddypress' ); ?>" />
58
+
59
+ <input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
60
+ <input type="hidden" id="x" name="x" />
61
+ <input type="hidden" id="y" name="y" />
62
+ <input type="hidden" id="w" name="w" />
63
+ <input type="hidden" id="h" name="h" />
64
+
65
+ <?php wp_nonce_field( 'bp_avatar_cropstore' ); ?>
66
+
67
+ <?php endif; ?>
bp-templates/bp-legacy/buddypress/groups/single/admin/group-cover-image.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Group Cover Image Settings
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2><?php _e( 'Cover Image', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the display of profile cover image upload content.
17
+ *
18
+ * @since 2.4.0
19
+ */
20
+ do_action( 'bp_before_group_settings_cover_image' ); ?>
21
+
22
+ <p><?php _e( 'The Cover Image will be used to customize the header of your group.', 'buddypress' ); ?></p>
23
+
24
+ <?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
25
+
26
+ <?php
27
+
28
+ /**
29
+ * Fires after the display of group cover image upload content.
30
+ *
31
+ * @since 2.4.0
32
+ */
33
+ do_action( 'bp_after_group_settings_cover_image' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/admin/group-settings.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Group Settings
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2 class="bp-screen-reader-text"><?php _e( 'Manage Group Settings', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the group settings admin display.
17
+ *
18
+ * @since 1.1.0
19
+ */
20
+ do_action( 'bp_before_group_settings_admin' ); ?>
21
+
22
+ <?php if ( bp_is_active( 'forums' ) ) : ?>
23
+
24
+ <?php if ( bp_forums_is_installed_correctly() ) : ?>
25
+
26
+ <div class="checkbox">
27
+ <label for="group-show-forum"><input type="checkbox" name="group-show-forum" id="group-show-forum" value="1"<?php bp_group_show_forum_setting(); ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ); ?></label>
28
+ </div>
29
+
30
+ <hr />
31
+
32
+ <?php endif; ?>
33
+
34
+ <?php endif; ?>
35
+
36
+ <fieldset class="group-create-privacy">
37
+
38
+ <legend><?php _e( 'Privacy Options', 'buddypress' ); ?></legend>
39
+
40
+ <div class="radio">
41
+
42
+ <label for="group-status-public"><input type="radio" name="group-status" id="group-status-public" value="public"<?php if ( 'public' == bp_get_new_group_status() || !bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="public-group-description" /> <?php _e( 'This is a public group', 'buddypress' ); ?></label>
43
+
44
+ <ul id="public-group-description">
45
+ <li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
46
+ <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
47
+ <li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
48
+ </ul>
49
+
50
+ <label for="group-status-private"><input type="radio" name="group-status" id="group-status-private" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="private-group-description" /> <?php _e( 'This is a private group', 'buddypress' ); ?></label>
51
+
52
+ <ul id="private-group-description">
53
+ <li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
54
+ <li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
55
+ <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
56
+ </ul>
57
+
58
+ <label for="group-status-hidden"><input type="radio" name="group-status" id="group-status-hidden" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> aria-describedby="hidden-group-description" /> <?php _e('This is a hidden group', 'buddypress' ); ?></label>
59
+
60
+ <ul id="hidden-group-description">
61
+ <li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
62
+ <li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
63
+ <li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
64
+ </ul>
65
+
66
+ </div>
67
+
68
+ </fieldset>
69
+
70
+ <?php // Group type selection ?>
71
+ <?php if ( $group_types = bp_groups_get_group_types( array( 'show_in_create_screen' => true ), 'objects' ) ): ?>
72
+
73
+ <fieldset class="group-create-types">
74
+ <legend><?php _e( 'Group Types', 'buddypress' ); ?></legend>
75
+
76
+ <p><?php _e( 'Select the types this group should be a part of.', 'buddypress' ); ?></p>
77
+
78
+ <?php foreach ( $group_types as $type ) : ?>
79
+ <div class="checkbox">
80
+ <label for="<?php printf( 'group-type-%s', $type->name ); ?>">
81
+ <input type="checkbox" name="group-types[]" id="<?php printf( 'group-type-%s', $type->name ); ?>" value="<?php echo esc_attr( $type->name ); ?>" <?php checked( bp_groups_has_group_type( bp_get_current_group_id(), $type->name ) ); ?>/> <?php echo esc_html( $type->labels['name'] ); ?>
82
+ <?php
83
+ if ( ! empty( $type->description ) ) {
84
+ printf( __( '&ndash; %s', 'buddypress' ), '<span class="bp-group-type-desc">' . esc_html( $type->description ) . '</span>' );
85
+ }
86
+ ?>
87
+ </label>
88
+ </div>
89
+
90
+ <?php endforeach; ?>
91
+
92
+ </fieldset>
93
+
94
+ <?php endif; ?>
95
+
96
+ <fieldset class="group-create-invitations">
97
+
98
+ <legend><?php _e( 'Group Invitations', 'buddypress' ); ?></legend>
99
+
100
+ <p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
101
+
102
+ <div class="radio">
103
+
104
+ <label for="group-invite-status-members"><input type="radio" name="group-invite-status" id="group-invite-status-members" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> /> <?php _e( 'All group members', 'buddypress' ); ?></label>
105
+
106
+ <label for="group-invite-status-mods"><input type="radio" name="group-invite-status" id="group-invite-status-mods" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> /> <?php _e( 'Group admins and mods only', 'buddypress' ); ?></label>
107
+
108
+ <label for="group-invite-status-admins"><input type="radio" name="group-invite-status" id="group-invite-status-admins" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> /> <?php _e( 'Group admins only', 'buddypress' ); ?></label>
109
+
110
+ </div>
111
+
112
+ </fieldset>
113
+
114
+ <?php
115
+
116
+ /**
117
+ * Fires after the group settings admin display.
118
+ *
119
+ * @since 1.1.0
120
+ */
121
+ do_action( 'bp_after_group_settings_admin' ); ?>
122
+
123
+ <p><input type="submit" value="<?php esc_attr_e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
124
+ <?php wp_nonce_field( 'groups_edit_group_settings' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/admin/manage-members.php ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Manage Members
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2 class="bp-screen-reader-text"><?php _e( 'Manage Members', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the group manage members admin display.
17
+ *
18
+ * @since 1.1.0
19
+ */
20
+ do_action( 'bp_before_group_manage_members_admin' ); ?>
21
+
22
+ <div aria-live="polite" aria-relevant="all" aria-atomic="true">
23
+
24
+ <div class="bp-widget group-members-list group-admins-list">
25
+ <h3 class="section-header"><?php _e( 'Administrators', 'buddypress' ); ?></h3>
26
+
27
+ <?php if ( bp_group_has_members( array( 'per_page' => 15, 'group_role' => array( 'admin' ), 'page_arg' => 'mlpage-admin' ) ) ) : ?>
28
+
29
+ <?php if ( bp_group_member_needs_pagination() ) : ?>
30
+
31
+ <div class="pagination no-ajax">
32
+
33
+ <div id="member-count" class="pag-count">
34
+ <?php bp_group_member_pagination_count(); ?>
35
+ </div>
36
+
37
+ <div id="member-admin-pagination" class="pagination-links">
38
+ <?php bp_group_member_admin_pagination(); ?>
39
+ </div>
40
+
41
+ </div>
42
+
43
+ <?php endif; ?>
44
+
45
+ <ul id="admins-list" class="item-list">
46
+ <?php while ( bp_group_members() ) : bp_group_the_member(); ?>
47
+ <li>
48
+ <div class="item-avatar">
49
+ <?php bp_group_member_avatar_thumb(); ?>
50
+ </div>
51
+
52
+ <div class="item">
53
+ <div class="item-title">
54
+ <?php bp_group_member_link(); ?>
55
+ </div>
56
+ <p class="joined item-meta">
57
+ <?php bp_group_member_joined_since(); ?>
58
+ </p>
59
+ <?php
60
+
61
+ /**
62
+ * Fires inside the item section of a member admin item in group management area.
63
+ *
64
+ * @since 1.1.0
65
+ * @since 2.7.0 Added $section parameter.
66
+ *
67
+ * @param $section Which list contains this item.
68
+ */
69
+ do_action( 'bp_group_manage_members_admin_item', 'admins-list' ); ?>
70
+ </div>
71
+
72
+ <div class="action">
73
+ <?php if ( count( bp_group_admin_ids( false, 'array' ) ) > 1 ) : ?>
74
+ <a class="button confirm admin-demote-to-member" href="<?php bp_group_member_demote_link(); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
75
+ <?php endif; ?>
76
+
77
+ <?php
78
+
79
+ /**
80
+ * Fires inside the action section of a member admin item in group management area.
81
+ *
82
+ * @since 2.7.0
83
+ *
84
+ * @param $section Which list contains this item.
85
+ */
86
+ do_action( 'bp_group_manage_members_admin_actions', 'admins-list' ); ?>
87
+ </div>
88
+ </li>
89
+ <?php endwhile; ?>
90
+ </ul>
91
+
92
+ <?php if ( bp_group_member_needs_pagination() ) : ?>
93
+
94
+ <div class="pagination no-ajax">
95
+
96
+ <div id="member-count" class="pag-count">
97
+ <?php bp_group_member_pagination_count(); ?>
98
+ </div>
99
+
100
+ <div id="member-admin-pagination" class="pagination-links">
101
+ <?php bp_group_member_admin_pagination(); ?>
102
+ </div>
103
+
104
+ </div>
105
+
106
+ <?php endif; ?>
107
+
108
+ <?php else: ?>
109
+
110
+ <div id="message" class="info">
111
+ <p><?php _e( 'No group administrators were found.', 'buddypress' ); ?></p>
112
+ </div>
113
+
114
+ <?php endif; ?>
115
+ </div>
116
+
117
+ <div class="bp-widget group-members-list group-mods-list">
118
+ <h3 class="section-header"><?php _e( 'Moderators', 'buddypress' ); ?></h3>
119
+
120
+ <?php if ( bp_group_has_members( array( 'per_page' => 15, 'group_role' => array( 'mod' ), 'page_arg' => 'mlpage-mod' ) ) ) : ?>
121
+
122
+ <?php if ( bp_group_member_needs_pagination() ) : ?>
123
+
124
+ <div class="pagination no-ajax">
125
+
126
+ <div id="member-count" class="pag-count">
127
+ <?php bp_group_member_pagination_count(); ?>
128
+ </div>
129
+
130
+ <div id="member-admin-pagination" class="pagination-links">
131
+ <?php bp_group_member_admin_pagination(); ?>
132
+ </div>
133
+
134
+ </div>
135
+
136
+ <?php endif; ?>
137
+
138
+ <ul id="mods-list" class="item-list">
139
+
140
+ <?php while ( bp_group_members() ) : bp_group_the_member(); ?>
141
+ <li>
142
+ <div class="item-avatar">
143
+ <?php bp_group_member_avatar_thumb(); ?>
144
+ </div>
145
+
146
+ <div class="item">
147
+ <div class="item-title">
148
+ <?php bp_group_member_link(); ?>
149
+ </div>
150
+ <p class="joined item-meta">
151
+ <?php bp_group_member_joined_since(); ?>
152
+ </p>
153
+ <?php
154
+
155
+ /**
156
+ * Fires inside the item section of a member admin item in group management area.
157
+ *
158
+ * @since 1.1.0
159
+ * @since 2.7.0 Added $section parameter.
160
+ *
161
+ * @param $section Which list contains this item.
162
+ */
163
+ do_action( 'bp_group_manage_members_admin_item', 'admins-list' ); ?>
164
+ </div>
165
+
166
+ <div class="action">
167
+ <a href="<?php bp_group_member_promote_admin_link(); ?>" class="button confirm mod-promote-to-admin"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
168
+ <a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link(); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
169
+
170
+ <?php
171
+
172
+ /**
173
+ * Fires inside the action section of a member admin item in group management area.
174
+ *
175
+ * @since 2.7.0
176
+ *
177
+ * @param $section Which list contains this item.
178
+ */
179
+ do_action( 'bp_group_manage_members_admin_actions', 'mods-list' ); ?>
180
+
181
+ </div>
182
+ </li>
183
+ <?php endwhile; ?>
184
+
185
+ </ul>
186
+
187
+ <?php if ( bp_group_member_needs_pagination() ) : ?>
188
+
189
+ <div class="pagination no-ajax">
190
+
191
+ <div id="member-count" class="pag-count">
192
+ <?php bp_group_member_pagination_count(); ?>
193
+ </div>
194
+
195
+ <div id="member-admin-pagination" class="pagination-links">
196
+ <?php bp_group_member_admin_pagination(); ?>
197
+ </div>
198
+
199
+ </div>
200
+
201
+ <?php endif; ?>
202
+
203
+ <?php else: ?>
204
+
205
+ <div id="message" class="info">
206
+ <p><?php _e( 'No group moderators were found.', 'buddypress' ); ?></p>
207
+ </div>
208
+
209
+ <?php endif; ?>
210
+ </div>
211
+
212
+ <div class="bp-widget group-members-list">
213
+ <h3 class="section-header"><?php _e( "Members", 'buddypress' ); ?></h3>
214
+
215
+ <?php if ( bp_group_has_members( array( 'per_page' => 15, 'exclude_banned' => 0 ) ) ) : ?>
216
+
217
+ <?php if ( bp_group_member_needs_pagination() ) : ?>
218
+
219
+ <div class="pagination no-ajax">
220
+
221
+ <div id="member-count" class="pag-count">
222
+ <?php bp_group_member_pagination_count(); ?>
223
+ </div>
224
+
225
+ <div id="member-admin-pagination" class="pagination-links">
226
+ <?php bp_group_member_admin_pagination(); ?>
227
+ </div>
228
+
229
+ </div>
230
+
231
+ <?php endif; ?>
232
+
233
+ <ul id="members-list" class="item-list">
234
+ <?php while ( bp_group_members() ) : bp_group_the_member(); ?>
235
+
236
+ <li class="<?php bp_group_member_css_class(); ?>">
237
+ <div class="item-avatar">
238
+ <?php bp_group_member_avatar_thumb(); ?>
239
+ </div>
240
+
241
+ <div class="item">
242
+ <div class="item-title">
243
+ <?php bp_group_member_link(); ?>
244
+ <?php
245
+ if ( bp_get_group_member_is_banned() ) {
246
+ echo ' <span class="banned">';
247
+ _e( '(banned)', 'buddypress' );
248
+ echo '</span>';
249
+ } ?>
250
+ </div>
251
+ <p class="joined item-meta">
252
+ <?php bp_group_member_joined_since(); ?>
253
+ </p>
254
+ <?php
255
+
256
+ /**
257
+ * Fires inside the item section of a member admin item in group management area.
258
+ *
259
+ * @since 1.1.0
260
+ * @since 2.7.0 Added $section parameter.
261
+ *
262
+ * @param $section Which list contains this item.
263
+ */
264
+ do_action( 'bp_group_manage_members_admin_item', 'admins-list' ); ?>
265
+ </div>
266
+
267
+ <div class="action">
268
+ <?php if ( bp_get_group_member_is_banned() ) : ?>
269
+
270
+ <a href="<?php bp_group_member_unban_link(); ?>" class="button confirm member-unban" title="<?php esc_attr_e( 'Unban this member', 'buddypress' ); ?>"><?php _e( 'Remove Ban', 'buddypress' ); ?></a>
271
+
272
+ <?php else : ?>
273
+
274
+ <a href="<?php bp_group_member_ban_link(); ?>" class="button confirm member-ban"><?php _e( 'Kick &amp; Ban', 'buddypress' ); ?></a>
275
+ <a href="<?php bp_group_member_promote_mod_link(); ?>" class="button confirm member-promote-to-mod"><?php _e( 'Promote to Mod', 'buddypress' ); ?></a>
276
+ <a href="<?php bp_group_member_promote_admin_link(); ?>" class="button confirm member-promote-to-admin"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
277
+
278
+ <?php endif; ?>
279
+
280
+ <a href="<?php bp_group_member_remove_link(); ?>" class="button confirm"><?php _e( 'Remove from group', 'buddypress' ); ?></a>
281
+
282
+ <?php
283
+
284
+ /**
285
+ * Fires inside the action section of a member admin item in group management area.
286
+ *
287
+ * @since 2.7.0
288
+ *
289
+ * @param $section Which list contains this item.
290
+ */
291
+ do_action( 'bp_group_manage_members_admin_actions', 'members-list' ); ?>
292
+ </div>
293
+ </li>
294
+
295
+ <?php endwhile; ?>
296
+ </ul>
297
+
298
+ <?php if ( bp_group_member_needs_pagination() ) : ?>
299
+
300
+ <div class="pagination no-ajax">
301
+
302
+ <div id="member-count" class="pag-count">
303
+ <?php bp_group_member_pagination_count(); ?>
304
+ </div>
305
+
306
+ <div id="member-admin-pagination" class="pagination-links">
307
+ <?php bp_group_member_admin_pagination(); ?>
308
+ </div>
309
+
310
+ </div>
311
+
312
+ <?php endif; ?>
313
+
314
+ <?php else: ?>
315
+
316
+ <div id="message" class="info">
317
+ <p><?php _e( 'No group members were found.', 'buddypress' ); ?></p>
318
+ </div>
319
+
320
+ <?php endif; ?>
321
+ </div>
322
+
323
+ </div>
324
+
325
+ <?php
326
+
327
+ /**
328
+ * Fires after the group manage members admin display.
329
+ *
330
+ * @since 1.1.0
331
+ */
332
+ do_action( 'bp_after_group_manage_members_admin' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/admin/membership-requests.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Admin - Membership Requests
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2 class="bp-screen-reader-text"><?php _e( 'Manage Membership Requests', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the display of group membership requests admin.
17
+ *
18
+ * @since 1.1.0
19
+ */
20
+ do_action( 'bp_before_group_membership_requests_admin' ); ?>
21
+
22
+ <div class="requests">
23
+
24
+ <?php bp_get_template_part( 'groups/single/requests-loop' ); ?>
25
+
26
+ </div>
27
+
28
+ <?php
29
+
30
+ /**
31
+ * Fires after the display of group membership requests admin.
32
+ *
33
+ * @since 1.1.0
34
+ */
35
+ do_action( 'bp_after_group_membership_requests_admin' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/cover-image-header.php CHANGED
@@ -1,123 +1,124 @@
1
- <?php
2
- /**
3
- * BuddyPress - Groups Cover Image Header.
4
- *
5
- * @package BuddyPress
6
- * @subpackage bp-legacy
7
- */
8
-
9
- /**
10
- * Fires before the display of a group's header.
11
- *
12
- * @since 1.2.0
13
- */
14
- do_action( 'bp_before_group_header' ); ?>
15
-
16
- <div id="cover-image-container">
17
- <a id="header-cover-image" href="<?php echo esc_url( bp_get_group_permalink() ); ?>"></a>
18
-
19
- <div id="item-header-cover-image">
20
- <?php if ( ! bp_disable_group_avatar_uploads() ) : ?>
21
- <div id="item-header-avatar">
22
- <a href="<?php echo esc_url( bp_get_group_permalink() ); ?>" title="<?php echo esc_attr( bp_get_group_name() ); ?>">
23
-
24
- <?php bp_group_avatar(); ?>
25
-
26
- </a>
27
- </div><!-- #item-header-avatar -->
28
- <?php endif; ?>
29
-
30
- <div id="item-header-content">
31
-
32
- <div id="item-buttons"><?php
33
-
34
- /**
35
- * Fires in the group header actions section.
36
- *
37
- * @since 1.2.6
38
- */
39
- do_action( 'bp_group_header_actions' ); ?></div><!-- #item-buttons -->
40
-
41
- <?php
42
-
43
- /**
44
- * Fires before the display of the group's header meta.
45
- *
46
- * @since 1.2.0
47
- */
48
- do_action( 'bp_before_group_header_meta' ); ?>
49
-
50
- <div id="item-meta">
51
-
52
- <?php
53
-
54
- /**
55
- * Fires after the group header actions section.
56
- *
57
- * @since 1.2.0
58
- */
59
- do_action( 'bp_group_header_meta' ); ?>
60
-
61
- <span class="highlight"><?php bp_group_type(); ?></span>
62
- <span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
63
-
64
- <?php bp_group_description(); ?>
65
-
66
- </div>
67
- </div><!-- #item-header-content -->
68
-
69
- <div id="item-actions">
70
-
71
- <?php if ( bp_group_is_visible() ) : ?>
72
-
73
- <h3><?php _e( 'Group Admins', 'buddypress' ); ?></h3>
74
-
75
- <?php bp_group_list_admins();
76
-
77
- /**
78
- * Fires after the display of the group's administrators.
79
- *
80
- * @since 1.1.0
81
- */
82
- do_action( 'bp_after_group_menu_admins' );
83
-
84
- if ( bp_group_has_moderators() ) :
85
-
86
- /**
87
- * Fires before the display of the group's moderators, if there are any.
88
- *
89
- * @since 1.1.0
90
- */
91
- do_action( 'bp_before_group_menu_mods' ); ?>
92
-
93
- <h3><?php _e( 'Group Mods' , 'buddypress' ); ?></h3>
94
-
95
- <?php bp_group_list_mods();
96
-
97
- /**
98
- * Fires after the display of the group's moderators, if there are any.
99
- *
100
- * @since 1.1.0
101
- */
102
- do_action( 'bp_after_group_menu_mods' );
103
-
104
- endif;
105
-
106
- endif; ?>
107
-
108
- </div><!-- #item-actions -->
109
-
110
- </div><!-- #item-header-cover-image -->
111
- </div><!-- #cover-image-container -->
112
-
113
- <?php
114
-
115
- /**
116
- * Fires after the display of a group's header.
117
- *
118
- * @since 1.2.0
119
- */
120
- do_action( 'bp_after_group_header' );
121
-
122
- /** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
123
- do_action( 'template_notices' ); ?>
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Groups Cover Image Header.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ /**
10
+ * Fires before the display of a group's header.
11
+ *
12
+ * @since 1.2.0
13
+ */
14
+ do_action( 'bp_before_group_header' ); ?>
15
+
16
+ <div id="cover-image-container">
17
+ <a id="header-cover-image" href="<?php echo esc_url( bp_get_group_permalink() ); ?>"></a>
18
+
19
+ <div id="item-header-cover-image">
20
+ <?php if ( ! bp_disable_group_avatar_uploads() ) : ?>
21
+ <div id="item-header-avatar">
22
+ <a href="<?php echo esc_url( bp_get_group_permalink() ); ?>" title="<?php echo esc_attr( bp_get_group_name() ); ?>">
23
+
24
+ <?php bp_group_avatar(); ?>
25
+
26
+ </a>
27
+ </div><!-- #item-header-avatar -->
28
+ <?php endif; ?>
29
+
30
+ <div id="item-header-content">
31
+
32
+ <div id="item-buttons"><?php
33
+
34
+ /**
35
+ * Fires in the group header actions section.
36
+ *
37
+ * @since 1.2.6
38
+ */
39
+ do_action( 'bp_group_header_actions' ); ?></div><!-- #item-buttons -->
40
+
41
+ <?php
42
+
43
+ /**
44
+ * Fires before the display of the group's header meta.
45
+ *
46
+ * @since 1.2.0
47
+ */
48
+ do_action( 'bp_before_group_header_meta' ); ?>
49
+
50
+ <div id="item-meta">
51
+
52
+ <?php
53
+
54
+ /**
55
+ * Fires after the group header actions section.
56
+ *
57
+ * @since 1.2.0
58
+ */
59
+ do_action( 'bp_group_header_meta' ); ?>
60
+
61
+ <span class="highlight"><?php bp_group_type(); ?></span>
62
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_group_last_active( 0, array( 'relative' => false ) ) ); ?>"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
63
+
64
+ <?php bp_group_description(); ?>
65
+
66
+ <?php bp_group_type_list(); ?>
67
+ </div>
68
+ </div><!-- #item-header-content -->
69
+
70
+ <div id="item-actions">
71
+
72
+ <?php if ( bp_group_is_visible() ) : ?>
73
+
74
+ <h2><?php _e( 'Group Admins', 'buddypress' ); ?></h2>
75
+
76
+ <?php bp_group_list_admins();
77
+
78
+ /**
79
+ * Fires after the display of the group's administrators.
80
+ *
81
+ * @since 1.1.0
82
+ */
83
+ do_action( 'bp_after_group_menu_admins' );
84
+
85
+ if ( bp_group_has_moderators() ) :
86
+
87
+ /**
88
+ * Fires before the display of the group's moderators, if there are any.
89
+ *
90
+ * @since 1.1.0
91
+ */
92
+ do_action( 'bp_before_group_menu_mods' ); ?>
93
+
94
+ <h2><?php _e( 'Group Mods' , 'buddypress' ); ?></h2>
95
+
96
+ <?php bp_group_list_mods();
97
+
98
+ /**
99
+ * Fires after the display of the group's moderators, if there are any.
100
+ *
101
+ * @since 1.1.0
102
+ */
103
+ do_action( 'bp_after_group_menu_mods' );
104
+
105
+ endif;
106
+
107
+ endif; ?>
108
+
109
+ </div><!-- #item-actions -->
110
+
111
+ </div><!-- #item-header-cover-image -->
112
+ </div><!-- #cover-image-container -->
113
+
114
+ <?php
115
+
116
+ /**
117
+ * Fires after the display of a group's header.
118
+ *
119
+ * @since 1.2.0
120
+ */
121
+ do_action( 'bp_after_group_header' );
122
+
123
+ /** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
124
+ do_action( 'template_notices' ); ?>
bp-templates/bp-legacy/buddypress/groups/single/forum.php CHANGED
@@ -21,7 +21,7 @@ elseif ( bp_is_group_forum_topic() ) :
21
 
22
  else : ?>
23
 
24
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
25
  <ul>
26
 
27
  <?php if ( is_user_logged_in() ) : ?>
21
 
22
  else : ?>
23
 
24
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Group secondary navigation', 'buddypress' ); ?>" role="navigation">
25
  <ul>
26
 
27
  <?php if ( is_user_logged_in() ) : ?>
bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php CHANGED
@@ -17,7 +17,7 @@ do_action( 'bp_before_group_forum_edit_form' ); ?>
17
 
18
  <form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
19
 
20
- <div class="item-list-tabs" id="subnav" role="navigation">
21
  <ul>
22
  <li>
23
  <a href="#post-topic-reply"><?php _e( 'Reply', 'buddypress' ); ?></a>
17
 
18
  <form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
19
 
20
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Forums secondary navigation', 'buddypress' ); ?>" role="navigation">
21
  <ul>
22
  <li>
23
  <a href="#post-topic-reply"><?php _e( 'Reply', 'buddypress' ); ?></a>
bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php CHANGED
@@ -14,7 +14,7 @@
14
  do_action( 'bp_before_group_forum_topic' ); ?>
15
 
16
  <form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
17
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
18
  <ul>
19
  <?php if ( is_user_logged_in() ) : ?>
20
 
14
  do_action( 'bp_before_group_forum_topic' ); ?>
15
 
16
  <form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
17
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Forums secondary navigation', 'buddypress' ); ?>" role="navigation">
18
  <ul>
19
  <?php if ( is_user_logged_in() ) : ?>
20
 
bp-templates/bp-legacy/buddypress/groups/single/group-header.php CHANGED
@@ -19,7 +19,7 @@ do_action( 'bp_before_group_header' );
19
 
20
  <?php if ( bp_group_is_visible() ) : ?>
21
 
22
- <h3><?php _e( 'Group Admins', 'buddypress' ); ?></h3>
23
 
24
  <?php bp_group_list_admins();
25
 
@@ -39,7 +39,7 @@ do_action( 'bp_before_group_header' );
39
  */
40
  do_action( 'bp_before_group_menu_mods' ); ?>
41
 
42
- <h3><?php _e( 'Group Mods' , 'buddypress' ); ?></h3>
43
 
44
  <?php bp_group_list_mods();
45
 
@@ -68,7 +68,7 @@ do_action( 'bp_before_group_header' );
68
 
69
  <div id="item-header-content">
70
  <span class="highlight"><?php bp_group_type(); ?></span>
71
- <span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
72
 
73
  <?php
74
 
@@ -83,6 +83,8 @@ do_action( 'bp_before_group_header' );
83
 
84
  <?php bp_group_description(); ?>
85
 
 
 
86
  <div id="item-buttons">
87
 
88
  <?php
19
 
20
  <?php if ( bp_group_is_visible() ) : ?>
21
 
22
+ <h2><?php _e( 'Group Admins', 'buddypress' ); ?></h2>
23
 
24
  <?php bp_group_list_admins();
25
 
39
  */
40
  do_action( 'bp_before_group_menu_mods' ); ?>
41
 
42
+ <h2><?php _e( 'Group Mods' , 'buddypress' ); ?></h2>
43
 
44
  <?php bp_group_list_mods();
45
 
68
 
69
  <div id="item-header-content">
70
  <span class="highlight"><?php bp_group_type(); ?></span>
71
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_group_last_active( 0, array( 'relative' => false ) ) ); ?>"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
72
 
73
  <?php
74
 
83
 
84
  <?php bp_group_description(); ?>
85
 
86
+ <?php bp_group_type_list(); ?>
87
+
88
  <div id="item-buttons">
89
 
90
  <?php
bp-templates/bp-legacy/buddypress/groups/single/home.php CHANGED
@@ -36,7 +36,7 @@
36
  </div><!-- #item-header -->
37
 
38
  <div id="item-nav">
39
- <div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
40
  <ul>
41
 
42
  <?php bp_get_options_nav(); ?>
36
  </div><!-- #item-header -->
37
 
38
  <div id="item-nav">
39
+ <div class="item-list-tabs no-ajax" id="object-nav" aria-label="<?php esc_attr_e( 'Group primary navigation', 'buddypress' ); ?>" role="navigation">
40
  <ul>
41
 
42
  <?php bp_get_options_nav(); ?>
bp-templates/bp-legacy/buddypress/groups/single/invites-loop.php CHANGED
@@ -58,7 +58,7 @@
58
  <li id="<?php bp_group_invite_item_id(); ?>">
59
  <?php bp_group_invite_user_avatar(); ?>
60
 
61
- <h4><?php bp_group_invite_user_link(); ?></h4>
62
  <span class="activity"><?php bp_group_invite_user_last_active(); ?></span>
63
 
64
  <?php
58
  <li id="<?php bp_group_invite_item_id(); ?>">
59
  <?php bp_group_invite_user_avatar(); ?>
60
 
61
+ <h3><?php bp_group_invite_user_link(); ?></h3>
62
  <span class="activity"><?php bp_group_invite_user_last_active(); ?></span>
63
 
64
  <?php
bp-templates/bp-legacy/buddypress/groups/single/members.php CHANGED
@@ -56,7 +56,7 @@
56
  </a>
57
 
58
  <h5><?php bp_group_member_link(); ?></h5>
59
- <span class="activity"><?php bp_group_member_joined_since(); ?></span>
60
 
61
  <?php
62
 
56
  </a>
57
 
58
  <h5><?php bp_group_member_link(); ?></h5>
59
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_group_member_joined_since( array( 'relative' => false ) ) ); ?>"><?php bp_group_member_joined_since(); ?></span>
60
 
61
  <?php
62
 
bp-templates/bp-legacy/buddypress/groups/single/request-membership.php CHANGED
@@ -14,6 +14,8 @@
14
  do_action( 'bp_before_group_request_membership_content' ); ?>
15
 
16
  <?php if ( !bp_group_has_requested_membership() ) : ?>
 
 
17
  <p><?php printf( __( "You are requesting to become a member of the group '%s'.", 'buddypress' ), bp_get_group_name( false ) ); ?></p>
18
 
19
  <form action="<?php bp_group_form_action('request-membership' ); ?>" method="post" name="request-membership-form" id="request-membership-form" class="standard-form">
14
  do_action( 'bp_before_group_request_membership_content' ); ?>
15
 
16
  <?php if ( !bp_group_has_requested_membership() ) : ?>
17
+ <h2 class="bp-screen-reader-text"><?php _e( 'Request form', 'buddypress' ); ?></h2>
18
+
19
  <p><?php printf( __( "You are requesting to become a member of the group '%s'.", 'buddypress' ), bp_get_group_name( false ) ); ?></p>
20
 
21
  <form action="<?php bp_group_form_action('request-membership' ); ?>" method="post" name="request-membership-form" id="request-membership-form" class="standard-form">
bp-templates/bp-legacy/buddypress/groups/single/requests-loop.php CHANGED
@@ -54,9 +54,9 @@
54
 
55
  <div class="action">
56
 
57
- <?php bp_button( array( 'id' => 'group_membership_accept', 'component' => 'groups', 'wrapper_class' => 'accept', 'link_href' => bp_get_group_request_accept_link(), 'link_title' => __( 'Accept', 'buddypress' ), 'link_text' => __( 'Accept', 'buddypress' ) ) ); ?>
58
 
59
- <?php bp_button( array( 'id' => 'group_membership_reject', 'component' => 'groups', 'wrapper_class' => 'reject', 'link_href' => bp_get_group_request_reject_link(), 'link_title' => __( 'Reject', 'buddypress' ), 'link_text' => __( 'Reject', 'buddypress' ) ) ); ?>
60
 
61
  <?php
62
 
54
 
55
  <div class="action">
56
 
57
+ <?php bp_button( array( 'id' => 'group_membership_accept', 'component' => 'groups', 'wrapper_class' => 'accept', 'link_href' => bp_get_group_request_accept_link(), 'link_text' => __( 'Accept', 'buddypress' ) ) ); ?>
58
 
59
+ <?php bp_button( array( 'id' => 'group_membership_reject', 'component' => 'groups', 'wrapper_class' => 'reject', 'link_href' => bp_get_group_request_reject_link(), 'link_text' => __( 'Reject', 'buddypress' ) ) ); ?>
60
 
61
  <?php
62
 
bp-templates/bp-legacy/buddypress/groups/single/send-invites.php CHANGED
@@ -17,10 +17,12 @@ do_action( 'bp_before_group_send_invites_content' ); ?>
17
  /* Does the user have friends that could be invited to the group? */
18
  if ( bp_get_new_group_invite_friend_list() ) : ?>
19
 
 
 
20
  <?php /* 'send-invite-form' is important for AJAX support */ ?>
21
  <form action="<?php bp_group_send_invite_form_action(); ?>" method="post" id="send-invite-form" class="standard-form">
22
 
23
- <div class="invite">
24
  <?php bp_get_template_part( 'groups/single/invites-loop' ); ?>
25
  </div>
26
 
17
  /* Does the user have friends that could be invited to the group? */
18
  if ( bp_get_new_group_invite_friend_list() ) : ?>
19
 
20
+ <h2 class="bp-screen-reader-text"><?php _e( 'Send invites', 'buddypress' ); ?></h2>
21
+
22
  <?php /* 'send-invite-form' is important for AJAX support */ ?>
23
  <form action="<?php bp_group_send_invite_form_action(); ?>" method="post" id="send-invite-form" class="standard-form">
24
 
25
+ <div class="invite" aria-live="polite" aria-atomic="false" aria-relevant="all">
26
  <?php bp_get_template_part( 'groups/single/invites-loop' ); ?>
27
  </div>
28
 
bp-templates/bp-legacy/buddypress/members/index.php CHANGED
@@ -33,12 +33,20 @@ do_action( 'bp_before_directory_members_page' ); ?>
33
  */
34
  do_action( 'bp_before_directory_members_content' ); ?>
35
 
36
- <div id="members-dir-search" class="dir-search" role="search">
37
- <?php bp_directory_members_search_form(); ?>
38
- </div><!-- #members-dir-search -->
39
 
40
- <?php
 
 
 
 
 
 
41
 
 
 
 
42
  /**
43
  * Fires before the display of the members list tabs.
44
  *
@@ -48,12 +56,12 @@ do_action( 'bp_before_directory_members_page' ); ?>
48
 
49
  <form action="" method="post" id="members-directory-form" class="dir-form">
50
 
51
- <div class="item-list-tabs" role="navigation">
52
  <ul>
53
  <li class="selected" id="members-all"><a href="<?php bp_members_directory_permalink(); ?>"><?php printf( __( 'All Members %s', 'buddypress' ), '<span>' . bp_get_total_member_count() . '</span>' ); ?></a></li>
54
 
55
  <?php if ( is_user_logged_in() && bp_is_active( 'friends' ) && bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
56
- <li id="members-personal"><a href="<?php echo bp_loggedin_user_domain() . bp_get_friends_slug() . '/my-friends/'; ?>"><?php printf( __( 'My Friends %s', 'buddypress' ), '<span>' . bp_get_total_friend_count( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
57
  <?php endif; ?>
58
 
59
  <?php
@@ -68,7 +76,7 @@ do_action( 'bp_before_directory_members_page' ); ?>
68
  </ul>
69
  </div><!-- .item-list-tabs -->
70
 
71
- <div class="item-list-tabs" id="subnav" role="navigation">
72
  <ul>
73
  <?php
74
 
@@ -102,6 +110,8 @@ do_action( 'bp_before_directory_members_page' ); ?>
102
  </ul>
103
  </div>
104
 
 
 
105
  <div id="members-dir-list" class="members dir-list">
106
  <?php bp_get_template_part( 'members/members-loop' ); ?>
107
  </div><!-- #members-dir-list -->
33
  */
34
  do_action( 'bp_before_directory_members_content' ); ?>
35
 
36
+ <?php /* Backward compatibility for inline search form. Use template part instead. */ ?>
37
+ <?php if ( has_filter( 'bp_directory_members_search_form' ) ) : ?>
 
38
 
39
+ <div id="members-dir-search" class="dir-search" role="search">
40
+ <?php bp_directory_members_search_form(); ?>
41
+ </div><!-- #members-dir-search -->
42
+
43
+ <?php else: ?>
44
+
45
+ <?php bp_get_template_part( 'common/search/dir-search-form' ); ?>
46
 
47
+ <?php endif; ?>
48
+
49
+ <?php
50
  /**
51
  * Fires before the display of the members list tabs.
52
  *
56
 
57
  <form action="" method="post" id="members-directory-form" class="dir-form">
58
 
59
+ <div class="item-list-tabs" aria-label="<?php esc_attr_e( 'Members directory main navigation', 'buddypress' ); ?>" role="navigation">
60
  <ul>
61
  <li class="selected" id="members-all"><a href="<?php bp_members_directory_permalink(); ?>"><?php printf( __( 'All Members %s', 'buddypress' ), '<span>' . bp_get_total_member_count() . '</span>' ); ?></a></li>
62
 
63
  <?php if ( is_user_logged_in() && bp_is_active( 'friends' ) && bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
64
+ <li id="members-personal"><a href="<?php echo esc_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/my-friends/' ); ?>"><?php printf( __( 'My Friends %s', 'buddypress' ), '<span>' . bp_get_total_friend_count( bp_loggedin_user_id() ) . '</span>' ); ?></a></li>
65
  <?php endif; ?>
66
 
67
  <?php
76
  </ul>
77
  </div><!-- .item-list-tabs -->
78
 
79
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Members directory secondary navigation', 'buddypress' ); ?>" role="navigation">
80
  <ul>
81
  <?php
82
 
110
  </ul>
111
  </div>
112
 
113
+ <h2 class="bp-screen-reader-text"><?php _e( 'Members directory', 'buddypress' ); ?></h2>
114
+
115
  <div id="members-dir-list" class="members dir-list">
116
  <?php bp_get_template_part( 'members/members-loop' ); ?>
117
  </div><!-- #members-dir-list -->
bp-templates/bp-legacy/buddypress/members/members-loop.php CHANGED
@@ -67,7 +67,7 @@ do_action( 'bp_before_members_loop' ); ?>
67
 
68
  </div>
69
 
70
- <div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
71
 
72
  <?php
73
 
67
 
68
  </div>
69
 
70
+ <div class="item-meta"><span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_member_last_active( array( 'relative' => false ) ) ); ?>"><?php bp_member_last_active(); ?></span></div>
71
 
72
  <?php
73
 
bp-templates/bp-legacy/buddypress/members/register.php CHANGED
@@ -71,7 +71,7 @@
71
 
72
  <?php /***** Basic Account Details ******/ ?>
73
 
74
- <h4><?php _e( 'Account Details', 'buddypress' ); ?></h4>
75
 
76
  <label for="signup_username"><?php _e( 'Username', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
77
  <?php
@@ -153,7 +153,7 @@
153
 
154
  <div class="register-section" id="profile-details-section">
155
 
156
- <h4><?php _e( 'Profile Details', 'buddypress' ); ?></h4>
157
 
158
  <?php /* Use the profile field loop to render input fields for the 'base' profile field group */ ?>
159
  <?php if ( bp_is_active( 'xprofile' ) ) : if ( bp_has_profile( array( 'profile_group_id' => 1, 'fetch_field_data' => false ) ) ) : while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
@@ -261,7 +261,7 @@
261
 
262
  <div class="register-section" id="blog-details-section">
263
 
264
- <h4><?php _e( 'Blog Details', 'buddypress' ); ?></h4>
265
 
266
  <p><label for="signup_with_blog"><input type="checkbox" name="signup_with_blog" id="signup_with_blog" value="1"<?php if ( (int) bp_get_signup_with_blog_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'Yes, I\'d like to create a new site', 'buddypress' ); ?></label></p>
267
 
71
 
72
  <?php /***** Basic Account Details ******/ ?>
73
 
74
+ <h2><?php _e( 'Account Details', 'buddypress' ); ?></h2>
75
 
76
  <label for="signup_username"><?php _e( 'Username', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
77
  <?php
153
 
154
  <div class="register-section" id="profile-details-section">
155
 
156
+ <h2><?php _e( 'Profile Details', 'buddypress' ); ?></h2>
157
 
158
  <?php /* Use the profile field loop to render input fields for the 'base' profile field group */ ?>
159
  <?php if ( bp_is_active( 'xprofile' ) ) : if ( bp_has_profile( array( 'profile_group_id' => 1, 'fetch_field_data' => false ) ) ) : while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
261
 
262
  <div class="register-section" id="blog-details-section">
263
 
264
+ <h2><?php _e( 'Blog Details', 'buddypress' ); ?></h2>
265
 
266
  <p><label for="signup_with_blog"><input type="checkbox" name="signup_with_blog" id="signup_with_blog" value="1"<?php if ( (int) bp_get_signup_with_blog_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'Yes, I\'d like to create a new site', 'buddypress' ); ?></label></p>
267
 
bp-templates/bp-legacy/buddypress/members/single/activity.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
 
14
  <?php bp_get_options_nav(); ?>
@@ -61,7 +61,7 @@ do_action( 'bp_after_member_activity_post_form' );
61
  */
62
  do_action( 'bp_before_member_activity_content' ); ?>
63
 
64
- <div class="activity">
65
 
66
  <?php bp_get_template_part( 'activity/activity-loop' ) ?>
67
 
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
 
14
  <?php bp_get_options_nav(); ?>
61
  */
62
  do_action( 'bp_before_member_activity_content' ); ?>
63
 
64
+ <div class="activity" aria-live="polite" aria-atomic="true" aria-relevant="all">
65
 
66
  <?php bp_get_template_part( 'activity/activity-loop' ) ?>
67
 
bp-templates/bp-legacy/buddypress/members/single/blogs.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs" id="subnav" role="navigation">
12
  <ul>
13
 
14
  <?php bp_get_options_nav(); ?>
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
 
14
  <?php bp_get_options_nav(); ?>
bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php CHANGED
@@ -1,103 +1,103 @@
1
- <?php
2
- /**
3
- * BuddyPress - Users Cover Image Header
4
- *
5
- * @package BuddyPress
6
- * @subpackage bp-legacy
7
- */
8
-
9
- ?>
10
-
11
- <?php
12
-
13
- /**
14
- * Fires before the display of a member's header.
15
- *
16
- * @since 1.2.0
17
- */
18
- do_action( 'bp_before_member_header' ); ?>
19
-
20
- <div id="cover-image-container">
21
- <a id="header-cover-image" href="<?php bp_displayed_user_link(); ?>"></a>
22
-
23
- <div id="item-header-cover-image">
24
- <div id="item-header-avatar">
25
- <a href="<?php bp_displayed_user_link(); ?>">
26
-
27
- <?php bp_displayed_user_avatar( 'type=full' ); ?>
28
-
29
- </a>
30
- </div><!-- #item-header-avatar -->
31
-
32
- <div id="item-header-content">
33
-
34
- <?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
35
- <h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
36
- <?php endif; ?>
37
-
38
- <div id="item-buttons"><?php
39
-
40
- /**
41
- * Fires in the member header actions section.
42
- *
43
- * @since 1.2.6
44
- */
45
- do_action( 'bp_member_header_actions' ); ?></div><!-- #item-buttons -->
46
-
47
- <span class="activity"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
48
-
49
- <?php
50
-
51
- /**
52
- * Fires before the display of the member's header meta.
53
- *
54
- * @since 1.2.0
55
- */
56
- do_action( 'bp_before_member_header_meta' ); ?>
57
-
58
- <div id="item-meta">
59
-
60
- <?php if ( bp_is_active( 'activity' ) ) : ?>
61
-
62
- <div id="latest-update">
63
-
64
- <?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
65
-
66
- </div>
67
-
68
- <?php endif; ?>
69
-
70
- <?php
71
-
72
- /**
73
- * Fires after the group header actions section.
74
- *
75
- * If you'd like to show specific profile fields here use:
76
- * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
77
- *
78
- * @since 1.2.0
79
- */
80
- do_action( 'bp_profile_header_meta' );
81
-
82
- ?>
83
-
84
- </div><!-- #item-meta -->
85
-
86
- </div><!-- #item-header-content -->
87
-
88
- </div><!-- #item-header-cover-image -->
89
- </div><!-- #cover-image-container -->
90
-
91
- <?php
92
-
93
- /**
94
- * Fires after the display of a member's header.
95
- *
96
- * @since 1.2.0
97
- */
98
- do_action( 'bp_after_member_header' ); ?>
99
-
100
- <?php
101
-
102
- /** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
103
- do_action( 'template_notices' ); ?>
1
+ <?php
2
+ /**
3
+ * BuddyPress - Users Cover Image Header
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <?php
12
+
13
+ /**
14
+ * Fires before the display of a member's header.
15
+ *
16
+ * @since 1.2.0
17
+ */
18
+ do_action( 'bp_before_member_header' ); ?>
19
+
20
+ <div id="cover-image-container">
21
+ <a id="header-cover-image" href="<?php bp_displayed_user_link(); ?>"></a>
22
+
23
+ <div id="item-header-cover-image">
24
+ <div id="item-header-avatar">
25
+ <a href="<?php bp_displayed_user_link(); ?>">
26
+
27
+ <?php bp_displayed_user_avatar( 'type=full' ); ?>
28
+
29
+ </a>
30
+ </div><!-- #item-header-avatar -->
31
+
32
+ <div id="item-header-content">
33
+
34
+ <?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
35
+ <h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
36
+ <?php endif; ?>
37
+
38
+ <div id="item-buttons"><?php
39
+
40
+ /**
41
+ * Fires in the member header actions section.
42
+ *
43
+ * @since 1.2.6
44
+ */
45
+ do_action( 'bp_member_header_actions' ); ?></div><!-- #item-buttons -->
46
+
47
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_user_last_activity( bp_displayed_user_id() ) ); ?>"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
48
+
49
+ <?php
50
+
51
+ /**
52
+ * Fires before the display of the member's header meta.
53
+ *
54
+ * @since 1.2.0
55
+ */
56
+ do_action( 'bp_before_member_header_meta' ); ?>
57
+
58
+ <div id="item-meta">
59
+
60
+ <?php if ( bp_is_active( 'activity' ) ) : ?>
61
+
62
+ <div id="latest-update">
63
+
64
+ <?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
65
+
66
+ </div>
67
+
68
+ <?php endif; ?>
69
+
70
+ <?php
71
+
72
+ /**
73
+ * Fires after the group header actions section.
74
+ *
75
+ * If you'd like to show specific profile fields here use:
76
+ * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
77
+ *
78
+ * @since 1.2.0
79
+ */
80
+ do_action( 'bp_profile_header_meta' );
81
+
82
+ ?>
83
+
84
+ </div><!-- #item-meta -->
85
+
86
+ </div><!-- #item-header-content -->
87
+
88
+ </div><!-- #item-header-cover-image -->
89
+ </div><!-- #cover-image-container -->
90
+
91
+ <?php
92
+
93
+ /**
94
+ * Fires after the display of a member's header.
95
+ *
96
+ * @since 1.2.0
97
+ */
98
+ do_action( 'bp_after_member_header' ); ?>
99
+
100
+ <?php
101
+
102
+ /** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
103
+ do_action( 'template_notices' ); ?>
bp-templates/bp-legacy/buddypress/members/single/forums.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
  <?php bp_get_options_nav(); ?>
14
 
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
  <?php bp_get_options_nav(); ?>
14
 
bp-templates/bp-legacy/buddypress/members/single/friends.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
  <?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
14
 
@@ -52,6 +52,12 @@ switch ( bp_current_action() ) :
52
  */
53
  do_action( 'bp_before_member_friends_content' ); ?>
54
 
 
 
 
 
 
 
55
  <div class="members friends">
56
 
57
  <?php bp_get_template_part( 'members/members-loop' ) ?>
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
  <?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
14
 
52
  */
53
  do_action( 'bp_before_member_friends_content' ); ?>
54
 
55
+ <?php if (is_user_logged_in() ) : ?>
56
+ <h2 class="bp-screen-reader-text"><?php _e( 'My friends', 'buddypress' ); ?></h2>
57
+ <?php else : ?>
58
+ <h2 class="bp-screen-reader-text"><?php _e( 'Friends', 'buddypress' ); ?></h2>
59
+ <?php endif ?>
60
+
61
  <div class="members friends">
62
 
63
  <?php bp_get_template_part( 'members/members-loop' ) ?>
bp-templates/bp-legacy/buddypress/members/single/friends/requests.php CHANGED
@@ -15,6 +15,8 @@ do_action( 'bp_before_member_friend_requests_content' ); ?>
15
 
16
  <?php if ( bp_has_members( 'type=alphabetical&include=' . bp_get_friendship_requests() ) ) : ?>
17
 
 
 
18
  <div id="pag-top" class="pagination no-ajax">
19
 
20
  <div class="pag-count" id="member-dir-count-top">
15
 
16
  <?php if ( bp_has_members( 'type=alphabetical&include=' . bp_get_friendship_requests() ) ) : ?>
17
 
18
+ <h2 class="bp-screen-reader-text"><?php _e( 'Friendship requests', 'buddypress' ); ?></h2>
19
+
20
  <div id="pag-top" class="pagination no-ajax">
21
 
22
  <div class="pag-count" id="member-dir-count-top">
bp-templates/bp-legacy/buddypress/members/single/groups.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
  <?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
14
 
@@ -54,6 +54,12 @@ switch ( bp_current_action() ) :
54
  */
55
  do_action( 'bp_before_member_groups_content' ); ?>
56
 
 
 
 
 
 
 
57
  <div class="groups mygroups">
58
 
59
  <?php bp_get_template_part( 'groups/groups-loop' ); ?>
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
  <?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
14
 
54
  */
55
  do_action( 'bp_before_member_groups_content' ); ?>
56
 
57
+ <?php if ( is_user_logged_in() ) : ?>
58
+ <h2 class="bp-screen-reader-text"><?php _e( 'My groups', 'buddypress' ); ?></h2>
59
+ <?php else : ?>
60
+ <h2 class="bp-screen-reader-text"><?php _e( 'Member\'s groups', 'buddypress' ); ?></h2>
61
+ <?php endif; ?>
62
+
63
  <div class="groups mygroups">
64
 
65
  <?php bp_get_template_part( 'groups/groups-loop' ); ?>
bp-templates/bp-legacy/buddypress/members/single/groups/invites.php CHANGED
@@ -15,6 +15,8 @@ do_action( 'bp_before_group_invites_content' ); ?>
15
 
16
  <?php if ( bp_has_groups( 'type=invites&user_id=' . bp_loggedin_user_id() ) ) : ?>
17
 
 
 
18
  <ul id="group-list" class="invites item-list">
19
 
20
  <?php while ( bp_groups() ) : bp_the_group(); ?>
15
 
16
  <?php if ( bp_has_groups( 'type=invites&user_id=' . bp_loggedin_user_id() ) ) : ?>
17
 
18
+ <h2 class="bp-screen-reader-text"><?php _e( 'Group invitations', 'buddypress' ); ?></h2>
19
+
20
  <ul id="group-list" class="invites item-list">
21
 
22
  <?php while ( bp_groups() ) : bp_the_group(); ?>
bp-templates/bp-legacy/buddypress/members/single/home.php CHANGED
@@ -35,7 +35,7 @@
35
  </div><!-- #item-header -->
36
 
37
  <div id="item-nav">
38
- <div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
39
  <ul>
40
 
41
  <?php bp_get_displayed_user_nav(); ?>
35
  </div><!-- #item-header -->
36
 
37
  <div id="item-nav">
38
+ <div class="item-list-tabs no-ajax" id="object-nav" aria-label="<?php esc_attr_e( 'Member primary navigation', 'buddypress' ); ?>" role="navigation">
39
  <ul>
40
 
41
  <?php bp_get_displayed_user_nav(); ?>
bp-templates/bp-legacy/buddypress/members/single/member-header.php CHANGED
@@ -31,7 +31,7 @@ do_action( 'bp_before_member_header' ); ?>
31
  <h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
32
  <?php endif; ?>
33
 
34
- <span class="activity"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
35
 
36
  <?php
37
 
31
  <h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
32
  <?php endif; ?>
33
 
34
+ <span class="activity" data-livestamp="<?php bp_core_iso8601_date( bp_get_user_last_activity( bp_displayed_user_id() ) ); ?>"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
35
 
36
  <?php
37
 
bp-templates/bp-legacy/buddypress/members/single/messages.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
 
14
  <?php bp_get_options_nav(); ?>
@@ -37,6 +37,12 @@ switch ( bp_current_action() ) :
37
  */
38
  do_action( 'bp_before_member_messages_content' ); ?>
39
 
 
 
 
 
 
 
40
  <div class="messages">
41
  <?php bp_get_template_part( 'members/single/messages/messages-loop' ); ?>
42
  </div><!-- .messages -->
@@ -71,6 +77,8 @@ switch ( bp_current_action() ) :
71
  */
72
  do_action( 'bp_before_member_messages_content' ); ?>
73
 
 
 
74
  <div class="messages">
75
  <?php bp_get_template_part( 'members/single/messages/notices-loop' ); ?>
76
  </div><!-- .messages -->
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
 
14
  <?php bp_get_options_nav(); ?>
37
  */
38
  do_action( 'bp_before_member_messages_content' ); ?>
39
 
40
+ <?php if ( bp_is_messages_inbox() ) : ?>
41
+ <h2 class="bp-screen-reader-text"><?php _e( 'Messages inbox', 'buddypress' ); ?></h2>
42
+ <?php elseif ( bp_is_messages_sentbox() ) : ?>
43
+ <h2 class="bp-screen-reader-text"><?php _e( 'Sent Messages', 'buddypress' ); ?></h2>
44
+ <?php endif; ?>
45
+
46
  <div class="messages">
47
  <?php bp_get_template_part( 'members/single/messages/messages-loop' ); ?>
48
  </div><!-- .messages -->
77
  */
78
  do_action( 'bp_before_member_messages_content' ); ?>
79
 
80
+ <h2 class="bp-screen-reader-text"><?php _e( 'Sitewide Notices', 'buddypress' ); ?></h2>
81
+
82
  <div class="messages">
83
  <?php bp_get_template_part( 'members/single/messages/notices-loop' ); ?>
84
  </div><!-- .messages -->
bp-templates/bp-legacy/buddypress/members/single/messages/compose.php CHANGED
@@ -7,6 +7,8 @@
7
  */
8
 
9
  ?>
 
 
10
  <form action="<?php bp_messages_form_action('compose' ); ?>" method="post" id="send_message_form" class="standard-form" enctype="multipart/form-data">
11
 
12
  <?php
7
  */
8
 
9
  ?>
10
+ <h2 class="bp-screen-reader-text"><?php _e( 'Compose Message', 'buddypress' ); ?></h2>
11
+
12
  <form action="<?php bp_messages_form_action('compose' ); ?>" method="post" id="send_message_form" class="standard-form" enctype="multipart/form-data">
13
 
14
  <?php
bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php CHANGED
@@ -15,6 +15,8 @@ do_action( 'bp_before_member_messages_loop' ); ?>
15
 
16
  <?php if ( bp_has_message_threads( bp_ajax_querystring( 'messages' ) ) ) : ?>
17
 
 
 
18
  <div class="pagination no-ajax" id="user-pag">
19
 
20
  <div class="pag-count" id="messages-dir-count">
15
 
16
  <?php if ( bp_has_message_threads( bp_ajax_querystring( 'messages' ) ) ) : ?>
17
 
18
+ <h2 class="bp-screen-reader-text"><?php _e( 'Starred messages', 'buddypress' ); ?></h2>
19
+
20
  <div class="pagination no-ajax" id="user-pag">
21
 
22
  <div class="pag-count" id="messages-dir-count">
bp-templates/bp-legacy/buddypress/members/single/messages/single.php CHANGED
@@ -20,7 +20,7 @@
20
 
21
  <?php if ( bp_thread_has_messages() ) : ?>
22
 
23
- <h3 id="message-subject"><?php bp_the_thread_subject(); ?></h3>
24
 
25
  <p id="message-recipients">
26
  <span class="highlight">
20
 
21
  <?php if ( bp_thread_has_messages() ) : ?>
22
 
23
+ <h2 id="message-subject"><?php bp_the_thread_subject(); ?></h2>
24
 
25
  <p id="message-recipients">
26
  <span class="highlight">
bp-templates/bp-legacy/buddypress/members/single/notifications.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
  <?php bp_get_options_nav(); ?>
14
 
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
  <?php bp_get_options_nav(); ?>
14
 
bp-templates/bp-legacy/buddypress/members/single/notifications/read.php CHANGED
@@ -10,6 +10,8 @@
10
 
11
  <?php if ( bp_has_notifications() ) : ?>
12
 
 
 
13
  <div id="pag-top" class="pagination no-ajax">
14
  <div class="pag-count" id="notifications-count-top">
15
  <?php bp_notifications_pagination_count(); ?>
10
 
11
  <?php if ( bp_has_notifications() ) : ?>
12
 
13
+ <h2 class="bp-screen-reader-text"><?php _e( 'Notifications', 'buddypress' ); ?></h2>
14
+
15
  <div id="pag-top" class="pagination no-ajax">
16
  <div class="pag-count" id="notifications-count-top">
17
  <?php bp_notifications_pagination_count(); ?>
bp-templates/bp-legacy/buddypress/members/single/notifications/unread.php CHANGED
@@ -10,6 +10,8 @@
10
 
11
  <?php if ( bp_has_notifications() ) : ?>
12
 
 
 
13
  <div id="pag-top" class="pagination no-ajax">
14
  <div class="pag-count" id="notifications-count-top">
15
  <?php bp_notifications_pagination_count(); ?>
10
 
11
  <?php if ( bp_has_notifications() ) : ?>
12
 
13
+ <h2 class="bp-screen-reader-text"><?php _e( 'Unread notifications', 'buddypress' ); ?></h2>
14
+
15
  <div id="pag-top" class="pagination no-ajax">
16
  <div class="pag-count" id="notifications-count-top">
17
  <?php bp_notifications_pagination_count(); ?>
bp-templates/bp-legacy/buddypress/members/single/plugins.php CHANGED
@@ -18,7 +18,7 @@
18
 
19
  <?php if ( ! bp_is_current_component_core() ) : ?>
20
 
21
- <div class="item-list-tabs no-ajax" id="subnav">
22
  <ul>
23
  <?php bp_get_options_nav(); ?>
24
 
18
 
19
  <?php if ( ! bp_is_current_component_core() ) : ?>
20
 
21
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
22
  <ul>
23
  <?php bp_get_options_nav(); ?>
24
 
bp-templates/bp-legacy/buddypress/members/single/profile.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
  <?php bp_get_options_nav(); ?>
14
  </ul>
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
  <?php bp_get_options_nav(); ?>
14
  </ul>
bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <h4><?php _e( 'Change Profile Photo', 'buddypress' ); ?></h4>
12
 
13
  <?php
14
 
@@ -42,7 +42,7 @@ do_action( 'bp_before_profile_avatar_upload_content' ); ?>
42
 
43
  <?php if ( bp_get_user_has_avatar() ) : ?>
44
  <p><?php _e( "If you'd like to delete your current profile photo but not upload a new one, please use the delete profile photo button.", 'buddypress' ); ?></p>
45
- <p><a class="button edit" href="<?php bp_avatar_delete_link(); ?>" title="<?php esc_attr_e( 'Delete Profile Photo', 'buddypress' ); ?>"><?php _e( 'Delete My Profile Photo', 'buddypress' ); ?></a></p>
46
  <?php endif; ?>
47
 
48
  <?php endif; ?>
8
 
9
  ?>
10
 
11
+ <h2><?php _e( 'Change Profile Photo', 'buddypress' ); ?></h2>
12
 
13
  <?php
14
 
42
 
43
  <?php if ( bp_get_user_has_avatar() ) : ?>
44
  <p><?php _e( "If you'd like to delete your current profile photo but not upload a new one, please use the delete profile photo button.", 'buddypress' ); ?></p>
45
+ <p><a class="button edit" href="<?php bp_avatar_delete_link(); ?>"><?php _e( 'Delete My Profile Photo', 'buddypress' ); ?></a></p>
46
  <?php endif; ?>
47
 
48
  <?php endif; ?>
bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
- /**
3
- * BuddyPress - Members Profile Change Cover Image
4
- *
5
- * @package BuddyPress
6
- * @subpackage bp-legacy
7
- */
8
-
9
- ?>
10
-
11
- <h4><?php _e( 'Change Cover Image', 'buddypress' ); ?></h4>
12
-
13
- <?php
14
-
15
- /**
16
- * Fires before the display of profile cover image upload content.
17
- *
18
- * @since 2.4.0
19
- */
20
- do_action( 'bp_before_profile_edit_cover_image' ); ?>
21
-
22
- <p><?php _e( 'Your Cover Image will be used to customize the header of your profile.', 'buddypress' ); ?></p>
23
-
24
- <?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
25
-
26
- <?php
27
-
28
- /**
29
- * Fires after the display of profile cover image upload content.
30
- *
31
- * @since 2.4.0
32
- */
33
- do_action( 'bp_after_profile_edit_cover_image' ); ?>
1
+ <?php
2
+ /**
3
+ * BuddyPress - Members Profile Change Cover Image
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage bp-legacy
7
+ */
8
+
9
+ ?>
10
+
11
+ <h2><?php _e( 'Change Cover Image', 'buddypress' ); ?></h2>
12
+
13
+ <?php
14
+
15
+ /**
16
+ * Fires before the display of profile cover image upload content.
17
+ *
18
+ * @since 2.4.0
19
+ */
20
+ do_action( 'bp_before_profile_edit_cover_image' ); ?>
21
+
22
+ <p><?php _e( 'Your Cover Image will be used to customize the header of your profile.', 'buddypress' ); ?></p>
23
+
24
+ <?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
25
+
26
+ <?php
27
+
28
+ /**
29
+ * Fires after the display of profile cover image upload content.
30
+ *
31
+ * @since 2.4.0
32
+ */
33
+ do_action( 'bp_after_profile_edit_cover_image' ); ?>
bp-templates/bp-legacy/buddypress/members/single/profile/edit.php CHANGED
@@ -23,7 +23,7 @@ if ( bp_has_profile( 'profile_group_id=' . bp_get_current_profile_group_id() ) )
23
  /** This action is documented in bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php */
24
  do_action( 'bp_before_profile_field_content' ); ?>
25
 
26
- <h4><?php printf( __( "Editing '%s' Profile Group", 'buddypress' ), bp_get_the_profile_group_name() ); ?></h4>
27
 
28
  <?php if ( bp_profile_has_multiple_groups() ) : ?>
29
  <ul class="button-nav">
23
  /** This action is documented in bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php */
24
  do_action( 'bp_before_profile_field_content' ); ?>
25
 
26
+ <h2><?php printf( __( "Editing '%s' Profile Group", 'buddypress' ), bp_get_the_profile_group_name() ); ?></h2>
27
 
28
  <?php if ( bp_profile_has_multiple_groups() ) : ?>
29
  <ul class="button-nav">
bp-templates/bp-legacy/buddypress/members/single/profile/profile-loop.php CHANGED
@@ -22,7 +22,7 @@ do_action( 'bp_before_profile_loop_content' ); ?>
22
 
23
  <div class="bp-widget <?php bp_the_profile_group_slug(); ?>">
24
 
25
- <h4><?php bp_the_profile_group_name(); ?></h4>
26
 
27
  <table class="profile-fields">
28
 
22
 
23
  <div class="bp-widget <?php bp_the_profile_group_slug(); ?>">
24
 
25
+ <h2><?php bp_the_profile_group_name(); ?></h2>
26
 
27
  <table class="profile-fields">
28
 
bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php CHANGED
@@ -25,7 +25,7 @@ do_action( 'bp_before_profile_loop_content' ); ?>
25
  do_action( 'bp_before_profile_field_content' ); ?>
26
 
27
  <div class="bp-widget wp-profile">
28
- <h4><?php bp_is_my_profile() ? _e( 'My Profile', 'buddypress' ) : printf( __( "%s's Profile", 'buddypress' ), bp_get_displayed_user_fullname() ); ?></h4>
29
 
30
  <table class="wp-profile-fields">
31
 
25
  do_action( 'bp_before_profile_field_content' ); ?>
26
 
27
  <div class="bp-widget wp-profile">
28
+ <h2><?php bp_is_my_profile() ? _e( 'My Profile', 'buddypress' ) : printf( __( "%s's Profile", 'buddypress' ), bp_get_displayed_user_fullname() ); ?></h2>
29
 
30
  <table class="wp-profile-fields">
31
 
bp-templates/bp-legacy/buddypress/members/single/settings.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  ?>
10
 
11
- <div class="item-list-tabs no-ajax" id="subnav" role="navigation">
12
  <ul>
13
  <?php if ( bp_core_can_edit_settings() ) : ?>
14
 
8
 
9
  ?>
10
 
11
+ <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
12
  <ul>
13
  <?php if ( bp_core_can_edit_settings() ) : ?>
14
 
bp-templates/bp-legacy/buddypress/members/single/settings/general.php CHANGED
@@ -9,6 +9,8 @@
9
  /** This action is documented in bp-templates/bp-legacy/buddypress/members/single/settings/profile.php */
10
  do_action( 'bp_before_member_settings_template' ); ?>
11
 
 
 
12
  <form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/general'; ?>" method="post" class="standard-form" id="settings-form">
13
 
14
  <?php if ( !is_super_admin() ) : ?>
9
  /** This action is documented in bp-templates/bp-legacy/buddypress/members/single/settings/profile.php */
10
  do_action( 'bp_before_member_settings_template' ); ?>
11
 
12
+ <h2 class="bp-screen-reader-text"><?php _e( 'Account settings', 'buddypress' ); ?></h2>
13
+
14
  <form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/general'; ?>" method="post" class="standard-form" id="settings-form">
15
 
16
  <?php if ( !is_super_admin() ) : ?>
bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php CHANGED
@@ -9,6 +9,8 @@
9
  /** This action is documented in bp-templates/bp-legacy/buddypress/members/single/settings/profile.php */
10
  do_action( 'bp_before_member_settings_template' ); ?>
11
 
 
 
12
  <form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/notifications'; ?>" method="post" class="standard-form" id="settings-form">
13
  <p><?php _e( 'Send an email notice when:', 'buddypress' ); ?></p>
14
 
9
  /** This action is documented in bp-templates/bp-legacy/buddypress/members/single/settings/profile.php */
10
  do_action( 'bp_before_member_settings_template' ); ?>
11
 
12
+ <h2 class="bp-screen-reader-text"><?php _e( 'Notification settings', 'buddypress' ); ?></h2>
13
+
14
  <form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/notifications'; ?>" method="post" class="standard-form" id="settings-form">
15
  <p><?php _e( 'Send an email notice when:', 'buddypress' ); ?></p>
16
 
bp-templates/bp-legacy/buddypress/members/single/settings/profile.php CHANGED
@@ -13,6 +13,8 @@
13
  */
14
  do_action( 'bp_before_member_settings_template' ); ?>
15
 
 
 
16
  <form action="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() . '/profile' ); ?>" method="post" class="standard-form" id="settings-form">
17
 
18
  <?php if ( bp_xprofile_get_settings_fields() ) : ?>
13
  */
14
  do_action( 'bp_before_member_settings_template' ); ?>
15
 
16
+ <h2 class="bp-screen-reader-text"><?php _e( 'Profile visibility settings', 'buddypress' ); ?></h2>
17
+
18
  <form action="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() . '/profile' ); ?>" method="post" class="standard-form" id="settings-form">
19
 
20
  <?php if ( bp_xprofile_get_settings_fields() ) : ?>
bp-templates/bp-legacy/css/buddypress-rtl.css CHANGED
@@ -624,7 +624,6 @@ body.activity-permalink #buddypress div.activity-comments div.acomment-content {
624
 
625
  #buddypress .standard-form textarea,
626
  #buddypress .standard-form input[type=text],
627
- #buddypress .standard-form input[type=text],
628
  #buddypress .standard-form input[type=color],
629
  #buddypress .standard-form input[type=date],
630
  #buddypress .standard-form input[type=datetime],
@@ -647,7 +646,7 @@ body.activity-permalink #buddypress div.activity-comments div.acomment-content {
647
  border: 1px solid #ccc;
648
  background: #fafafa;
649
  border-radius: 0;
650
- color: #767676;
651
  font: inherit;
652
  font-size: 100%;
653
  padding: 6px;
@@ -786,7 +785,7 @@ body.no-js #buddypress #messages-bulk-management #select-all-messages {
786
  padding: 5px;
787
  width: 160px;
788
  }
789
- #buddypress button,
790
  #buddypress a.button,
791
  #buddypress input[type=submit],
792
  #buddypress input[type=button],
@@ -805,7 +804,7 @@ a.bp-title-button {
805
  text-align: center;
806
  text-decoration: none;
807
  }
808
- #buddypress button:hover,
809
  #buddypress a.button:hover,
810
  #buddypress a.button:focus,
811
  #buddypress input[type=submit]:hover,
@@ -844,6 +843,7 @@ a.bp-title-button {
844
  float: right;
845
  }
846
 
 
847
  #buddypress form.standard-form .main-column ul#friend-list h4 {
848
  clear:none;
849
  }
@@ -1071,6 +1071,7 @@ a.bp-title-button {
1071
  #buddypress table.messages-notices tr.alt td,
1072
  #buddypress table.forum tr.alt td {
1073
  background: #f5f5f5;
 
1074
  }
1075
  #buddypress table.notification-settings {
1076
  margin-bottom: 20px;
@@ -1169,7 +1170,6 @@ a.bp-title-button {
1169
  #buddypress span.activity {
1170
  display: inline-block;
1171
  font-size: small;
1172
- opacity: 0.8;
1173
  padding: 0;
1174
  }
1175
  #buddypress span.user-nicename {
@@ -1244,6 +1244,7 @@ a.bp-title-button {
1244
  text-align: left;
1245
  width: 20%;
1246
  }
 
1247
  #buddypress div#item-header div#item-actions h3 {
1248
  margin: 0 0 5px 0;
1249
  }
@@ -1304,6 +1305,7 @@ body.activity-permalink #buddypress ul.item-list li.activity-item {
1304
  margin: 0 0 0 10px;
1305
  }
1306
  #buddypress ul.item-list li div.item-title,
 
1307
  #buddypress ul.item-list li h4 {
1308
  font-weight: normal;
1309
  font-size: 90%;
@@ -1389,7 +1391,7 @@ body.activity-permalink #buddypress ul.item-list li.activity-item {
1389
  #buddypress div.item-list-tabs ul li.current a {
1390
  background-color: #eee;
1391
  color: #555;
1392
- opacity: .8;
1393
  font-weight: bold;
1394
  }
1395
  #buddypress div.item-list-tabs ul li.selected a span,
@@ -1418,6 +1420,12 @@ body.activity-permalink #buddypress ul.item-list li.activity-item {
1418
  overflow: auto;
1419
  list-style: none;
1420
  }
 
 
 
 
 
 
1421
  #buddypress #item-buttons:empty {
1422
  display: none;
1423
  }
@@ -1558,7 +1566,7 @@ a.message-action-star:hover {
1558
  3.10 - Extended Profiles
1559
  --------------------------------------------------------------*/
1560
 
1561
- #buddypress div.profile h4 {
1562
  margin-bottom: auto;
1563
  margin-top: 15px;
1564
  }
@@ -1583,7 +1591,7 @@ body.no-js #buddypress .field-visibility-settings-close {
1583
  #buddypress .field-visibility-settings,
1584
  #buddypress .field-visibility-settings-toggle,
1585
  #buddypress .field-visibility-settings-notoggle {
1586
- color: #767676;
1587
  }
1588
  #buddypress .field-visibility-settings-toggle a,
1589
  #buddypress .field-visibility-settings a {
@@ -1615,12 +1623,14 @@ body.register #buddypress div.page ul {
1615
  border-bottom-right-radius: 0;
1616
  border-bottom-left-radius: 0;
1617
  background: #f5f5f5;
 
1618
  }
1619
  #buddypress .tmce-active button.switch-tmce {
1620
  border-bottom-color: transparent;
1621
  border-bottom-right-radius: 0;
1622
  border-bottom-left-radius: 0;
1623
  background: #f5f5f5;
 
1624
  }
1625
  #buddypress .standard-form .wp-editor-container textarea {
1626
  width: 100%;
@@ -1742,6 +1752,7 @@ body.register #buddypress div.page ul {
1742
  position: relative;
1743
  margin-bottom:1em;
1744
  }
 
1745
  #buddypress form.standard-form .main-column ul#friend-list h4{
1746
  width:100%;
1747
  }
624
 
625
  #buddypress .standard-form textarea,
626
  #buddypress .standard-form input[type=text],
 
627
  #buddypress .standard-form input[type=color],
628
  #buddypress .standard-form input[type=date],
629
  #buddypress .standard-form input[type=datetime],
646
  border: 1px solid #ccc;
647
  background: #fafafa;
648
  border-radius: 0;
649
+ color: #737373;
650
  font: inherit;
651
  font-size: 100%;
652
  padding: 6px;
785
  padding: 5px;
786
  width: 160px;
787
  }
788
+ #buddypress .standard-form button,
789
  #buddypress a.button,
790
  #buddypress input[type=submit],
791
  #buddypress input[type=button],
804
  text-align: center;
805
  text-decoration: none;
806
  }
807
+ #buddypress .standard-form button:hover,
808
  #buddypress a.button:hover,
809
  #buddypress a.button:focus,
810
  #buddypress input[type=submit]:hover,
843
  float: right;
844
  }
845
 
846
+ #buddypress form.standard-form .main-column ul#friend-list h3,
847
  #buddypress form.standard-form .main-column ul#friend-list h4 {
848
  clear:none;
849
  }
1071
  #buddypress table.messages-notices tr.alt td,
1072
  #buddypress table.forum tr.alt td {
1073
  background: #f5f5f5;
1074
+ color: #707070;
1075
  }
1076
  #buddypress table.notification-settings {
1077
  margin-bottom: 20px;
1170
  #buddypress span.activity {
1171
  display: inline-block;
1172
  font-size: small;
 
1173
  padding: 0;
1174
  }
1175
  #buddypress span.user-nicename {
1244
  text-align: left;
1245
  width: 20%;
1246
  }
1247
+ #buddypress div#item-header div#item-actions h2,
1248
  #buddypress div#item-header div#item-actions h3 {
1249
  margin: 0 0 5px 0;
1250
  }
1305
  margin: 0 0 0 10px;
1306
  }
1307
  #buddypress ul.item-list li div.item-title,
1308
+ #buddypress ul.item-list li h3,
1309
  #buddypress ul.item-list li h4 {
1310
  font-weight: normal;
1311
  font-size: 90%;
1391
  #buddypress div.item-list-tabs ul li.current a {
1392
  background-color: #eee;
1393
  color: #555;
1394
+ opacity: .9;
1395
  font-weight: bold;
1396
  }
1397
  #buddypress div.item-list-tabs ul li.selected a span,
1420
  overflow: auto;
1421
  list-style: none;
1422
  }
1423
+ #buddypress .group-members-list {
1424
+ width: 100%;
1425
+ margin-top: 1em;
1426
+ clear: both;
1427
+ overflow: auto;
1428
+ }
1429
  #buddypress #item-buttons:empty {
1430
  display: none;
1431
  }
1566
  3.10 - Extended Profiles
1567
  --------------------------------------------------------------*/
1568
 
1569
+ #buddypress div.profile h2 {
1570
  margin-bottom: auto;
1571
  margin-top: 15px;
1572
  }
1591
  #buddypress .field-visibility-settings,
1592
  #buddypress .field-visibility-settings-toggle,
1593
  #buddypress .field-visibility-settings-notoggle {
1594
+ color: #707070;
1595
  }
1596
  #buddypress .field-visibility-settings-toggle a,
1597
  #buddypress .field-visibility-settings a {
1623
  border-bottom-right-radius: 0;
1624
  border-bottom-left-radius: 0;
1625
  background: #f5f5f5;
1626
+ color: #707070;
1627
  }
1628
  #buddypress .tmce-active button.switch-tmce {
1629
  border-bottom-color: transparent;
1630
  border-bottom-right-radius: 0;
1631
  border-bottom-left-radius: 0;
1632
  background: #f5f5f5;
1633
+ color: #707070;
1634
  }
1635
  #buddypress .standard-form .wp-editor-container textarea {
1636
  width: 100%;
1752
  position: relative;
1753
  margin-bottom:1em;
1754
  }
1755
+ #buddypress form.standard-form .main-column ul#friend-list h3,
1756
  #buddypress form.standard-form .main-column ul#friend-list h4{
1757
  width:100%;
1758
  }
bp-templates/bp-legacy/css/buddypress-rtl.min.css CHANGED
@@ -1 +1 @@
1
- #buddypress div.pagination .pagination-links a:hover,#buddypress ul.button-nav li.current a{font-weight:700}#buddypress div.pagination{background:0 0;border:none;color:#767676;font-size:small;margin:0;position:relative;display:block;float:right;width:100%;padding:10px 0}#buddypress div.pagination .pag-count{float:right;margin-right:10px}#buddypress div.pagination .pagination-links{float:left;margin-left:10px}#buddypress div.pagination .pagination-links a,#buddypress div.pagination .pagination-links span{font-size:90%;padding:0 5px}#buddypress noscript div.pagination{margin-bottom:15px}#buddypress #nav-above{display:none}#buddypress .paged #nav-above{display:block}#buddypress img.wp-smiley{border:none!important;clear:none!important;float:none!important;margin:0!important;padding:0!important}#buddypress .clear{clear:right}#buddypress #activity-stream{margin-top:-5px}#buddypress #activity-stream p{margin:5px 0}#buddypress #item-body form#whats-new-form{margin:0;padding:0}#buddypress .home-page form#whats-new-form{border-bottom:none;padding-bottom:0}#buddypress form#whats-new-form #whats-new-avatar{float:right}#buddypress form#whats-new-form #whats-new-content{margin-right:55px;padding:0 20px 20px 0}#buddypress form#whats-new-form p.activity-greeting{line-height:.5em;margin-bottom:15px;margin-right:75px}#buddypress form#whats-new-form textarea{background:#fff;box-sizing:border-box;color:#555;font-family:inherit;font-size:medium;height:2.2em;line-height:1.4;padding:6px;width:100%}body.no-js #buddypress form#whats-new-form textarea{height:50px}#buddypress form#whats-new-form #whats-new-options select{max-width:200px;margin-top:12px}#buddypress form#whats-new-form #whats-new-submit{float:left;margin-top:12px}#buddypress #whats-new-options:after{clear:both;content:"";display:table}body.no-js #buddypress #whats-new-options{height:auto}#buddypress #whats-new:focus{border-color:rgba(31,179,221,.9)!important;outline-color:rgba(31,179,221,.9)}#buddypress ul.activity-list li{overflow:hidden;padding:15px 0 0;list-style:none}#buddypress .activity-list .activity-avatar{float:right}#buddypress ul.item-list.activity-list li.has-comments{padding-bottom:15px}body.activity-permalink #buddypress ul.activity-list li.has-comments{padding-bottom:0}#buddypress .activity-list li.mini{font-size:80%;position:relative}#buddypress .activity-list li.mini .activity-avatar img.FB_profile_pic,#buddypress .activity-list li.mini .activity-avatar img.avatar{height:20px;margin-right:30px;width:20px}#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.FB_profile_pic,#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.avatar{height:auto;margin-right:0;width:auto}body.activity-permalink #buddypress .activity-list>li:first-child{padding-top:0}#buddypress .activity-list li .activity-content{position:relative}#buddypress .activity-list li.mini .activity-content p{margin:0}#buddypress .activity-list li.mini .activity-comments{clear:both;font-size:120%}body.activity-permalink #buddypress li.mini .activity-meta{margin-top:4px}#buddypress .activity-list li .activity-inreplyto{color:#767676;font-size:80%}#buddypress .activity-list li .activity-inreplyto>p{margin:0;display:inline}#buddypress .activity-list li .activity-inreplyto blockquote,#buddypress .activity-list li .activity-inreplyto div.activity-inner{background:0 0;border:none;display:inline;margin:0;overflow:hidden;padding:0}#buddypress .activity-list .activity-content{margin:0 70px 0 0}body.activity-permalink #buddypress .activity-list li .activity-content{border:none;font-size:100%;line-height:150%;margin-right:170px;margin-left:0;padding:0}body.activity-permalink #buddypress .activity-list li .activity-header>p{margin:0;padding:5px 0 0}#buddypress .activity-list .activity-content .activity-header,#buddypress .activity-list .activity-content .comment-header{color:#767676;line-height:220%}#buddypress .activity-header{margin-left:20px}#buddypress .acomment-meta a,#buddypress .activity-header a,#buddypress .comment-meta a{text-decoration:none}#buddypress .activity-list .activity-content .activity-header img.avatar{float:none!important;margin:0 0 -8px 5px!important}#buddypress a.bp-secondary-action,#buddypress span.highlight{font-size:80%;padding:0;margin-left:5px;text-decoration:none}#buddypress .activity-list .activity-content .activity-inner,#buddypress .activity-list .activity-content blockquote{margin:10px 0 5px 10px;overflow:hidden}#buddypress .activity-list li.new_forum_post .activity-content .activity-inner,#buddypress .activity-list li.new_forum_topic .activity-content .activity-inner{border-right:2px solid #EAEAEA;margin-right:5px;padding-right:10px}body.activity-permalink #buddypress .activity-content .activity-inner,body.activity-permalink #buddypress .activity-content blockquote{margin-right:0;margin-top:5px}#buddypress .activity-inner>p{word-wrap:break-word}#buddypress .activity-inner>.activity-inner,#buddypress .activity-inner>blockquote{margin:0}#buddypress .activity-list .activity-content img.thumbnail{border:2px solid #eee;float:right;margin:0 0 5px 10px}#buddypress .activity-read-more{margin-right:1em;white-space:nowrap}#buddypress .activity-list li.load-more,#buddypress .activity-list li.load-newest{background:#f0f0f0;font-size:110%;margin:15px 0;padding:10px 15px;text-align:center}#buddypress .activity-list li.load-more a,#buddypress .activity-list li.load-newest a{color:#4D4D4D}#buddypress div.activity-meta{margin:18px 0 0}body.activity-permalink #buddypress div.activity-meta{margin-bottom:6px}#buddypress div.activity-meta a{padding:4px 8px}#buddypress a.activity-time-since{color:#767676;text-decoration:none}#buddypress a.activity-time-since:hover{color:#767676;text-decoration:underline}#buddypress #reply-title small a,#buddypress a.bp-primary-action{font-size:80%;margin-left:5px;text-decoration:none}#buddypress #reply-title small a span,#buddypress a.bp-primary-action span{background:#767676;color:#fff;font-size:90%;margin-right:2px;padding:0 5px}#buddypress #reply-title small a:hover span,#buddypress a.bp-primary-action:hover span{background:#555;color:#fff}#buddypress div.activity-comments{margin:0 70px 0 0;overflow:hidden;position:relative;width:auto;clear:both}body.activity-permalink #buddypress div.activity-comments{background:0 0;margin-right:170px;width:auto}#buddypress div.activity-comments>ul{padding:0 10px 0 0}#buddypress div.activity-comments ul,#buddypress div.activity-comments ul li{border:none;list-style:none}#buddypress div.activity-comments ul{clear:both;margin:0}#buddypress div.activity-comments ul li{border-top:1px solid #eee;padding:10px 0 0}body.activity-permalink #buddypress .activity-list li.mini .activity-comments{clear:none;margin-top:0}body.activity-permalink #buddypress div.activity-comments ul li{border-width:1px;padding:10px 0 0}#buddypress div.activity-comments>ul>li:first-child{border-top:none}#buddypress div.activity-comments ul li:last-child{margin-bottom:0}#buddypress div.activity-comments ul li>ul{margin-right:30px;margin-top:0;padding-right:10px}body.activity-permalink #buddypress div.activity-comments ul li>ul{margin-top:10px}body.activity-permalink #buddypress div.activity-comments>ul{padding:0 15px 0 10px}#buddypress div.activity-comments div.acomment-avatar img{border-width:1px;float:right;height:25px;margin-left:10px;width:25px}#buddypress div.activity-comments div.acomment-content{font-size:80%;margin:5px 40px 0 0}#buddypress div.acomment-content .activity-delete-link,#buddypress div.acomment-content .comment-header,#buddypress div.acomment-content .time-since{display:none}body.activity-permalink #buddypress div.activity-comments div.acomment-content{font-size:90%}#buddypress div.activity-comments div.acomment-meta{color:#767676;font-size:80%}#buddypress div.activity-comments form.ac-form{display:none;padding:10px}#buddypress div.activity-comments li form.ac-form{margin-left:15px;clear:both}#buddypress div.activity-comments form.root{margin-right:0}#buddypress div.activity-comments div#message{margin-top:15px;margin-bottom:0}#buddypress div.activity-comments form .ac-textarea{background:#fff;border:1px inset #ccc;margin-bottom:10px;padding:8px}#buddypress div.activity-comments form textarea{border:none;background:0 0;box-shadow:none;outline:0;color:#555;font-family:inherit;font-size:100%;height:60px;padding:0;margin:0;width:100%}#buddypress div.activity-comments form input{margin-top:5px}#buddypress div.activity-comments form div.ac-reply-avatar{float:right}#buddypress div.ac-reply-avatar img{border:1px solid #eee}#buddypress div.activity-comments form div.ac-reply-content{color:#767676;margin-right:50px;padding-right:15px}#buddypress div.activity-comments form div.ac-reply-content a{text-decoration:none}#buddypress .acomment-options{float:right;margin:5px 40px 5px 0}#buddypress .acomment-options a{color:#767676}#buddypress .acomment-options a:hover{color:inherit}#buddypress div.dir-search{float:left;margin:-39px 0 0}#buddypress div.dir-search input[type=text],#buddypress li.groups-members-search input[type=text]{font-size:90%;padding:1px 3px}#buddypress .current-member-type{font-style:italic}#buddypress .dir-form{clear:both}#buddypress div#message{margin:0 0 15px}#buddypress #message.info{margin-bottom:0}#buddypress div#message.updated{clear:both;display:block}#buddypress div#message p,#sitewide-notice p{font-size:90%;display:block;padding:10px 15px}#buddypress div#message.error p{background-color:#fdc;border:1px solid #a00;clear:right;color:#800}#buddypress div#message.warning p{background-color:#ffe0af;border:1px solid #ffd087;clear:right;color:#800}#buddypress div#message.updated p{background-color:#efc;border:1px solid #591;color:#250}#buddypress #pass-strength-result{background-color:#eee;border-color:#ddd;border-style:solid;border-width:1px;display:none;margin:5px 0 5px 5px;padding:5px;text-align:center;width:150px}#buddypress .standard-form #basic-details-section #pass-strength-result{width:35%}#buddypress #pass-strength-result.bad,#buddypress #pass-strength-result.error{background-color:#ffb78c;border-color:#ff853c!important;display:block}#buddypress #pass-strength-result.good{background-color:#ffec8b;border-color:#fc0!important;display:block}#buddypress #pass-strength-result.short{background-color:#ffa0a0;border-color:#f04040!important;display:block}#buddypress #pass-strength-result.strong{background-color:#c3ff88;border-color:#8dff1c!important;display:block}#buddypress .standard-form#signup_form div div.error{background:#faa;color:#a00;margin:0 0 10px;padding:6px;width:90%}#buddypress div.accept,#buddypress div.reject{float:right;margin-right:10px}#buddypress ul.button-nav li{float:right;margin:0 0 10px 10px;list-style:none}#sitewide-notice #message{right:2%;position:fixed;top:1em;width:96%;z-index:9999}#sitewide-notice.admin-bar-on #message{top:3.3em}#sitewide-notice strong{display:block;margin-bottom:-1em}#buddypress form fieldset{border:0;padding:0}#buddypress .dir-search input[type=search],#buddypress .dir-search input[type=text],#buddypress .groups-members-search input[type=search],#buddypress .groups-members-search input[type=text],#buddypress .standard-form input[type=color],#buddypress .standard-form input[type=date],#buddypress .standard-form input[type=datetime-local],#buddypress .standard-form input[type=datetime],#buddypress .standard-form input[type=email],#buddypress .standard-form input[type=month],#buddypress .standard-form input[type=number],#buddypress .standard-form input[type=password],#buddypress .standard-form input[type=range],#buddypress .standard-form input[type=search],#buddypress .standard-form input[type=tel],#buddypress .standard-form input[type=text],#buddypress .standard-form input[type=time],#buddypress .standard-form input[type=url],#buddypress .standard-form input[type=week],#buddypress .standard-form select,#buddypress .standard-form textarea{border:1px solid #ccc;background:#fafafa;border-radius:0;color:#767676;font:inherit;font-size:100%;padding:6px}#buddypress .standard-form select{padding:3px}#buddypress .standard-form input[type=password]{margin-bottom:5px}#buddypress .standard-form label,#buddypress .standard-form legend,#buddypress .standard-form span.label{display:block;font-weight:700;margin:15px 0 5px;width:auto}#buddypress .standard-form #invite-list label,#buddypress .standard-form p label{font-weight:400;margin:auto}#buddypress .standard-form .checkbox label,#buddypress .standard-form .radio label{color:#767676;font-size:100%;font-weight:400;margin:5px 0 0}#buddypress .standard-form .checkbox label input,#buddypress .standard-form .radio label input{margin-left:3px}#buddypress .standard-form#sidebar-login-form label{margin-top:5px}#buddypress .standard-form input[type=text]{width:75%}#buddypress .standard-form#sidebar-login-form input[type=password],#buddypress .standard-form#sidebar-login-form input[type=text]{padding:4px;width:95%}#buddypress .standard-form #basic-details-section input[type=password],#buddypress .standard-form #blog-details-section input#signup_blog_url{width:35%}#buddypress #commentform input[type=text],#buddypress #commentform textarea,#buddypress .form-allowed-tags,#buddypress .standard-form#signup_form input[type=text],#buddypress .standard-form#signup_form textarea{width:90%}#buddypress .standard-form#signup_form div.submit{float:left}#buddypress div#signup-avatar img{margin:0 0 10px 15px}#buddypress .standard-form textarea{width:75%;height:120px}#buddypress .standard-form textarea#message_content{height:200px}#buddypress .standard-form#send-reply textarea{width:97.5%}#buddypress .standard-form p.description{color:#767676;font-size:80%;margin:5px 0}#buddypress .standard-form div.submit{clear:both;padding:15px 0 0}#buddypress .standard-form p.submit{margin-bottom:0;padding:15px 0 0}#buddypress .standard-form div.submit input{margin-left:15px}#buddypress .standard-form div.radio ul{margin:10px 38px 15px 0;list-style:disc}#buddypress .standard-form div.radio ul li{margin-bottom:5px}#buddypress .standard-form a.clear-value{display:block;margin-top:5px;outline:0}#buddypress table.notification-settings td:first-child,#buddypress table.notification-settings th.icon,#buddypress table.notifications td:first-child,#buddypress table.notifications th.icon,body.no-js #buddypress #delete_inbox_messages,body.no-js #buddypress #delete_sentbox_messages,body.no-js #buddypress #message-type-select,body.no-js #buddypress #messages-bulk-management #select-all-messages,body.no-js #buddypress #notifications-bulk-management #select-all-notifications,body.no-js #buddypress label[for=message-type-select]{display:none}#buddypress .standard-form #basic-details-section,#buddypress .standard-form #blog-details-section,#buddypress .standard-form #profile-details-section{float:right;width:48%}#buddypress .standard-form #profile-details-section{float:left}#buddypress #notifications-bulk-management,#buddypress .standard-form #blog-details-section{clear:right}#buddypress .standard-form input:focus,#buddypress .standard-form select:focus,#buddypress .standard-form textarea:focus{background:#fafafa;color:#555}#buddypress form#send-invite-form{margin-top:20px}#buddypress div#invite-list{background:#f5f5f5;height:400px;margin:0 0 10px;overflow:auto;padding:5px;width:160px}#buddypress .comment-reply-link,#buddypress .generic-button a,#buddypress a.button,#buddypress button,#buddypress input[type=button],#buddypress input[type=reset],#buddypress input[type=submit],#buddypress ul.button-nav li a,a.bp-title-button{background:#fff;border:1px solid #ccc;color:#767676;font-size:small;cursor:pointer;outline:0;padding:4px 10px;text-align:center;text-decoration:none}#buddypress .comment-reply-link:hover,#buddypress a.button:focus,#buddypress a.button:hover,#buddypress button:hover,#buddypress div.generic-button a:hover,#buddypress input[type=button]:hover,#buddypress input[type=reset]:hover,#buddypress input[type=submit]:hover,#buddypress ul.button-nav li a:hover,#buddypress ul.button-nav li.current a{background:#ededed;border:1px solid #bbb;color:#555;outline:0;text-decoration:none}#buddypress form.standard-form .left-menu{float:right}#buddypress form.standard-form .left-menu #invite-list ul{margin:1%;list-style:none}#buddypress form.standard-form .left-menu #invite-list ul li{margin:0 1% 0 0}#buddypress form.standard-form .main-column{margin-right:190px}#buddypress form.standard-form .main-column ul#friend-list{clear:none;float:right}#buddypress form.standard-form .main-column ul#friend-list h4{clear:none}#buddypress .wp-editor-wrap a.button,#buddypress .wp-editor-wrap button,#buddypress .wp-editor-wrap input[type=button],#buddypress .wp-editor-wrap input[type=reset],#buddypress .wp-editor-wrap input[type=submit]{padding:0 8px 1px}#buddypress form [disabled=disabled]{cursor:default;opacity:.4}.bp-screen-reader-text{position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip:rect(0 0 0 0);border:0;word-wrap:normal!important}#buddypress a.loading,#buddypress input.loading{-webkit-animation:loader-pulsate .5s infinite ease-in-out alternate;-moz-animation:loader-pulsate .5s infinite ease-in-out alternate;border-color:#aaa}@-webkit-keyframes loader-pulsate{from{border-color:#aaa;-webkit-box-shadow:0 0 6px #ccc;box-shadow:0 0 6px #ccc}to{border-color:#ccc;-webkit-box-shadow:0 0 6px #f8f8f8;box-shadow:0 0 6px #f8f8f8}}@-moz-keyframes loader-pulsate{from{border-color:#aaa;-moz-box-shadow:0 0 6px #ccc;box-shadow:0 0 6px #ccc}to{border-color:#ccc;-moz-box-shadow:0 0 6px #f8f8f8;box-shadow:0 0 6px #f8f8f8}}#buddypress a.loading:hover,#buddypress input.loading:hover{color:#767676}#buddypress a.disabled,#buddypress button.disabled,#buddypress button.pending,#buddypress div.pending a,#buddypress input[type=submit].disabled,#buddypress input[type=submit].pending,#buddypress input[type=submit][disabled=disabled],#buddypress input[type=button].disabled,#buddypress input[type=button].pending,#buddypress input[type=reset].disabled,#buddypress input[type=reset].pending{border-color:#eee;color:#bbb;cursor:default}#buddypress a.disabled:hover,#buddypress button.disabled:hover,#buddypress button.pending:hover,#buddypress div.pending a:hover,#buddypress input[type=submit]:hover.disabled,#buddypress input[type=submit]:hover.pending,#buddypress input[type=button]:hover.disabled,#buddypress input[type=button]:hover.pending,#buddypress input[type=reset]:hover.disabled,#buddypress input[type=reset]:hover.pending{border-color:#eee;color:#bbb}#buddypress ul#topic-post-list{margin:0;width:auto}#buddypress ul#topic-post-list li{padding:15px;position:relative}#buddypress ul#topic-post-list li.alt{background:#f5f5f5}#buddypress ul#topic-post-list li div.poster-meta{color:#767676;margin-bottom:10px}#buddypress ul#topic-post-list li div.post-content{margin-right:54px}#buddypress div.topic-tags{font-size:80%}#buddypress div.admin-links{color:#767676;font-size:80%;position:absolute;top:15px;left:25px}#buddypress div#topic-meta{margin:0;padding:5px 19px 30px;position:relative}#buddypress div#topic-meta div.admin-links{left:19px;top:-36px}#buddypress div#topic-meta h3{margin:5px 0}#buddypress div#new-topic-post{display:none;margin:20px 0 0;padding:1px 0 0}#buddypress table.forum,#buddypress table.messages-notices,#buddypress table.notifications,#buddypress table.notifications-settings,#buddypress table.profile-fields,#buddypress table.profile-settings,#buddypress table.wp-profile-fields{width:100%}#buddypress table.forum thead tr,#buddypress table.messages-notices thead tr,#buddypress table.notifications thead tr,#buddypress table.notifications-settings thead tr,#buddypress table.profile-fields thead tr,#buddypress table.profile-settings thead tr,#buddypress table.wp-profile-fields thead tr{background:#eaeaea}#buddypress table#message-threads{clear:both}#buddypress table.profile-fields{margin-bottom:20px}#buddypress table tr td.thread-info p,#buddypress table.profile-fields p{margin:0}#buddypress table.profile-fields:last-child{margin-bottom:0}#buddypress table.profile-fields p:last-child{margin-top:0}#buddypress table.forum tr td,#buddypress table.forum tr th,#buddypress table.messages-notices tr td,#buddypress table.messages-notices tr th,#buddypress table.notifications tr td,#buddypress table.notifications tr th,#buddypress table.notifications-settings tr td,#buddypress table.notifications-settings tr th,#buddypress table.profile-fields tr td,#buddypress table.profile-fields tr th,#buddypress table.profile-settings tr td,#buddypress table.wp-profile-fields tr td,#buddypress table.wp-profile-fields tr th{padding:8px;vertical-align:middle}#buddypress table.forum tr td.label,#buddypress table.messages-notices tr td.label,#buddypress table.notifications tr td.label,#buddypress table.notifications-settings tr td.label,#buddypress table.profile-fields tr td.label,#buddypress table.wp-profile-fields tr td.label{border-left:1px solid #eaeaea;font-weight:700;width:25%}#buddypress #message-threads .thread-info{min-width:40%}#buddypress table tr td.thread-info p.thread-excerpt{color:#767676;font-size:80%;margin-top:3px}#buddypress table.forum td{text-align:center}#buddypress table.forum tr.alt td,#buddypress table.messages-notices tr.alt td,#buddypress table.notifications tr.alt td,#buddypress table.notifications-settings tr.alt td,#buddypress table.profile-fields tr.alt td,#buddypress table.profile-settings tr.alt td,#buddypress table.wp-profile-fields tr.alt td{background:#f5f5f5}#buddypress table.notification-settings{margin-bottom:20px;text-align:right}#buddypress #groups-notification-settings{margin-bottom:0}#buddypress table.notification-settings th.title,#buddypress table.profile-settings th.title{width:80%}#buddypress table.notification-settings .no,#buddypress table.notification-settings .yes{text-align:center;width:40px}#buddypress table.forum{margin:0;width:auto;clear:both}#buddypress table.forum tr.sticky td{font-size:110%;background:#fff9db;border-top:1px solid #ffe8c4;border-bottom:1px solid #ffe8c4}#buddypress table.forum tr.closed td.td-title{padding-right:35px}#buddypress table.forum td p.topic-text{color:#767676;font-size:100%}#buddypress table.forum tr>td:first-child,#buddypress table.forum tr>th:first-child{padding-right:15px}#buddypress table.forum tr>td:last-child,#buddypress table.forum tr>th:last-child{padding-left:15px}#buddypress table.forum td.td-group,#buddypress table.forum td.td-poster,#buddypress table.forum td.td-title,#buddypress table.forum tr th#th-group,#buddypress table.forum tr th#th-poster,#buddypress table.forum tr th#th-title{text-align:right}#buddypress table.forum tr td.td-title a.topic-title{font-size:110%}#buddypress table.forum td.td-freshness{white-space:nowrap}#buddypress table.forum td.td-freshness span.time-since{font-size:80%;color:#767676}#buddypress table.forum td img.avatar{float:none;margin:0 0 -8px 5px}#buddypress table.forum td.td-group,#buddypress table.forum td.td-poster{min-width:140px}#buddypress table.forum th#th-title{width:80%}#buddypress table.forum th#th-freshness{width:25%}#buddypress table.forum th#th-postcount{width:15%}#buddypress table.forum p.topic-meta{font-size:80%;margin:5px 0 0}#buddypress .item-body{margin:20px 0}#buddypress span.activity{display:inline-block;font-size:small;opacity:.8;padding:0}#buddypress span.user-nicename{color:#767676;display:inline-block;font-size:120%;font-weight:700}#buddypress div#message p,#sitewide-notice p{font-weight:400;margin-top:3px;text-decoration:none;background-color:#ffd;border:1px solid #cb2;color:#440}#buddypress #item-header:after{clear:both;content:"";display:table}#buddypress div#item-header div#item-header-content{float:right;margin-right:0}#buddypress div#item-header h2{line-height:120%;margin:0 0 15px}#buddypress div#item-header h2 a{color:#767676;text-decoration:none}#buddypress div#item-header img.avatar{float:right;margin:0 0 19px 15px}#buddypress div#item-header h2{margin-bottom:5px}#buddypress div#item-header h2 span.highlight{font-size:60%;font-weight:400;line-height:170%;vertical-align:middle;display:inline-block}#buddypress div#item-header ul h5,#buddypress div#item-header ul hr,#buddypress div#item-header ul span,body.no-js #buddypress div#item-header .js-self-profile-button{display:none}#buddypress div#item-header h2 span.highlight span{background:#a1dcfa;color:#fff;cursor:pointer;font-weight:700;font-size:80%;margin-bottom:2px;padding:1px 4px;position:relative;left:-2px;top:-2px;vertical-align:middle}#buddypress div#item-header div#item-meta{font-size:80%;color:#767676;overflow:hidden;margin:15px 0 5px;padding-bottom:10px}#buddypress div#item-header div#item-actions{float:left;margin:0 15px 15px 0;text-align:left;width:20%}#buddypress div#item-header div#item-actions h3{margin:0 0 5px}#buddypress div#item-header ul{margin-bottom:15px;overflow:hidden}#buddypress div#item-header ul li{float:left;list-style:none}#buddypress div#item-header ul img.avatar,#buddypress div#item-header ul.avatars img.avatar{height:30px;margin:2px;width:30px}#buddypress div#item-header a.button,#buddypress div#item-header div.generic-button{float:right;margin:10px 0 0 10px}#buddypress div#item-header div#message.info{line-height:80%}#buddypress ul.item-list{border-top:1px solid #eaeaea;width:100%;list-style:none;clear:both;margin:0;padding:0}body.activity-permalink #buddypress ul.item-list,body.activity-permalink #buddypress ul.item-list li.activity-item{border:none}#buddypress ul.item-list li{border-bottom:1px solid #eaeaea;padding:15px 0;margin:0;position:relative;list-style:none}#buddypress ul.single-line li{border:none}#buddypress ul.item-list li img.avatar{float:right;margin:0 0 0 10px}#buddypress ul.item-list li div.item-title,#buddypress ul.item-list li h4{font-weight:400;font-size:90%;margin:0;width:75%}#buddypress ul.item-list li div.item-title span{color:#767676;font-size:80%}#buddypress ul.item-list li div.item-desc{color:#767676;font-size:80%;margin:10px 60px 0 0;width:50%}#buddypress ul.item-list li.group-no-avatar div.item-desc{margin-right:0}#buddypress ul.item-list li div.action{position:absolute;top:15px;left:0;text-align:left}#buddypress ul.item-list li div.meta{color:#767676;font-size:80%;margin-top:10px}#buddypress ul.item-list li h5 span.small{float:left;font-size:80%;font-weight:400}#buddypress div.item-list-tabs{background:0 0;clear:right;overflow:hidden}#buddypress div.item-list-tabs ul{margin:0;padding:0}#buddypress div.item-list-tabs ul li{float:right;margin:0;list-style:none}#buddypress div.item-list-tabs#subnav ul li{margin-top:0}#buddypress div.item-list-tabs ul li.last{float:left;margin:7px 0 0}#buddypress div.item-list-tabs#subnav ul li.last{margin-top:4px}#buddypress div.item-list-tabs ul li.last select{max-width:185px}#buddypress div.item-list-tabs ul li a,#buddypress div.item-list-tabs ul li span{display:block;padding:5px 10px;text-decoration:none}#buddypress div.item-list-tabs ul li a span{background:#eee;border-radius:50%;border:1px solid #ccc;color:#6c6c6c;display:inline;font-size:70%;margin-right:2px;padding:3px 6px;text-align:center;vertical-align:middle}#buddypress div.item-list-tabs ul li.current a,#buddypress div.item-list-tabs ul li.selected a{background-color:#eee;color:#555;opacity:.8;font-weight:700}#buddypress div.item-list-tabs ul li a:hover span,#buddypress div.item-list-tabs ul li.current a span,#buddypress div.item-list-tabs ul li.selected a span{background-color:#eee}#buddypress div.item-list-tabs ul li.current a span,#buddypress div.item-list-tabs ul li.selected a span{background-color:#fff}#buddypress div#item-nav ul li.loading a{background-position:12% 50%}#buddypress div.item-list-tabs#object-nav{margin-top:0}#buddypress div.item-list-tabs#subnav{background:0 0;margin:10px 0;overflow:hidden}#buddypress #admins-list li,#buddypress #members-list li,#buddypress #mods-list li{overflow:auto;list-style:none}#buddypress div#message-thread div.message-metadata,.widget.buddypress div.avatar-block{overflow:hidden}#buddypress #item-buttons:empty{display:none}#buddypress #cover-image-container{position:relative;z-index:0}#buddypress #header-cover-image{background-color:#c5c5c5;background-position:center top;background-repeat:no-repeat;background-size:cover;border:0;display:block;right:0;margin:0;padding:0;position:absolute;top:0;width:100%;z-index:1}#buddypress #item-header-cover-image{padding:0 1em;position:relative;z-index:2}#buddypress table#message-threads tr.unread td{background:#fff9db;border-top:1px solid #ffe8c4;border-bottom:1px solid #ffe8c4;font-weight:700}#buddypress table#message-threads tr.unread td .activity,#buddypress table#message-threads tr.unread td .thread-excerpt,#buddypress table#message-threads tr.unread td.thread-options{font-weight:400}#buddypress li span.unread-count,#buddypress tr.unread span.unread-count{background:#d00;color:#fff;font-weight:700;padding:2px 8px}#buddypress div.item-list-tabs ul li a span.unread-count{padding:1px 6px;color:#fff}#buddypress div#message-thread div.message-box{margin:0;padding:15px}#buddypress div#message-thread div.alt{background:#f4f4f4}#buddypress div#message-thread p#message-recipients{margin:10px 0 20px}#buddypress div#message-thread img.avatar{float:right;margin:0 0 0 10px;vertical-align:middle}#buddypress div#message-thread strong{font-size:100%;margin:0}#buddypress div#message-thread strong a{text-decoration:none}#buddypress div#message-thread strong span.activity{margin-top:4px}#buddypress div#message-thread div.message-content{margin-right:45px}#buddypress div#message-thread div.message-options{text-align:left}#buddypress #message-threads img.avatar{max-width:none}#buddypress div.message-search{float:left;margin:0 20px}.message-metadata{position:relative}.message-star-actions{position:absolute;left:0;top:0}#buddypress a.message-action-star,#buddypress a.message-action-unstar{border-bottom:0;text-decoration:none;outline:0}a.message-action-star{opacity:.7}a.message-action-star:hover{opacity:1}.message-action-star span.icon:before,.message-action-unstar span.icon:before{font-family:dashicons;font-size:18px}.message-action-star span.icon:before{color:#767676;content:"\f154"}.message-action-unstar span.icon:before{color:#fcdd77;content:"\f155"}#buddypress div.profile h4{margin-bottom:auto;margin-top:15px}#buddypress #profile-edit-form ul.button-nav{margin-top:15px}body.no-js #buddypress .field-visibility-settings-close,body.no-js #buddypress .field-visibility-settings-toggle{display:none}#buddypress .field-visibility-settings{display:none;margin-top:10px}body.no-js #buddypress .field-visibility-settings{display:block}#buddypress .current-visibility-level{font-weight:700;font-style:normal}#buddypress .field-visibility-settings,#buddypress .field-visibility-settings-notoggle,#buddypress .field-visibility-settings-toggle{color:#767676}#buddypress .field-visibility-settings a,#buddypress .field-visibility-settings-toggle a{font-size:80%}body.register #buddypress div.page ul{list-style:none}#buddypress .standard-form .field-visibility-settings label{margin:0;font-weight:400}#buddypress .field-visibility-settings legend,#buddypress .field-visibility-settings-toggle{font-style:italic}#buddypress .field-visibility-settings .radio{list-style:none;margin-bottom:0}#buddypress .field-visibility select{margin:0}#buddypress .wp-editor-container{border:1px solid #dedede}#buddypress .html-active button.switch-html,#buddypress .tmce-active button.switch-tmce{border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0;background:#f5f5f5}#buddypress .standard-form .wp-editor-container textarea{width:100%;padding-top:0;padding-bottom:0}.widget.buddypress div.item-avatar img.avatar{float:right;margin:0 0 15px 10px}.widget.buddypress span.activity{display:inline-block;font-size:small;opacity:.8;padding:0}.widget.buddypress div.item-options{font-size:90%;margin:0 0 1em;padding:1em 0}.widget.buddypress div.item{margin:0 0 1em}.widget.buddypress div.item-content,.widget.buddypress div.item-meta{font-size:11px;margin-right:50px}.widget.buddypress ul.item-list img.avatar{height:40px;margin-left:10px;width:40px}.widget.buddypress div.item-avatar img{height:40px;margin:1px;width:40px}.widget.buddypress #bp-login-widget-form label{display:block;margin:1rem 0 .5rem}.widget.buddypress #bp-login-widget-form #bp-login-widget-submit{margin-left:10px}.widget.buddypress .bp-login-widget-user-avatar{float:right}.bp-login-widget-user-avatar img.avatar{height:40px;width:40px}.widget.buddypress .bp-login-widget-user-links>div{padding-right:60px;margin-bottom:.5rem}.widget.buddypress .bp-login-widget-user-links>div.bp-login-widget-user-link a{font-weight:700}.widget.buddypress #friends-list,.widget.buddypress #groups-list,.widget.buddypress #members-list{margin-right:0;padding-right:0}.widget.buddypress #friends-list li,.widget.buddypress #groups-list li,.widget.buddypress #members-list li{clear:both;list-style-type:none}@media only screen and (max-width:480px){#buddypress div.dir-search{float:left;margin-top:-50px;text-align:left}#buddypress div.dir-search input[type=text]{margin-bottom:1em;width:50%}a.bp-title-button{margin-right:10px}#buddypress form.standard-form .main-column div.action{position:relative;margin-bottom:1em}#buddypress form.standard-form .main-column ul#friend-list h4{width:100%}}@media only screen and (max-width:320px){#buddypress div.dir-search,#buddypress ul.item-list li div.action{margin-top:0;text-align:right;clear:right;float:right}#buddypress li#groups-order-select{clear:right;float:right}#buddypress ul.item-list li div.action{margin-right:70px;position:relative;top:0;left:0}#buddypress ul.item-list li div.item-desc{clear:right;float:right;margin:10px 0 0;width:auto}#buddypress li div.item{margin-right:70px;width:auto}#buddypress ul.item-list li div.meta{margin-top:0}#buddypress .item-desc p{margin:0 0 10px}#buddypress div.pagination .pag-count{margin-right:0}}@media only screen and (max-width:240px){#buddypress div.dir-search{float:right;margin:0}#buddypress div.dir-search input[type=text]{width:50%}#buddypress li#groups-order-select{float:right}#buddypress ul.item-list li img.avatar{width:30px;height:auto}#buddypress li div.item,#buddypress ul.item-list li div.action{margin-right:45px}h1 a.bp-title-button{clear:right;float:right;margin:10px 0 20px}}
1
+ #buddypress div.pagination .pagination-links a:hover,#buddypress ul.button-nav li.current a{font-weight:700}#buddypress div.pagination{background:0 0;border:none;color:#767676;font-size:small;margin:0;position:relative;display:block;float:right;width:100%;padding:10px 0}#buddypress div.pagination .pag-count{float:right;margin-right:10px}#buddypress div.pagination .pagination-links{float:left;margin-left:10px}#buddypress div.pagination .pagination-links a,#buddypress div.pagination .pagination-links span{font-size:90%;padding:0 5px}#buddypress noscript div.pagination{margin-bottom:15px}#buddypress #nav-above{display:none}#buddypress .paged #nav-above{display:block}#buddypress img.wp-smiley{border:none!important;clear:none!important;float:none!important;margin:0!important;padding:0!important}#buddypress .clear{clear:right}#buddypress #activity-stream{margin-top:-5px}#buddypress #activity-stream p{margin:5px 0}#buddypress #item-body form#whats-new-form{margin:0;padding:0}#buddypress .home-page form#whats-new-form{border-bottom:none;padding-bottom:0}#buddypress form#whats-new-form #whats-new-avatar{float:right}#buddypress form#whats-new-form #whats-new-content{margin-right:55px;padding:0 20px 20px 0}#buddypress form#whats-new-form p.activity-greeting{line-height:.5em;margin-bottom:15px;margin-right:75px}#buddypress form#whats-new-form textarea{background:#fff;box-sizing:border-box;color:#555;font-family:inherit;font-size:medium;height:2.2em;line-height:1.4;padding:6px;width:100%}body.no-js #buddypress form#whats-new-form textarea{height:50px}#buddypress form#whats-new-form #whats-new-options select{max-width:200px;margin-top:12px}#buddypress form#whats-new-form #whats-new-submit{float:left;margin-top:12px}#buddypress #whats-new-options:after{clear:both;content:"";display:table}body.no-js #buddypress #whats-new-options{height:auto}#buddypress #whats-new:focus{border-color:rgba(31,179,221,.9)!important;outline-color:rgba(31,179,221,.9)}#buddypress ul.activity-list li{overflow:hidden;padding:15px 0 0;list-style:none}#buddypress .activity-list .activity-avatar{float:right}#buddypress ul.item-list.activity-list li.has-comments{padding-bottom:15px}body.activity-permalink #buddypress ul.activity-list li.has-comments{padding-bottom:0}#buddypress .activity-list li.mini{font-size:80%;position:relative}#buddypress .activity-list li.mini .activity-avatar img.FB_profile_pic,#buddypress .activity-list li.mini .activity-avatar img.avatar{height:20px;margin-right:30px;width:20px}#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.FB_profile_pic,#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.avatar{height:auto;margin-right:0;width:auto}body.activity-permalink #buddypress .activity-list>li:first-child{padding-top:0}#buddypress .activity-list li .activity-content{position:relative}#buddypress .activity-list li.mini .activity-content p{margin:0}#buddypress .activity-list li.mini .activity-comments{clear:both;font-size:120%}body.activity-permalink #buddypress li.mini .activity-meta{margin-top:4px}#buddypress .activity-list li .activity-inreplyto{color:#767676;font-size:80%}#buddypress .activity-list li .activity-inreplyto>p{margin:0;display:inline}#buddypress .activity-list li .activity-inreplyto blockquote,#buddypress .activity-list li .activity-inreplyto div.activity-inner{background:0 0;border:none;display:inline;margin:0;overflow:hidden;padding:0}#buddypress .activity-list .activity-content{margin:0 70px 0 0}body.activity-permalink #buddypress .activity-list li .activity-content{border:none;font-size:100%;line-height:150%;margin-right:170px;margin-left:0;padding:0}body.activity-permalink #buddypress .activity-list li .activity-header>p{margin:0;padding:5px 0 0}#buddypress .activity-list .activity-content .activity-header,#buddypress .activity-list .activity-content .comment-header{color:#767676;line-height:220%}#buddypress .activity-header{margin-left:20px}#buddypress .acomment-meta a,#buddypress .activity-header a,#buddypress .comment-meta a{text-decoration:none}#buddypress .activity-list .activity-content .activity-header img.avatar{float:none!important;margin:0 0 -8px 5px!important}#buddypress a.bp-secondary-action,#buddypress span.highlight{font-size:80%;padding:0;margin-left:5px;text-decoration:none}#buddypress .activity-list .activity-content .activity-inner,#buddypress .activity-list .activity-content blockquote{margin:10px 0 5px 10px;overflow:hidden}#buddypress .activity-list li.new_forum_post .activity-content .activity-inner,#buddypress .activity-list li.new_forum_topic .activity-content .activity-inner{border-right:2px solid #EAEAEA;margin-right:5px;padding-right:10px}body.activity-permalink #buddypress .activity-content .activity-inner,body.activity-permalink #buddypress .activity-content blockquote{margin-right:0;margin-top:5px}#buddypress .activity-inner>p{word-wrap:break-word}#buddypress .activity-inner>.activity-inner,#buddypress .activity-inner>blockquote{margin:0}#buddypress .activity-list .activity-content img.thumbnail{border:2px solid #eee;float:right;margin:0 0 5px 10px}#buddypress .activity-read-more{margin-right:1em;white-space:nowrap}#buddypress .activity-list li.load-more,#buddypress .activity-list li.load-newest{background:#f0f0f0;font-size:110%;margin:15px 0;padding:10px 15px;text-align:center}#buddypress .activity-list li.load-more a,#buddypress .activity-list li.load-newest a{color:#4D4D4D}#buddypress div.activity-meta{margin:18px 0 0}body.activity-permalink #buddypress div.activity-meta{margin-bottom:6px}#buddypress div.activity-meta a{padding:4px 8px}#buddypress a.activity-time-since{color:#767676;text-decoration:none}#buddypress a.activity-time-since:hover{color:#767676;text-decoration:underline}#buddypress #reply-title small a,#buddypress a.bp-primary-action{font-size:80%;margin-left:5px;text-decoration:none}#buddypress #reply-title small a span,#buddypress a.bp-primary-action span{background:#767676;color:#fff;font-size:90%;margin-right:2px;padding:0 5px}#buddypress #reply-title small a:hover span,#buddypress a.bp-primary-action:hover span{background:#555;color:#fff}#buddypress div.activity-comments{margin:0 70px 0 0;overflow:hidden;position:relative;width:auto;clear:both}body.activity-permalink #buddypress div.activity-comments{background:0 0;margin-right:170px;width:auto}#buddypress div.activity-comments>ul{padding:0 10px 0 0}#buddypress div.activity-comments ul,#buddypress div.activity-comments ul li{border:none;list-style:none}#buddypress div.activity-comments ul{clear:both;margin:0}#buddypress div.activity-comments ul li{border-top:1px solid #eee;padding:10px 0 0}body.activity-permalink #buddypress .activity-list li.mini .activity-comments{clear:none;margin-top:0}body.activity-permalink #buddypress div.activity-comments ul li{border-width:1px;padding:10px 0 0}#buddypress div.activity-comments>ul>li:first-child{border-top:none}#buddypress div.activity-comments ul li:last-child{margin-bottom:0}#buddypress div.activity-comments ul li>ul{margin-right:30px;margin-top:0;padding-right:10px}body.activity-permalink #buddypress div.activity-comments ul li>ul{margin-top:10px}body.activity-permalink #buddypress div.activity-comments>ul{padding:0 15px 0 10px}#buddypress div.activity-comments div.acomment-avatar img{border-width:1px;float:right;height:25px;margin-left:10px;width:25px}#buddypress div.activity-comments div.acomment-content{font-size:80%;margin:5px 40px 0 0}#buddypress div.acomment-content .activity-delete-link,#buddypress div.acomment-content .comment-header,#buddypress div.acomment-content .time-since{display:none}body.activity-permalink #buddypress div.activity-comments div.acomment-content{font-size:90%}#buddypress div.activity-comments div.acomment-meta{color:#767676;font-size:80%}#buddypress div.activity-comments form.ac-form{display:none;padding:10px}#buddypress div.activity-comments li form.ac-form{margin-left:15px;clear:both}#buddypress div.activity-comments form.root{margin-right:0}#buddypress div.activity-comments div#message{margin-top:15px;margin-bottom:0}#buddypress div.activity-comments form .ac-textarea{background:#fff;border:1px inset #ccc;margin-bottom:10px;padding:8px}#buddypress div.activity-comments form textarea{border:none;background:0 0;box-shadow:none;outline:0;color:#555;font-family:inherit;font-size:100%;height:60px;padding:0;margin:0;width:100%}#buddypress div.activity-comments form input{margin-top:5px}#buddypress div.activity-comments form div.ac-reply-avatar{float:right}#buddypress div.ac-reply-avatar img{border:1px solid #eee}#buddypress div.activity-comments form div.ac-reply-content{color:#767676;margin-right:50px;padding-right:15px}#buddypress div.activity-comments form div.ac-reply-content a{text-decoration:none}#buddypress .acomment-options{float:right;margin:5px 40px 5px 0}#buddypress .acomment-options a{color:#767676}#buddypress .acomment-options a:hover{color:inherit}#buddypress div.dir-search{float:left;margin:-39px 0 0}#buddypress div.dir-search input[type=text],#buddypress li.groups-members-search input[type=text]{font-size:90%;padding:1px 3px}#buddypress .current-member-type{font-style:italic}#buddypress .dir-form{clear:both}#buddypress div#message{margin:0 0 15px}#buddypress #message.info{margin-bottom:0}#buddypress div#message.updated{clear:both;display:block}#buddypress div#message p,#sitewide-notice p{font-size:90%;display:block;padding:10px 15px}#buddypress div#message.error p{background-color:#fdc;border:1px solid #a00;clear:right;color:#800}#buddypress div#message.warning p{background-color:#ffe0af;border:1px solid #ffd087;clear:right;color:#800}#buddypress div#message.updated p{background-color:#efc;border:1px solid #591;color:#250}#buddypress #pass-strength-result{background-color:#eee;border-color:#ddd;border-style:solid;border-width:1px;display:none;margin:5px 0 5px 5px;padding:5px;text-align:center;width:150px}#buddypress .standard-form #basic-details-section #pass-strength-result{width:35%}#buddypress #pass-strength-result.bad,#buddypress #pass-strength-result.error{background-color:#ffb78c;border-color:#ff853c!important;display:block}#buddypress #pass-strength-result.good{background-color:#ffec8b;border-color:#fc0!important;display:block}#buddypress #pass-strength-result.short{background-color:#ffa0a0;border-color:#f04040!important;display:block}#buddypress #pass-strength-result.strong{background-color:#c3ff88;border-color:#8dff1c!important;display:block}#buddypress .standard-form#signup_form div div.error{background:#faa;color:#a00;margin:0 0 10px;padding:6px;width:90%}#buddypress div.accept,#buddypress div.reject{float:right;margin-right:10px}#buddypress ul.button-nav li{float:right;margin:0 0 10px 10px;list-style:none}#sitewide-notice #message{right:2%;position:fixed;top:1em;width:96%;z-index:9999}#sitewide-notice.admin-bar-on #message{top:3.3em}#sitewide-notice strong{display:block;margin-bottom:-1em}#buddypress form fieldset{border:0;padding:0}#buddypress .dir-search input[type=search],#buddypress .dir-search input[type=text],#buddypress .groups-members-search input[type=search],#buddypress .groups-members-search input[type=text],#buddypress .standard-form input[type=color],#buddypress .standard-form input[type=date],#buddypress .standard-form input[type=datetime-local],#buddypress .standard-form input[type=datetime],#buddypress .standard-form input[type=email],#buddypress .standard-form input[type=month],#buddypress .standard-form input[type=number],#buddypress .standard-form input[type=password],#buddypress .standard-form input[type=range],#buddypress .standard-form input[type=search],#buddypress .standard-form input[type=tel],#buddypress .standard-form input[type=text],#buddypress .standard-form input[type=time],#buddypress .standard-form input[type=url],#buddypress .standard-form input[type=week],#buddypress .standard-form select,#buddypress .standard-form textarea{border:1px solid #ccc;background:#fafafa;border-radius:0;color:#737373;font:inherit;font-size:100%;padding:6px}#buddypress .standard-form select{padding:3px}#buddypress .standard-form input[type=password]{margin-bottom:5px}#buddypress .standard-form label,#buddypress .standard-form legend,#buddypress .standard-form span.label{display:block;font-weight:700;margin:15px 0 5px;width:auto}#buddypress .standard-form #invite-list label,#buddypress .standard-form p label{font-weight:400;margin:auto}#buddypress .standard-form .checkbox label,#buddypress .standard-form .radio label{color:#767676;font-size:100%;font-weight:400;margin:5px 0 0}#buddypress .standard-form .checkbox label input,#buddypress .standard-form .radio label input{margin-left:3px}#buddypress .standard-form#sidebar-login-form label{margin-top:5px}#buddypress .standard-form input[type=text]{width:75%}#buddypress .standard-form#sidebar-login-form input[type=password],#buddypress .standard-form#sidebar-login-form input[type=text]{padding:4px;width:95%}#buddypress .standard-form #basic-details-section input[type=password],#buddypress .standard-form #blog-details-section input#signup_blog_url{width:35%}#buddypress #commentform input[type=text],#buddypress #commentform textarea,#buddypress .form-allowed-tags,#buddypress .standard-form#signup_form input[type=text],#buddypress .standard-form#signup_form textarea{width:90%}#buddypress .standard-form#signup_form div.submit{float:left}#buddypress div#signup-avatar img{margin:0 0 10px 15px}#buddypress .standard-form textarea{width:75%;height:120px}#buddypress .standard-form textarea#message_content{height:200px}#buddypress .standard-form#send-reply textarea{width:97.5%}#buddypress .standard-form p.description{color:#767676;font-size:80%;margin:5px 0}#buddypress .standard-form div.submit{clear:both;padding:15px 0 0}#buddypress .standard-form p.submit{margin-bottom:0;padding:15px 0 0}#buddypress .standard-form div.submit input{margin-left:15px}#buddypress .standard-form div.radio ul{margin:10px 38px 15px 0;list-style:disc}#buddypress .standard-form div.radio ul li{margin-bottom:5px}#buddypress .standard-form a.clear-value{display:block;margin-top:5px;outline:0}#buddypress table.notification-settings td:first-child,#buddypress table.notification-settings th.icon,#buddypress table.notifications td:first-child,#buddypress table.notifications th.icon,body.no-js #buddypress #delete_inbox_messages,body.no-js #buddypress #delete_sentbox_messages,body.no-js #buddypress #message-type-select,body.no-js #buddypress #messages-bulk-management #select-all-messages,body.no-js #buddypress #notifications-bulk-management #select-all-notifications,body.no-js #buddypress label[for=message-type-select]{display:none}#buddypress .standard-form #basic-details-section,#buddypress .standard-form #blog-details-section,#buddypress .standard-form #profile-details-section{float:right;width:48%}#buddypress .standard-form #profile-details-section{float:left}#buddypress #notifications-bulk-management,#buddypress .standard-form #blog-details-section{clear:right}#buddypress .standard-form input:focus,#buddypress .standard-form select:focus,#buddypress .standard-form textarea:focus{background:#fafafa;color:#555}#buddypress form#send-invite-form{margin-top:20px}#buddypress div#invite-list{background:#f5f5f5;height:400px;margin:0 0 10px;overflow:auto;padding:5px;width:160px}#buddypress .comment-reply-link,#buddypress .generic-button a,#buddypress .standard-form button,#buddypress a.button,#buddypress input[type=button],#buddypress input[type=reset],#buddypress input[type=submit],#buddypress ul.button-nav li a,a.bp-title-button{background:#fff;border:1px solid #ccc;color:#767676;font-size:small;cursor:pointer;outline:0;padding:4px 10px;text-align:center;text-decoration:none}#buddypress .comment-reply-link:hover,#buddypress .standard-form button:hover,#buddypress a.button:focus,#buddypress a.button:hover,#buddypress div.generic-button a:hover,#buddypress input[type=button]:hover,#buddypress input[type=reset]:hover,#buddypress input[type=submit]:hover,#buddypress ul.button-nav li a:hover,#buddypress ul.button-nav li.current a{background:#ededed;border:1px solid #bbb;color:#555;outline:0;text-decoration:none}#buddypress form.standard-form .left-menu{float:right}#buddypress form.standard-form .left-menu #invite-list ul{margin:1%;list-style:none}#buddypress form.standard-form .left-menu #invite-list ul li{margin:0 1% 0 0}#buddypress form.standard-form .main-column{margin-right:190px}#buddypress form.standard-form .main-column ul#friend-list{clear:none;float:right}#buddypress form.standard-form .main-column ul#friend-list h3,#buddypress form.standard-form .main-column ul#friend-list h4{clear:none}#buddypress .wp-editor-wrap a.button,#buddypress .wp-editor-wrap button,#buddypress .wp-editor-wrap input[type=button],#buddypress .wp-editor-wrap input[type=reset],#buddypress .wp-editor-wrap input[type=submit]{padding:0 8px 1px}#buddypress form [disabled=disabled]{cursor:default;opacity:.4}.bp-screen-reader-text{position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip:rect(0 0 0 0);border:0;word-wrap:normal!important}#buddypress a.loading,#buddypress input.loading{-webkit-animation:loader-pulsate .5s infinite ease-in-out alternate;-moz-animation:loader-pulsate .5s infinite ease-in-out alternate;border-color:#aaa}@-webkit-keyframes loader-pulsate{from{border-color:#aaa;-webkit-box-shadow:0 0 6px #ccc;box-shadow:0 0 6px #ccc}to{border-color:#ccc;-webkit-box-shadow:0 0 6px #f8f8f8;box-shadow:0 0 6px #f8f8f8}}@-moz-keyframes loader-pulsate{from{border-color:#aaa;-moz-box-shadow:0 0 6px #ccc;box-shadow:0 0 6px #ccc}to{border-color:#ccc;-moz-box-shadow:0 0 6px #f8f8f8;box-shadow:0 0 6px #f8f8f8}}#buddypress a.loading:hover,#buddypress input.loading:hover{color:#767676}#buddypress a.disabled,#buddypress button.disabled,#buddypress button.pending,#buddypress div.pending a,#buddypress input[type=submit].disabled,#buddypress input[type=submit].pending,#buddypress input[type=submit][disabled=disabled],#buddypress input[type=button].disabled,#buddypress input[type=button].pending,#buddypress input[type=reset].disabled,#buddypress input[type=reset].pending{border-color:#eee;color:#bbb;cursor:default}#buddypress a.disabled:hover,#buddypress button.disabled:hover,#buddypress button.pending:hover,#buddypress div.pending a:hover,#buddypress input[type=submit]:hover.disabled,#buddypress input[type=submit]:hover.pending,#buddypress input[type=button]:hover.disabled,#buddypress input[type=button]:hover.pending,#buddypress input[type=reset]:hover.disabled,#buddypress input[type=reset]:hover.pending{border-color:#eee;color:#bbb}#buddypress ul#topic-post-list{margin:0;width:auto}#buddypress ul#topic-post-list li{padding:15px;position:relative}#buddypress ul#topic-post-list li.alt{background:#f5f5f5}#buddypress ul#topic-post-list li div.poster-meta{color:#767676;margin-bottom:10px}#buddypress ul#topic-post-list li div.post-content{margin-right:54px}#buddypress div.topic-tags{font-size:80%}#buddypress div.admin-links{color:#767676;font-size:80%;position:absolute;top:15px;left:25px}#buddypress div#topic-meta{margin:0;padding:5px 19px 30px;position:relative}#buddypress div#topic-meta div.admin-links{left:19px;top:-36px}#buddypress div#topic-meta h3{margin:5px 0}#buddypress div#new-topic-post{display:none;margin:20px 0 0;padding:1px 0 0}#buddypress table.forum,#buddypress table.messages-notices,#buddypress table.notifications,#buddypress table.notifications-settings,#buddypress table.profile-fields,#buddypress table.profile-settings,#buddypress table.wp-profile-fields{width:100%}#buddypress table.forum thead tr,#buddypress table.messages-notices thead tr,#buddypress table.notifications thead tr,#buddypress table.notifications-settings thead tr,#buddypress table.profile-fields thead tr,#buddypress table.profile-settings thead tr,#buddypress table.wp-profile-fields thead tr{background:#eaeaea}#buddypress table#message-threads{clear:both}#buddypress table.profile-fields{margin-bottom:20px}#buddypress table tr td.thread-info p,#buddypress table.profile-fields p{margin:0}#buddypress table.profile-fields:last-child{margin-bottom:0}#buddypress table.profile-fields p:last-child{margin-top:0}#buddypress table.forum tr td,#buddypress table.forum tr th,#buddypress table.messages-notices tr td,#buddypress table.messages-notices tr th,#buddypress table.notifications tr td,#buddypress table.notifications tr th,#buddypress table.notifications-settings tr td,#buddypress table.notifications-settings tr th,#buddypress table.profile-fields tr td,#buddypress table.profile-fields tr th,#buddypress table.profile-settings tr td,#buddypress table.wp-profile-fields tr td,#buddypress table.wp-profile-fields tr th{padding:8px;vertical-align:middle}#buddypress table.forum tr td.label,#buddypress table.messages-notices tr td.label,#buddypress table.notifications tr td.label,#buddypress table.notifications-settings tr td.label,#buddypress table.profile-fields tr td.label,#buddypress table.wp-profile-fields tr td.label{border-left:1px solid #eaeaea;font-weight:700;width:25%}#buddypress #message-threads .thread-info{min-width:40%}#buddypress table tr td.thread-info p.thread-excerpt{color:#767676;font-size:80%;margin-top:3px}#buddypress table.forum td{text-align:center}#buddypress table.forum tr.alt td,#buddypress table.messages-notices tr.alt td,#buddypress table.notifications tr.alt td,#buddypress table.notifications-settings tr.alt td,#buddypress table.profile-fields tr.alt td,#buddypress table.profile-settings tr.alt td,#buddypress table.wp-profile-fields tr.alt td{background:#f5f5f5;color:#707070}#buddypress table.notification-settings{margin-bottom:20px;text-align:right}#buddypress #groups-notification-settings{margin-bottom:0}#buddypress table.notification-settings th.title,#buddypress table.profile-settings th.title{width:80%}#buddypress table.notification-settings .no,#buddypress table.notification-settings .yes{text-align:center;width:40px}#buddypress table.forum{margin:0;width:auto;clear:both}#buddypress table.forum tr.sticky td{font-size:110%;background:#fff9db;border-top:1px solid #ffe8c4;border-bottom:1px solid #ffe8c4}#buddypress table.forum tr.closed td.td-title{padding-right:35px}#buddypress table.forum td p.topic-text{color:#767676;font-size:100%}#buddypress table.forum tr>td:first-child,#buddypress table.forum tr>th:first-child{padding-right:15px}#buddypress table.forum tr>td:last-child,#buddypress table.forum tr>th:last-child{padding-left:15px}#buddypress table.forum td.td-group,#buddypress table.forum td.td-poster,#buddypress table.forum td.td-title,#buddypress table.forum tr th#th-group,#buddypress table.forum tr th#th-poster,#buddypress table.forum tr th#th-title{text-align:right}#buddypress table.forum tr td.td-title a.topic-title{font-size:110%}#buddypress table.forum td.td-freshness{white-space:nowrap}#buddypress table.forum td.td-freshness span.time-since{font-size:80%;color:#767676}#buddypress table.forum td img.avatar{float:none;margin:0 0 -8px 5px}#buddypress table.forum td.td-group,#buddypress table.forum td.td-poster{min-width:140px}#buddypress table.forum th#th-title{width:80%}#buddypress table.forum th#th-freshness{width:25%}#buddypress table.forum th#th-postcount{width:15%}#buddypress table.forum p.topic-meta{font-size:80%;margin:5px 0 0}#buddypress .item-body{margin:20px 0}#buddypress span.activity{display:inline-block;font-size:small;padding:0}#buddypress span.user-nicename{color:#767676;display:inline-block;font-size:120%;font-weight:700}#buddypress div#message p,#sitewide-notice p{font-weight:400;margin-top:3px;text-decoration:none;background-color:#ffd;border:1px solid #cb2;color:#440}#buddypress #item-header:after{clear:both;content:"";display:table}#buddypress div#item-header div#item-header-content{float:right;margin-right:0}#buddypress div#item-header h2{line-height:120%;margin:0 0 15px}#buddypress div#item-header h2 a{color:#767676;text-decoration:none}#buddypress div#item-header img.avatar{float:right;margin:0 0 19px 15px}#buddypress div#item-header h2{margin-bottom:5px}#buddypress div#item-header h2 span.highlight{font-size:60%;font-weight:400;line-height:170%;vertical-align:middle;display:inline-block}#buddypress div#item-header ul h5,#buddypress div#item-header ul hr,#buddypress div#item-header ul span,body.no-js #buddypress div#item-header .js-self-profile-button{display:none}#buddypress div#item-header h2 span.highlight span{background:#a1dcfa;color:#fff;cursor:pointer;font-weight:700;font-size:80%;margin-bottom:2px;padding:1px 4px;position:relative;left:-2px;top:-2px;vertical-align:middle}#buddypress div#item-header div#item-meta{font-size:80%;color:#767676;overflow:hidden;margin:15px 0 5px;padding-bottom:10px}#buddypress div#item-header div#item-actions{float:left;margin:0 15px 15px 0;text-align:left;width:20%}#buddypress div#item-header div#item-actions h2,#buddypress div#item-header div#item-actions h3{margin:0 0 5px}#buddypress div#item-header ul{margin-bottom:15px;overflow:hidden}#buddypress div#item-header ul li{float:left;list-style:none}#buddypress div#item-header ul img.avatar,#buddypress div#item-header ul.avatars img.avatar{height:30px;margin:2px;width:30px}#buddypress div#item-header a.button,#buddypress div#item-header div.generic-button{float:right;margin:10px 0 0 10px}#buddypress div#item-header div#message.info{line-height:80%}#buddypress ul.item-list{border-top:1px solid #eaeaea;width:100%;list-style:none;clear:both;margin:0;padding:0}body.activity-permalink #buddypress ul.item-list,body.activity-permalink #buddypress ul.item-list li.activity-item{border:none}#buddypress ul.item-list li{border-bottom:1px solid #eaeaea;padding:15px 0;margin:0;position:relative;list-style:none}#buddypress ul.single-line li{border:none}#buddypress ul.item-list li img.avatar{float:right;margin:0 0 0 10px}#buddypress ul.item-list li div.item-title,#buddypress ul.item-list li h3,#buddypress ul.item-list li h4{font-weight:400;font-size:90%;margin:0;width:75%}#buddypress ul.item-list li div.item-title span{color:#767676;font-size:80%}#buddypress ul.item-list li div.item-desc{color:#767676;font-size:80%;margin:10px 60px 0 0;width:50%}#buddypress ul.item-list li.group-no-avatar div.item-desc{margin-right:0}#buddypress ul.item-list li div.action{position:absolute;top:15px;left:0;text-align:left}#buddypress ul.item-list li div.meta{color:#767676;font-size:80%;margin-top:10px}#buddypress ul.item-list li h5 span.small{float:left;font-size:80%;font-weight:400}#buddypress div.item-list-tabs{background:0 0;clear:right;overflow:hidden}#buddypress div.item-list-tabs ul{margin:0;padding:0}#buddypress div.item-list-tabs ul li{float:right;margin:0;list-style:none}#buddypress div.item-list-tabs#subnav ul li{margin-top:0}#buddypress div.item-list-tabs ul li.last{float:left;margin:7px 0 0}#buddypress div.item-list-tabs#subnav ul li.last{margin-top:4px}#buddypress div.item-list-tabs ul li.last select{max-width:185px}#buddypress div.item-list-tabs ul li a,#buddypress div.item-list-tabs ul li span{display:block;padding:5px 10px;text-decoration:none}#buddypress div.item-list-tabs ul li a span{background:#eee;border-radius:50%;border:1px solid #ccc;color:#6c6c6c;display:inline;font-size:70%;margin-right:2px;padding:3px 6px;text-align:center;vertical-align:middle}#buddypress div.item-list-tabs ul li.current a,#buddypress div.item-list-tabs ul li.selected a{background-color:#eee;color:#555;opacity:.9;font-weight:700}#buddypress div.item-list-tabs ul li a:hover span,#buddypress div.item-list-tabs ul li.current a span,#buddypress div.item-list-tabs ul li.selected a span{background-color:#eee}#buddypress div.item-list-tabs ul li.current a span,#buddypress div.item-list-tabs ul li.selected a span{background-color:#fff}#buddypress div#item-nav ul li.loading a{background-position:12% 50%}#buddypress div.item-list-tabs#object-nav{margin-top:0}#buddypress div.item-list-tabs#subnav{background:0 0;margin:10px 0;overflow:hidden}#buddypress #admins-list li,#buddypress #members-list li,#buddypress #mods-list li{overflow:auto;list-style:none}#buddypress .group-members-list{width:100%;margin-top:1em;clear:both;overflow:auto}#buddypress div#message-thread div.message-metadata,.widget.buddypress div.avatar-block{overflow:hidden}#buddypress #item-buttons:empty{display:none}#buddypress #cover-image-container{position:relative;z-index:0}#buddypress #header-cover-image{background-color:#c5c5c5;background-position:center top;background-repeat:no-repeat;background-size:cover;border:0;display:block;right:0;margin:0;padding:0;position:absolute;top:0;width:100%;z-index:1}#buddypress #item-header-cover-image{padding:0 1em;position:relative;z-index:2}#buddypress table#message-threads tr.unread td{background:#fff9db;border-top:1px solid #ffe8c4;border-bottom:1px solid #ffe8c4;font-weight:700}#buddypress table#message-threads tr.unread td .activity,#buddypress table#message-threads tr.unread td .thread-excerpt,#buddypress table#message-threads tr.unread td.thread-options{font-weight:400}#buddypress li span.unread-count,#buddypress tr.unread span.unread-count{background:#d00;color:#fff;font-weight:700;padding:2px 8px}#buddypress div.item-list-tabs ul li a span.unread-count{padding:1px 6px;color:#fff}#buddypress div#message-thread div.message-box{margin:0;padding:15px}#buddypress div#message-thread div.alt{background:#f4f4f4}#buddypress div#message-thread p#message-recipients{margin:10px 0 20px}#buddypress div#message-thread img.avatar{float:right;margin:0 0 0 10px;vertical-align:middle}#buddypress div#message-thread strong{font-size:100%;margin:0}#buddypress div#message-thread strong a{text-decoration:none}#buddypress div#message-thread strong span.activity{margin-top:4px}#buddypress div#message-thread div.message-content{margin-right:45px}#buddypress div#message-thread div.message-options{text-align:left}#buddypress #message-threads img.avatar{max-width:none}#buddypress div.message-search{float:left;margin:0 20px}.message-metadata{position:relative}.message-star-actions{position:absolute;left:0;top:0}#buddypress a.message-action-star,#buddypress a.message-action-unstar{border-bottom:0;text-decoration:none;outline:0}a.message-action-star{opacity:.7}a.message-action-star:hover{opacity:1}.message-action-star span.icon:before,.message-action-unstar span.icon:before{font-family:dashicons;font-size:18px}.message-action-star span.icon:before{color:#767676;content:"\f154"}.message-action-unstar span.icon:before{color:#fcdd77;content:"\f155"}#buddypress div.profile h2{margin-bottom:auto;margin-top:15px}#buddypress #profile-edit-form ul.button-nav{margin-top:15px}body.no-js #buddypress .field-visibility-settings-close,body.no-js #buddypress .field-visibility-settings-toggle{display:none}#buddypress .field-visibility-settings{display:none;margin-top:10px}body.no-js #buddypress .field-visibility-settings{display:block}#buddypress .current-visibility-level{font-weight:700;font-style:normal}#buddypress .field-visibility-settings,#buddypress .field-visibility-settings-notoggle,#buddypress .field-visibility-settings-toggle{color:#707070}#buddypress .field-visibility-settings a,#buddypress .field-visibility-settings-toggle a{font-size:80%}body.register #buddypress div.page ul{list-style:none}#buddypress .standard-form .field-visibility-settings label{margin:0;font-weight:400}#buddypress .field-visibility-settings legend,#buddypress .field-visibility-settings-toggle{font-style:italic}#buddypress .field-visibility-settings .radio{list-style:none;margin-bottom:0}#buddypress .field-visibility select{margin:0}#buddypress .wp-editor-container{border:1px solid #dedede}#buddypress .html-active button.switch-html,#buddypress .tmce-active button.switch-tmce{border-bottom-color:transparent;border-bottom-right-radius:0;bord