BuddyPress - Version 5.0.0-beta1

Version Description

= 4.4.0 = See: https://codex.buddypress.org/releases/version-4-4-0/

= 4.3.0 = See: https://codex.buddypress.org/releases/version-4-3-0/

= 4.2.0 = See: https://codex.buddypress.org/releases/version-4-2-0/

= 4.1.0 = See: https://codex.buddypress.org/releases/version-4-1-0/

= 4.0.0 = See: https://codex.buddypress.org/releases/version-4-0-0/

Download this release

Release Info

Developer imath
Plugin Icon 128x128 BuddyPress
Version 5.0.0-beta1
Comparing to
See all releases

Code changes from version 4.4.0 to 5.0.0-beta1

Files changed (131) hide show
  1. bp-activity/actions/post.php +7 -4
  2. bp-activity/bp-activity-admin.php +21 -8
  3. bp-activity/bp-activity-cssjs.php +1 -1
  4. bp-activity/bp-activity-filters.php +4 -2
  5. bp-activity/bp-activity-template.php +5 -0
  6. bp-activity/classes/class-bp-activity-activity.php +8 -3
  7. bp-activity/classes/class-bp-activity-component.php +36 -3
  8. bp-activity/classes/class-bp-activity-list-table.php +23 -17
  9. bp-activity/classes/class-bp-activity-template.php +4 -2
  10. bp-activity/classes/class-bp-rest-activity-endpoint.php +1550 -0
  11. bp-blogs/classes/class-bp-blogs-recent-posts-widget.php +12 -6
  12. bp-core/admin/bp-core-admin-functions.php +39 -0
  13. bp-core/admin/bp-core-admin-schema.php +51 -0
  14. bp-core/admin/bp-core-admin-tools.php +79 -0
  15. bp-core/bp-core-avatars.php +3 -2
  16. bp-core/bp-core-cache.php +11 -0
  17. bp-core/bp-core-catchuri.php +1 -1
  18. bp-core/bp-core-cssjs.php +18 -2
  19. bp-core/bp-core-filters.php +24 -2
  20. bp-core/bp-core-functions.php +23 -3
  21. bp-core/bp-core-rest-api.php +392 -0
  22. bp-core/bp-core-template.php +1 -1
  23. bp-core/bp-core-update.php +48 -0
  24. bp-core/classes/class-bp-admin.php +1 -1
  25. bp-core/classes/class-bp-component.php +22 -0
  26. bp-core/classes/class-bp-email-address.php +40 -0
  27. bp-core/classes/class-bp-email-participant.php +84 -0
  28. bp-core/classes/class-bp-email-recipient.php +13 -29
  29. bp-core/classes/class-bp-email-sender.php +8 -0
  30. bp-core/classes/class-bp-email.php +11 -5
  31. bp-core/classes/class-bp-embed.php +7 -1
  32. bp-core/classes/class-bp-invitation-manager.php +717 -0
  33. bp-core/classes/class-bp-invitation.php +1056 -0
  34. bp-core/classes/class-bp-rest-attachments-group-avatar-endpoint.php +499 -0
  35. bp-core/classes/class-bp-rest-attachments-member-avatar-endpoint.php +515 -0
  36. bp-core/classes/class-bp-rest-components-endpoint.php +537 -0
  37. bp-core/classes/class-bp-user-query.php +1 -1
  38. bp-core/classes/trait-attachments.php +300 -0
  39. bp-core/deprecated/2.1.php +1 -1
  40. bp-core/js/bp-api-request.js +45 -0
  41. bp-core/js/bp-api-request.min.js +1 -0
  42. bp-friends/bp-friends-filters.php +10 -6
  43. bp-friends/classes/class-bp-core-friends-widget.php +1 -1
  44. bp-groups/actions/create.php +2 -2
  45. bp-groups/actions/leave-group.php +32 -1
  46. bp-groups/admin/css/admin-rtl.css +33 -0
  47. bp-groups/admin/css/admin-rtl.min.css +1 -1
  48. bp-groups/admin/css/admin.css +33 -0
  49. bp-groups/admin/css/admin.min.css +1 -1
  50. bp-groups/bp-groups-activity.php +145 -9
  51. bp-groups/bp-groups-admin.php +19 -1
  52. bp-groups/bp-groups-cache.php +36 -2
  53. bp-groups/bp-groups-cssjs.php +62 -0
  54. bp-groups/bp-groups-filters.php +14 -12
  55. bp-groups/bp-groups-functions.php +595 -362
  56. bp-groups/bp-groups-notifications.php +56 -18
  57. bp-groups/bp-groups-template.php +82 -2
  58. bp-groups/classes/class-bp-group-member-query.php +94 -1
  59. bp-groups/classes/class-bp-groups-component.php +27 -2
  60. bp-groups/classes/class-bp-groups-group-members-template.php +3 -2
  61. bp-groups/classes/class-bp-groups-group.php +34 -23
  62. bp-groups/classes/class-bp-groups-invitation-manager.php +191 -0
  63. bp-groups/classes/class-bp-groups-invite-template.php +3 -2
  64. bp-groups/classes/class-bp-groups-list-table.php +10 -2
  65. bp-groups/classes/class-bp-groups-member.php +32 -88
  66. bp-groups/classes/class-bp-groups-membership-requests-template.php +3 -2
  67. bp-groups/classes/class-bp-groups-template.php +3 -2
  68. bp-groups/classes/class-bp-groups-widget.php +13 -4
  69. bp-groups/classes/class-bp-rest-group-invites-endpoint.php +1037 -0
  70. bp-groups/classes/class-bp-rest-group-membership-endpoint.php +950 -0
  71. bp-groups/classes/class-bp-rest-group-membership-request-endpoint.php +906 -0
  72. bp-groups/classes/class-bp-rest-groups-endpoint.php +1216 -0
  73. bp-groups/js/manage-members.js +549 -0
  74. bp-groups/js/manage-members.min.js +1 -0
  75. bp-groups/screens/single/admin/membership-requests.php +24 -14
  76. bp-groups/screens/single/send-invites.php +2 -2
  77. bp-loader.php +1 -1
  78. bp-members/bp-members-functions.php +94 -17
  79. bp-members/classes/class-bp-core-members-widget.php +12 -6
  80. bp-members/classes/class-bp-core-recently-active-widget.php +14 -6
  81. bp-members/classes/class-bp-core-whos-online-widget.php +14 -6
  82. bp-members/classes/class-bp-members-admin.php +1 -1
  83. bp-members/classes/class-bp-members-component.php +22 -0
  84. bp-members/classes/class-bp-rest-members-endpoint.php +811 -0
  85. bp-members/classes/class-bp-signup.php +6 -1
  86. bp-messages/bp-messages-cssjs.php +1 -1
  87. bp-messages/bp-messages-filters.php +4 -2
  88. bp-messages/bp-messages-functions.php +7 -0
  89. bp-messages/bp-messages-template.php +34 -14
  90. bp-messages/classes/class-bp-messages-box-template.php +3 -2
  91. bp-messages/classes/class-bp-messages-component.php +12 -0
  92. bp-messages/classes/class-bp-messages-thread.php +4 -2
  93. bp-messages/classes/class-bp-rest-messages-endpoint.php +1282 -0
  94. bp-notifications/bp-notifications-filters.php +4 -2
  95. bp-notifications/classes/class-bp-notifications-component.php +12 -0
  96. bp-notifications/classes/class-bp-rest-notifications-endpoint.php +897 -0
  97. bp-settings/bp-settings-filters.php +4 -2
  98. bp-settings/bp-settings-functions.php +27 -7
  99. bp-templates/bp-legacy/buddypress-functions.php +1 -1
  100. bp-templates/bp-legacy/css/buddypress-rtl.css +8 -3
  101. bp-templates/bp-legacy/css/buddypress-rtl.min.css +1 -1
  102. bp-templates/bp-legacy/css/buddypress.css +8 -3
  103. bp-templates/bp-legacy/css/buddypress.min.css +1 -1
  104. bp-templates/bp-legacy/js/buddypress.js +1 -1
  105. bp-templates/bp-legacy/js/buddypress.min.js +1 -1
  106. bp-templates/bp-nouveau/buddypress-functions.php +8 -1
  107. bp-templates/bp-nouveau/buddypress/common/js-templates/activity/form.php +6 -1
  108. bp-templates/bp-nouveau/buddypress/common/js-templates/group-members/index.php +147 -0
  109. bp-templates/bp-nouveau/buddypress/groups/single/admin/manage-members.php +14 -3
  110. bp-templates/bp-nouveau/buddypress/members/single/friends/requests-loop.php +46 -0
  111. bp-templates/bp-nouveau/buddypress/members/single/friends/requests.php +5 -40
  112. bp-templates/bp-nouveau/buddypress/members/single/settings/general.php +38 -13
  113. bp-templates/bp-nouveau/common-styles/_bp-mixins.scss +21 -0
  114. bp-templates/bp-nouveau/common-styles/_bp-variables.scss +4 -2
  115. bp-templates/bp-nouveau/common-styles/_bp_activity_entries.scss +13 -3
  116. bp-templates/bp-nouveau/common-styles/_bp_buttons.scss +10 -1
  117. bp-templates/bp-nouveau/common-styles/_bp_forms.scss +4 -3
  118. bp-templates/bp-nouveau/common-styles/_bp_generic_and_typography.scss +9 -3
  119. bp-templates/bp-nouveau/common-styles/_bp_groups_create.scss +5 -0
  120. bp-templates/bp-nouveau/common-styles/_bp_groups_management.scss +33 -0
  121. bp-templates/bp-nouveau/common-styles/_bp_info_messages.scss +8 -3
  122. bp-templates/bp-nouveau/common-styles/_bp_item_body_general.scss +3 -1
  123. bp-templates/bp-nouveau/common-styles/_bp_item_header_general.scss +4 -1
  124. bp-templates/bp-nouveau/common-styles/_bp_lists.scss +5 -2
  125. bp-templates/bp-nouveau/common-styles/_bp_registration.scss +57 -0
  126. bp-templates/bp-nouveau/common-styles/_bp_search.scss +12 -6
  127. bp-templates/bp-nouveau/common-styles/_bp_update_form.scss +13 -3
  128. bp-templates/bp-nouveau/common-styles/_bp_user_profile.scss +3 -3
  129. bp-templates/bp-nouveau/common-styles/_bp_user_settings.scss +80 -1
  130. bp-templates/bp-nouveau/css/buddypress-rtl.css +214 -35
  131. bp-templates/bp-nouveau/css/buddypress-rtl.min.css +1 -1
bp-activity/actions/post.php CHANGED
@@ -77,12 +77,15 @@ function bp_activity_action_post_update() {
77
  * Filters activity object for BuddyPress core and plugin authors before posting activity update.
78
  *
79
  * @since 1.2.0
 
 
80
  *
81
- * @param string $object Activity item being associated to.
82
- * @param string $item_id Component ID being posted to.
83
- * @param string $content Activity content being posted.
 
84
  */
85
- $activity_id = apply_filters( 'bp_activity_custom_update', $object, $item_id, $content );
86
  }
87
 
88
  // Provide user feedback.
77
  * Filters activity object for BuddyPress core and plugin authors before posting activity update.
78
  *
79
  * @since 1.2.0
80
+ * @since 5.0.0 Fixed filter signature to match other instances of filter,
81
+ * with $activity_id as the first param.
82
  *
83
+ * @param int $activity_id ID of the activity item.
84
+ * @param string $object Activity item being associated to.
85
+ * @param string $item_id Component ID being posted to.
86
+ * @param string $content Activity content being posted.
87
  */
88
+ $activity_id = apply_filters( 'bp_activity_custom_update', 0, $object, $item_id, $content );
89
  }
90
 
91
  // Provide user feedback.
bp-activity/bp-activity-admin.php CHANGED
@@ -310,7 +310,7 @@ function bp_activity_admin_load() {
310
  ) );
311
  wp_enqueue_style( 'bp_activity_admin_css', $bp->plugin_url . "bp-activity/admin/css/admin{$min}.css", array(), bp_get_version() );
312
 
313
- wp_style_add_data( 'bp_activity_admin_css', 'rtl', true );
314
  if ( $min ) {
315
  wp_style_add_data( 'bp_activity_admin_css', 'suffix', $min );
316
  }
@@ -840,13 +840,19 @@ function bp_activity_admin_get_activity_actions() {
840
  $action = array_values( (array) $action );
841
 
842
  for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
 
 
 
 
 
 
 
 
 
843
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
844
  }
845
  }
846
 
847
- // This was a mis-named activity type from before BP 1.6.
848
- unset( $actions['friends_register_activity_action'] );
849
-
850
  // Sort array by the human-readable value.
851
  natsort( $actions );
852
 
@@ -870,13 +876,20 @@ function bp_activity_admin_edit_metabox_type( $item ) {
870
  foreach ( bp_activity_get_actions() as $action ) {
871
  $action = array_values( (array) $action );
872
 
873
- for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
 
 
 
 
 
 
 
 
 
874
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
 
875
  }
876
 
877
- // This was a mis-named activity type from before BP 1.6.
878
- unset( $actions['friends_register_activity_action'] );
879
-
880
  // Sort array by the human-readable value.
881
  natsort( $actions );
882
 
310
  ) );
311
  wp_enqueue_style( 'bp_activity_admin_css', $bp->plugin_url . "bp-activity/admin/css/admin{$min}.css", array(), bp_get_version() );
312
 
313
+ wp_style_add_data( 'bp_activity_admin_css', 'rtl', 'replace' );
314
  if ( $min ) {
315
  wp_style_add_data( 'bp_activity_admin_css', 'suffix', $min );
316
  }
840
  $action = array_values( (array) $action );
841
 
842
  for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
843
+ /**
844
+ * Don't take in account:
845
+ * - a mis-named Friends activity type from before BP 1.6,
846
+ * - The Group's component 'activity_update' one as the Activity component is using it.
847
+ */
848
+ if ( 'friends_register_activity_action' === $action[$i]['key'] || 'bp_groups_format_activity_action_group_activity_update' === $action[$i]['format_callback'] ) {
849
+ continue;
850
+ }
851
+
852
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
853
  }
854
  }
855
 
 
 
 
856
  // Sort array by the human-readable value.
857
  natsort( $actions );
858
 
876
  foreach ( bp_activity_get_actions() as $action ) {
877
  $action = array_values( (array) $action );
878
 
879
+ for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
880
+ /**
881
+ * Don't take in account:
882
+ * - a mis-named Friends activity type from before BP 1.6,
883
+ * - The Group's component 'activity_update' one as the Activity component is using it.
884
+ */
885
+ if ( 'friends_register_activity_action' === $action[$i]['key'] || 'bp_groups_format_activity_action_group_activity_update' === $action[$i]['format_callback'] ) {
886
+ continue;
887
+ }
888
+
889
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
890
+ }
891
  }
892
 
 
 
 
893
  // Sort array by the human-readable value.
894
  natsort( $actions );
895
 
bp-activity/bp-activity-cssjs.php CHANGED
@@ -36,7 +36,7 @@ function bp_activity_mentions_script() {
36
  wp_enqueue_script( 'bp-mentions', buddypress()->plugin_url . "bp-activity/js/mentions{$min}.js", array( 'jquery', 'jquery-atwho' ), bp_get_version(), true );
37
  wp_enqueue_style( 'bp-mentions-css', buddypress()->plugin_url . "bp-activity/css/mentions{$min}.css", array(), bp_get_version() );
38
 
39
- wp_style_add_data( 'bp-mentions-css', 'rtl', true );
40
  if ( $min ) {
41
  wp_style_add_data( 'bp-mentions-css', 'suffix', $min );
42
  }
36
  wp_enqueue_script( 'bp-mentions', buddypress()->plugin_url . "bp-activity/js/mentions{$min}.js", array( 'jquery', 'jquery-atwho' ), bp_get_version(), true );
37
  wp_enqueue_style( 'bp-mentions-css', buddypress()->plugin_url . "bp-activity/css/mentions{$min}.css", array(), bp_get_version() );
38
 
39
+ wp_style_add_data( 'bp-mentions-css', 'rtl', 'replace' );
40
  if ( $min ) {
41
  wp_style_add_data( 'bp-mentions-css', 'suffix', $min );
42
  }
bp-activity/bp-activity-filters.php CHANGED
@@ -818,14 +818,16 @@ add_filter( 'bp_activity_set_mentions_scope_args', 'bp_activity_filter_mentions_
818
  * Registers Activity personal data exporter.
819
  *
820
  * @since 4.0.0
 
821
  *
822
  * @param array $exporters An array of personal data exporters.
823
  * @return array An array of personal data exporters.
824
  */
825
  function bp_activity_register_personal_data_exporter( $exporters ) {
826
  $exporters['buddypress-activity'] = array(
827
- 'exporter_friendly_name' => __( 'BuddyPress Activity Data', 'buddypress' ),
828
- 'callback' => 'bp_activity_personal_data_exporter',
 
829
  );
830
 
831
  return $exporters;
818
  * Registers Activity personal data exporter.
819
  *
820
  * @since 4.0.0
821
+ * @since 5.0.0 adds an `exporter_bp_friendly_name` param to exporters.
822
  *
823
  * @param array $exporters An array of personal data exporters.
824
  * @return array An array of personal data exporters.
825
  */
826
  function bp_activity_register_personal_data_exporter( $exporters ) {
827
  $exporters['buddypress-activity'] = array(
828
+ 'exporter_friendly_name' => __( 'BuddyPress Activity Data', 'buddypress' ),
829
+ 'callback' => 'bp_activity_personal_data_exporter',
830
+ 'exporter_bp_friendly_name' => _x( 'Activity Data', 'BuddyPress Activity data exporter friendly name', 'buddypress' ),
831
  );
832
 
833
  return $exporters;
bp-activity/bp-activity-template.php CHANGED
@@ -3848,6 +3848,11 @@ function bp_activity_show_filters( $context = '' ) {
3848
  $action['key'] = 'friendship_accepted,friendship_created';
3849
  }
3850
 
 
 
 
 
 
3851
  $filters[ $action['key'] ] = $action['label'];
3852
  }
3853
 
3848
  $action['key'] = 'friendship_accepted,friendship_created';
3849
  }
3850
 
3851
+ // The 'activity_update' filter is already used by the Activity component.
3852
+ if ( 'bp_groups_format_activity_action_group_activity_update' === $action['format_callback'] ) {
3853
+ continue;
3854
+ }
3855
+
3856
  $filters[ $action['key'] ] = $action['label'];
3857
  }
3858
 
bp-activity/classes/class-bp-activity-activity.php CHANGED
@@ -360,8 +360,10 @@ class BP_Activity_Activity {
360
  public static function get( $args = array() ) {
361
  global $wpdb;
362
 
 
 
363
  // Backward compatibility with old method of passing arguments.
364
- if ( !is_array( $args ) || func_num_args() > 1 ) {
365
  _deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
366
 
367
  $old_args_keys = array(
@@ -378,7 +380,7 @@ class BP_Activity_Activity {
378
  10 => 'spam'
379
  );
380
 
381
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
382
  }
383
 
384
  $bp = buddypress();
@@ -1467,6 +1469,8 @@ class BP_Activity_Activity {
1467
  public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
1468
  global $wpdb;
1469
 
 
 
1470
  if ( empty( $top_level_parent_id ) ) {
1471
  $top_level_parent_id = $activity_id;
1472
  }
@@ -1514,7 +1518,7 @@ class BP_Activity_Activity {
1514
  * @param BP_Activity_Activity $value Magic method referring to currently called method.
1515
  * @param array $func_args Array of the method's argument list.
1516
  */
1517
- if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, func_get_args() ) ) {
1518
 
1519
  /**
1520
  * Filters the MySQL prepared statement for the legacy activity query.
@@ -1539,6 +1543,7 @@ class BP_Activity_Activity {
1539
  $descendant_ids = $wpdb->get_col( $sql );
1540
  $descendants = self::get_activity_data( $descendant_ids );
1541
  $descendants = self::append_user_fullnames( $descendants );
 
1542
  }
1543
 
1544
  $ref = array();
360
  public static function get( $args = array() ) {
361
  global $wpdb;
362
 
363
+ $function_args = func_get_args();
364
+
365
  // Backward compatibility with old method of passing arguments.
366
+ if ( !is_array( $args ) || count( $function_args ) > 1 ) {
367
  _deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
368
 
369
  $old_args_keys = array(
380
  10 => 'spam'
381
  );
382
 
383
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
384
  }
385
 
386
  $bp = buddypress();
1469
  public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
1470
  global $wpdb;
1471
 
1472
+ $function_args = func_get_args();
1473
+
1474
  if ( empty( $top_level_parent_id ) ) {
1475
  $top_level_parent_id = $activity_id;
1476
  }
1518
  * @param BP_Activity_Activity $value Magic method referring to currently called method.
1519
  * @param array $func_args Array of the method's argument list.
1520
  */
1521
+ if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, $function_args ) ) {
1522
 
1523
  /**
1524
  * Filters the MySQL prepared statement for the legacy activity query.
1543
  $descendant_ids = $wpdb->get_col( $sql );
1544
  $descendants = self::get_activity_data( $descendant_ids );
1545
  $descendants = self::append_user_fullnames( $descendants );
1546
+ $descendants = self::generate_action_strings( $descendants );
1547
  }
1548
 
1549
  $ref = array();
bp-activity/classes/class-bp-activity-component.php CHANGED
@@ -124,9 +124,30 @@ class BP_Activity_Component extends BP_Component {
124
  require $this->path . 'bp-activity/screens/just-me.php';
125
  }
126
 
127
- // Screens - User secondary nav.
128
- if ( bp_is_user() && in_array( bp_current_action(), array( 'friends', 'groups', 'favorites', 'mentions' ), true ) ) {
129
- require $this->path . 'bp-activity/screens/' . bp_current_action() . '.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
131
 
132
  // Screens - Single permalink.
@@ -435,4 +456,16 @@ class BP_Activity_Component extends BP_Component {
435
 
436
  parent::setup_cache_groups();
437
  }
 
 
 
 
 
 
 
 
 
 
 
 
438
  }
124
  require $this->path . 'bp-activity/screens/just-me.php';
125
  }
126
 
127
+ /**
128
+ * Screens - User secondary nav.
129
+ *
130
+ * For these specific actions, slugs can be customized using `BP_{COMPONENT}_SLUGS`.
131
+ * As a result, we need to map filenames with slugs.
132
+ */
133
+ $filenames = array(
134
+ 'favorites' => 'favorites',
135
+ 'mentions' => 'mentions',
136
+ );
137
+
138
+ if ( bp_is_active( 'friends' ) ) {
139
+ $filenames[bp_get_friends_slug()] = 'friends';
140
+ }
141
+
142
+ if ( bp_is_active( 'groups' ) ) {
143
+ $filenames[bp_get_groups_slug()] = 'groups';
144
+ }
145
+
146
+ // The slug is the current action requested.
147
+ $slug = bp_current_action();
148
+
149
+ if ( bp_is_user() && isset( $filenames[ $slug ] ) ) {
150
+ require $this->path . 'bp-activity/screens/' . $filenames[ $slug ] . '.php';
151
  }
152
 
153
  // Screens - Single permalink.
456
 
457
  parent::setup_cache_groups();
458
  }
459
+
460
+ /**
461
+ * Init the BP REST API.
462
+ *
463
+ * @since 5.0.0
464
+ */
465
+ public function rest_api_init() {
466
+ $controller = new BP_REST_Activity_Endpoint();
467
+ $controller->register_routes();
468
+
469
+ parent::rest_api_init();
470
+ }
471
  }
bp-activity/classes/class-bp-activity-list-table.php CHANGED
@@ -338,11 +338,7 @@ class BP_Activity_List_Table extends WP_List_Table {
338
  *
339
  * @return array Key/value pairs for the bulk actions dropdown.
340
  */
341
- function get_bulk_actions() {
342
- $actions = array();
343
- $actions['bulk_spam'] = __( 'Mark as Spam', 'buddypress' );
344
- $actions['bulk_ham'] = __( 'Not Spam', 'buddypress' );
345
- $actions['bulk_delete'] = __( 'Delete Permanently', 'buddypress' );
346
 
347
  /**
348
  * Filters the default bulk actions so plugins can add custom actions.
@@ -351,7 +347,11 @@ class BP_Activity_List_Table extends WP_List_Table {
351
  *
352
  * @param array $actions Default available actions for bulk operations.
353
  */
354
- return apply_filters( 'bp_activity_list_table_get_bulk_actions', $actions );
 
 
 
 
355
  }
356
 
357
  /**
@@ -364,6 +364,7 @@ class BP_Activity_List_Table extends WP_List_Table {
364
  * @return array The columns to appear in the Activity list table.
365
  */
366
  function get_columns() {
 
367
  /**
368
  * Filters the titles for the columns for the activity list table.
369
  *
@@ -373,7 +374,7 @@ class BP_Activity_List_Table extends WP_List_Table {
373
  */
374
  return apply_filters( 'bp_activity_list_table_get_columns', array(
375
  'cb' => '<input name type="checkbox" />',
376
- 'author' => _x('Author', 'Admin SWA column header', 'buddypress' ),
377
  'comment' => _x( 'Activity', 'Admin SWA column header', 'buddypress' ),
378
  'action' => _x( 'Action', 'Admin SWA column header', 'buddypress' ),
379
  'response' => _x( 'In Response To', 'Admin SWA column header', 'buddypress' ),
@@ -383,20 +384,20 @@ class BP_Activity_List_Table extends WP_List_Table {
383
  /**
384
  * Get the column names for sortable columns.
385
  *
386
- * Currently, returns an empty array (no columns are sortable).
387
- *
388
  * @since 1.6.0
389
- * @todo For this to work, BP_Activity_Activity::get() needs updating
390
- * to support ordering by specific fields.
391
  *
392
  * @return array The columns that can be sorted on the Activity screen.
393
  */
394
- function get_sortable_columns() {
395
- return array();
396
 
397
- /*return array(
398
- 'author' => array( 'activity_author', false ), // Intentionally not using "=>"
399
- );*/
 
 
 
 
 
400
  }
401
 
402
  /**
@@ -434,6 +435,11 @@ class BP_Activity_List_Table extends WP_List_Table {
434
  $component = 'xprofile';
435
  }
436
 
 
 
 
 
 
437
  if ( bp_is_active( $component ) ) {
438
  if ( $component === 'xprofile' ) {
439
  $component_name = buddypress()->profile->name;
@@ -454,7 +460,7 @@ class BP_Activity_List_Table extends WP_List_Table {
454
  <?php
455
 
456
  // Skip the incorrectly named pre-1.6 action.
457
- if ( 'friends_register_activity_action' !== $action_key ) : ?>
458
 
459
  <option value="<?php echo esc_attr( $action_key ); ?>" <?php selected( $action_key, $selected ); ?>><?php echo esc_html( $action_values[ 'value' ] ); ?></option>
460
 
338
  *
339
  * @return array Key/value pairs for the bulk actions dropdown.
340
  */
341
+ public function get_bulk_actions() {
 
 
 
 
342
 
343
  /**
344
  * Filters the default bulk actions so plugins can add custom actions.
347
  *
348
  * @param array $actions Default available actions for bulk operations.
349
  */
350
+ return apply_filters( 'bp_activity_list_table_get_bulk_actions', array(
351
+ 'bulk_spam' => __( 'Mark as Spam', 'buddypress' ),
352
+ 'bulk_ham' => __( 'Not Spam', 'buddypress' ),
353
+ 'bulk_delete' => __( 'Delete Permanently', 'buddypress' ),
354
+ ) );
355
  }
356
 
357
  /**
364
  * @return array The columns to appear in the Activity list table.
365
  */
366
  function get_columns() {
367
+
368
  /**
369
  * Filters the titles for the columns for the activity list table.
370
  *
374
  */
375
  return apply_filters( 'bp_activity_list_table_get_columns', array(
376
  'cb' => '<input name type="checkbox" />',
377
+ 'author' => _x( 'Author', 'Admin SWA column header', 'buddypress' ),
378
  'comment' => _x( 'Activity', 'Admin SWA column header', 'buddypress' ),
379
  'action' => _x( 'Action', 'Admin SWA column header', 'buddypress' ),
380
  'response' => _x( 'In Response To', 'Admin SWA column header', 'buddypress' ),
384
  /**
385
  * Get the column names for sortable columns.
386
  *
 
 
387
  * @since 1.6.0
 
 
388
  *
389
  * @return array The columns that can be sorted on the Activity screen.
390
  */
391
+ public function get_sortable_columns() {
 
392
 
393
+ /**
394
+ * Filters the column names for the sortable columns.
395
+ *
396
+ * @since 5.0.0
397
+ *
398
+ * @param array $value Array of column names.
399
+ */
400
+ return apply_filters( 'bp_activity_list_table_get_sortable_columns', array() );
401
  }
402
 
403
  /**
435
  $component = 'xprofile';
436
  }
437
 
438
+ // The 'activity_update' filter is already used by the Activity component.
439
+ if ( isset( $actions->activity_update ) && 'bp_groups_format_activity_action_group_activity_update' === $actions->activity_update['format_callback'] ) {
440
+ unset( $actions->activity_update );
441
+ }
442
+
443
  if ( bp_is_active( $component ) ) {
444
  if ( $component === 'xprofile' ) {
445
  $component_name = buddypress()->profile->name;
460
  <?php
461
 
462
  // Skip the incorrectly named pre-1.6 action.
463
+ if ( 'friends_register_activity_action' !== $action_key ) : ?>
464
 
465
  <option value="<?php echo esc_attr( $action_key ); ?>" <?php selected( $action_key, $selected ); ?>><?php echo esc_html( $action_values[ 'value' ] ); ?></option>
466
 
bp-activity/classes/class-bp-activity-template.php CHANGED
@@ -139,8 +139,10 @@ class BP_Activity_Template {
139
  public function __construct( $args ) {
140
  $bp = buddypress();
141
 
 
 
142
  // Backward compatibility with old method of passing arguments.
143
- if ( !is_array( $args ) || func_num_args() > 1 ) {
144
  _deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
145
 
146
  $old_args_keys = array(
@@ -159,7 +161,7 @@ class BP_Activity_Template {
159
  12 => 'page_arg'
160
  );
161
 
162
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
163
  }
164
 
165
  $defaults = array(
139
  public function __construct( $args ) {
140
  $bp = buddypress();
141
 
142
+ $function_args = func_get_args();
143
+
144
  // Backward compatibility with old method of passing arguments.
145
+ if ( !is_array( $args ) || count( $function_args ) > 1 ) {
146
  _deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
147
 
148
  $old_args_keys = array(
161
  12 => 'page_arg'
162
  );
163
 
164
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
165
  }
166
 
167
  $defaults = array(
bp-activity/classes/class-bp-rest-activity-endpoint.php ADDED
@@ -0,0 +1,1550 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Activity_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Activity endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Activity_Endpoint extends WP_REST_Controller {
17
+
18
+ /**
19
+ * User favorites.
20
+ *
21
+ * @since 5.0.0
22
+ *
23
+ * @var array|null
24
+ */
25
+ protected $user_favorites = null;
26
+
27
+ /**
28
+ * Constructor.
29
+ *
30
+ * @since 5.0.0
31
+ */
32
+ public function __construct() {
33
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
34
+ $this->rest_base = buddypress()->activity->id;
35
+ }
36
+
37
+ /**
38
+ * Register the component routes.
39
+ *
40
+ * @since 5.0.0
41
+ */
42
+ public function register_routes() {
43
+ register_rest_route(
44
+ $this->namespace,
45
+ '/' . $this->rest_base,
46
+ array(
47
+ array(
48
+ 'methods' => WP_REST_Server::READABLE,
49
+ 'callback' => array( $this, 'get_items' ),
50
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
51
+ 'args' => $this->get_collection_params(),
52
+ ),
53
+ array(
54
+ 'methods' => WP_REST_Server::CREATABLE,
55
+ 'callback' => array( $this, 'create_item' ),
56
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
57
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
58
+ ),
59
+ 'schema' => array( $this, 'get_item_schema' ),
60
+ )
61
+ );
62
+
63
+ $activity_endpoint = '/' . $this->rest_base . '/(?P<id>[\d]+)';
64
+
65
+ register_rest_route(
66
+ $this->namespace,
67
+ $activity_endpoint,
68
+ array(
69
+ 'args' => array(
70
+ 'id' => array(
71
+ 'description' => __( 'A unique numeric ID for the activity.', 'buddypress' ),
72
+ 'type' => 'integer',
73
+ ),
74
+ ),
75
+ array(
76
+ 'methods' => WP_REST_Server::READABLE,
77
+ 'callback' => array( $this, 'get_item' ),
78
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
79
+ 'args' => array(
80
+ 'context' => $this->get_context_param(
81
+ array(
82
+ 'default' => 'view',
83
+ )
84
+ ),
85
+ ),
86
+ ),
87
+ array(
88
+ 'methods' => WP_REST_Server::EDITABLE,
89
+ 'callback' => array( $this, 'update_item' ),
90
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
91
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
92
+ ),
93
+ array(
94
+ 'methods' => WP_REST_Server::DELETABLE,
95
+ 'callback' => array( $this, 'delete_item' ),
96
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
97
+ ),
98
+ 'schema' => array( $this, 'get_item_schema' ),
99
+ )
100
+ );
101
+
102
+ // Register the favorite route.
103
+ register_rest_route(
104
+ $this->namespace,
105
+ $activity_endpoint . '/favorite',
106
+ array(
107
+ 'args' => array(
108
+ 'id' => array(
109
+ 'description' => __( 'A unique numeric ID for the activity.', 'buddypress' ),
110
+ 'type' => 'integer',
111
+ ),
112
+ ),
113
+ array(
114
+ 'methods' => WP_REST_Server::EDITABLE,
115
+ 'callback' => array( $this, 'update_favorite' ),
116
+ 'permission_callback' => array( $this, 'update_favorite_permissions_check' ),
117
+ ),
118
+ 'schema' => array( $this, 'get_item_schema' ),
119
+ )
120
+ );
121
+ }
122
+
123
+ /**
124
+ * Retrieve activities.
125
+ *
126
+ * @since 5.0.0
127
+ *
128
+ * @param WP_REST_Request $request Full details about the request.
129
+ * @return WP_REST_Response List of activities response data.
130
+ */
131
+ public function get_items( $request ) {
132
+ $args = array(
133
+ 'exclude' => $request['exclude'],
134
+ 'in' => $request['include'],
135
+ 'page' => $request['page'],
136
+ 'per_page' => $request['per_page'],
137
+ 'search_terms' => $request['search'],
138
+ 'sort' => $request['order'],
139
+ 'spam' => $request['status'],
140
+ 'display_comments' => $request['display_comments'],
141
+ 'site_id' => $request['site_id'],
142
+ 'group_id' => $request['group_id'],
143
+ 'count_total' => true,
144
+ 'fields' => 'all',
145
+ 'show_hidden' => false,
146
+ 'update_meta_cache' => true,
147
+ 'filter' => false,
148
+ );
149
+
150
+ if ( empty( $args['display_comments'] ) || 'false' === $args['display_comments'] ) {
151
+ $args['display_comments'] = false;
152
+ }
153
+
154
+ if ( empty( $request['exclude'] ) ) {
155
+ $args['exclude'] = false;
156
+ }
157
+
158
+ if ( empty( $request['include'] ) ) {
159
+ $args['in'] = false;
160
+ }
161
+
162
+ if ( isset( $request['after'] ) ) {
163
+ $args['since'] = $request['after'];
164
+ }
165
+
166
+ if ( isset( $request['user_id'] ) ) {
167
+ $args['filter']['user_id'] = $request['user_id'];
168
+ }
169
+
170
+ $item_id = 0;
171
+ if ( ! empty( $args['group_id'] ) ) {
172
+ $args['filter']['object'] = 'groups';
173
+ $args['filter']['primary_id'] = $args['group_id'];
174
+
175
+ $item_id = $args['group_id'];
176
+ }
177
+
178
+ if ( ! empty( $args['site_id'] ) ) {
179
+ $args['filter']['object'] = 'blogs';
180
+ $args['filter']['primary_id'] = $args['site_id'];
181
+
182
+ $item_id = $args['site_id'];
183
+ }
184
+
185
+ if ( empty( $args['group_id'] ) && empty( $args['site_id'] ) ) {
186
+ if ( isset( $request['component'] ) ) {
187
+ $args['filter']['object'] = $request['component'];
188
+ }
189
+
190
+ if ( ! empty( $request['primary_id'] ) ) {
191
+ $item_id = $request['primary_id'];
192
+ $args['filter']['primary_id'] = $item_id;
193
+ }
194
+ }
195
+
196
+ if ( isset( $request['type'] ) ) {
197
+ $args['filter']['action'] = $request['type'];
198
+ }
199
+
200
+ if ( ! empty( $request['secondary_id'] ) ) {
201
+ $args['filter']['secondary_id'] = $request['secondary_id'];
202
+ }
203
+
204
+ if ( $args['in'] ) {
205
+ $args['count_total'] = false;
206
+ }
207
+
208
+ if ( $this->show_hidden( $request['component'], $item_id ) ) {
209
+ $args['show_hidden'] = true;
210
+ }
211
+
212
+ /**
213
+ * Filter the query arguments for the request.
214
+ *
215
+ * @since 5.0.0
216
+ *
217
+ * @param array $args Key value array of query var to query value.
218
+ * @param WP_REST_Request $request The request sent to the API.
219
+ */
220
+ $args = apply_filters( 'bp_rest_activity_get_items_query_args', $args, $request );
221
+
222
+ // Actually, query it.
223
+ $activities = bp_activity_get( $args );
224
+
225
+ $retval = array();
226
+ foreach ( $activities['activities'] as $activity ) {
227
+ $retval[] = $this->prepare_response_for_collection(
228
+ $this->prepare_item_for_response( $activity, $request )
229
+ );
230
+ }
231
+
232
+ $response = rest_ensure_response( $retval );
233
+ $response = bp_rest_response_add_total_headers( $response, $activities['total'], $args['per_page'] );
234
+
235
+ /**
236
+ * Fires after a list of activities is fetched via the REST API.
237
+ *
238
+ * @since 5.0.0
239
+ *
240
+ * @param array $activities Fetched activities.
241
+ * @param WP_REST_Response $response The response data.
242
+ * @param WP_REST_Request $request The request sent to the API.
243
+ */
244
+ do_action( 'bp_rest_activity_get_items', $activities, $response, $request );
245
+
246
+ return $response;
247
+ }
248
+
249
+ /**
250
+ * Check if a given request has access to activity items.
251
+ *
252
+ * @since 5.0.0
253
+ *
254
+ * @param WP_REST_Request $request Full data about the request.
255
+ * @return bool|WP_Error
256
+ */
257
+ public function get_items_permissions_check( $request ) {
258
+
259
+ /**
260
+ * Filter the activity `get_items` permissions check.
261
+ *
262
+ * @since 5.0.0
263
+ *
264
+ * @param bool|WP_Error $retval Returned value.
265
+ * @param WP_REST_Request $request The request sent to the API.
266
+ */
267
+ return apply_filters( 'bp_rest_activity_get_items_permissions_check', true, $request );
268
+ }
269
+
270
+ /**
271
+ * Retrieve an activity.
272
+ *
273
+ * @since 5.0.0
274
+ *
275
+ * @param WP_REST_Request $request Full details about the request.
276
+ * @return WP_REST_Response|WP_Error
277
+ */
278
+ public function get_item( $request ) {
279
+ $activity = $this->get_activity_object( $request );
280
+
281
+ $retval = array(
282
+ $this->prepare_response_for_collection(
283
+ $this->prepare_item_for_response( $activity, $request )
284
+ ),
285
+ );
286
+
287
+ $response = rest_ensure_response( $retval );
288
+
289
+ /**
290
+ * Fires after an activity is fetched via the REST API.
291
+ *
292
+ * @since 5.0.0
293
+ *
294
+ * @param BP_Activity_Activity $activity Fetched activity.
295
+ * @param WP_REST_Response $response The response data.
296
+ * @param WP_REST_Request $request The request sent to the API.
297
+ */
298
+ do_action( 'bp_rest_activity_get_item', $activity, $response, $request );
299
+
300
+ return $response;
301
+ }
302
+
303
+ /**
304
+ * Check if a given request has access to get information about a specific activity.
305
+ *
306
+ * @since 5.0.0
307
+ *
308
+ * @param WP_REST_Request $request Full data about the request.
309
+ * @return bool|WP_Error
310
+ */
311
+ public function get_item_permissions_check( $request ) {
312
+ $retval = true;
313
+
314
+ if ( ! $this->can_see( $request ) ) {
315
+ $retval = new WP_Error(
316
+ 'bp_rest_authorization_required',
317
+ __( 'Sorry, you cannot view the activities.', 'buddypress' ),
318
+ array(
319
+ 'status' => rest_authorization_required_code(),
320
+ )
321
+ );
322
+ }
323
+
324
+ /**
325
+ * Filter the activity `get_item` permissions check.
326
+ *
327
+ * @since 5.0.0
328
+ *
329
+ * @param bool|WP_Error $retval Returned value.
330
+ * @param WP_REST_Request $request The request sent to the API.
331
+ */
332
+ return apply_filters( 'bp_rest_activity_get_item_permissions_check', $retval, $request );
333
+ }
334
+
335
+ /**
336
+ * Create an activity.
337
+ *
338
+ * @since 5.0.0
339
+ *
340
+ * @param WP_REST_Request $request Full data about the request.
341
+ * @return WP_REST_Response|WP_Error
342
+ */
343
+ public function create_item( $request ) {
344
+ $request->set_param( 'context', 'edit' );
345
+
346
+ if ( empty( $request['content'] ) ) {
347
+ return new WP_Error(
348
+ 'bp_rest_create_activity_empty_content',
349
+ __( 'Please, enter some content.', 'buddypress' ),
350
+ array(
351
+ 'status' => 500,
352
+ )
353
+ );
354
+ }
355
+
356
+ $prepared_activity = $this->prepare_item_for_database( $request );
357
+
358
+ // Fallback for the activity_update type.
359
+ $type = 'activity_update';
360
+ if ( ! empty( $request['type'] ) ) {
361
+ $type = $request['type'];
362
+ }
363
+
364
+ $prime = $request['primary_item_id'];
365
+ $activity_id = 0;
366
+
367
+ // Post a regular activity update.
368
+ if ( 'activity_update' === $type ) {
369
+ if ( bp_is_active( 'groups' ) && ! is_null( $prime ) ) {
370
+ $activity_id = groups_post_update( $prepared_activity );
371
+ } else {
372
+ $activity_id = bp_activity_post_update( $prepared_activity );
373
+ }
374
+
375
+ // Post an activity comment.
376
+ } elseif ( 'activity_comment' === $type ) {
377
+
378
+ // ID of the root activity item.
379
+ if ( isset( $prime ) ) {
380
+ $prepared_activity->activity_id = (int) $prime;
381
+ }
382
+
383
+ // ID of a parent comment.
384
+ if ( isset( $request['secondary_item_id'] ) ) {
385
+ $prepared_activity->parent_id = (int) $request['secondary_item_id'];
386
+ }
387
+
388
+ $activity_id = bp_activity_new_comment( $prepared_activity );
389
+
390
+ // Otherwise add an activity.
391
+ } else {
392
+ $activity_id = bp_activity_add( $prepared_activity );
393
+ }
394
+
395
+ if ( ! is_numeric( $activity_id ) ) {
396
+ return new WP_Error(
397
+ 'bp_rest_user_cannot_create_activity',
398
+ __( 'Cannot create new activity.', 'buddypress' ),
399
+ array(
400
+ 'status' => 500,
401
+ )
402
+ );
403
+ }
404
+
405
+ $activity = bp_activity_get(
406
+ array(
407
+ 'in' => $activity_id,
408
+ 'display_comments' => 'stream',
409
+ 'show_hidden' => $request['hidden'],
410
+ )
411
+ );
412
+
413
+ $activity = current( $activity['activities'] );
414
+ $fields_update = $this->update_additional_fields_for_object( $activity, $request );
415
+
416
+ if ( is_wp_error( $fields_update ) ) {
417
+ return $fields_update;
418
+ }
419
+
420
+ $retval = array(
421
+ $this->prepare_response_for_collection(
422
+ $this->prepare_item_for_response( $activity, $request )
423
+ ),
424
+ );
425
+
426
+ $response = rest_ensure_response( $retval );
427
+
428
+ /**
429
+ * Fires after an activity item is created via the REST API.
430
+ *
431
+ * @since 5.0.0
432
+ *
433
+ * @param BP_Activity_Activity $activity The created activity.
434
+ * @param WP_REST_Response $response The response data.
435
+ * @param WP_REST_Request $request The request sent to the API.
436
+ */
437
+ do_action( 'bp_rest_activity_create_item', $activity, $response, $request );
438
+
439
+ return $response;
440
+ }
441
+
442
+ /**
443
+ * Checks if a given request has access to create an activity.
444
+ *
445
+ * @since 5.0.0
446
+ *
447
+ * @param WP_REST_Request $request Full details about the request.
448
+ * @return bool|WP_Error
449
+ */
450
+ public function create_item_permissions_check( $request ) {
451
+ $retval = true;
452
+
453
+ if ( ! is_user_logged_in() ) {
454
+ $retval = new WP_Error(
455
+ 'bp_rest_authorization_required',
456
+ __( 'Sorry, you are not allowed to create activities.', 'buddypress' ),
457
+ array(
458
+ 'status' => rest_authorization_required_code(),
459
+ )
460
+ );
461
+ }
462
+
463
+ $item_id = $request['primary_item_id'];
464
+ $component = $request['component'];
465
+
466
+ if ( true === $retval && bp_is_active( 'groups' ) && buddypress()->groups->id === $component && ! is_null( $item_id ) ) {
467
+ if ( ! $this->show_hidden( $component, $item_id ) ) {
468
+ $retval = new WP_Error(
469
+ 'bp_rest_authorization_required',
470
+ __( 'Sorry, you are not allowed to create activities.', 'buddypress' ),
471
+ array(
472
+ 'status' => rest_authorization_required_code(),
473
+ )
474
+ );
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Filter the activity `create_item` permissions check.
480
+ *
481
+ * @since 5.0.0
482
+ *
483
+ * @param bool|WP_Error $retval Returned value.
484
+ * @param WP_REST_Request $request The request sent to the API.
485
+ */
486
+ return apply_filters( 'bp_rest_activity_create_item_permissions_check', $retval, $request );
487
+ }
488
+
489
+ /**
490
+ * Update an activity.
491
+ *
492
+ * @since 5.0.0
493
+ *
494
+ * @param WP_REST_Request $request Full details about the request.
495
+ * @return WP_REST_Response|WP_Error
496
+ */
497
+ public function update_item( $request ) {
498
+ $request->set_param( 'context', 'edit' );
499
+
500
+ if ( empty( $request['content'] ) ) {
501
+ return new WP_Error(
502
+ 'bp_rest_update_activity_empty_content',
503
+ __( 'Please, enter some content.', 'buddypress' ),
504
+ array(
505
+ 'status' => 500,
506
+ )
507
+ );
508
+ }
509
+
510
+ $activity_id = bp_activity_add( $this->prepare_item_for_database( $request ) );
511
+
512
+ if ( ! is_numeric( $activity_id ) ) {
513
+ return new WP_Error(
514
+ 'bp_rest_user_cannot_update_activity',
515
+ __( 'Cannot update existing activity.', 'buddypress' ),
516
+ array(
517
+ 'status' => 500,
518
+ )
519
+ );
520
+ }
521
+
522
+ $activity = $this->get_activity_object( $activity_id );
523
+ $fields_update = $this->update_additional_fields_for_object( $activity, $request );
524
+
525
+ if ( is_wp_error( $fields_update ) ) {
526
+ return $fields_update;
527
+ }
528
+
529
+ $retval = array(
530
+ $this->prepare_response_for_collection(
531
+ $this->prepare_item_for_response( $activity, $request )
532
+ ),
533
+ );
534
+
535
+ $response = rest_ensure_response( $retval );
536
+
537
+ /**
538
+ * Fires after an activity is updated via the REST API.
539
+ *
540
+ * @since 5.0.0
541
+ *
542
+ * @param BP_Activity_Activity $activity The updated activity.
543
+ * @param WP_REST_Response $response The response data.
544
+ * @param WP_REST_Request $request The request sent to the API.
545
+ */
546
+ do_action( 'bp_rest_activity_update_item', $activity, $response, $request );
547
+
548
+ return $response;
549
+ }
550
+
551
+ /**
552
+ * Check if a given request has access to update an activity.
553
+ *
554
+ * @since 5.0.0
555
+ *
556
+ * @param WP_REST_Request $request Full details about the request.
557
+ * @return bool|WP_Error
558
+ */
559
+ public function update_item_permissions_check( $request ) {
560
+ $retval = true;
561
+
562
+ if ( ! is_user_logged_in() ) {
563
+ $retval = new WP_Error(
564
+ 'bp_rest_authorization_required',
565
+ __( 'Sorry, you are not allowed to update this activity.', 'buddypress' ),
566
+ array(
567
+ 'status' => rest_authorization_required_code(),
568
+ )
569
+ );
570
+ }
571
+
572
+ $activity = $this->get_activity_object( $request );
573
+
574
+ if ( true === $retval && empty( $activity->id ) ) {
575
+ $retval = new WP_Error(
576
+ 'bp_rest_invalid_id',
577
+ __( 'Invalid activity id.', 'buddypress' ),
578
+ array(
579
+ 'status' => 404,
580
+ )
581
+ );
582
+ }
583
+
584
+ if ( true === $retval && ! bp_activity_user_can_delete( $activity ) ) {
585
+ $retval = new WP_Error(
586
+ 'bp_rest_authorization_required',
587
+ __( 'Sorry, you are not allowed to update this activity.', 'buddypress' ),
588
+ array(
589
+ 'status' => 500,
590
+ )
591
+ );
592
+ }
593
+
594
+ /**
595
+ * Filter the activity `update_item` permissions check.
596
+ *
597
+ * @since 5.0.0
598
+ *
599
+ * @param bool|WP_Error $retval Returned value.
600
+ * @param WP_REST_Request $request The request sent to the API.
601
+ */
602
+ return apply_filters( 'bp_rest_activity_update_item_permissions_check', $retval, $request );
603
+ }
604
+
605
+ /**
606
+ * Delete activity.
607
+ *
608
+ * @since 5.0.0
609
+ *
610
+ * @param WP_REST_Request $request Full details about the request.
611
+ * @return WP_REST_Response|WP_Error
612
+ */
613
+ public function delete_item( $request ) {
614
+ // Setting context.
615
+ $request->set_param( 'context', 'edit' );
616
+
617
+ // Get the activity before it's deleted.
618
+ $activity = $this->get_activity_object( $request );
619
+ $previous = $this->prepare_item_for_response( $activity, $request );
620
+
621
+ if ( 'activity_comment' === $activity->type ) {
622
+ $retval = bp_activity_delete_comment( $activity->item_id, $activity->id );
623
+ } else {
624
+ $retval = bp_activity_delete(
625
+ array(
626
+ 'id' => $activity->id,
627
+ )
628
+ );
629
+ }
630
+
631
+ if ( ! $retval ) {
632
+ return new WP_Error(
633
+ 'bp_rest_activity_cannot_delete',
634
+ __( 'Could not delete the activity.', 'buddypress' ),
635
+ array(
636
+ 'status' => 500,
637
+ )
638
+ );
639
+ }
640
+
641
+ // Build the response.
642
+ $response = new WP_REST_Response();
643
+ $response->set_data(
644
+ array(
645
+ 'deleted' => true,
646
+ 'previous' => $previous->get_data(),
647
+ )
648
+ );
649
+
650
+ /**
651
+ * Fires after an activity is deleted via the REST API.
652
+ *
653
+ * @since 5.0.0
654
+ *
655
+ * @param BP_Activity_Activity $activity The deleted activity.
656
+ * @param WP_REST_Response $response The response data.
657
+ * @param WP_REST_Request $request The request sent to the API.
658
+ */
659
+ do_action( 'bp_rest_activity_delete_item', $activity, $response, $request );
660
+
661
+ return $response;
662
+ }
663
+
664
+ /**
665
+ * Check if a given request has access to delete an activity.
666
+ *
667
+ * @since 5.0.0
668
+ *
669
+ * @param WP_REST_Request $request Full details about the request.
670
+ * @return bool|WP_Error
671
+ */
672
+ public function delete_item_permissions_check( $request ) {
673
+ $retval = true;
674
+
675
+ if ( ! is_user_logged_in() ) {
676
+ $retval = new WP_Error(
677
+ 'bp_rest_authorization_required',
678
+ __( 'Sorry, you are not allowed to delete this activity.', 'buddypress' ),
679
+ array(
680
+ 'status' => rest_authorization_required_code(),
681
+ )
682
+ );
683
+ }
684
+
685
+ $activity = $this->get_activity_object( $request );
686
+
687
+ if ( true === $retval && empty( $activity->id ) ) {
688
+ $retval = new WP_Error(
689
+ 'bp_rest_invalid_id',
690
+ __( 'Invalid activity id.', 'buddypress' ),
691
+ array(
692
+ 'status' => 404,
693
+ )
694
+ );
695
+ }
696
+
697
+ if ( true === $retval && ! bp_activity_user_can_delete( $activity ) ) {
698
+ $retval = new WP_Error(
699
+ 'bp_rest_authorization_required',
700
+ __( 'Sorry, you are not allowed to delete this activity.', 'buddypress' ),
701
+ array(
702
+ 'status' => rest_authorization_required_code(),
703
+ )
704
+ );
705
+ }
706
+
707
+ /**
708
+ * Filter the activity `delete_item` permissions check.
709
+ *
710
+ * @since 5.0.0
711
+ *
712
+ * @param bool|WP_Error $retval Returned value.
713
+ * @param WP_REST_Request $request The request sent to the API.
714
+ */
715
+ return apply_filters( 'bp_rest_activity_delete_item_permissions_check', $retval, $request );
716
+ }
717
+
718
+ /**
719
+ * Gets the current user's favorites.
720
+ *
721
+ * @since 5.0.0
722
+ *
723
+ * @return array Array of activity IDs.
724
+ */
725
+ public function get_user_favorites() {
726
+ if ( null === $this->user_favorites ) {
727
+ if ( is_user_logged_in() ) {
728
+ $user_favorites = bp_activity_get_user_favorites( get_current_user_id() );
729
+ $this->user_favorites = array_filter( wp_parse_id_list( $user_favorites ) );
730
+ } else {
731
+ $this->user_favorites = array();
732
+ }
733
+ }
734
+
735
+ return $this->user_favorites;
736
+ }
737
+
738
+ /**
739
+ * Adds or removes the activity from the current user's favorites.
740
+ *
741
+ * @since 5.0.0
742
+ *
743
+ * @param WP_REST_Request $request Full details about the request.
744
+ * @return WP_REST_Response|WP_Error
745
+ */
746
+ public function update_favorite( $request ) {
747
+ $activity = $this->get_activity_object( $request );
748
+
749
+ if ( empty( $activity->id ) ) {
750
+ return new WP_Error(
751
+ 'bp_rest_invalid_id',
752
+ __( 'Invalid activity id.', 'buddypress' ),
753
+ array(
754
+ 'status' => 404,
755
+ )
756
+ );
757
+ }
758
+
759
+ $user_id = get_current_user_id();
760
+
761
+ $result = false;
762
+ if ( in_array( $activity->id, $this->get_user_favorites(), true ) ) {
763
+ $result = bp_activity_remove_user_favorite( $activity->id, $user_id );
764
+ $message = __( 'Sorry, you cannot remove the activity from your favorites.', 'buddypress' );
765
+
766
+ // Update the user favorites, removing the activity ID.
767
+ $this->user_favorites = array_diff( $this->get_user_favorites(), array( $activity->id ) );
768
+ } else {
769
+ $result = bp_activity_add_user_favorite( $activity->id, $user_id );
770
+ $message = __( 'Sorry, you cannot add the activity to your favorites.', 'buddypress' );
771
+
772
+ // Update the user favorites, adding the activity ID.
773
+ $this->user_favorites[] = (int) $activity->id;
774
+ }
775
+
776
+ if ( ! $result ) {
777
+ return new WP_Error(
778
+ 'bp_rest_user_cannot_update_activity_favorite',
779
+ $message,
780
+ array(
781
+ 'status' => 500,
782
+ )
783
+ );
784
+ }
785
+
786
+ // Setting context.
787
+ $request->set_param( 'context', 'edit' );
788
+
789
+ // Prepare the response now the user favorites has been updated.
790
+ $retval = array(
791
+ $this->prepare_response_for_collection(
792
+ $this->prepare_item_for_response( $activity, $request )
793
+ ),
794
+ );
795
+
796
+ $response = rest_ensure_response( $retval );
797
+
798
+ /**
799
+ * Fires after user favorited activities has been updated via the REST API.
800
+ *
801
+ * @since 5.0.0
802
+ *
803
+ * @param BP_Activity_Activity $activity The updated activity.
804
+ * @param array $user_favorites The updated user favorites.
805
+ * @param WP_REST_Response $response The response data.
806
+ * @param WP_REST_Request $request The request sent to the API.
807
+ */
808
+ do_action( 'bp_rest_activity_update_favorite', $activity, $this->get_user_favorites(), $response, $request );
809
+
810
+ return $response;
811
+ }
812
+
813
+ /**
814
+ * Check if a given request has access to update user favorites.
815
+ *
816
+ * @since 5.0.0
817
+ *
818
+ * @param WP_REST_Request $request Full details about the request.
819
+ * @return bool|WP_Error
820
+ */
821
+ public function update_favorite_permissions_check( $request ) {
822
+ $retval = true;
823
+
824
+ if ( ! ( is_user_logged_in() && bp_activity_can_favorite() ) ) {
825
+ $retval = new WP_Error(
826
+ 'bp_rest_authorization_required',
827
+ __( 'Sorry, you are not allowed to update favorites.', 'buddypress' ),
828
+ array(
829
+ 'status' => rest_authorization_required_code(),
830
+ )
831
+ );
832
+ }
833
+
834
+ /**
835
+ * Filter the activity `update_favorite` permissions check.
836
+ *
837
+ * @since 5.0.0
838
+ *
839
+ * @param bool|WP_Error $retval Returned value.
840
+ * @param WP_REST_Request $request The request sent to the API.
841
+ */
842
+ return apply_filters( 'bp_rest_activity_update_favorite_permissions_check', $retval, $request );
843
+ }
844
+
845
+ /**
846
+ * Renders the content of an activity.
847
+ *
848
+ * @since 5.0.0
849
+ *
850
+ * @param BP_Activity_Activity $activity Activity data.
851
+ * @return string The rendered activity content.
852
+ */
853
+ public function render_item( $activity ) {
854
+ $rendered = '';
855
+
856
+ if ( empty( $activity->content ) ) {
857
+ return $rendered;
858
+ }
859
+
860
+ // Do not truncate activities.
861
+ add_filter( 'bp_activity_maybe_truncate_entry', '__return_false' );
862
+
863
+ if ( 'activity_comment' === $activity->type ) {
864
+ $rendered = apply_filters( 'bp_get_activity_content', $activity->content );
865
+ } else {
866
+ $activities_template = null;
867
+
868
+ if ( isset( $GLOBALS['activities_template'] ) ) {
869
+ $activities_template = $GLOBALS['activities_template'];
870
+ }
871
+
872
+ // Set the `activities_template` global for the current activity.
873
+ $GLOBALS['activities_template'] = new stdClass();
874
+ $GLOBALS['activities_template']->activity = $activity;
875
+
876
+ // Set up activity oEmbed cache.
877
+ bp_activity_embed();
878
+
879
+ $rendered = apply_filters( 'bp_get_activity_content_body', $activity->content );
880
+
881
+ // Restore the `activities_template` global.
882
+ $GLOBALS['activities_template'] = $activities_template;
883
+ }
884
+
885
+ // Restore the filter to truncate activities.
886
+ remove_filter( 'bp_activity_maybe_truncate_entry', '__return_false' );
887
+
888
+ return $rendered;
889
+ }
890
+
891
+ /**
892
+ * Prepares activity data for return as an object.
893
+ *
894
+ * @since 5.0.0
895
+ *
896
+ * @param BP_Activity_Activity $activity Activity data.
897
+ * @param WP_REST_Request $request Full details about the request.
898
+ * @return WP_REST_Response
899
+ */
900
+ public function prepare_item_for_response( $activity, $request ) {
901
+ $data = array(
902
+ 'user_id' => $activity->user_id,
903
+ 'component' => $activity->component,
904
+ 'content' => array(
905
+ 'raw' => $activity->content,
906
+ 'rendered' => $this->render_item( $activity ),
907
+ ),
908
+ 'date' => bp_rest_prepare_date_response( $activity->date_recorded ),
909
+ 'id' => $activity->id,
910
+ 'link' => bp_activity_get_permalink( $activity->id ),
911
+ 'primary_item_id' => $activity->item_id,
912
+ 'secondary_item_id' => $activity->secondary_item_id,
913
+ 'status' => $activity->is_spam ? 'spam' : 'published',
914
+ 'title' => $activity->action,
915
+ 'type' => $activity->type,
916
+ 'favorited' => in_array( $activity->id, $this->get_user_favorites(), true ),
917
+ );
918
+
919
+ // Get item schema.
920
+ $schema = $this->get_item_schema();
921
+
922
+ // Get comments (count).
923
+ if ( ! empty( $activity->children ) ) {
924
+ $comment_count = wp_filter_object_list( $activity->children, array( 'type' => 'activity_comment' ), 'AND', 'id' );
925
+ $data['comment_count'] = ! empty( $comment_count ) ? count( $comment_count ) : 0;
926
+
927
+ if ( ! empty( $schema['properties']['comments'] ) && 'threaded' === $request['display_comments'] ) {
928
+ $data['comments'] = $this->prepare_activity_comments( $activity->children, $request );
929
+ }
930
+ }
931
+
932
+ if ( ! empty( $schema['properties']['user_avatar'] ) ) {
933
+ $data['user_avatar'] = array(
934
+ 'full' => bp_core_fetch_avatar(
935
+ array(
936
+ 'item_id' => $activity->user_id,
937
+ 'html' => false,
938
+ 'type' => 'full',
939
+ )
940
+ ),
941
+
942
+ 'thumb' => bp_core_fetch_avatar(
943
+ array(
944
+ 'item_id' => $activity->user_id,
945
+ 'html' => false,
946
+ )
947
+ ),
948
+ );
949
+ }
950
+
951
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
952
+ $data = $this->add_additional_fields_to_object( $data, $request );
953
+ $data = $this->filter_response_by_context( $data, $context );
954
+
955
+ $response = rest_ensure_response( $data );
956
+ $response->add_links( $this->prepare_links( $activity ) );
957
+
958
+ /**
959
+ * Filter an activity value returned from the API.
960
+ *
961
+ * @since 5.0.0
962
+ *
963
+ * @param WP_REST_Response $response The response data.
964
+ * @param WP_REST_Request $request Request used to generate the response.
965
+ * @param BP_Activity_Activity $activity The activity object.
966
+ */
967
+ return apply_filters( 'bp_rest_activity_prepare_value', $response, $request, $activity );
968
+ }
969
+
970
+ /**
971
+ * Prepare activity comments.
972
+ *
973
+ * @since 5.0.0
974
+ *
975
+ * @param array $comments Comments.
976
+ * @param WP_REST_Request $request Full details about the request.
977
+ * @return array An array of activity comments.
978
+ */
979
+ protected function prepare_activity_comments( $comments, $request ) {
980
+ $data = array();
981
+
982
+ if ( empty( $comments ) ) {
983
+ return $data;
984
+ }
985
+
986
+ foreach ( $comments as $comment ) {
987
+ $data[] = $this->prepare_response_for_collection(
988
+ $this->prepare_item_for_response( $comment, $request )
989
+ );
990
+ }
991
+
992
+ /**
993
+ * Filter activity comments returned from the API.
994
+ *
995
+ * @since 5.0.0
996
+ *
997
+ * @param array $data An array of activity comments.
998
+ * @param array $comments Comments.
999
+ * @param WP_REST_Request $request Request used to generate the response.
1000
+ */
1001
+ return apply_filters( 'bp_rest_activity_prepare_comments', $data, $comments, $request );
1002
+ }
1003
+
1004
+ /**
1005
+ * Prepare an activity for create or update.
1006
+ *
1007
+ * @since 5.0.0
1008
+ *
1009
+ * @param WP_REST_Request $request Request object.
1010
+ * @return stdClass|WP_Error Object or WP_Error.
1011
+ */
1012
+ protected function prepare_item_for_database( $request ) {
1013
+ $prepared_activity = new stdClass();
1014
+ $schema = $this->get_item_schema();
1015
+ $activity = $this->get_activity_object( $request );
1016
+
1017
+ if ( ! empty( $schema['properties']['id'] ) && ! empty( $activity->id ) ) {
1018
+ $prepared_activity->id = $activity->id;
1019
+
1020
+ if ( 'activity_comment' !== $request['type'] ) {
1021
+ $prepared_activity->error_type = 'wp_error';
1022
+ }
1023
+ }
1024
+
1025
+ // Activity author ID.
1026
+ if ( ! empty( $schema['properties']['user_id'] ) && isset( $request['user_id'] ) ) {
1027
+ $prepared_activity->user_id = (int) $request['user_id'];
1028
+ } else {
1029
+ $prepared_activity->user_id = get_current_user_id();
1030
+ }
1031
+
1032
+ // Activity component.
1033
+ if ( ! empty( $schema['properties']['component'] ) && isset( $request['component'] ) ) {
1034
+ $prepared_activity->component = $request['component'];
1035
+ } else {
1036
+ $prepared_activity->component = buddypress()->activity->id;
1037
+ }
1038
+
1039
+ // Activity Item ID.
1040
+ if ( ! empty( $schema['properties']['primary_item_id'] ) && isset( $request['primary_item_id'] ) ) {
1041
+ $item_id = (int) $request['primary_item_id'];
1042
+
1043
+ // Set the group ID of the activity.
1044
+ if ( bp_is_active( 'groups' ) && isset( $prepared_activity->component ) && buddypress()->groups->id === $prepared_activity->component ) {
1045
+ $prepared_activity->group_id = $item_id;
1046
+
1047
+ // Use a generic item ID for other components.
1048
+ } else {
1049
+ $prepared_activity->item_id = $item_id;
1050
+ }
1051
+ }
1052
+
1053
+ // Secondary Item ID.
1054
+ if ( ! empty( $schema['properties']['secondary_item_id'] ) && isset( $request['secondary_item_id'] ) ) {
1055
+ $prepared_activity->secondary_item_id = (int) $request['secondary_item_id'];
1056
+ }
1057
+
1058
+ // Activity type.
1059
+ if ( ! empty( $schema['properties']['type'] ) && isset( $request['type'] ) ) {
1060
+ $prepared_activity->type = $request['type'];
1061
+ }
1062
+
1063
+ // Activity content.
1064
+ if ( ! empty( $schema['properties']['content'] ) && isset( $request['content'] ) ) {
1065
+ if ( is_string( $request['content'] ) ) {
1066
+ $prepared_activity->content = $request['content'];
1067
+ } elseif ( isset( $request['content']['raw'] ) ) {
1068
+ $prepared_activity->content = $request['content']['raw'];
1069
+ }
1070
+ }
1071
+
1072
+ // Activity Sitewide visibility.
1073
+ if ( ! empty( $schema['properties']['hidden'] ) && isset( $request['hidden'] ) ) {
1074
+ $prepared_activity->hide_sitewide = (bool) $request['hidden'];
1075
+ }
1076
+
1077
+ /**
1078
+ * Filters an activity before it is inserted or updated via the REST API.
1079
+ *
1080
+ * @since 5.0.0
1081
+ *
1082
+ * @param stdClass $prepared_activity An object prepared for inserting or updating the database.
1083
+ * @param WP_REST_Request $request Request object.
1084
+ */
1085
+ return apply_filters( 'bp_rest_activity_pre_insert_value', $prepared_activity, $request );
1086
+ }
1087
+
1088
+ /**
1089
+ * Prepare links for the request.
1090
+ *
1091
+ * @since 5.0.0
1092
+ *
1093
+ * @param BP_Activity_Activity $activity Activity object.
1094
+ * @return array
1095
+ */
1096
+ protected function prepare_links( $activity ) {
1097
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
1098
+ $url = $base . $activity->id;
1099
+
1100
+ // Entity meta.
1101
+ $links = array(
1102
+ 'self' => array(
1103
+ 'href' => rest_url( $url ),
1104
+ ),
1105
+ 'collection' => array(
1106
+ 'href' => rest_url( $base ),
1107
+ ),
1108
+ 'user' => array(
1109
+ 'href' => rest_url( bp_rest_get_user_url( $activity->user_id ) ),
1110
+ 'embeddable' => true,
1111
+ ),
1112
+ );
1113
+
1114
+ if ( 'activity_comment' === $activity->type ) {
1115
+ $links['up'] = array(
1116
+ 'href' => rest_url( $url ),
1117
+ );
1118
+ }
1119
+
1120
+ if ( bp_activity_can_favorite() ) {
1121
+ $links['favorite'] = array(
1122
+ 'href' => rest_url( $url . '/favorite' ),
1123
+ );
1124
+ }
1125
+
1126
+ if ( bp_is_active( 'groups' ) && 'groups' === $activity->component && ! empty( $activity->item_id ) ) {
1127
+ $group = groups_get_group( $activity->item_id );
1128
+
1129
+ $links['group'] = array(
1130
+ 'href' => bp_get_group_permalink( $group ),
1131
+ 'embeddable' => true,
1132
+ );
1133
+ }
1134
+
1135
+ /**
1136
+ * Filter links prepared for the REST response.
1137
+ *
1138
+ * @since 5.0.0
1139
+ *
1140
+ * @param array $links The prepared links of the REST response.
1141
+ * @param BP_Activity_Activity $activity Activity object.
1142
+ */
1143
+ return apply_filters( 'bp_rest_activity_prepare_links', $links, $activity );
1144
+ }
1145
+
1146
+ /**
1147
+ * Can this user see the activity?
1148
+ *
1149
+ * @since 5.0.0
1150
+ *
1151
+ * @param WP_REST_Request $request Full details about the request.
1152
+ * @return boolean
1153
+ */
1154
+ protected function can_see( $request ) {
1155
+ return bp_activity_user_can_read(
1156
+ $this->get_activity_object( $request ),
1157
+ bp_loggedin_user_id()
1158
+ );
1159
+ }
1160
+
1161
+ /**
1162
+ * Show hidden activity?
1163
+ *
1164
+ * @since 5.0.0
1165
+ *
1166
+ * @param string $component The activity component.
1167
+ * @param int $item_id The activity item ID.
1168
+ * @return boolean
1169
+ */
1170
+ protected function show_hidden( $component, $item_id ) {
1171
+ $user_id = get_current_user_id();
1172
+ $retval = false;
1173
+
1174
+ if ( ! is_null( $component ) ) {
1175
+ // If activity is from a group, do an extra cap check.
1176
+ if ( ! $retval && ! empty( $item_id ) && bp_is_active( $component ) && buddypress()->groups->id === $component ) {
1177
+ // Group admins and mods have access as well.
1178
+ if ( groups_is_user_admin( $user_id, $item_id ) || groups_is_user_mod( $user_id, $item_id ) ) {
1179
+ $retval = true;
1180
+
1181
+ // User is a member of the group.
1182
+ } elseif ( (bool) groups_is_user_member( $user_id, $item_id ) ) {
1183
+ $retval = true;
1184
+ }
1185
+ }
1186
+ }
1187
+
1188
+ // Moderators as well.
1189
+ if ( bp_current_user_can( 'bp_moderate' ) ) {
1190
+ $retval = true;
1191
+ }
1192
+
1193
+ return (bool) $retval;
1194
+ }
1195
+
1196
+ /**
1197
+ * Get activity object.
1198
+ *
1199
+ * @since 5.0.0
1200
+ *
1201
+ * @param WP_REST_Request $request Full details about the request.
1202
+ * @return BP_Activity_Activity|string An activity object.
1203
+ */
1204
+ public function get_activity_object( $request ) {
1205
+ $activity_id = is_numeric( $request ) ? $request : (int) $request['id'];
1206
+
1207
+ $activity = bp_activity_get_specific(
1208
+ array(
1209
+ 'activity_ids' => array( $activity_id ),
1210
+ 'display_comments' => true,
1211
+ )
1212
+ );
1213
+
1214
+ if ( is_array( $activity ) && ! empty( $activity['activities'][0] ) ) {
1215
+ return $activity['activities'][0];
1216
+ }
1217
+
1218
+ return '';
1219
+ }
1220
+
1221
+ /**
1222
+ * Edit the type of the some properties for the CREATABLE & EDITABLE methods.
1223
+ *
1224
+ * @since 5.0.0
1225
+ *
1226
+ * @param string $method Optional. HTTP method of the request.
1227
+ * @return array Endpoint arguments.
1228
+ */
1229
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
1230
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
1231
+ $key = 'get_item';
1232
+
1233
+ if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) {
1234
+ $key = 'create_item';
1235
+ $args['content']['type'] = 'string';
1236
+ unset( $args['content']['properties'] );
1237
+
1238
+ if ( WP_REST_Server::EDITABLE === $method ) {
1239
+ $key = 'update_item';
1240
+ $args['type']['required'] = true;
1241
+ }
1242
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
1243
+ $key = 'delete_item';
1244
+ }
1245
+
1246
+ /**
1247
+ * Filters the method query arguments.
1248
+ *
1249
+ * @since 5.0.0
1250
+ *
1251
+ * @param array $args Query arguments.
1252
+ * @param string $method HTTP method of the request.
1253
+ */
1254
+ return apply_filters( "bp_rest_activity_{$key}_query_arguments", $args, $method );
1255
+ }
1256
+
1257
+ /**
1258
+ * Get the plugin schema, conforming to JSON Schema.
1259
+ *
1260
+ * @since 5.0.0
1261
+ *
1262
+ * @return array
1263
+ */
1264
+ public function get_item_schema() {
1265
+ $schema = array(
1266
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
1267
+ 'title' => 'bp_activity',
1268
+ 'type' => 'object',
1269
+ 'properties' => array(
1270
+ 'id' => array(
1271
+ 'context' => array( 'view', 'edit' ),
1272
+ 'description' => __( 'A unique numeric ID for the activity.', 'buddypress' ),
1273
+ 'readonly' => true,
1274
+ 'type' => 'integer',
1275
+ ),
1276
+ 'primary_item_id' => array(
1277
+ 'context' => array( 'view', 'edit' ),
1278
+ 'description' => __( 'The ID of some other object primarily associated with this one.', 'buddypress' ),
1279
+ 'type' => 'integer',
1280
+ ),
1281
+ 'secondary_item_id' => array(
1282
+ 'context' => array( 'view', 'edit' ),
1283
+ 'description' => __( 'The ID of some other object also associated with this one.', 'buddypress' ),
1284
+ 'type' => 'integer',
1285
+ ),
1286
+ 'user_id' => array(
1287
+ 'context' => array( 'view', 'edit' ),
1288
+ 'description' => __( 'The ID for the author of the activity.', 'buddypress' ),
1289
+ 'type' => 'integer',
1290
+ ),
1291
+ 'link' => array(
1292
+ 'context' => array( 'view', 'edit' ),
1293
+ 'description' => __( 'The permalink to this activity on the site.', 'buddypress' ),
1294
+ 'format' => 'uri',
1295
+ 'type' => 'string',
1296
+ ),
1297
+ 'component' => array(
1298
+ 'context' => array( 'view', 'edit' ),
1299
+ 'description' => __( 'The active BuddyPress component the activity relates to.', 'buddypress' ),
1300
+ 'type' => 'string',
1301
+ 'enum' => array_keys( buddypress()->active_components ),
1302
+ 'arg_options' => array(
1303
+ 'sanitize_callback' => 'sanitize_key',
1304
+ ),
1305
+ ),
1306
+ 'type' => array(
1307
+ 'context' => array( 'view', 'edit' ),
1308
+ 'description' => __( 'The activity type of the activity.', 'buddypress' ),
1309
+ 'type' => 'string',
1310
+ 'enum' => array_keys( bp_activity_get_types() ),
1311
+ 'arg_options' => array(
1312
+ 'sanitize_callback' => 'sanitize_key',
1313
+ ),
1314
+ ),
1315
+ 'title' => array(
1316
+ 'context' => array( 'view', 'edit' ),
1317
+ 'description' => __( 'The description of the activity\'s type (eg: Username posted an update)', 'buddypress' ),
1318
+ 'type' => 'string',
1319
+ 'readonly' => true,
1320
+ 'arg_options' => array(
1321
+ 'sanitize_callback' => 'sanitize_text_field',
1322
+ ),
1323
+ ),
1324
+ 'content' => array(
1325
+ 'context' => array( 'view', 'edit' ),
1326
+ 'description' => __( 'Allowed HTML content for the activity.', 'buddypress' ),
1327
+ 'type' => 'object',
1328
+ 'arg_options' => array(
1329
+ 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database().
1330
+ 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database().
1331
+ ),
1332
+ 'properties' => array(
1333
+ 'raw' => array(
1334
+ 'description' => __( 'Content for the activity, as it exists in the database.', 'buddypress' ),
1335
+ 'type' => 'string',
1336
+ 'context' => array( 'edit' ),
1337
+ ),
1338
+ 'rendered' => array(
1339
+ 'description' => __( 'HTML content for the activity, transformed for display.', 'buddypress' ),
1340
+ 'type' => 'string',
1341
+ 'context' => array( 'view', 'edit' ),
1342
+ 'readonly' => true,
1343
+ ),
1344
+ ),
1345
+ ),
1346
+ 'date' => array(
1347
+ 'context' => array( 'view', 'edit' ),
1348
+ 'description' => __( "The date the activity was published, in the site's timezone.", 'buddypress' ),
1349
+ 'type' => 'string',
1350
+ 'format' => 'date-time',
1351
+ ),
1352
+ 'status' => array(
1353
+ 'context' => array( 'view', 'edit' ),
1354
+ 'description' => __( 'Whether the activity has been marked as spam or not.', 'buddypress' ),
1355
+ 'type' => 'string',
1356
+ 'enum' => array( 'published', 'spam' ),
1357
+ 'readonly' => true,
1358
+ 'arg_options' => array(
1359
+ 'sanitize_callback' => 'sanitize_key',
1360
+ ),
1361
+ ),
1362
+ 'comments' => array(
1363
+ 'context' => array( 'view', 'edit' ),
1364
+ 'description' => __( 'A list of objects children of the activity object.', 'buddypress' ),
1365
+ 'type' => 'array',
1366
+ 'readonly' => true,
1367
+ ),
1368
+ 'comment_count' => array(
1369
+ 'context' => array( 'view', 'edit' ),
1370
+ 'description' => __( 'Total number of comments of the activity object.', 'buddypress' ),
1371
+ 'type' => 'integer',
1372
+ 'readonly' => true,
1373
+ ),
1374
+ 'hidden' => array(
1375
+ 'context' => array( 'edit' ),
1376
+ 'description' => __( 'Whether the activity object should be sitewide hidden or not.', 'buddypress' ),
1377
+ 'type' => 'boolean',
1378
+ ),
1379
+ 'favorited' => array(
1380
+ 'context' => array( 'view', 'edit' ),
1381
+ 'description' => __( 'Whether the activity object has been favorited by the current user.', 'buddypress' ),
1382
+ 'type' => 'boolean',
1383
+ 'readonly' => true,
1384
+ ),
1385
+ ),
1386
+ );
1387
+
1388
+ // Avatars.
1389
+ if ( true === buddypress()->avatar->show_avatars ) {
1390
+ $avatar_properties = array();
1391
+
1392
+ $avatar_properties['full'] = array(
1393
+ 'context' => array( 'view', 'edit' ),
1394
+ /* translators: Full image size for the member Avatar */
1395
+ 'description' => sprintf( __( 'Avatar URL with full image size (%1$d x %2$d pixels).', 'buddypress' ), number_format_i18n( bp_core_avatar_full_width() ), number_format_i18n( bp_core_avatar_full_height() ) ),
1396
+ 'type' => 'string',
1397
+ 'format' => 'uri',
1398
+ );
1399
+
1400
+ $avatar_properties['thumb'] = array(
1401
+ 'context' => array( 'view', 'edit' ),
1402
+ /* translators: Thumb imaze size for the member Avatar */
1403
+ 'description' => sprintf( __( 'Avatar URL with thumb image size (%1$d x %2$d pixels).', 'buddypress' ), number_format_i18n( bp_core_avatar_thumb_width() ), number_format_i18n( bp_core_avatar_thumb_height() ) ),
1404
+ 'type' => 'string',
1405
+ 'format' => 'uri',
1406
+ );
1407
+
1408
+ $schema['properties']['user_avatar'] = array(
1409
+ 'context' => array( 'view', 'edit' ),
1410
+ 'description' => __( 'Avatar URLs for the author of the activity.', 'buddypress' ),
1411
+ 'type' => 'object',
1412
+ 'readonly' => true,
1413
+ 'properties' => $avatar_properties,
1414
+ );
1415
+ }
1416
+
1417
+ /**
1418
+ * Filters the activity schema.
1419
+ *
1420
+ * @param string $schema The endpoint schema.
1421
+ */
1422
+ return apply_filters( 'bp_rest_activity_schema', $this->add_additional_fields_schema( $schema ) );
1423
+ }
1424
+
1425
+ /**
1426
+ * Get the query params for collections of plugins.
1427
+ *
1428
+ * @since 5.0.0
1429
+ *
1430
+ * @return array
1431
+ */
1432
+ public function get_collection_params() {
1433
+ $params = parent::get_collection_params();
1434
+ $params['context']['default'] = 'view';
1435
+
1436
+ $params['exclude'] = array(
1437
+ 'description' => __( 'Ensure result set excludes specific IDs.', 'buddypress' ),
1438
+ 'default' => array(),
1439
+ 'type' => 'array',
1440
+ 'items' => array( 'type' => 'integer' ),
1441
+ 'sanitize_callback' => 'wp_parse_id_list',
1442
+ 'validate_callback' => 'rest_validate_request_arg',
1443
+ );
1444
+
1445
+ $params['include'] = array(
1446
+ 'description' => __( 'Ensure result set includes specific IDs.', 'buddypress' ),
1447
+ 'default' => array(),
1448
+ 'type' => 'array',
1449
+ 'items' => array( 'type' => 'integer' ),
1450
+ 'sanitize_callback' => 'wp_parse_id_list',
1451
+ 'validate_callback' => 'rest_validate_request_arg',
1452
+ );
1453
+
1454
+ $params['order'] = array(
1455
+ 'description' => __( 'Order sort attribute ascending or descending.', 'buddypress' ),
1456
+ 'default' => 'desc',
1457
+ 'type' => 'string',
1458
+ 'enum' => array( 'asc', 'desc' ),
1459
+ 'sanitize_callback' => 'sanitize_key',
1460
+ 'validate_callback' => 'rest_validate_request_arg',
1461
+ );
1462
+
1463
+ $params['after'] = array(
1464
+ 'description' => __( 'Limit result set to items published after a given ISO8601 compliant date.', 'buddypress' ),
1465
+ 'type' => 'string',
1466
+ 'format' => 'date-time',
1467
+ 'validate_callback' => 'rest_validate_request_arg',
1468
+ );
1469
+
1470
+ $params['user_id'] = array(
1471
+ 'description' => __( 'Limit result set to items created by a specific user (ID).', 'buddypress' ),
1472
+ 'default' => 0,
1473
+ 'type' => 'integer',
1474
+ 'sanitize_callback' => 'absint',
1475
+ 'validate_callback' => 'rest_validate_request_arg',
1476
+ );
1477
+
1478
+ $params['status'] = array(
1479
+ 'description' => __( 'Limit result set to items with a specific status.', 'buddypress' ),
1480
+ 'default' => 'ham_only',
1481
+ 'type' => 'string',
1482
+ 'enum' => array( 'ham_only', 'spam_only', 'all' ),
1483
+ 'sanitize_callback' => 'sanitize_key',
1484
+ 'validate_callback' => 'rest_validate_request_arg',
1485
+ );
1486
+
1487
+ $params['group_id'] = array(
1488
+ 'description' => __( 'Limit result set to items created by a specific group.', 'buddypress' ),
1489
+ 'default' => 0,
1490
+ 'type' => 'integer',
1491
+ 'sanitize_callback' => 'absint',
1492
+ 'validate_callback' => 'rest_validate_request_arg',
1493
+ );
1494
+
1495
+ $params['site_id'] = array(
1496
+ 'description' => __( 'Limit result set to items created by a specific site.', 'buddypress' ),
1497
+ 'default' => 0,
1498
+ 'type' => 'integer',
1499
+ 'sanitize_callback' => 'absint',
1500
+ 'validate_callback' => 'rest_validate_request_arg',
1501
+ );
1502
+
1503
+ $params['primary_id'] = array(
1504
+ 'description' => __( 'Limit result set to items with a specific prime association ID.', 'buddypress' ),
1505
+ 'default' => 0,
1506
+ 'type' => 'integer',
1507
+ 'sanitize_callback' => 'absint',
1508
+ 'validate_callback' => 'rest_validate_request_arg',
1509
+ );
1510
+
1511
+ $params['secondary_id'] = array(
1512
+ 'description' => __( 'Limit result set to items with a specific secondary association ID.', 'buddypress' ),
1513
+ 'default' => 0,
1514
+ 'type' => 'integer',
1515
+ 'sanitize_callback' => 'absint',
1516
+ 'validate_callback' => 'rest_validate_request_arg',
1517
+ );
1518
+
1519
+ $params['component'] = array(
1520
+ 'description' => __( 'Limit result set to items with a specific active BuddyPress component.', 'buddypress' ),
1521
+ 'type' => 'string',
1522
+ 'enum' => array_keys( buddypress()->active_components ),
1523
+ 'sanitize_callback' => 'sanitize_key',
1524
+ 'validate_callback' => 'rest_validate_request_arg',
1525
+ );
1526
+
1527
+ $params['type'] = array(
1528
+ 'description' => __( 'Limit result set to items with a specific activity type.', 'buddypress' ),
1529
+ 'type' => 'string',
1530
+ 'enum' => array_keys( bp_activity_get_types() ),
1531
+ 'sanitize_callback' => 'sanitize_key',
1532
+ 'validate_callback' => 'rest_validate_request_arg',
1533
+ );
1534
+
1535
+ $params['display_comments'] = array(
1536
+ 'description' => __( 'No comments by default, stream for within stream display, threaded for below each activity item.', 'buddypress' ),
1537
+ 'default' => '',
1538
+ 'type' => 'string',
1539
+ 'sanitize_callback' => 'sanitize_key',
1540
+ 'validate_callback' => 'rest_validate_request_arg',
1541
+ );
1542
+
1543
+ /**
1544
+ * Filters the collection query params.
1545
+ *
1546
+ * @param array $params Query params.
1547
+ */
1548
+ return apply_filters( 'bp_rest_activity_collection_params', $params );
1549
+ }
1550
+ }
bp-blogs/classes/class-bp-blogs-recent-posts-widget.php CHANGED
@@ -61,7 +61,8 @@ class BP_Blogs_Recent_Posts_Widget extends WP_Widget {
61
  echo $args['before_widget'];
62
  echo $args['before_title'] . $title . $args['after_title'];
63
 
64
- if ( empty( $instance['max_posts'] ) || empty( $instance['max_posts'] ) ) {
 
65
  $instance['max_posts'] = 10;
66
  }
67
 
@@ -128,10 +129,13 @@ class BP_Blogs_Recent_Posts_Widget extends WP_Widget {
128
  * @return array $instance The parsed options to be saved.
129
  */
130
  public function update( $new_instance, $old_instance ) {
131
- $instance = $old_instance;
 
 
 
132
  $instance['title'] = strip_tags( $new_instance['title'] );
133
- $instance['max_posts'] = strip_tags( $new_instance['max_posts'] );
134
- $instance['link_title'] = (bool) $new_instance['link_title'];
135
 
136
  return $instance;
137
  }
@@ -150,15 +154,17 @@ class BP_Blogs_Recent_Posts_Widget extends WP_Widget {
150
  'link_title' => false,
151
  ) );
152
 
 
 
153
  $title = strip_tags( $instance['title'] );
154
- $max_posts = strip_tags( $instance['max_posts'] );
155
  $link_title = (bool) $instance['link_title'];
156
 
157
  ?>
158
 
159
  <p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _ex( 'Title:', 'Label for the Title field of the Recent Networkwide Posts widget', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" style="width: 100%;" /></label></p>
160
  <p><label for="<?php echo $this->get_field_id( 'link_title' ); ?>"><input type="checkbox" name="<?php echo $this->get_field_name( 'link_title' ); ?>" value="1" <?php checked( $link_title ); ?> /> <?php _e( 'Link widget title to Blogs directory', 'buddypress' ); ?></label></p>
161
- <p><label for="<?php echo $this->get_field_id( 'max_posts' ); ?>"><?php _e( 'Max posts to show:', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_posts' ); ?>" name="<?php echo $this->get_field_name( 'max_posts' ); ?>" type="text" value="<?php echo esc_attr( $max_posts ); ?>" style="width: 30%" /></label></p>
162
  <?php
163
  }
164
  }
61
  echo $args['before_widget'];
62
  echo $args['before_title'] . $title . $args['after_title'];
63
 
64
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
65
+ if ( empty( $instance['max_posts'] ) || $instance['max_posts'] > $max_limit ) {
66
  $instance['max_posts'] = 10;
67
  }
68
 
129
  * @return array $instance The parsed options to be saved.
130
  */
131
  public function update( $new_instance, $old_instance ) {
132
+ $instance = $old_instance;
133
+
134
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
135
+
136
  $instance['title'] = strip_tags( $new_instance['title'] );
137
+ $instance['max_posts'] = $new_instance['max_posts'] > $max_limit ? $max_limit : intval( $new_instance['max_posts'] );
138
+ $instance['link_title'] = ! empty( $new_instance['link_title'] );
139
 
140
  return $instance;
141
  }
154
  'link_title' => false,
155
  ) );
156
 
157
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
158
+
159
  $title = strip_tags( $instance['title'] );
160
+ $max_posts = $instance['max_posts'] > $max_limit ? $max_limit : intval( $instance['max_posts'] );
161
  $link_title = (bool) $instance['link_title'];
162
 
163
  ?>
164
 
165
  <p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _ex( 'Title:', 'Label for the Title field of the Recent Networkwide Posts widget', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" style="width: 100%;" /></label></p>
166
  <p><label for="<?php echo $this->get_field_id( 'link_title' ); ?>"><input type="checkbox" name="<?php echo $this->get_field_name( 'link_title' ); ?>" value="1" <?php checked( $link_title ); ?> /> <?php _e( 'Link widget title to Blogs directory', 'buddypress' ); ?></label></p>
167
+ <p><label for="<?php echo $this->get_field_id( 'max_posts' ); ?>"><?php _e( 'Max posts to show:', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_posts' ); ?>" name="<?php echo $this->get_field_name( 'max_posts' ); ?>" type="number" min="1" max="<?php echo esc_attr( $max_limit ); ?>" value="<?php echo esc_attr( $max_posts ); ?>" style="width: 30%" /></label></p>
168
  <?php
169
  }
170
  }
bp-core/admin/bp-core-admin-functions.php CHANGED
@@ -1135,3 +1135,42 @@ function bp_core_admin_body_classes( $classes ) {
1135
  return $classes . ' buddypress';
1136
  }
1137
  add_filter( 'admin_body_class', 'bp_core_admin_body_classes' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1135
  return $classes . ' buddypress';
1136
  }
1137
  add_filter( 'admin_body_class', 'bp_core_admin_body_classes' );
1138
+
1139
+ /**
1140
+ * Adds a BuddyPress category to house BuddyPress blocks.
1141
+ *
1142
+ * @since 5.0.0
1143
+ *
1144
+ * @param array $categories Array of block categories.
1145
+ * @param WP_Post $post Post being loaded.
1146
+ */
1147
+ function bp_block_category( $categories = array(), WP_Post $post ) {
1148
+ /**
1149
+ * Filter here to add/remove the supported post types for the BuddyPress blocks category.
1150
+ *
1151
+ * @since 5.0.0
1152
+ *
1153
+ * @param array $value The list of supported post types. Defaults to WordPress built-in ones.
1154
+ */
1155
+ $post_types = apply_filters( 'bp_block_category_post_types', array( 'post', 'page' ) );
1156
+
1157
+ if ( ! $post_types ) {
1158
+ return $categories;
1159
+ }
1160
+
1161
+ // Get the post type of the current item.
1162
+ $post_type = get_post_type( $post );
1163
+
1164
+ if ( ! in_array( $post_type, $post_types, true ) ) {
1165
+ return $categories;
1166
+ }
1167
+
1168
+ return array_merge( $categories, array(
1169
+ array(
1170
+ 'slug' => 'buddypress',
1171
+ 'title' => __( 'BuddyPress', 'buddypress' ),
1172
+ 'icon' => 'buddicons-buddypress-logo',
1173
+ ),
1174
+ ) );
1175
+ }
1176
+ add_filter( 'block_categories', 'bp_block_category', 1, 2 );
bp-core/admin/bp-core-admin-schema.php CHANGED
@@ -382,6 +382,11 @@ function bp_core_install_extended_profiles() {
382
 
383
  if ( ! $wpdb->get_var( "SELECT id FROM {$bp_prefix}bp_xprofile_fields WHERE id = 1" ) ) {
384
  $insert_sql[] = "INSERT INTO {$bp_prefix}bp_xprofile_fields ( group_id, parent_id, type, name, description, is_required, can_delete ) VALUES ( 1, 0, 'textbox', " . $wpdb->prepare( '%s', stripslashes( bp_get_option( 'bp-xprofile-fullname-field-name' ) ) ) . ", '', 1, 0 );";
 
 
 
 
 
385
  }
386
 
387
  dbDelta( $insert_sql );
@@ -535,3 +540,49 @@ function bp_core_install_emails() {
535
  */
536
  do_action( 'bp_core_install_emails' );
537
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
  if ( ! $wpdb->get_var( "SELECT id FROM {$bp_prefix}bp_xprofile_fields WHERE id = 1" ) ) {
384
  $insert_sql[] = "INSERT INTO {$bp_prefix}bp_xprofile_fields ( group_id, parent_id, type, name, description, is_required, can_delete ) VALUES ( 1, 0, 'textbox', " . $wpdb->prepare( '%s', stripslashes( bp_get_option( 'bp-xprofile-fullname-field-name' ) ) ) . ", '', 1, 0 );";
385
+
386
+ // Make sure the custom visibility is disabled for the default field.
387
+ if ( ! $wpdb->get_var( "SELECT id FROM {$bp_prefix}bp_xprofile_meta WHERE id = 1" ) ) {
388
+ $insert_sql[] = "INSERT INTO {$bp_prefix}bp_xprofile_meta ( object_id, object_type, meta_key, meta_value ) VALUES ( 1, 'field', 'allow_custom_visibility', 'disabled' );";
389
+ }
390
  }
391
 
392
  dbDelta( $insert_sql );
540
  */
541
  do_action( 'bp_core_install_emails' );
542
  }
543
+
544
+ /**
545
+ * Install database tables for the Invitations API
546
+ *
547
+ * @since 5.0.0
548
+ *
549
+ * @uses bp_core_set_charset()
550
+ * @uses bp_core_get_table_prefix()
551
+ * @uses dbDelta()
552
+ */
553
+ function bp_core_install_invitations() {
554
+ $sql = array();
555
+ $charset_collate = $GLOBALS['wpdb']->get_charset_collate();
556
+ $bp_prefix = bp_core_get_table_prefix();
557
+ $sql[] = "CREATE TABLE {$bp_prefix}bp_invitations (
558
+ id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
559
+ user_id bigint(20) NOT NULL,
560
+ inviter_id bigint(20) NOT NULL,
561
+ invitee_email varchar(100) DEFAULT NULL,
562
+ class varchar(120) NOT NULL,
563
+ item_id bigint(20) NOT NULL,
564
+ secondary_item_id bigint(20) DEFAULT NULL,
565
+ type varchar(12) NOT NULL DEFAULT 'invite',
566
+ content longtext DEFAULT '',
567
+ date_modified datetime NOT NULL,
568
+ invite_sent tinyint(1) NOT NULL DEFAULT '0',
569
+ accepted tinyint(1) NOT NULL DEFAULT '0',
570
+ KEY user_id (user_id),
571
+ KEY inviter_id (inviter_id),
572
+ KEY invitee_email (invitee_email),
573
+ KEY class (class),
574
+ KEY item_id (item_id),
575
+ KEY secondary_item_id (secondary_item_id),
576
+ KEY type (type),
577
+ KEY invite_sent (invite_sent),
578
+ KEY accepted (accepted)
579
+ ) {$charset_collate};";
580
+ dbDelta( $sql );
581
+
582
+ /**
583
+ * Fires after BuddyPress adds the invitations table.
584
+ *
585
+ * @since 5.0.0
586
+ */
587
+ do_action( 'bp_core_install_invitations' );
588
+ }
bp-core/admin/bp-core-admin-tools.php CHANGED
@@ -488,3 +488,82 @@ function bp_core_admin_notice_repopulate_blogs_resume() {
488
  echo '<div class="error"><p>' . __( 'It looks like you have more sites to record. Resume recording by checking the "Repopulate site tracking records" option.', 'buddypress' ) . '</p></div>';
489
  }
490
  add_action( 'network_admin_notices', 'bp_core_admin_notice_repopulate_blogs_resume' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  echo '<div class="error"><p>' . __( 'It looks like you have more sites to record. Resume recording by checking the "Repopulate site tracking records" option.', 'buddypress' ) . '</p></div>';
489
  }
490
  add_action( 'network_admin_notices', 'bp_core_admin_notice_repopulate_blogs_resume' );
491
+
492
+ /**
493
+ * Add BuddyPress debug info to the WordPress Site Health info screen.
494
+ *
495
+ * @since 5.0.0
496
+ *
497
+ * @param array $debug_info The Site's debug info.
498
+ * @return array The Site's debug info, including the BuddyPress specific ones.
499
+ */
500
+ function bp_core_admin_debug_information( $debug_info = array() ) {
501
+ global $wp_settings_fields;
502
+ $active_components = array_intersect_key( bp_core_get_components(), buddypress()->active_components );
503
+ $bp_settings = array();
504
+
505
+ foreach ( $wp_settings_fields['buddypress'] as $section => $settings ) {
506
+ $prefix = '';
507
+ $component_id = str_replace( 'bp_', '', $section );
508
+
509
+ if ( isset( $active_components[ $component_id ]['title'] ) ) {
510
+ $prefix = $active_components[ $component_id ]['title'] .': ';
511
+ }
512
+
513
+ foreach( $settings as $bp_setting ) {
514
+ $reverse = (
515
+ strpos( $bp_setting['id'], 'hide' ) !== false ||
516
+ strpos( $bp_setting['id'], 'restrict' ) !== false ||
517
+ strpos( $bp_setting['id'], 'disable' ) !== false
518
+ );
519
+
520
+ if ( ! isset( $bp_setting['id'] ) || '_bp_theme_package_id' === $bp_setting['id'] ) {
521
+ continue;
522
+ }
523
+
524
+ $bp_setting_value = bp_get_option( $bp_setting['id'] );
525
+ if ( '0' === $bp_setting_value || '1' === $bp_setting_value ) {
526
+ if ( ( $reverse && '0' === $bp_setting_value ) || ( ! $reverse && '1' === $bp_setting_value ) ) {
527
+ $bp_setting_value = __( 'Yes', 'buddypress' );
528
+ } else {
529
+ $bp_setting_value = __( 'No', 'buddypress' );
530
+ }
531
+ }
532
+
533
+ // Make sure to show the setting is reversed when site info is copied to clipboard.
534
+ $bp_settings_id = $bp_setting['id'];
535
+ if ( $reverse ) {
536
+ $bp_settings_id = '! ' . $bp_settings_id;
537
+ }
538
+
539
+ $bp_settings[ $bp_settings_id ] = array(
540
+ 'label' => $prefix . $bp_setting['title'],
541
+ 'value' => $bp_setting_value,
542
+ );
543
+ }
544
+ }
545
+
546
+ $debug_info['buddypress'] = array(
547
+ 'label' => __( 'BuddyPress', 'buddypress' ),
548
+ 'fields' => array_merge(
549
+ array(
550
+ 'version' => array(
551
+ 'label' => __( 'Version', 'buddypress' ),
552
+ 'value' => bp_get_version(),
553
+ ),
554
+ 'active_components' => array(
555
+ 'label' => __( 'Active components', 'buddypress' ),
556
+ 'value' => implode( wp_list_pluck( $active_components, 'title' ), ', ' ),
557
+ ),
558
+ 'template_pack' => array(
559
+ 'label' => __( 'Active template pack', 'buddypress' ),
560
+ 'value' => bp_get_theme_compat_name() . ' ' . bp_get_theme_compat_version(),
561
+ ),
562
+ ),
563
+ $bp_settings
564
+ )
565
+ );
566
+
567
+ return $debug_info;
568
+ }
569
+ add_filter( 'debug_information', 'bp_core_admin_debug_information' );
bp-core/bp-core-avatars.php CHANGED
@@ -476,7 +476,7 @@ function bp_core_fetch_avatar( $args = '' ) {
476
  $legacy_group_avatar_name = ( 'full' == $params['type'] ) ? '-groupavatar-full' : '-groupavatar-thumb';
477
 
478
  // Check for directory.
479
- if ( file_exists( $avatar_folder_dir ) ) {
480
 
481
  // Open directory.
482
  if ( $av_dir = opendir( $avatar_folder_dir ) ) {
@@ -637,6 +637,7 @@ function bp_core_fetch_avatar( $args = '' ) {
637
  // Custom Gravatar URL args.
638
  if ( ! empty( $params['force_default'] ) ) {
639
  $url_args['f'] = 'y';
 
640
  }
641
  if ( ! empty( $params['rating'] ) ) {
642
  $url_args['r'] = strtolower( $params['rating'] );
@@ -653,7 +654,7 @@ function bp_core_fetch_avatar( $args = '' ) {
653
  $default_grav = apply_filters( 'bp_core_avatar_default', $default_grav, $params );
654
 
655
  // Only set default image if 'Gravatar Logo' is not requested.
656
- if ( 'gravatar_default' !== $default_grav ) {
657
  $url_args['d'] = $default_grav;
658
  }
659
 
476
  $legacy_group_avatar_name = ( 'full' == $params['type'] ) ? '-groupavatar-full' : '-groupavatar-thumb';
477
 
478
  // Check for directory.
479
+ if ( ! $params['force_default'] && file_exists( $avatar_folder_dir ) ) {
480
 
481
  // Open directory.
482
  if ( $av_dir = opendir( $avatar_folder_dir ) ) {
637
  // Custom Gravatar URL args.
638
  if ( ! empty( $params['force_default'] ) ) {
639
  $url_args['f'] = 'y';
640
+ $url_args['d'] = $params['default'];
641
  }
642
  if ( ! empty( $params['rating'] ) ) {
643
  $url_args['r'] = strtolower( $params['rating'] );
654
  $default_grav = apply_filters( 'bp_core_avatar_default', $default_grav, $params );
655
 
656
  // Only set default image if 'Gravatar Logo' is not requested.
657
+ if ( ! $params['force_default'] && 'gravatar_default' !== $default_grav ) {
658
  $url_args['d'] = $default_grav;
659
  }
660
 
bp-core/bp-core-cache.php CHANGED
@@ -379,3 +379,14 @@ function bp_core_get_incrementor( $group ) {
379
  function bp_core_reset_incrementor( $group ) {
380
  return wp_cache_delete( 'incrementor', $group );
381
  }
 
 
 
 
 
 
 
 
 
 
 
379
  function bp_core_reset_incrementor( $group ) {
380
  return wp_cache_delete( 'incrementor', $group );
381
  }
382
+
383
+ /**
384
+ * Resets all incremented bp_invitations caches.
385
+ *
386
+ * @since 5.0.0
387
+ */
388
+ function bp_invitations_reset_cache_incrementor() {
389
+ bp_core_reset_incrementor( 'bp_invitations' );
390
+ }
391
+ add_action( 'bp_invitation_after_save', 'bp_invitations_reset_cache_incrementor' );
392
+ add_action( 'bp_invitation_after_delete', 'bp_invitations_reset_cache_incrementor' );
bp-core/bp-core-catchuri.php CHANGED
@@ -240,7 +240,7 @@ function bp_core_set_uri_globals() {
240
  }
241
 
242
  // Search doesn't have an associated page, so we check for it separately.
243
- if ( !empty( $bp_uri[0] ) && ( bp_get_search_slug() == $bp_uri[0] ) ) {
244
  $matches[] = 1;
245
  $match = new stdClass;
246
  $match->key = 'search';
240
  }
241
 
242
  // Search doesn't have an associated page, so we check for it separately.
243
+ if ( isset( $_POST['search-terms'] ) && !empty( $bp_uri[0] ) && ( bp_get_search_slug() == $bp_uri[0] ) ) {
244
  $matches[] = 1;
245
  $match = new stdClass;
246
  $match->key = 'search';
bp-core/bp-core-cssjs.php CHANGED
@@ -27,7 +27,23 @@ function bp_core_register_common_scripts() {
27
  * eg. French (France) locale for WP is fr_FR. Here, we try to find fr-fr.js
28
  * (this file doesn't exist).
29
  */
30
- $locale = sanitize_file_name( strtolower( get_locale() ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  $locale = str_replace( '_', '-', $locale );
32
  if ( file_exists( buddypress()->core->path . "bp-core/js/vendor/moment-js/locale/{$locale}{$min}.js" ) ) {
33
  $moment_locale_url = $url . "vendor/moment-js/locale/{$locale}{$min}.js";
@@ -140,7 +156,7 @@ function bp_core_register_common_styles() {
140
  foreach ( $styles as $id => $style ) {
141
  wp_register_style( $id, $style['file'], $style['dependencies'], bp_get_version() );
142
 
143
- wp_style_add_data( $id, 'rtl', true );
144
  if ( $min ) {
145
  wp_style_add_data( $id, 'suffix', $min );
146
  }
27
  * eg. French (France) locale for WP is fr_FR. Here, we try to find fr-fr.js
28
  * (this file doesn't exist).
29
  */
30
+ $wp_locale = sanitize_file_name( strtolower( get_locale() ) );
31
+
32
+ // WP uses ISO 639-2 or -3 codes for some locales, which we must translate back to ISO 639-1.
33
+ $iso_locales = array(
34
+ 'bel' => 'be',
35
+ 'bre' => 'br',
36
+ 'kir' => 'ky',
37
+ 'mri' => 'mi',
38
+ 'ssw' => 'ss',
39
+ );
40
+
41
+ if ( isset( $iso_locales[ $wp_locale ] ) ) {
42
+ $locale = $iso_locales[ $wp_locale ];
43
+ } else {
44
+ $locale = $wp_locale;
45
+ }
46
+
47
  $locale = str_replace( '_', '-', $locale );
48
  if ( file_exists( buddypress()->core->path . "bp-core/js/vendor/moment-js/locale/{$locale}{$min}.js" ) ) {
49
  $moment_locale_url = $url . "vendor/moment-js/locale/{$locale}{$min}.js";
156
  foreach ( $styles as $id => $style ) {
157
  wp_register_style( $id, $style['file'], $style['dependencies'], bp_get_version() );
158
 
159
+ wp_style_add_data( $id, 'rtl', 'replace' );
160
  if ( $min ) {
161
  wp_style_add_data( $id, 'suffix', $min );
162
  }
bp-core/bp-core-filters.php CHANGED
@@ -469,7 +469,22 @@ function bp_core_activation_signup_blog_notification( $domain, $path, $title, $u
469
  'user.email' => $user_email,
470
  ),
471
  );
472
- bp_send_email( 'core-user-registration-with-blog', array( array( $user_email => $user ) ), $args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
 
474
  // Return false to stop the original WPMU function from continuing.
475
  return false;
@@ -523,6 +538,13 @@ function bp_core_activation_signup_user_notification( $user, $user_email, $key,
523
  $user_id = $user_object->ID;
524
  }
525
 
 
 
 
 
 
 
 
526
  $args = array(
527
  'tokens' => array(
528
  'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ),
@@ -531,7 +553,7 @@ function bp_core_activation_signup_user_notification( $user, $user_email, $key,
531
  'user.id' => $user_id,
532
  ),
533
  );
534
- bp_send_email( 'core-user-registration', array( array( $user_email => $user ) ), $args );
535
 
536
  // Return false to stop the original WPMU function from continuing.
537
  return false;
469
  'user.email' => $user_email,
470
  ),
471
  );
472
+
473
+ $signups = BP_Signup::get(
474
+ array(
475
+ 'user_login' => $user,
476
+ )
477
+ );
478
+
479
+ $salutation = $user;
480
+ if ( $signups ) {
481
+ $signup = $signups['signups'][0];
482
+ if ( isset( $signup->meta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) {
483
+ $salutation = $signup->meta[ 'field_' . bp_xprofile_fullname_field_id() ];
484
+ }
485
+ }
486
+
487
+ bp_send_email( 'core-user-registration-with-blog', array( array( $user_email => $salutation ) ), $args );
488
 
489
  // Return false to stop the original WPMU function from continuing.
490
  return false;
538
  $user_id = $user_object->ID;
539
  }
540
 
541
+ $salutation = $user;
542
+ if ( isset( $meta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) {
543
+ $salutation = $meta[ 'field_' . bp_xprofile_fullname_field_id() ];
544
+ } elseif ( $user_id ) {
545
+ $salutation = bp_core_get_user_displayname( $user_id );
546
+ }
547
+
548
  $args = array(
549
  'tokens' => array(
550
  'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ),
553
  'user.id' => $user_id,
554
  ),
555
  );
556
+ bp_send_email( 'core-user-registration', array( array( $user_email => $salutation ) ), $args );
557
 
558
  // Return false to stop the original WPMU function from continuing.
559
  return false;
bp-core/bp-core-functions.php CHANGED
@@ -3225,7 +3225,7 @@ function bp_send_email( $email_type, $to, $args = array() ) {
3225
  */
3226
  $delivery_class = apply_filters( 'bp_send_email_delivery_class', 'BP_PHPMailer', $email_type, $to, $args );
3227
  if ( ! class_exists( $delivery_class ) ) {
3228
- return new WP_Error( 'missing_class', __CLASS__, $this );
3229
  }
3230
 
3231
  $delivery = new $delivery_class();
@@ -3479,7 +3479,7 @@ function bp_email_get_schema() {
3479
  /* translators: do not remove {} brackets or translate its contents. */
3480
  'post_title' => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ),
3481
  /* translators: do not remove {} brackets or translate its contents. */
3482
- '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' ),
3483
  /* translators: do not remove {} brackets or translate its contents. */
3484
  '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' ),
3485
  ),
@@ -3495,7 +3495,7 @@ function bp_email_get_schema() {
3495
  /* translators: do not remove {} brackets or translate its contents. */
3496
  'post_title' => __( '[{{{site.name}}}] Membership request for group: {{group.name}}', 'buddypress' ),
3497
  /* translators: do not remove {} brackets or translate its contents. */
3498
- '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' ),
3499
  /* translators: do not remove {} brackets or translate its contents. */
3500
  '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' ),
3501
  ),
@@ -3928,3 +3928,23 @@ function bp_is_large_install() {
3928
  */
3929
  return (bool) apply_filters( 'bp_is_large_install', $is_large );
3930
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3225
  */
3226
  $delivery_class = apply_filters( 'bp_send_email_delivery_class', 'BP_PHPMailer', $email_type, $to, $args );
3227
  if ( ! class_exists( $delivery_class ) ) {
3228
+ return new WP_Error( 'missing_class', 'No class found by that name', $delivery_class );
3229
  }
3230
 
3231
  $delivery = new $delivery_class();
3479
  /* translators: do not remove {} brackets or translate its contents. */
3480
  'post_title' => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ),
3481
  /* translators: do not remove {} brackets or translate its contents. */
3482
+ 'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: &quot;{{group.name}}&quot;.\n{{invite.message}}\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' ),
3483
  /* translators: do not remove {} brackets or translate its contents. */
3484
  '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' ),
3485
  ),
3495
  /* translators: do not remove {} brackets or translate its contents. */
3496
  'post_title' => __( '[{{{site.name}}}] Membership request for group: {{group.name}}', 'buddypress' ),
3497
  /* translators: do not remove {} brackets or translate its contents. */
3498
+ 'post_content' => __( "<a href=\"{{{profile.url}}}\">{{requesting-user.name}}</a> wants to join the group &quot;{{group.name}}&quot;.\n {{request.message}}\n 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' ),
3499
  /* translators: do not remove {} brackets or translate its contents. */
3500
  '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' ),
3501
  ),
3928
  */
3929
  return (bool) apply_filters( 'bp_is_large_install', $is_large );
3930
  }
3931
+
3932
+ /**
3933
+ * Returns the upper limit on the "max" item count, for widgets that support it.
3934
+ *
3935
+ * @since 5.0.0
3936
+ *
3937
+ * @param string $widget_class Optional. Class name of the calling widget.
3938
+ * @return int
3939
+ */
3940
+ function bp_get_widget_max_count_limit( $widget_class = '' ) {
3941
+ /**
3942
+ * Filters the upper limit on the "max" item count, for widgets that support it.
3943
+ *
3944
+ * @since 5.0.0
3945
+ *
3946
+ * @param int $count Defaults to 50.
3947
+ * @param string $widget_class Class name of the calling widget.
3948
+ */
3949
+ return apply_filters( 'bp_get_widget_max_count_limit', 50, $widget_class );
3950
+ }
bp-core/bp-core-rest-api.php ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Core REST API functions.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Core
7
+ * @since 5.0.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Is the BP REST plugin is active?
15
+ *
16
+ * @since 5.0.0
17
+ *
18
+ * @return boolean True if the BP REST plugin is active. False otherwise.
19
+ */
20
+ function bp_rest_is_plugin_active() {
21
+ return (bool) has_action( 'bp_rest_api_init', 'bp_rest', 5 );
22
+ }
23
+
24
+ /**
25
+ * Should we use the REST Endpoints of built BuddyPress?
26
+ *
27
+ * If the BP REST plugin is active, it overrides BuddyPress REST enpoints.
28
+ * This allows us to carry on maintaining all the BP REST API endpoints from
29
+ * the BP REST plugin on GitHub.
30
+ *
31
+ * @since 5.0.0
32
+ *
33
+ * @return bool Whether to use the REST Endpoints of built BuddyPress.
34
+ */
35
+ function bp_rest_in_buddypress() {
36
+ $is_src = defined( 'BP_SOURCE_SUBDIRECTORY' ) && BP_SOURCE_SUBDIRECTORY === 'src';
37
+
38
+ return ! $is_src && ! bp_rest_is_plugin_active();
39
+ }
40
+
41
+ /**
42
+ * Check the availability of the BP REST API.
43
+ *
44
+ * @since 5.0.0
45
+ *
46
+ * @return boolean True if the BP REST API is available. False otherwise.
47
+ */
48
+ function bp_rest_api_is_available() {
49
+
50
+ /**
51
+ * Filter here to disable the BP REST API.
52
+ *
53
+ * The BP REST API requires at least WordPress 4.7.0
54
+ *
55
+ * @since 5.0.0
56
+ *
57
+ * @param boolean $value True if the BP REST API is available. False otherwise.
58
+ */
59
+ return apply_filters( 'bp_rest_api_is_available', function_exists( 'create_initial_rest_routes' ) && bp_rest_in_buddypress() ) || bp_rest_is_plugin_active();
60
+ }
61
+
62
+ /**
63
+ * Register the jQuery.ajax wrapper for BP REST API requests.
64
+ *
65
+ * @since 5.0.0
66
+ */
67
+ function bp_rest_api_register_request_script() {
68
+ if ( ! bp_rest_api_is_available() ) {
69
+ return;
70
+ }
71
+
72
+ $dependencies = array( 'jquery' );
73
+
74
+ // The wrapper for WP REST API requests was introduced in WordPress 4.9.0
75
+ if ( wp_script_is( 'wp-api-request', 'registered' ) ) {
76
+ $dependencies = array( 'wp-api-request' );
77
+ }
78
+
79
+ wp_register_script(
80
+ 'bp-api-request',
81
+ sprintf( '%1$sbp-core/js/bp-api-request%2$s.js', buddypress()->plugin_url, bp_core_get_minified_asset_suffix() ),
82
+ $dependencies,
83
+ bp_get_version(),
84
+ true
85
+ );
86
+ wp_localize_script(
87
+ 'bp-api-request',
88
+ 'bpApiSettings',
89
+ array(
90
+ 'root' => esc_url_raw( get_rest_url() ),
91
+ 'nonce' => wp_create_nonce( 'wp_rest' ),
92
+ )
93
+ );
94
+ }
95
+ add_action( 'bp_init', 'bp_rest_api_register_request_script' );
96
+
97
+ /**
98
+ * BuddyPress REST API namespace.
99
+ *
100
+ * @since 5.0.0
101
+ *
102
+ * @return string
103
+ */
104
+ function bp_rest_namespace() {
105
+
106
+ /**
107
+ * Filter API namespace.
108
+ *
109
+ * @since 5.0.0
110
+ *
111
+ * @param string $namespace BuddyPress core namespace.
112
+ */
113
+ return apply_filters( 'bp_rest_namespace', 'buddypress' );
114
+ }
115
+
116
+ /**
117
+ * BuddyPress REST API version.
118
+ *
119
+ * @since 5.0.0
120
+ *
121
+ * @return string
122
+ */
123
+ function bp_rest_version() {
124
+
125
+ /**
126
+ * Filter API version.
127
+ *
128
+ * @since 5.0.0
129
+ *
130
+ * @param string $version BuddyPress core version.
131
+ */
132
+ return apply_filters( 'bp_rest_version', 'v1' );
133
+ }
134
+
135
+ /**
136
+ * Get user URL.
137
+ *
138
+ * @since 5.0.0
139
+ *
140
+ * @param int $user_id User ID.
141
+ * @return string
142
+ */
143
+ function bp_rest_get_user_url( $user_id ) {
144
+ return sprintf(
145
+ '/%s/%s/members/%d',
146
+ bp_rest_namespace(),
147
+ bp_rest_version(),
148
+ $user_id
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Set headers to let the Client Script be aware of the pagination.
154
+ *
155
+ * @since 5.0.0
156
+ *
157
+ * @param WP_REST_Response $response The response data.
158
+ * @param integer $total The total number of found items.
159
+ * @param integer $per_page The number of items per page of results.
160
+ * @return WP_REST_Response $response The response data.
161
+ */
162
+ function bp_rest_response_add_total_headers( WP_REST_Response $response, $total = 0, $per_page = 0 ) {
163
+ if ( ! $total || ! $per_page ) {
164
+ return $response;
165
+ }
166
+
167
+ $total_items = (int) $total;
168
+ $max_pages = ceil( $total_items / (int) $per_page );
169
+
170
+ $response->header( 'X-WP-Total', $total_items );
171
+ $response->header( 'X-WP-TotalPages', (int) $max_pages );
172
+
173
+ return $response;
174
+ }
175
+
176
+ /**
177
+ * Convert the input date to RFC3339 format.
178
+ *
179
+ * @since 5.0.0
180
+ *
181
+ * @param string $date_gmt Date GMT format.
182
+ * @param string|null $date Optional. Date object.
183
+ * @return string|null ISO8601/RFC3339 formatted datetime.
184
+ */
185
+ function bp_rest_prepare_date_response( $date_gmt, $date = null ) {
186
+ if ( isset( $date ) ) {
187
+ return mysql_to_rfc3339( $date );
188
+ }
189
+
190
+ if ( '0000-00-00 00:00:00' === $date_gmt ) {
191
+ return null;
192
+ }
193
+
194
+ return mysql_to_rfc3339( $date_gmt );
195
+ }
196
+
197
+ /**
198
+ * Clean up member_type input.
199
+ *
200
+ * @since 5.0.0
201
+ *
202
+ * @param string $value Comma-separated list of group types.
203
+ * @return array|null
204
+ */
205
+ function bp_rest_sanitize_member_types( $value ) {
206
+ if ( empty( $value ) ) {
207
+ return $value;
208
+ }
209
+
210
+ $types = explode( ',', $value );
211
+ $registered_types = bp_get_member_types();
212
+ $registered_types[] = 'any';
213
+ $valid_types = array_intersect( $types, $registered_types );
214
+
215
+ return ( ! empty( $valid_types ) ) ? $valid_types : null;
216
+ }
217
+
218
+ /**
219
+ * Validate member_type input.
220
+ *
221
+ * @since 5.0.0
222
+ *
223
+ * @param mixed $value Mixed value.
224
+ * @return WP_Error|boolean
225
+ */
226
+ function bp_rest_validate_member_types( $value ) {
227
+ if ( empty( $value ) ) {
228
+ return true;
229
+ }
230
+
231
+ $types = explode( ',', $value );
232
+ $registered_types = bp_get_member_types();
233
+
234
+ // Add the special value.
235
+ $registered_types[] = 'any';
236
+ foreach ( $types as $type ) {
237
+ if ( ! in_array( $type, $registered_types, true ) ) {
238
+ return new WP_Error(
239
+ 'bp_rest_invalid_group_type',
240
+ sprintf(
241
+ /* translators: %1$s and %2$s is replaced with the registered type(s) */
242
+ __( 'The member type you provided, %$1s, is not one of %$2s.', 'buddypress' ),
243
+ $type,
244
+ implode( ', ', $registered_types )
245
+ )
246
+ );
247
+ }
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Clean up group_type input.
253
+ *
254
+ * @since 5.0.0
255
+ *
256
+ * @param string $value Comma-separated list of group types.
257
+ * @return array|null
258
+ */
259
+ function bp_rest_sanitize_group_types( $value ) {
260
+ if ( empty( $value ) ) {
261
+ return null;
262
+ }
263
+
264
+ $types = explode( ',', $value );
265
+ $valid_types = array_intersect( $types, bp_groups_get_group_types() );
266
+
267
+ return empty( $valid_types ) ? null : $valid_types;
268
+ }
269
+
270
+ /**
271
+ * Validate group_type input.
272
+ *
273
+ * @since 5.0.0
274
+ *
275
+ * @param mixed $value Mixed value.
276
+ * @return WP_Error|bool
277
+ */
278
+ function bp_rest_validate_group_types( $value ) {
279
+ if ( empty( $value ) ) {
280
+ return true;
281
+ }
282
+
283
+ $types = explode( ',', $value );
284
+ $registered_types = bp_groups_get_group_types();
285
+ foreach ( $types as $type ) {
286
+ if ( ! in_array( $type, $registered_types, true ) ) {
287
+ return new WP_Error(
288
+ 'bp_rest_invalid_group_type',
289
+ sprintf(
290
+ /* translators: %1$s and %2$s is replaced with the registered types */
291
+ __( 'The group type you provided, %1$s, is not one of %2$s.', 'buddypress' ),
292
+ $type,
293
+ implode( ', ', $registered_types )
294
+ )
295
+ );
296
+ }
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Clean up an array, comma- or space-separated list of strings.
302
+ *
303
+ * @since 5.0.0
304
+ *
305
+ * @param array|string $list List of strings.
306
+ * @return array Sanitized array of strings.
307
+ */
308
+ function bp_rest_sanitize_string_list( $list ) {
309
+ if ( ! is_array( $list ) ) {
310
+ $list = preg_split( '/[\s,]+/', $list );
311
+ }
312
+
313
+ return array_unique( array_map( 'sanitize_text_field', $list ) );
314
+ }
315
+
316
+ /**
317
+ * Get the user object, if the ID is valid.
318
+ *
319
+ * @since 5.0.0
320
+ *
321
+ * @param int $user_id Supplied user ID.
322
+ * @return WP_User|boolean
323
+ */
324
+ function bp_rest_get_user( $user_id ) {
325
+ if ( (int) $user_id <= 0 ) {
326
+ return false;
327
+ }
328
+
329
+ $user = get_userdata( (int) $user_id );
330
+ if ( empty( $user ) || ! $user->exists() ) {
331
+ return false;
332
+ }
333
+
334
+ return $user;
335
+ }
336
+
337
+ /**
338
+ * Registers a new field on an existing BuddyPress object.
339
+ *
340
+ * @since 5.0.0
341
+ *
342
+ * @param string $component_id The name of the *active* component (eg: `activity`, `groups`, `xprofile`).
343
+ * Required.
344
+ * @param string $attribute The attribute name. Required.
345
+ * @param array $args {
346
+ * Optional. An array of arguments used to handle the registered field.
347
+ * @see `register_rest_field()` for a full description.
348
+ * }
349
+ * @param string $object_type The xProfile object type to get. This parameter is only required for
350
+ * the Extended Profiles component. Not used for all other components.
351
+ * Possible values are `data`, `field` or `group`.
352
+ * @return bool True if the field has been registered successfully. False otherwise.
353
+ */
354
+ function bp_rest_register_field( $component_id, $attribute, $args = array(), $object_type = '' ) {
355
+ $registered_fields = false;
356
+
357
+ if ( ! $component_id || ! bp_is_active( $component_id ) || ! $attribute ) {
358
+ return $registered_fields;
359
+ }
360
+
361
+ // Use the `bp_` prefix as we're using a WordPress global used for Post Types.
362
+ $field_name = 'bp_' . $component_id;
363
+
364
+ // Use the meta type as a suffix for the field name.
365
+ if ( 'xprofile' === $component_id ) {
366
+ if ( ! in_array( $object_type, array( 'data', 'field', 'group' ), true ) ) {
367
+ return $registered_fields;
368
+ }
369
+
370
+ $field_name .= '_' . $object_type;
371
+ }
372
+
373
+ $args = bp_parse_args(
374
+ $args,
375
+ array(
376
+ 'get_callback' => null,
377
+ 'update_callback' => null,
378
+ 'schema' => null,
379
+ ),
380
+ 'rest_register_field'
381
+ );
382
+
383
+ // Register the field.
384
+ register_rest_field( $field_name, $attribute, $args );
385
+
386
+ if ( isset( $GLOBALS['wp_rest_additional_fields'][ $field_name ] ) ) {
387
+ $registered_fields = $GLOBALS['wp_rest_additional_fields'][ $field_name ];
388
+ }
389
+
390
+ // Check it has been registered.
391
+ return isset( $registered_fields[ $attribute ] );
392
+ }
bp-core/bp-core-template.php CHANGED
@@ -3030,7 +3030,7 @@ function bp_get_title_parts( $seplocation = 'right' ) {
3030
  $component_subnav_name = '';
3031
 
3032
  if ( ! empty( $bp->members->nav ) ) {
3033
- $primary_nav_item = $bp->members->nav->get_primary( array( 'slug' => $component_id ), false );
3034
  $primary_nav_item = reset( $primary_nav_item );
3035
  }
3036
 
3030
  $component_subnav_name = '';
3031
 
3032
  if ( ! empty( $bp->members->nav ) ) {
3033
+ $primary_nav_item = (array) $bp->members->nav->get_primary( array( 'slug' => $component_id ), false );
3034
  $primary_nav_item = reset( $primary_nav_item );
3035
  }
3036
 
bp-core/bp-core-update.php CHANGED
@@ -211,6 +211,7 @@ function bp_version_updater() {
211
  bp_update_option( 'bp-active-components', $default_components );
212
  bp_core_add_page_mappings( $default_components, 'delete' );
213
  bp_core_install_emails();
 
214
 
215
  // Upgrades.
216
  } else {
@@ -268,6 +269,11 @@ function bp_version_updater() {
268
  if ( $raw_db_version < 11105 ) {
269
  bp_update_to_2_7();
270
  }
 
 
 
 
 
271
  }
272
 
273
  /* All done! *************************************************************/
@@ -542,6 +548,48 @@ function bp_update_to_2_7() {
542
  bp_add_option( '_bp_ignore_deprecated_code', false );
543
  }
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  /**
546
  * Updates the component field for new_members type.
547
  *
211
  bp_update_option( 'bp-active-components', $default_components );
212
  bp_core_add_page_mappings( $default_components, 'delete' );
213
  bp_core_install_emails();
214
+ bp_core_install_invitations();
215
 
216
  // Upgrades.
217
  } else {
269
  if ( $raw_db_version < 11105 ) {
270
  bp_update_to_2_7();
271
  }
272
+
273
+ // Version 5.0.0.
274
+ if ( $raw_db_version < 12385 ) {
275
+ bp_update_to_5_0();
276
+ }
277
  }
278
 
279
  /* All done! *************************************************************/
548
  bp_add_option( '_bp_ignore_deprecated_code', false );
549
  }
550
 
551
+ /**
552
+ * 5.0.0 update routine.
553
+ *
554
+ * - Make sure the custom visibility is disabled for the default profile field.
555
+ * - Create the invitations table.
556
+ * - Migrate requests and invitations to the new table.
557
+ *
558
+ * @since 5.0.0
559
+ */
560
+ function bp_update_to_5_0() {
561
+ /**
562
+ * The xProfile component is active by default on new installs, even if it
563
+ * might be inactive during this update, we need to set the custom visibility
564
+ * for the default field, in case the Administrator decides to reactivate it.
565
+ */
566
+ global $wpdb;
567
+ $bp_prefix = bp_core_get_table_prefix();
568
+ $field_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp_prefix}bp_xprofile_fields WHERE name = %s", addslashes( bp_get_option( 'bp-xprofile-fullname-field-name' ) ) ) );
569
+
570
+ $wpdb->insert(
571
+ $bp_prefix . 'bp_xprofile_meta',
572
+ array(
573
+ 'object_id' => $field_id,
574
+ 'object_type' => 'field',
575
+ 'meta_key' => 'allow_custom_visibility',
576
+ 'meta_value' => 'disabled'
577
+ ),
578
+ array(
579
+ '%d',
580
+ '%s',
581
+ '%s',
582
+ '%s'
583
+ )
584
+ );
585
+
586
+ bp_core_install_invitations();
587
+
588
+ if ( bp_is_active( 'groups' ) ) {
589
+ bp_groups_migrate_invitations();
590
+ }
591
+ }
592
+
593
  /**
594
  * Updates the component field for new_members type.
595
  *
bp-core/classes/class-bp-admin.php CHANGED
@@ -1105,7 +1105,7 @@ class BP_Admin {
1105
 
1106
  foreach ( $styles as $id => $style ) {
1107
  wp_register_style( $id, $style['file'], $style['dependencies'], $version );
1108
- wp_style_add_data( $id, 'rtl', true );
1109
 
1110
  if ( $min ) {
1111
  wp_style_add_data( $id, 'suffix', $min );
1105
 
1106
  foreach ( $styles as $id => $style ) {
1107
  wp_register_style( $id, $style['file'], $style['dependencies'], $version );
1108
+ wp_style_add_data( $id, 'rtl', 'replace' );
1109
 
1110
  if ( $min ) {
1111
  wp_style_add_data( $id, 'suffix', $min );
bp-core/classes/class-bp-component.php CHANGED
@@ -461,6 +461,11 @@ class BP_Component {
461
  // Generate rewrite rules.
462
  add_action( 'bp_generate_rewrite_rules', array( $this, 'generate_rewrite_rules' ), 10 );
463
 
 
 
 
 
 
464
  /**
465
  * Fires at the end of the setup_actions method inside BP_Component.
466
  *
@@ -857,5 +862,22 @@ class BP_Component {
857
  */
858
  do_action( 'bp_' . $this->id . '_generate_rewrite_rules' );
859
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
860
  }
861
  endif; // BP_Component.
461
  // Generate rewrite rules.
462
  add_action( 'bp_generate_rewrite_rules', array( $this, 'generate_rewrite_rules' ), 10 );
463
 
464
+ // Register BP REST Endpoints
465
+ if ( bp_rest_in_buddypress() && bp_rest_api_is_available() ) {
466
+ add_action( 'bp_rest_api_init', array( $this, 'rest_api_init' ), 10 );
467
+ }
468
+
469
  /**
470
  * Fires at the end of the setup_actions method inside BP_Component.
471
  *
862
  */
863
  do_action( 'bp_' . $this->id . '_generate_rewrite_rules' );
864
  }
865
+
866
+ /**
867
+ * Init the BP REST API.
868
+ *
869
+ * @since 5.0.0
870
+ */
871
+ public function rest_api_init() {
872
+
873
+ /**
874
+ * Fires in the rest_api_init method inside BP_Component.
875
+ *
876
+ * This is a dynamic hook that is based on the component string ID.
877
+ *
878
+ * @since 5.0.0
879
+ */
880
+ do_action( 'bp_' . $this->id . '_rest_api_init' );
881
+ }
882
  }
883
  endif; // BP_Component.
bp-core/classes/class-bp-email-address.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Interface for objects that have email address properties (address, name).
4
+ *
5
+ * @since 5.0.0
6
+ */
7
+
8
+ interface BP_Email_Address {
9
+ /**
10
+ * Gets the email address of the user.
11
+ *
12
+ * @since 5.0.0
13
+ */
14
+ public function get_address();
15
+
16
+ /**
17
+ * Gets the display name of the user.
18
+ *
19
+ * @since 5.0.0
20
+ */
21
+ public function get_name();
22
+
23
+ /**
24
+ * Sets the email address of the user.
25
+ *
26
+ * @since 5.0.0
27
+ *
28
+ * @param string $email_address Email address.
29
+ */
30
+ public function set_address( $email_address );
31
+
32
+ /**
33
+ * Sets the name of the user.
34
+ *
35
+ * @since 5.0.0
36
+ *
37
+ * @param string $name Name.
38
+ */
39
+ public function set_name( $name );
40
+ }
bp-core/classes/class-bp-email-participant.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Base class for email "participants" (recipient, sender, Reply-To, etc).
4
+ *
5
+ * @since 5.0.0
6
+ */
7
+
8
+ abstract class BP_Email_Participant implements BP_Email_Address {
9
+ /**
10
+ * Recipient's email address.
11
+ *
12
+ * @since 5.0.0
13
+ *
14
+ * @var string
15
+ */
16
+ protected $address = '';
17
+
18
+ /**
19
+ * Recipient's name.
20
+ *
21
+ * @since 5.0.0
22
+ *
23
+ * @var string
24
+ */
25
+ protected $name = '';
26
+
27
+ /**
28
+ * Gets the email address of the user.
29
+ *
30
+ * @since 5.0.0
31
+ */
32
+ public function get_address() {
33
+ /**
34
+ * Filters an email user's address before it's returned.
35
+ *
36
+ * @since 5.0.0
37
+ *
38
+ * @param string $address User's address.
39
+ * @param BP_Email_User $user Current instance of the email user class.
40
+ */
41
+ return apply_filters( 'bp_email_user_get_address', $this->address, $this );
42
+ }
43
+
44
+ /**
45
+ * Gets the email name of the user.
46
+ *
47
+ * @since 5.0.0
48
+ *
49
+ * @return string
50
+ */
51
+ public function get_name() {
52
+ /**
53
+ * Filters an email user's name before it's returned.
54
+ *
55
+ * @since 5.0.0
56
+ *
57
+ * @param string $name Recipient's name.
58
+ * @param BP_Email_User $user Current instance of the email user class.
59
+ */
60
+ return apply_filters( 'bp_email_recipient_get_name', $this->name, $this );
61
+ }
62
+
63
+ /**
64
+ * Sets the email address of the user.
65
+ *
66
+ * @since 5.0.0
67
+ *
68
+ * @param string $email_address Email address.
69
+ */
70
+ public function set_address( $email_address ) {
71
+ $this->address = $email_address;
72
+ }
73
+
74
+ /**
75
+ * Sets the name of the user.
76
+ *
77
+ * @since 5.0.0
78
+ *
79
+ * @param string $name Name.
80
+ */
81
+ public function set_name( $name ) {
82
+ $this->name = $name;
83
+ }
84
+ }
bp-core/classes/class-bp-email-recipient.php CHANGED
@@ -14,25 +14,7 @@ defined( 'ABSPATH' ) || exit;
14
  *
15
  * @since 2.5.0
16
  */
17
- class BP_Email_Recipient {
18
-
19
- /**
20
- * Recipient's email address.
21
- *
22
- * @since 2.5.0
23
- *
24
- * @var string
25
- */
26
- protected $address = '';
27
-
28
- /**
29
- * Recipient's name.
30
- *
31
- * @since 2.5.0
32
- *
33
- * @var string
34
- */
35
- protected $name = '';
36
 
37
  /**
38
  * Optional. A `WP_User` object relating to this recipient.
@@ -88,7 +70,7 @@ class BP_Email_Recipient {
88
 
89
  // Set address if we have one.
90
  if ( ! empty( $address ) ) {
91
- $this->address = sanitize_email( $address );
92
  }
93
 
94
  // Still no user object; try to query user by email address.
@@ -101,14 +83,14 @@ class BP_Email_Recipient {
101
  // This is escaped with esc_html in bp_core_get_user_displayname()
102
  $wp_name = wp_specialchars_decode( bp_core_get_user_displayname( $this->user_object->ID ), ENT_QUOTES );
103
 
104
- $this->address = $this->user_object->user_email;
105
- $this->name = sanitize_text_field( $wp_name );
106
 
107
  }
108
 
109
  // Custom name override.
110
  if ( $name ) {
111
- $this->name = $name;
112
  }
113
 
114
  /**
@@ -132,16 +114,17 @@ class BP_Email_Recipient {
132
  * @return string
133
  */
134
  public function get_address() {
 
135
 
136
  /**
137
  * Filters the recipient's address before it's returned.
138
  *
139
  * @since 2.5.0
140
  *
141
- * @param string $address Recipient's address.
142
- * @param BP_Email $recipient $this Current instance of the email recipient class.
143
  */
144
- return apply_filters( 'bp_email_recipient_get_address', $this->address, $this );
145
  }
146
 
147
  /**
@@ -152,16 +135,17 @@ class BP_Email_Recipient {
152
  * @return string
153
  */
154
  public function get_name() {
 
155
 
156
  /**
157
  * Filters the recipient's name before it's returned.
158
  *
159
  * @since 2.5.0
160
  *
161
- * @param string $name Recipient's name.
162
- * @param BP_Email $recipient $this Current instance of the email recipient class.
163
  */
164
- return apply_filters( 'bp_email_recipient_get_name', $this->name, $this );
165
  }
166
 
167
  /**
14
  *
15
  * @since 2.5.0
16
  */
17
+ class BP_Email_Recipient extends BP_Email_Participant {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  /**
20
  * Optional. A `WP_User` object relating to this recipient.
70
 
71
  // Set address if we have one.
72
  if ( ! empty( $address ) ) {
73
+ $this->set_address( sanitize_email( $address ) );
74
  }
75
 
76
  // Still no user object; try to query user by email address.
83
  // This is escaped with esc_html in bp_core_get_user_displayname()
84
  $wp_name = wp_specialchars_decode( bp_core_get_user_displayname( $this->user_object->ID ), ENT_QUOTES );
85
 
86
+ $this->set_address( $this->user_object->user_email );
87
+ $this->set_name( $wp_name );
88
 
89
  }
90
 
91
  // Custom name override.
92
  if ( $name ) {
93
+ $this->set_name( $name );
94
  }
95
 
96
  /**
114
  * @return string
115
  */
116
  public function get_address() {
117
+ $address = parent::get_address();
118
 
119
  /**
120
  * Filters the recipient's address before it's returned.
121
  *
122
  * @since 2.5.0
123
  *
124
+ * @param string $address Recipient's address.
125
+ * @param BP_Email_Recipient $recipient Current instance of the email recipient class.
126
  */
127
+ return apply_filters( 'bp_email_recipient_get_address', $address, $this );
128
  }
129
 
130
  /**
135
  * @return string
136
  */
137
  public function get_name() {
138
+ $name = parent::get_name();
139
 
140
  /**
141
  * Filters the recipient's name before it's returned.
142
  *
143
  * @since 2.5.0
144
  *
145
+ * @param string $name Recipient's name.
146
+ * @param BP_Email_Recipient $recipient Current instance of the email recipient class.
147
  */
148
+ return apply_filters( 'bp_email_recipient_get_name', $name, $this );
149
  }
150
 
151
  /**
bp-core/classes/class-bp-email-sender.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Email sender object (From, Reply-To).
4
+ *
5
+ * @since 5.0.0
6
+ */
7
+
8
+ class BP_Email_Sender extends BP_Email_Participant {}
bp-core/classes/class-bp-email.php CHANGED
@@ -65,7 +65,7 @@ class BP_Email {
65
  *
66
  * @since 2.5.0
67
  *
68
- * @var BP_Email_Recipient Sender details.
69
  */
70
  protected $from = null;
71
 
@@ -101,7 +101,7 @@ class BP_Email {
101
  *
102
  * @since 2.5.0
103
  *
104
- * @var BP_Email_Recipient "Reply to" details.
105
  */
106
  protected $reply_to = null;
107
 
@@ -430,7 +430,7 @@ class BP_Email {
430
  *
431
  * @param string $transform Optional. How to transform the return value.
432
  * Accepts 'raw' (default) or 'replace-tokens'.
433
- * @return BP_Email_Recipient "From" recipient.
434
  */
435
  public function get_from( $transform = 'raw' ) {
436
  return $this->get( 'from', $transform );
@@ -738,7 +738,10 @@ class BP_Email {
738
  * @return BP_Email
739
  */
740
  public function set_from( $email_address, $name = '' ) {
741
- $from = new BP_Email_Recipient( $email_address, $name );
 
 
 
742
 
743
  /**
744
  * Filters the new value of the email's "from" property.
@@ -810,7 +813,10 @@ class BP_Email {
810
  * @return BP_Email
811
  */
812
  public function set_reply_to( $email_address, $name = '' ) {
813
- $reply_to = new BP_Email_Recipient( $email_address, $name );
 
 
 
814
 
815
  /**
816
  * Filters the new value of the email's "reply to" property.
65
  *
66
  * @since 2.5.0
67
  *
68
+ * @var BP_Email_Sender Sender details.
69
  */
70
  protected $from = null;
71
 
101
  *
102
  * @since 2.5.0
103
  *
104
+ * @var BP_Email_Sender "Reply to" details.
105
  */
106
  protected $reply_to = null;
107
 
430
  *
431
  * @param string $transform Optional. How to transform the return value.
432
  * Accepts 'raw' (default) or 'replace-tokens'.
433
+ * @return BP_Email_Sender "From" recipient.
434
  */
435
  public function get_from( $transform = 'raw' ) {
436
  return $this->get( 'from', $transform );
738
  * @return BP_Email
739
  */
740
  public function set_from( $email_address, $name = '' ) {
741
+ $from = new BP_Email_Sender();
742
+
743
+ $from->set_address( $email_address );
744
+ $from->set_name( $name );
745
 
746
  /**
747
  * Filters the new value of the email's "from" property.
813
  * @return BP_Email
814
  */
815
  public function set_reply_to( $email_address, $name = '' ) {
816
+ $reply_to = new BP_Email_Sender();
817
+
818
+ $reply_to->set_address( $email_address );
819
+ $reply_to->set_name( $name );
820
 
821
  /**
822
  * Filters the new value of the email's "reply to" property.
bp-core/classes/class-bp-embed.php CHANGED
@@ -138,7 +138,13 @@ class BP_Embed extends WP_Embed {
138
  $attr['discover'] = ( apply_filters( 'bp_embed_oembed_discover', $default_discovery ) && $unfiltered_html );
139
 
140
  // Set up a new WP oEmbed object to check URL with registered oEmbed providers.
141
- require_once( ABSPATH . WPINC . '/class-oembed.php' );
 
 
 
 
 
 
142
  $oembed_obj = _wp_oembed_get_object();
143
 
144
  // If oEmbed discovery is true, skip oEmbed provider check.
138
  $attr['discover'] = ( apply_filters( 'bp_embed_oembed_discover', $default_discovery ) && $unfiltered_html );
139
 
140
  // Set up a new WP oEmbed object to check URL with registered oEmbed providers.
141
+ if ( file_exists( ABSPATH . WPINC . '/class-wp-oembed.php' ) ) {
142
+ require_once( ABSPATH . WPINC . '/class-wp-oembed.php' );
143
+ } else {
144
+ // class-oembed.php is deprecated in WordPress 5.3.0.
145
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
146
+ }
147
+
148
  $oembed_obj = _wp_oembed_get_object();
149
 
150
  // If oEmbed discovery is true, skip oEmbed provider check.
bp-core/classes/class-bp-invitation-manager.php ADDED
@@ -0,0 +1,717 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Core invitations class.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Core
7
+ * @since 5.0.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * BP Invitations class.
15
+ *
16
+ * Extend it to manage your class's invitations.
17
+ * Your extension class, must, at a minimum, provide the
18
+ * run_send_action() and run_acceptance_action() methods.
19
+ *
20
+ * @since 5.0.0
21
+ */
22
+ abstract class BP_Invitation_Manager {
23
+
24
+ /**
25
+ * The name of the related class.
26
+ *
27
+ * @since 5.0.0
28
+ * @access public
29
+ * @var string
30
+ */
31
+ protected $class_name;
32
+
33
+ /**
34
+ * Construct parameters.
35
+ *
36
+ * @since 5.0.0
37
+ *
38
+ * @param array|string $args {
39
+ * }
40
+ */
41
+ public function __construct( $args = array() ) {
42
+ $this->class_name = get_class( $this );
43
+ }
44
+
45
+ /**
46
+ * Get the invitations table name.
47
+ *
48
+ * @since 5.0.0
49
+ * @access public
50
+ * @return string
51
+ */
52
+ public static function get_table_name() {
53
+ return buddypress()->table_prefix . 'bp_invitations';
54
+ }
55
+
56
+ /** Create ********************************************************************/
57
+
58
+ /**
59
+ * Add an invitation to a specific user, from a specific user, related to a
60
+ * specific class.
61
+ *
62
+ * @since 5.0.0
63
+ *
64
+ * @param array $args {
65
+ * Array of arguments describing the invitation. All are optional.
66
+ * @type int $user_id ID of the invited user.
67
+ * @type int $inviter_id ID of the user who created the invitation.
68
+ * @type string $invitee_email Email address of the invited user.
69
+ * @type int $item_id ID associated with the invitation and class.
70
+ * @type int $secondary_item_id Secondary ID associated with the
71
+ * invitation and class.
72
+ * @type string $type Type of record this is: 'invite' or 'request'.
73
+ * @type string $content Extra information provided by the requester
74
+ * or inviter.
75
+ * @type string $date_modified Date the invitation was last modified.
76
+ * @type int $send_invite Should the invitation also be sent, or is it a
77
+ * draft invite?
78
+ * }
79
+ * @return int|bool ID of the newly created invitation on success, false
80
+ * on failure.
81
+ */
82
+ public function add_invitation( $args = array() ) {
83
+
84
+ $r = bp_parse_args( $args, array(
85
+ 'user_id' => 0,
86
+ 'invitee_email' => '',
87
+ 'inviter_id' => 0,
88
+ 'item_id' => 0,
89
+ 'secondary_item_id' => 0,
90
+ 'type' => 'invite',
91
+ 'content' => '',
92
+ 'date_modified' => bp_core_current_time(),
93
+ 'send_invite' => 0,
94
+ 'accepted' => 0
95
+ ), 'add_invitation' );
96
+
97
+ // Invitations must have an invitee and inviter.
98
+ if ( ! ( ( $r['user_id'] || $r['invitee_email'] ) && $r['inviter_id'] ) ) {
99
+ return false;
100
+ }
101
+
102
+ /**
103
+ * Is this user allowed to extend invitations in this situation?
104
+ *
105
+ * @since 5.0.0
106
+ *
107
+ * @param array $r Describes the invitation to be added.
108
+ */
109
+ if ( ! $this->allow_invitation( $r ) ) {
110
+ return false;
111
+ }
112
+
113
+ // Avoid creating duplicate invitations.
114
+ $invite_id = $this->invitation_exists( array(
115
+ 'user_id' => $r['user_id'],
116
+ 'invitee_email' => $r['invitee_email'],
117
+ 'inviter_id' => $r['inviter_id'],
118
+ 'item_id' => $r['item_id'],
119
+ 'secondary_item_id' => $r['secondary_item_id'],
120
+ ) );
121
+
122
+ if ( ! $invite_id ) {
123
+ // Set up the new invitation as a draft.
124
+ $invitation = new BP_Invitation;
125
+ $invitation->user_id = $r['user_id'];
126
+ $invitation->inviter_id = $r['inviter_id'];
127
+ $invitation->invitee_email = $r['invitee_email'];
128
+ $invitation->class = $this->class_name;
129
+ $invitation->item_id = $r['item_id'];
130
+ $invitation->secondary_item_id = $r['secondary_item_id'];
131
+ $invitation->type = $r['type'];
132
+ $invitation->content = $r['content'];
133
+ $invitation->date_modified = $r['date_modified'];
134
+ $invitation->invite_sent = 0;
135
+ $invitation->accepted = 0;
136
+
137
+ $invite_id = $invitation->save();
138
+ }
139
+
140
+ // "Send" the invite if necessary.
141
+ if ( $invite_id && $r['send_invite'] ) {
142
+ $sent = $this->send_invitation_by_id( $invite_id );
143
+ if ( ! $sent ) {
144
+ return false;
145
+ }
146
+ }
147
+
148
+ return $invite_id;
149
+ }
150
+
151
+ /**
152
+ * Send an invitation notification.
153
+ *
154
+ * @since 5.0.0
155
+ * @access public
156
+ *
157
+ * @param int $invitation_id ID of invitation to send.
158
+ *
159
+ * @return int|bool The number of rows updated, or false on error.
160
+ */
161
+ public function send_invitation_by_id( $invitation_id = 0 ) {
162
+ $updated = false;
163
+
164
+ $invitation = new BP_Invitation( $invitation_id );
165
+
166
+ if ( ! $invitation->id ) {
167
+ return false;
168
+ }
169
+
170
+ /**
171
+ * Fires before an invitation is sent.
172
+ *
173
+ * @since 5.0.0
174
+ *
175
+ * @param BP_Invitation object $invitation Invitation about to be sent.
176
+ */
177
+ do_action( 'bp_invitations_send_invitation_by_id_before_send', $invitation );
178
+
179
+ /*
180
+ * Before sending an invitation, check for outstanding requests to the same item.
181
+ * A sent invitation + a request = acceptance.
182
+ */
183
+ $request_args = array(
184
+ 'user_id' => $invitation->user_id,
185
+ 'invitee_email' => $invitation->invitee_email,
186
+ 'item_id' => $invitation->item_id,
187
+ 'secondary_item_id' => $invitation->secondary_item_id,
188
+ );
189
+ $request = $this->request_exists( $request_args );
190
+
191
+ if ( ! empty( $request ) ) {
192
+ // Accept the request.
193
+ return $this->accept_request( $request_args );
194
+ }
195
+
196
+ // Perform the send action.
197
+ $this->run_send_action( $invitation );
198
+
199
+ $updated = BP_Invitation::mark_sent( $invitation->id );
200
+
201
+ return $updated;
202
+ }
203
+
204
+ /**
205
+ * Add a request to an item for a specific user, related to a
206
+ * specific class.
207
+ *
208
+ * @since 5.0.0
209
+ *
210
+ * @param array $args {
211
+ * Array of arguments describing the invitation. All are optional.
212
+ * @type int $user_id ID of the invited user.
213
+ * @type int $inviter_id ID of the user who created the invitation.
214
+ * @type string $class Name of the invitations class.
215
+ * @type int $item_id ID associated with the invitation and class.
216
+ * @type int $secondary_item_id secondary ID associated with the
217
+ * invitation and class.
218
+ * @type string $type @TODO. < missing description.
219
+ * @type string $content Extra information provided by the requester
220
+ * or inviter.
221
+ * @type string $date_modified Date the invitation was last modified.
222
+ * @type int $invite_sent Has the invitation been sent, or is it a
223
+ * draft invite?
224
+ * }
225
+ * @return int|bool ID of the newly created invitation on success, false
226
+ * on failure.
227
+ */
228
+ public function add_request( $args = array() ) {
229
+
230
+ $r = bp_parse_args( $args, array(
231
+ 'user_id' => 0,
232
+ 'inviter_id' => 0,
233
+ 'invitee_email' => '',
234
+ 'item_id' => 0,
235
+ 'secondary_item_id' => 0,
236
+ 'type' => 'request',
237
+ 'content' => '',
238
+ 'date_modified' => bp_core_current_time(),
239
+ 'invite_sent' => 0,
240
+ 'accepted' => 0
241
+ ), 'add_request' );
242
+
243
+ // If there is no invitee, bail.
244
+ if ( ! ( $r['user_id'] || $r['invitee_email'] ) ) {
245
+ return false;
246
+ }
247
+
248
+ /**
249
+ * Is this user allowed to make a request in this situation?
250
+ *
251
+ * @since 5.0.0
252
+ *
253
+ * @param array $r Describes the invitation to be added.
254
+ */
255
+ if ( ! $this->allow_request( $r ) ) {
256
+ return false;
257
+ }
258
+
259
+ /*
260
+ * Avoid creating duplicate requests.
261
+ */
262
+ $base_args = array(
263
+ 'user_id' => $r['user_id'],
264
+ 'invitee_email' => $r['invitee_email'],
265
+ 'item_id' => $r['item_id'],
266
+ 'secondary_item_id' => $r['secondary_item_id'],
267
+ );
268
+ if ( $this->request_exists( $base_args ) ) {
269
+ return false;
270
+ }
271
+
272
+ /*
273
+ * Check for outstanding invitations to the same item.
274
+ * A request + a sent invite = acceptance.
275
+ */
276
+ $invite_args = array_merge( $base_args, array( 'invite_sent' => 'sent' ) );
277
+ $invite = $this->invitation_exists( $invite_args );
278
+
279
+ if ( $invite ) {
280
+ // Accept the invite.
281
+ return $this->accept_invitation( $base_args );
282
+ } else {
283
+ // Set up the new request.
284
+ $request = new BP_Invitation;
285
+ $request->user_id = $r['user_id'];
286
+ $request->inviter_id = $r['inviter_id'];
287
+ $request->invitee_email = $r['invitee_email'];
288
+ $request->class = $this->class_name;
289
+ $request->item_id = $r['item_id'];
290
+ $request->secondary_item_id = $r['secondary_item_id'];
291
+ $request->type = $r['type'];
292
+ $request->content = $r['content'];
293
+ $request->date_modified = $r['date_modified'];
294
+ $request->invite_sent = $r['invite_sent'];
295
+ $request->accepted = $r['accepted'];
296
+
297
+ // Save the new invitation.
298
+ return $request->save();
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Send a request notification.
304
+ *
305
+ * @since 5.0.0
306
+ * @access public
307
+ *
308
+ * @param int $request_id ID of request to send.
309
+ *
310
+ * @return int|bool The number of rows updated, or false on error.
311
+ */
312
+ public function send_request_notification_by_id( $request_id = 0 ) {
313
+ $updated = false;
314
+
315
+ $request = new BP_Invitation( $request_id );
316
+
317
+ if ( ! $request->id ) {
318
+ return false;
319
+ }
320
+
321
+ // Different uses may need different actions on sending. Plugins can hook in here to perform their own tasks.
322
+ do_action( 'bp_invitations_send_request_notification_by_id_before_send', $request_id, $request );
323
+
324
+ /*
325
+ * Before sending notifications, check for outstanding invitations to the same item.
326
+ * A sent invitation + a request = acceptance.
327
+ */
328
+ $args = array(
329
+ 'user_id' => $request->user_id,
330
+ 'invitee_email' => $request->invitee_email,
331
+ 'item_id' => $request->item_id,
332
+ 'secondary_item_id' => $request->secondary_item_id,
333
+ 'invite_sent' => 'sent'
334
+ );
335
+ $invites = $this->invitation_exists( $args );
336
+
337
+ if ( ! empty( $invites ) ) {
338
+ // Accept the request.
339
+ return $this->accept_invitation( $args );
340
+ }
341
+
342
+ // Perform the send action.
343
+ $this->run_send_action( $request );
344
+
345
+ $updated = BP_Invitation::mark_sent( $request->id );
346
+
347
+ return $updated;
348
+ }
349
+
350
+ /** Retrieve ******************************************************************/
351
+
352
+ /**
353
+ * Get a specific invitation by its ID.
354
+ *
355
+ * @since 5.0.0
356
+ *
357
+ * @param int $id ID of the invitation.
358
+ * @return BP_Invitation object
359
+ */
360
+ public function get_by_id( $id = 0 ) {
361
+ return new BP_Invitation( $id );
362
+ }
363
+
364
+ /**
365
+ * Get invitations, based on provided filter parameters.
366
+ *
367
+ * @since 5.0.0
368
+ *
369
+ * @see BP_Invitation::get() for a description of accepted parameters.
370
+ *
371
+ * @return array Located invitations.
372
+ */
373
+ public function get_invitations( $args = array() ) {
374
+ // Default to returning invitations, not requests.
375
+ if ( empty( $args['type'] ) ) {
376
+ $args['type'] = 'invite';
377
+ }
378
+ // Use the class_name property value.
379
+ $args['class'] = $this->class_name;
380
+
381
+ return BP_Invitation::get( $args );
382
+ }
383
+
384
+ /**
385
+ * Get requests, based on provided filter parameters.
386
+ *
387
+ * @since 5.0.0
388
+ *
389
+ * @see BP_Invitation::get() for a description of accepted parameters.
390
+ *
391
+ * @return array Located invitations.
392
+ */
393
+ public function get_requests( $args = array() ) {
394
+ // Set request-specific parameters.
395
+ $args['type'] = 'request';
396
+ $args['inviter_id'] = false;
397
+ $args['invite_sent'] = 'all';
398
+
399
+ // Use the class_name property value.
400
+ $args['class'] = $this->class_name;
401
+
402
+ return BP_Invitation::get( $args );
403
+ }
404
+
405
+ /**
406
+ * Check whether an invitation exists matching the passed arguments.
407
+ *
408
+ * @since 5.0.0
409
+ *
410
+ * @see BP_Invitation::get() for a description of accepted parameters.
411
+ *
412
+ * @return int|bool ID of first found invitation or false if none found.
413
+ */
414
+ public function invitation_exists( $args = array() ) {
415
+ $is_invited = false;
416
+
417
+ $args['fields'] = 'ids';
418
+ $invites = $this->get_invitations( $args );
419
+ if ( $invites ) {
420
+ $is_invited = current( $invites );
421
+ }
422
+ return $is_invited;
423
+ }
424
+
425
+ /**
426
+ * Check whether a request exists matching the passed arguments.
427
+ *
428
+ * @since 5.0.0
429
+ *
430
+ * @see BP_Invitation::get() for a description of accepted parameters.
431
+ *
432
+ * @return int|bool ID of existing request or false if none found.
433
+ */
434
+ public function request_exists( $args = array() ) {
435
+ $has_request = false;
436
+
437
+ $args['fields'] = 'ids';
438
+ $requests = $this->get_requests( $args );
439
+ if ( $requests ) {
440
+ $has_request = current( $requests );
441
+ }
442
+ return $has_request;
443
+ }
444
+
445
+ /** Update ********************************************************************/
446
+
447
+ /**
448
+ * Accept invitation, based on provided filter parameters.
449
+ *
450
+ * @since 5.0.0
451
+ *
452
+ * @see BP_Invitation::get() for a description of
453
+ * accepted update/where arguments.
454
+ *
455
+ * @param array $update_args Associative array of fields to update,
456
+ * and the values to update them to. Of the format
457
+ * array( 'user_id' => 4 )
458
+ *
459
+ * @return int|bool Number of rows updated on success, false on failure.
460
+ */
461
+ public function accept_invitation( $args = array() ) {
462
+
463
+ /*
464
+ * Some basic info is required to accept an invitation,
465
+ * because we'll need to mark all similar invitations and requests.
466
+ * The following, except the optional 'secondary_item_id', are required.
467
+ */
468
+ $r = bp_parse_args( $args, array(
469
+ 'user_id' => 0,
470
+ 'invitee_email' => '',
471
+ 'item_id' => null,
472
+ 'secondary_item_id' => null,
473
+ 'invite_sent' => 'sent',
474
+ ), 'accept_invitation' );
475
+ $r['class'] = $this->class_name;
476
+
477
+ if ( ! ( ( $r['user_id'] || $r['invitee_email'] ) && $r['class'] && $r['item_id'] ) ) {
478
+ return false;
479
+ }
480
+
481
+ if ( ! $this->invitation_exists( $r ) ) {
482
+ return false;
483
+ }
484
+
485
+ $success = $this->run_acceptance_action( 'invite', $r );
486
+ if ( $success ) {
487
+ // Mark invitations & requests to this item for this user.
488
+ $this->mark_accepted( $r );
489
+
490
+ // Allow plugins an opportunity to act on the change.
491
+ do_action( 'bp_invitations_accepted_invite', $r );
492
+ }
493
+ return $success;
494
+ }
495
+
496
+ /**
497
+ * Accept invitation, based on provided filter parameters.
498
+ *
499
+ * @since 5.0.0
500
+ *
501
+ * @see BP_Invitation::get() for a description of
502
+ * accepted update/where arguments.
503
+ *
504
+ * @param array $update_args Associative array of fields to update,
505
+ * and the values to update them to. Of the format
506
+ * array( 'user_id' => 4 )
507
+ *
508
+ * @return bool Number of rows updated on success, false on failure.
509
+ */
510
+ public function accept_request( $args = array() ) {
511
+ /*
512
+ * Some basic info is required to accept an invitation,
513
+ * because we'll need to accept all similar invitations and requests.
514
+ * The following, except the optional 'secondary_item_id', are required.
515
+ */
516
+ $r = bp_parse_args( $args, array(
517
+ 'user_id' => 0,
518
+ 'item_id' => null,
519
+ 'secondary_item_id' => null,
520
+ ), 'accept_request' );
521
+ $r['class'] = $this->class_name;
522
+
523
+ if ( ! ( $r['user_id'] && $r['class'] && $r['item_id'] ) ) {
524
+ return false;
525
+ }
526
+
527
+ if ( ! $this->request_exists( $r ) ) {
528
+ return false;
529
+ }
530
+
531
+ $success = $this->run_acceptance_action( 'request', $r );
532
+ if ( $success ) {
533
+ // Update/Delete all related invitations & requests to this item for this user.
534
+ $this->mark_accepted( $r );
535
+
536
+ // Allow plugins an opportunity to act on the change.
537
+ do_action( 'bp_invitations_accepted_request', $r );
538
+ }
539
+ return $success;
540
+ }
541
+
542
+ /**
543
+ * Update invitation, based on provided filter parameters.
544
+ *
545
+ * @since 5.0.0
546
+ *
547
+ * @see BP_Invitation::get() for a description of
548
+ * accepted update/where arguments.
549
+ *
550
+ * @param array $update_args Associative array of fields to update,
551
+ * and the values to update them to. Of the format
552
+ * array( 'user_id' => 4 )
553
+ * @param array $where_args Associative array of columns/values, to
554
+ * determine which invitations should be updated. Formatted as
555
+ * array( 'item_id' => 7 )
556
+ * @return int|bool Number of rows updated on success, false on failure.
557
+ */
558
+ public function update_invitation( $update_args = array(), $where_args = array() ) {
559
+ $update_args['class'] = $this->class_name;
560
+ return BP_Invitation::update( $update_args, $where_args );
561
+ }
562
+
563
+ /**
564
+ * This is where custom actions are added (in child classes)
565
+ * to run when an invitation or request needs to be "sent."
566
+ *
567
+ * @since 5.0.0
568
+ *
569
+ * @param BP_Invitation $invitation The invitation to send.
570
+ * @return bool True on success, false on failure.
571
+ */
572
+ abstract public function run_send_action( BP_Invitation $invitation );
573
+
574
+ /**
575
+ * Mark invitations as sent that are found by user_id, inviter_id,
576
+ * invitee_email, class name, optional item id,
577
+ * optional secondary item id.
578
+ *
579
+ * @since 5.0.0
580
+ *
581
+ * @param array $args {
582
+ * Associative array of arguments. All arguments but $page and
583
+ * $per_page can be treated as filter values for get_where_sql()
584
+ * and get_query_clauses(). All items are optional.
585
+ * @type int|array $user_id ID of user being queried. Can be an
586
+ * array of user IDs.
587
+ * @type int|array $inviter_id ID of user who created the
588
+ * invitation. Can be an array of user IDs.
589
+ * Special cases
590
+ * @type string|array $invitee_email Email address of invited users
591
+ * being queried. Can be an array of addresses.
592
+ * @type string|array $class Name of the class to
593
+ * filter by. Can be an array of class names.
594
+ * @type int|array $item_id ID of associated item. Can be an array
595
+ * of multiple item IDs.
596
+ * @type int|array $secondary_item_id ID of secondary associated
597
+ * item. Can be an array of multiple IDs.
598
+ * }
599
+ */
600
+ public function mark_sent( $args ) {
601
+ $args['class'] = $this->class_name;
602
+ return BP_Invitation::mark_sent_by_data( $args );
603
+ }
604
+
605
+ /**
606
+ * This is where custom actions are added (in child classes)
607
+ * to run when an invitation or request is accepted.
608
+ *
609
+ * @since 5.0.0
610
+ *
611
+ * @param int $id The ID of the invitation to mark as sent.
612
+ * @return bool True on success, false on failure.
613
+ */
614
+ abstract public function run_acceptance_action( $type = 'invite', $r );
615
+
616
+ /**
617
+ * Mark invitation as accepted by invitation ID.
618
+ *
619
+ * @since 5.0.0
620
+ *
621
+ * @param int $id The ID of the invitation to mark as sent.
622
+ * @return bool True on success, false on failure.
623
+ */
624
+ public function mark_accepted_by_id( $id ) {
625
+ return BP_Invitation::mark_accepted( $id );
626
+ }
627
+
628
+ /**
629
+ * Mark invitations as sent that are found by user_id, inviter_id,
630
+ * invitee_email, class name, item id, and
631
+ * optional secondary item id.
632
+ *
633
+ * @since 5.0.0
634
+ *
635
+ * @see BP_Invitation::mark_accepted_by_data()
636
+ * for a description of arguments.
637
+ */
638
+ public function mark_accepted( $args ) {
639
+ $args['class'] = $this->class_name;
640
+ return BP_Invitation::mark_accepted_by_data( $args );
641
+ }
642
+
643
+ /** Delete ********************************************************************/
644
+
645
+ /**
646
+ * Delete an invitation or invitations by query data.
647
+ *
648
+ * @since 5.0.0
649
+ *
650
+ * @see BP_Invitation::delete for a description of arguments.
651
+ * @return int|bool Number of rows deleted on success, false on failure.
652
+ */
653
+ public function delete( $args ) {
654
+ if ( empty( $args['type'] ) ) {
655
+ $args['type'] = 'invite';
656
+ }
657
+ $args['class'] = $this->class_name;
658
+ return BP_Invitation::delete( $args );
659
+ }
660
+
661
+ /**
662
+ * Delete a request or requests by query data.
663
+ *
664
+ * @since 5.0.0
665
+ *
666
+ * @see BP_Invitation::delete for a description of arguments.
667
+ *
668
+ * @return int|bool Number of rows deleted on success, false on failure.
669
+ */
670
+ public function delete_requests( $args ) {
671
+ $args['type'] = 'request';
672
+ return $this->delete( $args );
673
+ }
674
+
675
+ /**
676
+ * Delete all invitations by class.
677
+ *
678
+ * Used when clearing out invitations for an entire class. Possibly used
679
+ * when deactivating a component related to a class that created invitations.
680
+ *
681
+ * @since 5.0.0
682
+ *
683
+ * @return int|bool Number of rows deleted on success, false on failure.
684
+ */
685
+ public function delete_all() {
686
+ return BP_Invitation::delete( array(
687
+ 'class' => $this->class_name,
688
+ ) );
689
+ }
690
+
691
+ /**
692
+ * This is where custom actions are added (in child classes)
693
+ * to determine whether an invitation should be allowed.
694
+ *
695
+ * @since 5.0.0
696
+ *
697
+ * @param array $args The parameters describing the invitation.
698
+ * @return bool True if allowed, false to end process.
699
+ */
700
+ public function allow_invitation( $args ) {
701
+ return true;
702
+ }
703
+
704
+ /**
705
+ * This is where custom actions are added (in child classes)
706
+ * to determine whether a request should be allowed.
707
+ *
708
+ * @since 5.0.0
709
+ *
710
+ * @param array $args The parameters describing the request.
711
+ * @return bool True if allowed, false to end process.
712
+ */
713
+ public function allow_request( $args ) {
714
+ return true;
715
+ }
716
+
717
+ }
bp-core/classes/class-bp-invitation.php ADDED
@@ -0,0 +1,1056 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Invitation Class
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Invitations
7
+ *
8
+ * @since 5.0.0
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ /**
15
+ * BuddyPress Invitations.
16
+ *
17
+ * Use this class to create, access, edit, or delete BuddyPress Invitations.
18
+ *
19
+ * @since 5.0.0
20
+ */
21
+ class BP_Invitation {
22
+
23
+ /**
24
+ * The invitation ID.
25
+ *
26
+ * @since 5.0.0
27
+ * @access public
28
+ * @var int
29
+ */
30
+ public $id;
31
+
32
+ /**
33
+ * The ID of the invited user.
34
+ *
35
+ * @since 5.0.0
36
+ * @access public
37
+ * @var int
38
+ */
39
+ public $user_id;
40
+
41
+ /**
42
+ * The ID of the user who created the invitation.
43
+ *
44
+ * @since 5.0.0
45
+ * @access public
46
+ * @var int
47
+ */
48
+ public $inviter_id;
49
+
50
+ /**
51
+ * The email address of the invited user.
52
+ * Used when extending an invitation to someone who does not belong to the site.
53
+ *
54
+ * @since 5.0.0
55
+ * @access public
56
+ * @var string
57
+ */
58
+ public $invitee_email;
59
+
60
+ /**
61
+ * The name of the related class.
62
+ *
63
+ * @since 5.0.0
64
+ * @access public
65
+ * @var string
66
+ */
67
+ public $class;
68
+
69
+ /**
70
+ * The ID associated with the invitation and component.
71
+ * Example: the group ID if a group invitation
72
+ *
73
+ * @since 5.0.0
74
+ * @access public
75
+ * @var int
76
+ */
77
+ public $item_id;
78
+
79
+ /**
80
+ * The secondary ID associated with the invitation and component.
81
+ * Example: a taxonomy term ID if invited to a site's category-specific RSS feed
82
+ *
83
+ * @since 5.0.0
84
+ * @access public
85
+ * @var int
86
+ */
87
+ public $secondary_item_id = null;
88
+
89
+ /**
90
+ * Invite or request.
91
+ *
92
+ * @since 5.0.0
93
+ * @access public
94
+ * @var string
95
+ */
96
+ public $type;
97
+
98
+ /**
99
+ * Extra information provided by the requester or inviter.
100
+ *
101
+ * @since 5.0.0
102
+ * @access public
103
+ * @var string
104
+ */
105
+ public $content;
106
+
107
+ /**
108
+ * The date the invitation was last modified.
109
+ *
110
+ * @since 5.0.0
111
+ * @access public
112
+ * @var string
113
+ */
114
+ public $date_modified;
115
+
116
+ /**
117
+ * Has the invitation been sent, or is it a draft invite?
118
+ *
119
+ * @since 5.0.0
120
+ * @access public
121
+ * @var bool
122
+ */
123
+ public $invite_sent;
124
+
125
+ /**
126
+ * Has the invitation been accepted by the invitee?
127
+ *
128
+ * @since 5.0.0
129
+ * @access public
130
+ * @var bool
131
+ */
132
+ public $accepted;
133
+
134
+ /** Public Methods ****************************************************/
135
+
136
+ /**
137
+ * Constructor method.
138
+ *
139
+ * @since 5.0.0
140
+ *
141
+ * @param int $id Optional. Provide an ID to access an existing
142
+ * invitation item.
143
+ */
144
+ public function __construct( $id = 0 ) {
145
+ if ( ! empty( $id ) ) {
146
+ $this->id = (int) $id;
147
+ $this->populate();
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Update or insert invitation details into the database.
153
+ *
154
+ * @since 5.0.0
155
+ *
156
+ * @global wpdb $wpdb WordPress database object.
157
+ *
158
+ * @return bool True on success, false on failure.
159
+ */
160
+ public function save() {
161
+
162
+ // Return value
163
+ $retval = false;
164
+
165
+ // Default data and format
166
+ $data = array(
167
+ 'user_id' => $this->user_id,
168
+ 'inviter_id' => $this->inviter_id,
169
+ 'invitee_email' => $this->invitee_email,
170
+ 'class' => sanitize_key( $this->class ),
171
+ 'item_id' => $this->item_id,
172
+ 'secondary_item_id' => $this->secondary_item_id,
173
+ 'type' => $this->type,
174
+ 'content' => wp_kses( wp_unslash( $this->content ), array() ),
175
+ 'date_modified' => $this->date_modified,
176
+ 'invite_sent' => $this->invite_sent,
177
+ 'accepted' => $this->accepted,
178
+ );
179
+ $data_format = array( '%d', '%d', '%s', '%s', '%d', '%d', '%s', '%s', '%s', '%d', '%d' );
180
+
181
+ /**
182
+ * Fires before an invitation is saved.
183
+ *
184
+ * @since 5.0.0
185
+ *
186
+ * @param BP_Invitation object $this Characteristics of the invitation to be saved.
187
+ */
188
+ do_action_ref_array( 'bp_invitation_before_save', array( &$this ) );
189
+
190
+ // Update
191
+ if ( ! empty( $this->id ) ) {
192
+ $result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) );
193
+ // Insert
194
+ } else {
195
+ $result = self::_insert( $data, $data_format );
196
+ }
197
+
198
+ // Set the invitation ID if successful
199
+ if ( ! empty( $result ) && ! is_wp_error( $result ) ) {
200
+ global $wpdb;
201
+
202
+ $this->id = $wpdb->insert_id;
203
+ $retval = $wpdb->insert_id;
204
+ }
205
+
206
+ wp_cache_delete( $this->id, 'bp_invitations' );
207
+
208
+ /**
209
+ * Fires after an invitation is saved.
210
+ *
211
+ * @since 5.0.0
212
+ *
213
+ * @param BP_Invitation object $this Characteristics of the invitation just saved.
214
+ */
215
+ do_action_ref_array( 'bp_invitation_after_save', array( &$this ) );
216
+
217
+ // Return the result
218
+ return $retval;
219
+ }
220
+
221
+ /**
222
+ * Fetch data for an existing invitation from the database.
223
+ *
224
+ * @since 5.0.0
225
+ *
226
+ * @global BuddyPress $bp The one true BuddyPress instance.
227
+ * @global wpdb $wpdb WordPress database object.
228
+ */
229
+ public function populate() {
230
+ global $wpdb;
231
+ $invites_table_name = BP_Invitation_Manager::get_table_name();
232
+
233
+ // Check cache for invitation data.
234
+ $invitation = wp_cache_get( $this->id, 'bp_invitations' );
235
+
236
+ // Cache missed, so query the DB.
237
+ if ( false === $invitation ) {
238
+ $invitation = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$invites_table_name} WHERE id = %d", $this->id ) );
239
+ wp_cache_set( $this->id, $invitation,'bp_invitations' );
240
+ }
241
+
242
+ // No invitation found so set the ID and bail.
243
+ if ( empty( $invitation ) || is_wp_error( $invitation ) ) {
244
+ $this->id = 0;
245
+ return;
246
+ }
247
+
248
+ $this->user_id = (int) $invitation->user_id;
249
+ $this->inviter_id = (int) $invitation->inviter_id;
250
+ $this->invitee_email = $invitation->invitee_email;
251
+ $this->class = sanitize_key( $invitation->class );
252
+ $this->item_id = (int) $invitation->item_id;
253
+ $this->secondary_item_id = (int) $invitation->secondary_item_id;
254
+ $this->type = $invitation->type;
255
+ $this->content = $invitation->content;
256
+ $this->date_modified = $invitation->date_modified;
257
+ $this->invite_sent = (int) $invitation->invite_sent;
258
+ $this->accepted = (int) $invitation->accepted;
259
+
260
+ }
261
+
262
+ /** Protected Static Methods ******************************************/
263
+
264
+ /**
265
+ * Create an invitation entry.
266
+ *
267
+ * @since 5.0.0
268
+ *
269
+ * @param array $data {
270
+ * Array of invitation data, passed to {@link wpdb::insert()}.
271
+ * @type int $user_id ID of the invited user.
272
+ * @type int $inviter_id ID of the user who created the invitation.
273
+ * @type string $invitee_email Email address of the invited user.
274
+ * @type string $class Name of the related class.
275
+ * @type int $item_id ID associated with the invitation and component.
276
+ * @type int $secondary_item_id Secondary ID associated with the invitation and
277
+ * component.
278
+ * @type string $content Extra information provided by the requester
279
+ * or inviter.
280
+ * @type string $date_modified Date the invitation was last modified.
281
+ * @type int $invite_sent Has the invitation been sent, or is it a draft
282
+ * invite?
283
+ * }
284
+ * @param array $data_format See {@link wpdb::insert()}.
285
+ * @return int|false The number of rows inserted, or false on error.
286
+ */
287
+ protected static function _insert( $data = array(), $data_format = array() ) {
288
+ global $wpdb;
289
+ return $wpdb->insert( BP_Invitation_Manager::get_table_name(), $data, $data_format );
290
+ }
291
+
292
+ /**
293
+ * Update invitations.
294
+ *
295
+ * @since 5.0.0
296
+ *
297
+ * @see wpdb::update() for further description of paramater formats.
298
+ *
299
+ * @param array $data Array of invitation data to update, passed to
300
+ * {@link wpdb::update()}. Accepts any property of a
301
+ * BP_Invitation object.
302
+ * @param array $where The WHERE params as passed to wpdb::update().
303
+ * Typically consists of array( 'ID' => $id ) to specify the ID
304
+ * of the item being updated. See {@link wpdb::update()}.
305
+ * @param array $data_format See {@link wpdb::insert()}.
306
+ * @param array $where_format See {@link wpdb::insert()}.
307
+ * @return int|false The number of rows updated, or false on error.
308
+ */
309
+ protected static function _update( $data = array(), $where = array(), $data_format = array(), $where_format = array() ) {
310
+ global $wpdb;
311
+ return $wpdb->update( BP_Invitation_Manager::get_table_name(), $data, $where, $data_format, $where_format );
312
+ }
313
+
314
+ /**
315
+ * Delete invitations.
316
+ *
317
+ * @since 5.0.0
318
+ *
319
+ * @see wpdb::update() for further description of paramater formats.
320
+ *
321
+ * @param array $where Array of WHERE clauses to filter by, passed to
322
+ * {@link wpdb::delete()}. Accepts any property of a
323
+ * BP_Invitation object.
324
+ * @param array $where_format See {@link wpdb::insert()}.
325
+ * @return int|false The number of rows updated, or false on error.
326
+ */
327
+ protected static function _delete( $where = array(), $where_format = array() ) {
328
+ global $wpdb;
329
+ return $wpdb->delete( BP_Invitation_Manager::get_table_name(), $where, $where_format );
330
+ }
331
+
332
+ /**
333
+ * Assemble the WHERE clause of a get() SQL statement.
334
+ *
335
+ * Used by BP_Invitation::get() to create its WHERE
336
+ * clause.
337
+ *
338
+ * @since 5.0.0
339
+ *
340
+ * @param array $args See {@link BP_Invitation::get()} for more details.
341
+ * @return string WHERE clause.
342
+ */
343
+ protected static function get_where_sql( $args = array() ) {
344
+ global $wpdb;
345
+
346
+ $where_conditions = array();
347
+ $where = '';
348
+
349
+ // id
350
+ if ( false !== $args['id'] ) {
351
+ $id_in = implode( ',', wp_parse_id_list( $args['id'] ) );
352
+ $where_conditions['id'] = "id IN ({$id_in})";
353
+ }
354
+
355
+ // user_id
356
+ if ( ! empty( $args['user_id'] ) ) {
357
+ $user_id_in = implode( ',', wp_parse_id_list( $args['user_id'] ) );
358
+ $where_conditions['user_id'] = "user_id IN ({$user_id_in})";
359
+ }
360
+
361
+ // inviter_id. 0 can be meaningful, in the case of requests.
362
+ if ( ! empty( $args['inviter_id'] ) || 0 === $args['inviter_id'] ) {
363
+ $inviter_id_in = implode( ',', wp_parse_id_list( $args['inviter_id'] ) );
364
+ $where_conditions['inviter_id'] = "inviter_id IN ({$inviter_id_in})";
365
+ }
366
+
367
+ // invitee_email
368
+ if ( ! empty( $args['invitee_email'] ) ) {
369
+ if ( ! is_array( $args['invitee_email'] ) ) {
370
+ $invitee_emails = explode( ',', $args['invitee_email'] );
371
+ } else {
372
+ $invitee_emails = $args['invitee_email'];
373
+ }
374
+
375
+ $email_clean = array();
376
+ foreach ( $invitee_emails as $email ) {
377
+ $email_clean[] = $wpdb->prepare( '%s', $email );
378
+ }
379
+
380
+ $invitee_email_in = implode( ',', $email_clean );
381
+ $where_conditions['invitee_email'] = "invitee_email IN ({$invitee_email_in})";
382
+ }
383
+
384
+ // class
385
+ if ( ! empty( $args['class'] ) ) {
386
+ if ( ! is_array( $args['class'] ) ) {
387
+ $class_names = explode( ',', $args['class'] );
388
+ } else {
389
+ $class_names = $args['class'];
390
+ }
391
+
392
+ $cn_clean = array();
393
+ foreach ( $class_names as $cn ) {
394
+ $cn_clean[] = $wpdb->prepare( '%s', sanitize_key( $cn ) );
395
+ }
396
+
397
+ $cn_in = implode( ',', $cn_clean );
398
+ $where_conditions['class'] = "class IN ({$cn_in})";
399
+ }
400
+
401
+ // item_id
402
+ if ( ! empty( $args['item_id'] ) ) {
403
+ $item_id_in = implode( ',', wp_parse_id_list( $args['item_id'] ) );
404
+ $where_conditions['item_id'] = "item_id IN ({$item_id_in})";
405
+ }
406
+
407
+ // secondary_item_id
408
+ if ( ! empty( $args['secondary_item_id'] ) ) {
409
+ $secondary_item_id_in = implode( ',', wp_parse_id_list( $args['secondary_item_id'] ) );
410
+ $where_conditions['secondary_item_id'] = "secondary_item_id IN ({$secondary_item_id_in})";
411
+ }
412
+
413
+ // type
414
+ if ( ! empty( $args['type'] ) && 'all' !== $args['type'] ) {
415
+ if ( 'invite' == $args['type'] || 'request' == $args['type'] ) {
416
+ $type_clean = $wpdb->prepare( '%s', $args['type'] );
417
+ $where_conditions['type'] = "type = {$type_clean}";
418
+ }
419
+ }
420
+
421
+ /**
422
+ * invite_sent
423
+ * Only create a where statement if something less than "all" has been
424
+ * specifically requested.
425
+ */
426
+ if ( ! empty( $args['invite_sent'] ) && 'all' !== $args['invite_sent'] ) {
427
+ if ( $args['invite_sent'] == 'draft' ) {
428
+ $where_conditions['invite_sent'] = "invite_sent = 0";
429
+ } else if ( $args['invite_sent'] == 'sent' ) {
430
+ $where_conditions['invite_sent'] = "invite_sent = 1";
431
+ }
432
+ }
433
+
434
+ // accepted
435
+ if ( ! empty( $args['accepted'] ) && 'all' !== $args['accepted'] ) {
436
+ if ( $args['accepted'] == 'pending' ) {
437
+ $where_conditions['accepted'] = "accepted = 0";
438
+ } else if ( $args['accepted'] == 'accepted' ) {
439
+ $where_conditions['accepted'] = "accepted = 1";
440
+ }
441
+ }
442
+
443
+ // search_terms
444
+ if ( ! empty( $args['search_terms'] ) ) {
445
+ $search_terms_like = '%' . bp_esc_like( $args['search_terms'] ) . '%';
446
+ $where_conditions['search_terms'] = $wpdb->prepare( "( class LIKE %s )", $search_terms_like, $search_terms_like );
447
+ }
448
+
449
+ // Custom WHERE
450
+ if ( ! empty( $where_conditions ) ) {
451
+ $where = 'WHERE ' . implode( ' AND ', $where_conditions );
452
+ }
453
+
454
+ return $where;
455
+ }
456
+
457
+ /**
458
+ * Assemble the ORDER BY clause of a get() SQL statement.
459
+ *
460
+ * Used by BP_Invitation::get() to create its ORDER BY
461
+ * clause.
462
+ *
463
+ * @since 5.0.0
464
+ *
465
+ * @param array $args See {@link BP_Invitation::get()} for more details.
466
+ * @return string ORDER BY clause.
467
+ */
468
+ protected static function get_order_by_sql( $args = array() ) {
469
+
470
+ // Setup local variable
471
+ $conditions = array();
472
+ $retval = '';
473
+
474
+ // Order by
475
+ if ( ! empty( $args['order_by'] ) ) {
476
+ $order_by = implode( ', ', (array) $args['order_by'] );
477
+ $conditions['order_by'] = "{$order_by}";
478
+ }
479
+
480
+ // Sort order direction
481
+ if ( ! empty( $args['sort_order'] ) ) {
482
+ $sort_order = bp_esc_sql_order( $args['sort_order'] );
483
+ $conditions['sort_order'] = "{$sort_order}";
484
+ }
485
+
486
+ // Custom ORDER BY
487
+ if ( ! empty( $conditions ) ) {
488
+ $retval = 'ORDER BY ' . implode( ' ', $conditions );
489
+ }
490
+
491
+ return $retval;
492
+ }
493
+
494
+ /**
495
+ * Assemble the LIMIT clause of a get() SQL statement.
496
+ *
497
+ * Used by BP_Invitation::get() to create its LIMIT clause.
498
+ *
499
+ * @since 5.0.0
500
+ *
501
+ * @param array $args See {@link BP_Invitation::get()} for more details.
502
+ * @return string LIMIT clause.
503
+ */
504
+ protected static function get_paged_sql( $args = array() ) {
505
+ global $wpdb;
506
+
507
+ // Setup local variable
508
+ $retval = '';
509
+
510
+ // Custom LIMIT
511
+ if ( ! empty( $args['page'] ) && ! empty( $args['per_page'] ) ) {
512
+ $page = absint( $args['page'] );
513
+ $per_page = absint( $args['per_page'] );
514
+ $offset = $per_page * ( $page - 1 );
515
+ $retval = $wpdb->prepare( "LIMIT %d, %d", $offset, $per_page );
516
+ }
517
+
518
+ return $retval;
519
+ }
520
+
521
+ /**
522
+ * Assemble query clauses, based on arguments, to pass to $wpdb methods.
523
+ *
524
+ * The insert(), update(), and delete() methods of {@link wpdb} expect
525
+ * arguments of the following forms:
526
+ *
527
+ * - associative arrays whose key/value pairs are column => value, to
528
+ * be used in WHERE, SET, or VALUES clauses
529
+ * - arrays of "formats", which tell $wpdb->prepare() which type of
530
+ * value to expect when sanitizing (eg, array( '%s', '%d' ))
531
+ *
532
+ * This utility method can be used to assemble both kinds of params,
533
+ * out of a single set of associative array arguments, such as:
534
+ *
535
+ * $args = array(
536
+ * 'user_id' => 4,
537
+ * 'class' => 'BP_Groups_Invitation_Manager',
538
+ * );
539
+ *
540
+ * This will be converted to:
541
+ *
542
+ * array(
543
+ * 'data' => array(
544
+ * 'user_id' => 4,
545
+ * 'class' => 'BP_Groups_Invitation_Manager',
546
+ * ),
547
+ * 'format' => array(
548
+ * '%d',
549
+ * '%s',
550
+ * ),
551
+ * )
552
+ *
553
+ * which can easily be passed as arguments to the $wpdb methods.
554
+ *
555
+ * @since 5.0.0
556
+ *
557
+ * @param array $args Associative array of filter arguments.
558
+ * See {@BP_Invitation::get()} for a breakdown.
559
+ * @return array Associative array of 'data' and 'format' args.
560
+ */
561
+ protected static function get_query_clauses( $args = array() ) {
562
+ $where_clauses = array(
563
+ 'data' => array(),
564
+ 'format' => array(),
565
+ );
566
+
567
+ // id
568
+ if ( ! empty( $args['id'] ) ) {
569
+ $where_clauses['data']['id'] = absint( $args['id'] );
570
+ $where_clauses['format'][] = '%d';
571
+ }
572
+
573
+ // user_id
574
+ if ( ! empty( $args['user_id'] ) ) {
575
+ $where_clauses['data']['user_id'] = absint( $args['user_id'] );
576
+ $where_clauses['format'][] = '%d';
577
+ }
578
+
579
+ // inviter_id
580
+ if ( ! empty( $args['inviter_id'] ) ) {
581
+ $where_clauses['data']['inviter_id'] = absint( $args['inviter_id'] );
582
+ $where_clauses['format'][] = '%d';
583
+ }
584
+
585
+ // invitee_email
586
+ if ( ! empty( $args['invitee_email'] ) ) {
587
+ $where_clauses['data']['invitee_email'] = $args['invitee_email'];
588
+ $where_clauses['format'][] = '%s';
589
+ }
590
+
591
+ // class
592
+ if ( ! empty( $args['class'] ) ) {
593
+ $where_clauses['data']['class'] = $args['class'];
594
+ $where_clauses['format'][] = '%s';
595
+ }
596
+
597
+ // item_id
598
+ if ( ! empty( $args['item_id'] ) ) {
599
+ $where_clauses['data']['item_id'] = absint( $args['item_id'] );
600
+ $where_clauses['format'][] = '%d';
601
+ }
602
+
603
+ // secondary_item_id
604
+ if ( ! empty( $args['secondary_item_id'] ) ) {
605
+ $where_clauses['data']['secondary_item_id'] = absint( $args['secondary_item_id'] );
606
+ $where_clauses['format'][] = '%d';
607
+ }
608
+
609
+ // type
610
+ if ( ! empty( $args['type'] ) && 'all' !== $args['type'] ) {
611
+ if ( 'invite' == $args['type'] || 'request' == $args['type'] ) {
612
+ $where_clauses['data']['type'] = $args['type'];
613
+ $where_clauses['format'][] = '%s';
614
+ }
615
+ }
616
+
617
+ /**
618
+ * invite_sent
619
+ * Only create a where statement if something less than "all" has been
620
+ * specifically requested.
621
+ */
622
+ if ( isset( $args['invite_sent'] ) && 'all' !== $args['invite_sent'] ) {
623
+ if ( $args['invite_sent'] == 'draft' ) {
624
+ $where_clauses['data']['invite_sent'] = 0;
625
+ $where_clauses['format'][] = '%d';
626
+ } else if ( $args['invite_sent'] == 'sent' ) {
627
+ $where_clauses['data']['invite_sent'] = 1;
628
+ $where_clauses['format'][] = '%d';
629
+ }
630
+ }
631
+
632
+ // accepted
633
+ if ( ! empty( $args['accepted'] ) && 'all' !== $args['accepted'] ) {
634
+ if ( $args['accepted'] == 'pending' ) {
635
+ $where_clauses['data']['accepted'] = 0;
636
+ $where_clauses['format'][] = '%d';
637
+ } else if ( $args['accepted'] == 'accepted' ) {
638
+ $where_clauses['data']['accepted'] = 1;
639
+ $where_clauses['format'][] = '%d';
640
+ }
641
+ }
642
+
643
+ return $where_clauses;
644
+ }
645
+
646
+ /** Public Static Methods *********************************************/
647
+
648
+ /**
649
+ * Get invitations, based on provided filter parameters.
650
+ *
651
+ * @since 5.0.0
652
+ *
653
+ * @param array $args {
654
+ * Associative array of arguments. All arguments but $page and
655
+ * $per_page can be treated as filter values for get_where_sql()
656
+ * and get_query_clauses(). All items are optional.
657
+ * @type int|array $id ID of invitation being updated.
658
+ * Can be an array of IDs.
659
+ * @type int|array $user_id ID of user being queried. Can be an
660
+ * Can be an array of IDs.
661
+ * @type int|array $inviter_id ID of user who created the
662
+ * invitation. Can be an array of IDs.
663
+ * @type string|array $invitee_email Email address of invited users
664
+ * being queried. Can be an array of
665
+ * addresses.
666
+ * @type string|array $class Name of the class to filter by.
667
+ * Can be an array of class names.
668
+ * @type int|array $item_id ID of associated item.
669
+ * Can be an array of multiple item IDs.
670
+ * @type int|array $secondary_item_id ID of secondary associated item.
671
+ * Can be an array of multiple IDs.
672
+ * @type string|array $type Type of item. An "invite" is sent
673
+ * from one user to another.
674
+ * A "request" is submitted by a
675
+ * user and no inviter is required.
676
+ * 'all' returns all. Default: 'all'.
677
+ * @type string $invite_sent Limit to draft, sent or all
678
+ * 'draft' limits to unsent invites,
679
+ * 'sent' returns only sent invites,
680
+ * 'all' returns all. Default: 'all'.
681
+ * @type bool $accepted Limit to accepted or
682
+ * not-yet-accepted invitations.
683
+ * 'accepted' returns accepted invites,
684
+ * 'pending' returns pending invites,
685
+ * 'all' returns all. Default: 'pending'
686
+ * @type string $search_terms Term to match against class field.
687
+ * @type string $order_by Database column to order by.
688
+ * @type string $sort_order Either 'ASC' or 'DESC'.
689
+ * @type string $order_by Field to order results by.
690
+ * @type string $sort_order ASC or DESC.
691
+ * @type int $page Number of the current page of results.
692
+ * Default: false (no pagination,
693
+ * all items).
694
+ * @type int $per_page Number of items to show per page.
695
+ * Default: false (no pagination,
696
+ * all items).
697
+ * @type string $fields Which fields to return. Specify 'item_ids' to fetch a list of Item_IDs.
698
+ * Specify 'ids' to fetch a list of Invitation IDs.
699
+ * Default: 'all' (return BP_Invitation objects).
700
+ * }
701
+ *
702
+ * @return array BP_Invitation objects | IDs of found invit.
703
+ */
704
+ public static function get( $args = array() ) {
705
+ global $wpdb;
706
+ $invites_table_name = BP_Invitation_Manager::get_table_name();
707
+
708
+ // Parse the arguments
709
+ $r = bp_parse_args( $args, array(
710
+ 'id' => false,
711
+ 'user_id' => false,
712
+ 'inviter_id' => false,
713
+ 'invitee_email' => false,
714
+ 'class' => false,
715
+ 'item_id' => false,
716
+ 'secondary_item_id' => false,
717
+ 'type' => 'all',
718
+ 'invite_sent' => 'all',
719
+ 'accepted' => 'pending',
720
+ 'search_terms' => '',
721
+ 'order_by' => false,
722
+ 'sort_order' => false,
723
+ 'page' => false,
724
+ 'per_page' => false,
725
+ 'fields' => 'all',
726
+ ), 'bp_invitations_invitation_get' );
727
+
728
+ $sql = array(
729
+ 'select' => "SELECT",
730
+ 'fields' => '',
731
+ 'from' => "FROM {$invites_table_name} i",
732
+ 'where' => '',
733
+ 'orderby' => '',
734
+ 'pagination' => '',
735
+ );
736
+
737
+ if ( 'item_ids' === $r['fields'] ) {
738
+ $sql['fields'] = "DISTINCT i.item_id";
739
+ } else if ( 'user_ids' === $r['fields'] ) {
740
+ $sql['fields'] = "DISTINCT i.user_id";
741
+ } else if ( 'inviter_ids' === $r['fields'] ) {
742
+ $sql['fields'] = "DISTINCT i.inviter_id";
743
+ } else {
744
+ $sql['fields'] = 'DISTINCT i.id';
745
+ }
746
+
747
+ // WHERE
748
+ $sql['where'] = self::get_where_sql( array(
749
+ 'id' => $r['id'],
750
+ 'user_id' => $r['user_id'],
751
+ 'inviter_id' => $r['inviter_id'],
752
+ 'invitee_email' => $r['invitee_email'],
753
+ 'class' => $r['class'],
754
+ 'item_id' => $r['item_id'],
755
+ 'secondary_item_id' => $r['secondary_item_id'],
756
+ 'type' => $r['type'],
757
+ 'invite_sent' => $r['invite_sent'],
758
+ 'accepted' => $r['accepted'],
759
+ 'search_terms' => $r['search_terms'],
760
+ ) );
761
+
762
+ // ORDER BY
763
+ $sql['orderby'] = self::get_order_by_sql( array(
764
+ 'order_by' => $r['order_by'],
765
+ 'sort_order' => $r['sort_order']
766
+ ) );
767
+
768
+ // LIMIT %d, %d
769
+ $sql['pagination'] = self::get_paged_sql( array(
770
+ 'page' => $r['page'],
771
+ 'per_page' => $r['per_page'],
772
+ ) );
773
+
774
+ $paged_invites_sql = "{$sql['select']} {$sql['fields']} {$sql['from']} {$sql['where']} {$sql['orderby']} {$sql['pagination']}";
775
+
776
+ /**
777
+ * Filters the pagination SQL statement.
778
+ *
779
+ * @since 5.0.0
780
+ *
781
+ * @param string $value Concatenated SQL statement.
782
+ * @param array $sql Array of SQL parts before concatenation.
783
+ * @param array $r Array of parsed arguments for the get method.
784
+ */
785
+ $paged_invites_sql = apply_filters( 'bp_invitations_get_paged_invitations_sql', $paged_invites_sql, $sql, $r );
786
+
787
+ $cached = bp_core_get_incremented_cache( $paged_invites_sql, 'bp_invitations' );
788
+ if ( false === $cached ) {
789
+ $paged_invite_ids = $wpdb->get_col( $paged_invites_sql );
790
+ bp_core_set_incremented_cache( $paged_invites_sql, 'bp_invitations', $paged_invite_ids );
791
+ } else {
792
+ $paged_invite_ids = $cached;
793
+ }
794
+
795
+ // Special return format cases.
796
+ if ( in_array( $r['fields'], array( 'ids', 'item_ids', 'user_ids', 'inviter_ids' ), true ) ) {
797
+ // We only want the field that was found.
798
+ return array_map( 'intval', $paged_invite_ids );
799
+ }
800
+
801
+ $uncached_ids = bp_get_non_cached_ids( $paged_invite_ids, 'bp_invitations' );
802
+ if ( $uncached_ids ) {
803
+ $ids_sql = implode( ',', array_map( 'intval', $uncached_ids ) );
804
+ $data_objects = $wpdb->get_results( "SELECT i.* FROM {$invites_table_name} i WHERE i.id IN ({$ids_sql})" );
805
+ foreach ( $data_objects as $data_object ) {
806
+ wp_cache_set( $data_object->id, $data_object, 'bp_invitations' );
807
+ }
808
+ }
809
+
810
+ $paged_invites = array();
811
+ foreach ( $paged_invite_ids as $paged_invite_id ) {
812
+ $paged_invites[] = new BP_Invitation( $paged_invite_id );
813
+ }
814
+
815
+ return $paged_invites;
816
+ }
817
+
818
+ /**
819
+ * Get a count of total invitations matching a set of arguments.
820
+ *
821
+ * @since 5.0.0
822
+ *
823
+ * @see BP_Invitation::get() for a description of
824
+ * arguments.
825
+ *
826
+ * @param array $args See {@link BP_Invitation::get()}.
827
+ * @return int Count of located items.
828
+ */
829
+ public static function get_total_count( $args ) {
830
+ global $wpdb;
831
+ $invites_table_name = BP_Invitation_Manager::get_table_name();
832
+
833
+ // Build the query
834
+ $select_sql = "SELECT COUNT(*)";
835
+ $from_sql = "FROM {$invites_table_name}";
836
+ $where_sql = self::get_where_sql( $args );
837
+ $sql = "{$select_sql} {$from_sql} {$where_sql}";
838
+
839
+ // Return the queried results
840
+ return $wpdb->get_var( $sql );
841
+ }
842
+
843
+ /**
844
+ * Update invitations.
845
+ *
846
+ * @since 5.0.0
847
+ *
848
+ * @see BP_Invitation::get() for a description of
849
+ * accepted update/where arguments.
850
+ *
851
+ * @param array $update_args Associative array of fields to update,
852
+ * and the values to update them to. Of the format
853
+ * array( 'user_id' => 4, 'class' => 'BP_Groups_Invitation_Manager', ).
854
+ * @param array $where_args Associative array of columns/values, to
855
+ * determine which rows should be updated. Of the format
856
+ * array( 'item_id' => 7, 'class' => 'BP_Groups_Invitation_Manager', ).
857
+ * @return int|bool Number of rows updated on success, false on failure.
858
+ */
859
+ public static function update( $update_args = array(), $where_args = array() ) {
860
+ $update = self::get_query_clauses( $update_args );
861
+ $where = self::get_query_clauses( $where_args );
862
+
863
+ /**
864
+ * Fires before an invitation is updated.
865
+ *
866
+ * @since 5.0.0
867
+ *
868
+ * @param array $where_args Associative array of columns/values describing
869
+ * invitations about to be deleted.
870
+ * @param array $update_args Array of new values.
871
+ */
872
+ do_action( 'bp_invitation_before_update', $where_args, $update_args );
873
+
874
+ $retval = self::_update( $update['data'], $where['data'], $update['format'], $where['format'] );
875
+
876
+ // Clear matching items from the cache.
877
+ $cache_args = $where_args;
878
+ $cache_args['fields'] = 'ids';
879
+ $maybe_cached_ids = self::get( $cache_args );
880
+ foreach ( $maybe_cached_ids as $invite_id ) {
881
+ wp_cache_delete( $invite_id, 'bp_invitations' );
882
+ }
883
+
884
+ /**
885
+ * Fires after an invitation is updated.
886
+ *
887
+ * @since 5.0.0
888
+ *
889
+ * @param array $where_args Associative array of columns/values describing
890
+ * invitations about to be deleted.
891
+ * @param array $update_args Array of new values.
892
+ */
893
+ do_action( 'bp_invitation_after_update', $where_args, $update_args );
894
+
895
+ return $retval;
896
+ }
897
+
898
+ /**
899
+ * Delete invitations.
900
+ *
901
+ * @since 5.0.0
902
+ *
903
+ * @see BP_Invitation::get() for a description of
904
+ * accepted where arguments.
905
+ *
906
+ * @param array $args Associative array of columns/values, to determine
907
+ * which rows should be deleted. Of the format
908
+ * array( 'item_id' => 7, 'class' => 'BP_Groups_Invitation_Manager', ).
909
+ * @return int|bool Number of rows deleted on success, false on failure.
910
+ */
911
+ public static function delete( $args = array() ) {
912
+ $where = self::get_query_clauses( $args );
913
+
914
+ /**
915
+ * Fires before an invitation is deleted.
916
+ *
917
+ * @since 5.0.0
918
+ *
919
+ * @param array $args Characteristics of the invitations to be deleted.
920
+ */
921
+ do_action( 'bp_invitation_before_delete', $args );
922
+
923
+ // Clear matching items from the cache.
924
+ $cache_args = $args;
925
+ $cache_args['fields'] = 'ids';
926
+ $maybe_cached_ids = self::get( $cache_args );
927
+ foreach ( $maybe_cached_ids as $invite_id ) {
928
+ wp_cache_delete( $invite_id, 'bp_invitations' );
929
+ }
930
+
931
+ $retval = self::_delete( $where['data'], $where['format'] );
932
+
933
+ /**
934
+ * Fires after an invitation is deleted.
935
+ *
936
+ * @since 5.0.0
937
+ *
938
+ * @param array $args Characteristics of the invitations just deleted.
939
+ */
940
+ do_action( 'bp_invitation_after_delete', $args );
941
+
942
+ return $retval;
943
+ }
944
+
945
+ /** Convenience methods ***********************************************/
946
+
947
+ /**
948
+ * Delete a single invitation by ID.
949
+ *
950
+ * @since 5.0.0
951
+ *
952
+ * @see BP_Invitation::delete() for explanation of
953
+ * return value.
954
+ *
955
+ * @param int $id ID of the invitation item to be deleted.
956
+ * @return bool True on success, false on failure.
957
+ */
958
+ public static function delete_by_id( $id ) {
959
+ return self::delete( array(
960
+ 'id' => $id,
961
+ ) );
962
+ }
963
+
964
+ /** Sent status ***********************************************************/
965
+
966
+ /**
967
+ * Mark specific invitations as sent by invitation ID.
968
+ *
969
+ * @since 5.0.0
970
+ *
971
+ * @param int $id The ID of the invitation to mark as sent.
972
+ */
973
+ public static function mark_sent( $id = 0 ) {
974
+
975
+ if ( ! $id ) {
976
+ return false;
977
+ }
978
+
979
+ // Values to be updated
980
+ $update_args = array(
981
+ 'invite_sent' => 'sent',
982
+ );
983
+
984
+ // WHERE clauses
985
+ $where_args = array(
986
+ 'id' => $id,
987
+ );
988
+
989
+ return self::update( $update_args, $where_args );
990
+ }
991
+
992
+ /**
993
+ * Mark invitations as sent that are found by user_id, inviter_id, item id, and optional
994
+ * secondary item id, and class name.
995
+ *
996
+ * @since 5.0.0
997
+ *
998
+ * @param array $args See BP_Invitation::update().
999
+ */
1000
+ public static function mark_sent_by_data( $args ) {
1001
+
1002
+ // Values to be updated
1003
+ $update_args = array(
1004
+ 'invite_sent' => 'sent',
1005
+ );
1006
+
1007
+ return self::update( $update_args, $args );
1008
+ }
1009
+
1010
+ /** Accepted status ***********************************************************/
1011
+
1012
+ /**
1013
+ * Mark specific invitations as accepted by invitation ID.
1014
+ *
1015
+ * @since 5.0.0
1016
+ *
1017
+ * @param int $id The ID of the invitation to mark as sent.
1018
+ */
1019
+ public static function mark_accepted( $id = 0 ) {
1020
+
1021
+ if ( ! $id ) {
1022
+ return false;
1023
+ }
1024
+
1025
+ // Values to be updated
1026
+ $update_args = array(
1027
+ 'accepted' => 'accepted',
1028
+ );
1029
+
1030
+ // WHERE clauses
1031
+ $where_args = array(
1032
+ 'id' => $id,
1033
+ );
1034
+
1035
+ return self::update( $update_args, $where_args );
1036
+ }
1037
+
1038
+ /**
1039
+ * Mark invitations as accepted that are found by user_id, inviter_id,
1040
+ * item id, and optional secondary item id, and class name.
1041
+ *
1042
+ * @since 5.0.0
1043
+ *
1044
+ * @param array $args See BP_Invitation::update().
1045
+ */
1046
+ public static function mark_accepted_by_data( $args ) {
1047
+
1048
+ // Values to be updated
1049
+ $update_args = array(
1050
+ 'accepted' => 'accepted',
1051
+ );
1052
+
1053
+ return self::update( $update_args, $args );
1054
+ }
1055
+
1056
+ }
bp-core/classes/class-bp-rest-attachments-group-avatar-endpoint.php ADDED
@@ -0,0 +1,499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Attachments_Group_Avatar_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Group Avatar endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Attachments_Group_Avatar_Endpoint extends WP_REST_Controller {
17
+
18
+ use BP_REST_Attachments;
19
+
20
+ /**
21
+ * Reuse some parts of the BP_REST_Groups_Endpoint class.
22
+ *
23
+ * @since 5.0.0
24
+ *
25
+ * @var BP_REST_Groups_Endpoint
26
+ */
27
+ protected $groups_endpoint;
28
+
29
+ /**
30
+ * BP_Attachment_Avatar Instance.
31
+ *
32
+ * @since 5.0.0
33
+ *
34
+ * @var BP_Attachment_Avatar
35
+ */
36
+ protected $avatar_instance;
37
+
38
+ /**
39
+ * Hold the group object.
40
+ *
41
+ * @since 5.0.0
42
+ *
43
+ * @var BP_Groups_Group
44
+ */
45
+ protected $group;
46
+
47
+ /**
48
+ * Group object type.
49
+ *
50
+ * @since 5.0.0
51
+ *
52
+ * @var string
53
+ */
54
+ protected $object = 'group';
55
+
56
+ /**
57
+ * Constructor.
58
+ *
59
+ * @since 5.0.0
60
+ */
61
+ public function __construct() {
62
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
63
+ $this->rest_base = buddypress()->groups->id;
64
+ $this->groups_endpoint = new BP_REST_Groups_Endpoint();
65
+ $this->avatar_instance = new BP_Attachment_Avatar();
66
+ }
67
+
68
+ /**
69
+ * Register the component routes.
70
+ *
71
+ * @since 5.0.0
72
+ */
73
+ public function register_routes() {
74
+ register_rest_route(
75
+ $this->namespace,
76
+ '/' . $this->rest_base . '/(?P<group_id>[\d]+)/avatar',
77
+ array(
78
+ 'args' => array(
79
+ 'group_id' => array(
80
+ 'description' => __( 'A unique numeric ID for the Group.', 'buddypress' ),
81
+ 'type' => 'integer',
82
+ ),
83
+ ),
84
+ array(
85
+ 'methods' => WP_REST_Server::READABLE,
86
+ 'callback' => array( $this, 'get_item' ),
87
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
88
+ 'args' => $this->get_item_collection_params(),
89
+ ),
90
+ array(
91
+ 'methods' => WP_REST_Server::CREATABLE,
92
+ 'callback' => array( $this, 'create_item' ),
93
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
94
+ ),
95
+ array(
96
+ 'methods' => WP_REST_Server::DELETABLE,
97
+ 'callback' => array( $this, 'delete_item' ),
98
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
99
+ ),
100
+ 'schema' => array( $this, 'get_item_schema' ),
101
+ )
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Fetch an existing group avatar.
107
+ *
108
+ * @since 5.0.0
109
+ *
110
+ * @param WP_REST_Request $request Full details about the request.
111
+ * @return WP_REST_Response|WP_Error
112
+ */
113
+ public function get_item( $request ) {
114
+ $args = array();
115
+
116
+ foreach ( array( 'full', 'thumb' ) as $type ) {
117
+ $args[ $type ] = bp_core_fetch_avatar(
118
+ array(
119
+ 'object' => $this->object,
120
+ 'type' => $type,
121
+ 'item_id' => (int) $this->group->id,
122
+ 'html' => (bool) $request['html'],
123
+ 'alt' => $request['alt'],
124
+ )
125
+ );
126
+ }
127
+
128
+ // Get the avatar object.
129
+ $avatar = $this->get_avatar_object( $args );
130
+
131
+ if ( ! $avatar->full && ! $avatar->thumb ) {
132
+ return new WP_Error(
133
+ 'bp_rest_attachments_group_avatar_no_image',
134
+ __( 'Sorry, there was a problem fetching this group avatar.', 'buddypress' ),
135
+ array(
136
+ 'status' => 500,
137
+ )
138
+ );
139
+ }
140
+
141
+ $retval = array(
142
+ $this->prepare_response_for_collection(
143
+ $this->prepare_item_for_response( $avatar, $request )
144
+ ),
145
+ );
146
+
147
+ $response = rest_ensure_response( $retval );
148
+
149
+ /**
150
+ * Fires after a group avatar is fetched via the REST API.
151
+ *
152
+ * @since 5.0.0
153
+ *
154
+ * @param string $avatar The group avatar.
155
+ * @param WP_REST_Response $response The response data.
156
+ * @param WP_REST_Request $request The request sent to the API.
157
+ */
158
+ do_action( 'bp_rest_attachments_group_avatar_get_item', $avatar, $response, $request );
159
+
160
+ return $response;
161
+ }
162
+
163
+ /**
164
+ * Checks if a given request has access to get a group avatar.
165
+ *
166
+ * @since 5.0.0
167
+ *
168
+ * @param WP_REST_Request $request Full details about the request.
169
+ * @return bool|WP_Error
170
+ */
171
+ public function get_item_permissions_check( $request ) {
172
+ $retval = true;
173
+ $this->group = $this->groups_endpoint->get_group_object( $request );
174
+
175
+ if ( ! $this->group ) {
176
+ $retval = new WP_Error(
177
+ 'bp_rest_group_invalid_id',
178
+ __( 'Invalid group id.', 'buddypress' ),
179
+ array(
180
+ 'status' => 404,
181
+ )
182
+ );
183
+ }
184
+
185
+ /**
186
+ * Filter the group avatar `get_item` permissions check.
187
+ *
188
+ * @since 5.0.0
189
+ *
190
+ * @param bool|WP_Error $retval Returned value.
191
+ * @param WP_REST_Request $request The request sent to the API.
192
+ */
193
+ return apply_filters( 'bp_rest_attachments_group_avatar_get_item_permissions_check', $retval, $request );
194
+ }
195
+
196
+ /**
197
+ * Upload a group avatar.
198
+ *
199
+ * @since 5.0.0
200
+ *
201
+ * @param WP_REST_Request $request Full details about the request.
202
+ * @return WP_REST_Response|WP_Error
203
+ */
204
+ public function create_item( $request ) {
205
+ $request->set_param( 'context', 'edit' );
206
+
207
+ // Get the image file from $_FILES.
208
+ $files = $request->get_file_params();
209
+
210
+ if ( empty( $files ) ) {
211
+ return new WP_Error(
212
+ 'bp_rest_attachments_group_avatar_no_image_file',
213
+ __( 'Sorry, you need an image file to upload.', 'buddypress' ),
214
+ array(
215
+ 'status' => 500,
216
+ )
217
+ );
218
+ }
219
+
220
+ // Upload the avatar.
221
+ $avatar = $this->upload_avatar_from_file( $files );
222
+ if ( is_wp_error( $avatar ) ) {
223
+ return $avatar;
224
+ }
225
+
226
+ $retval = array(
227
+ $this->prepare_response_for_collection(
228
+ $this->prepare_item_for_response( $avatar, $request )
229
+ ),
230
+ );
231
+
232
+ $response = rest_ensure_response( $retval );
233
+
234
+ /**
235
+ * Fires after a group avatar is uploaded via the REST API.
236
+ *
237
+ * @since 5.0.0
238
+ *
239
+ * @param stdClass $avatar The group avatar object.
240
+ * @param WP_REST_Response $response The response data.
241
+ * @param WP_REST_Request $request The request sent to the API.
242
+ */
243
+ do_action( 'bp_rest_attachments_group_avatar_create_item', $avatar, $response, $request );
244
+
245
+ return $response;
246
+ }
247
+
248
+ /**
249
+ * Checks if a given request has access to upload a group avatar.
250
+ *
251
+ * @since 5.0.0
252
+ *
253
+ * @param WP_REST_Request $request Full details about the request.
254
+ * @return bool|WP_Error
255
+ */
256
+ public function create_item_permissions_check( $request ) {
257
+ $retval = $this->get_item_permissions_check( $request );
258
+
259
+ if ( true === $retval && ( bp_disable_group_avatar_uploads() || ! buddypress()->avatar->show_avatars ) ) {
260
+ $retval = new WP_Error(
261
+ 'bp_rest_attachments_group_avatar_disabled',
262
+ __( 'Sorry, group avatar upload is disabled.', 'buddypress' ),
263
+ array(
264
+ 'status' => 500,
265
+ )
266
+ );
267
+ }
268
+
269
+ if ( true === $retval
270
+ && ! groups_is_user_admin( bp_loggedin_user_id(), $this->group->id )
271
+ && ! current_user_can( 'bp_moderate' )
272
+ ) {
273
+ $retval = new WP_Error(
274
+ 'bp_rest_authorization_required',
275
+ __( 'Sorry, you are unauthorized to perform this action.', 'buddypress' ),
276
+ array(
277
+ 'status' => rest_authorization_required_code(),
278
+ )
279
+ );
280
+ }
281
+
282
+ /**
283
+ * Filter the group avatar `create_item` permissions check.
284
+ *
285
+ * @since 5.0.0
286
+ *
287
+ * @param bool|WP_Error $retval Returned value.
288
+ * @param WP_REST_Request $request The request sent to the API.
289
+ */
290
+ return apply_filters( 'bp_rest_attachments_group_avatar_create_item_permissions_check', $retval, $request );
291
+ }
292
+
293
+ /**
294
+ * Delete an existing group avatar.
295
+ *
296
+ * @since 5.0.0
297
+ *
298
+ * @param WP_REST_Request $request Full details about the request.
299
+ * @return WP_REST_Response|WP_Error
300
+ */
301
+ public function delete_item( $request ) {
302
+ $request->set_param( 'context', 'edit' );
303
+ $group_id = (int) $this->group->id;
304
+
305
+ if ( ! bp_get_group_has_avatar( $group_id ) ) {
306
+ return new WP_Error(
307
+ 'bp_rest_attachments_group_avatar_no_uploaded_avatar',
308
+ __( 'Sorry, there are no uploaded avatars for this group on this site.', 'buddypress' ),
309
+ array(
310
+ 'status' => 404,
311
+ )
312
+ );
313
+ }
314
+
315
+ $args = array();
316
+
317
+ foreach ( array( 'full', 'thumb' ) as $type ) {
318
+ $args[ $type ] = bp_core_fetch_avatar(
319
+ array(
320
+ 'object' => $this->object,
321
+ 'type' => $type,
322
+ 'item_id' => $group_id,
323
+ 'html' => false,
324
+ )
325
+ );
326
+ }
327
+
328
+ // Get the avatar object before deleting it.
329
+ $avatar = $this->get_avatar_object( $args );
330
+
331
+ $deleted = bp_core_delete_existing_avatar(
332
+ array(
333
+ 'object' => $this->object,
334
+ 'item_id' => $group_id,
335
+ )
336
+ );
337
+
338
+ if ( ! $deleted ) {
339
+ return new WP_Error(
340
+ 'bp_rest_attachments_group_avatar_delete_failed',
341
+ __( 'Sorry, there was a problem deleting this group avatar.', 'buddypress' ),
342
+ array(
343
+ 'status' => 500,
344
+ )
345
+ );
346
+ }
347
+
348
+ // Build the response.
349
+ $response = new WP_REST_Response();
350
+ $response->set_data(
351
+ array(
352
+ 'deleted' => true,
353
+ 'previous' => $avatar,
354
+ )
355
+ );
356
+
357
+ /**
358
+ * Fires after a group avatar is deleted via the REST API.
359
+ *
360
+ * @since 5.0.0
361
+ *
362
+ * @param WP_REST_Response $response The response data.
363
+ * @param WP_REST_Request $request The request sent to the API.
364
+ */
365
+ do_action( 'bp_rest_attachments_group_avatar_delete_item', $response, $request );
366
+
367
+ return $response;
368
+ }
369
+
370
+ /**
371
+ * Checks if a given request has access to delete a group avatar.
372
+ *
373
+ * @since 5.0.0
374
+ *
375
+ * @param WP_REST_Request $request Full details about the request.
376
+ * @return bool|WP_Error
377
+ */
378
+ public function delete_item_permissions_check( $request ) {
379
+ $retval = $this->create_item_permissions_check( $request );
380
+
381
+ /**
382
+ * Filter the group avatar `delete_item` permissions check.
383
+ *
384
+ * @since 5.0.0
385
+ *
386
+ * @param bool|WP_Error $retval Returned value.
387
+ * @param WP_REST_Request $request The request sent to the API.
388
+ */
389
+ return apply_filters( 'bp_rest_attachments_group_avatar_delete_item_permissions_check', $retval, $request );
390
+ }
391
+
392
+ /**
393
+ * Prepares avatar data to return as an object.
394
+ *
395
+ * @since 5.0.0
396
+ *
397
+ * @param stdClass|string $avatar Avatar object or string with url or image with html.
398
+ * @param WP_REST_Request $request Full details about the request.
399
+ * @return WP_REST_Response
400
+ */
401
+ public function prepare_item_for_response( $avatar, $request ) {
402
+ $data = array(
403
+ 'full' => $avatar->full,
404
+ 'thumb' => $avatar->thumb,
405
+ );
406
+
407
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
408
+ $data = $this->add_additional_fields_to_object( $data, $request );
409
+ $data = $this->filter_response_by_context( $data, $context );
410
+
411
+ // @todo add prepare_links
412
+ $response = rest_ensure_response( $data );
413
+
414
+ /**
415
+ * Filter a group avatar value returned from the API.
416
+ *
417
+ * @since 5.0.0
418
+ *
419
+ * @param WP_REST_Response $response Response.
420
+ * @param WP_REST_Request $request Request used to generate the response.
421
+ * @param stdClass|string $avatar Avatar object or string with url or image with html.
422
+ */
423
+ return apply_filters( 'bp_rest_attachments_group_avatar_prepare_value', $response, $request, $avatar );
424
+ }
425
+
426
+ /**
427
+ * Get the plugin schema, conforming to JSON Schema.
428
+ *
429
+ * @since 5.0.0
430
+ *
431
+ * @return array
432
+ */
433
+ public function get_item_schema() {
434
+ $schema = array(
435
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
436
+ 'title' => 'bp_attachments_group_avatar',
437
+ 'type' => 'object',
438
+ 'properties' => array(
439
+ 'full' => array(
440
+ 'context' => array( 'view', 'edit' ),
441
+ 'description' => __( 'Full size of the image file.', 'buddypress' ),
442
+ 'type' => 'string',
443
+ 'readonly' => true,
444
+ ),
445
+ 'thumb' => array(
446
+ 'context' => array( 'view', 'edit' ),
447
+ 'description' => __( 'Thumb size of the image file.', 'buddypress' ),
448
+ 'type' => 'string',
449
+ 'readonly' => true,
450
+ ),
451
+ ),
452
+ );
453
+
454
+ /**
455
+ * Filters the group avatar schema.
456
+ *
457
+ * @param string $schema The endpoint schema.
458
+ */
459
+ return apply_filters( 'bp_rest_attachments_group_avatar_schema', $this->add_additional_fields_schema( $schema ) );
460
+ }
461
+
462
+ /**
463
+ * Get the query params for the `get_item`.
464
+ *
465
+ * @since 5.0.0
466
+ *
467
+ * @return array
468
+ */
469
+ public function get_item_collection_params() {
470
+ $params = parent::get_collection_params();
471
+ $params['context']['default'] = 'view';
472
+
473
+ // Removing unused params.
474
+ unset( $params['search'], $params['page'], $params['per_page'] );
475
+
476
+ $params['html'] = array(
477
+ 'description' => __( 'Whether to return an <img> HTML element, vs a raw URL to a group avatar.', 'buddypress' ),
478
+ 'default' => false,
479
+ 'type' => 'boolean',
480
+ 'sanitize_callback' => 'rest_sanitize_boolean',
481
+ 'validate_callback' => 'rest_validate_request_arg',
482
+ );
483
+
484
+ $params['alt'] = array(
485
+ 'description' => __( 'The alt attribute for the <img> element.', 'buddypress' ),
486
+ 'default' => '',
487
+ 'type' => 'string',
488
+ 'sanitize_callback' => 'sanitize_text_field',
489
+ 'validate_callback' => 'rest_validate_request_arg',
490
+ );
491
+
492
+ /**
493
+ * Filters the item collection query params.
494
+ *
495
+ * @param array $params Query params.
496
+ */
497
+ return apply_filters( 'bp_rest_attachments_group_avatar_collection_params', $params );
498
+ }
499
+ }
bp-core/classes/class-bp-rest-attachments-member-avatar-endpoint.php ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Attachments_Member_Avatar_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Member Avatar endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Attachments_Member_Avatar_Endpoint extends WP_REST_Controller {
17
+
18
+ use BP_REST_Attachments;
19
+
20
+ /**
21
+ * BP_Attachment_Avatar Instance.
22
+ *
23
+ * @since 5.0.0
24
+ *
25
+ * @var BP_Attachment_Avatar
26
+ */
27
+ protected $avatar_instance;
28
+
29
+ /**
30
+ * Member object type.
31
+ *
32
+ * @since 5.0.0
33
+ *
34
+ * @var string
35
+ */
36
+ protected $object = 'user';
37
+
38
+ /**
39
+ * Member object.
40
+ *
41
+ * @since 5.0.0
42
+ *
43
+ * @var WP_User
44
+ */
45
+ protected $user;
46
+
47
+ /**
48
+ * Constructor.
49
+ *
50
+ * @since 5.0.0
51
+ */
52
+ public function __construct() {
53
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
54
+ $this->rest_base = 'members';
55
+ $this->avatar_instance = new BP_Attachment_Avatar();
56
+ }
57
+
58
+ /**
59
+ * Register the component routes.
60
+ *
61
+ * @since 5.0.0
62
+ */
63
+ public function register_routes() {
64
+ register_rest_route(
65
+ $this->namespace,
66
+ '/' . $this->rest_base . '/(?P<user_id>[\d]+)/avatar',
67
+ array(
68
+ 'args' => array(
69
+ 'user_id' => array(
70
+ 'description' => __( 'A unique numeric ID for the Member.', 'buddypress' ),
71
+ 'type' => 'integer',
72
+ ),
73
+ ),
74
+ array(
75
+ 'methods' => WP_REST_Server::READABLE,
76
+ 'callback' => array( $this, 'get_item' ),
77
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
78
+ 'args' => $this->get_item_collection_params(),
79
+ ),
80
+ array(
81
+ 'methods' => WP_REST_Server::CREATABLE,
82
+ 'callback' => array( $this, 'create_item' ),
83
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
84
+ ),
85
+ array(
86
+ 'methods' => WP_REST_Server::DELETABLE,
87
+ 'callback' => array( $this, 'delete_item' ),
88
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
89
+ ),
90
+ 'schema' => array( $this, 'get_item_schema' ),
91
+ )
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Fetch an existing member avatar.
97
+ *
98
+ * @since 5.0.0
99
+ *
100
+ * @param WP_REST_Request $request Full details about the request.
101
+ * @return WP_REST_Response|WP_Error
102
+ */
103
+ public function get_item( $request ) {
104
+ $args = array();
105
+
106
+ foreach ( array( 'full', 'thumb' ) as $type ) {
107
+ $args[ $type ] = bp_core_fetch_avatar(
108
+ array(
109
+ 'object' => $this->object,
110
+ 'type' => $type,
111
+ 'item_id' => (int) $this->user->ID,
112
+ 'html' => (bool) $request['html'],
113
+ 'alt' => $request['alt'],
114
+ 'no_grav' => (bool) $request['no_gravatar'],
115
+ )
116
+ );
117
+ }
118
+
119
+ // Get the avatar object.
120
+ $avatar = $this->get_avatar_object( $args );
121
+
122
+ if ( ! $avatar->full && ! $avatar->thumb ) {
123
+ return new WP_Error(
124
+ 'bp_rest_attachments_member_avatar_no_image',
125
+ __( 'Sorry, there was a problem fetching the avatar.', 'buddypress' ),
126
+ array(
127
+ 'status' => 500,
128
+ )
129
+ );
130
+ }
131
+
132
+ $retval = array(
133
+ $this->prepare_response_for_collection(
134
+ $this->prepare_item_for_response( $avatar, $request )
135
+ ),
136
+ );
137
+
138
+ $response = rest_ensure_response( $retval );
139
+
140
+ /**
141
+ * Fires after a member avatar is fetched via the REST API.
142
+ *
143
+ * @since 5.0.0
144
+ *
145
+ * @param string $avatar The avatar.
146
+ * @param WP_REST_Response $response The response data.
147
+ * @param WP_REST_Request $request The request sent to the API.
148
+ */
149
+ do_action( 'bp_rest_attachments_member_avatar_get_item', $avatar, $response, $request );
150
+
151
+ return $response;
152
+ }
153
+
154
+ /**
155
+ * Checks if a given request has access to get a member avatar.
156
+ *
157
+ * @since 5.0.0
158
+ *
159
+ * @param WP_REST_Request $request Full details about the request.
160
+ * @return bool|WP_Error
161
+ */
162
+ public function get_item_permissions_check( $request ) {
163
+ $retval = true;
164
+ $this->user = bp_rest_get_user( $request['user_id'] );
165
+
166
+ if ( true === $retval && ! $this->user instanceof WP_User ) {
167
+ $retval = new WP_Error(
168
+ 'bp_rest_member_invalid_id',
169
+ __( 'Invalid member id.', 'buddypress' ),
170
+ array(
171
+ 'status' => 404,
172
+ )
173
+ );
174
+ }
175
+
176
+ /**
177
+ * Filter the member avatar `get_item` permissions check.
178
+ *
179
+ * @since 5.0.0
180
+ *
181
+ * @param bool|WP_Error $retval Returned value.
182
+ * @param WP_REST_Request $request The request sent to the API.
183
+ */
184
+ return apply_filters( 'bp_rest_attachments_member_avatar_get_item_permissions_check', $retval, $request );
185
+ }
186
+
187
+ /**
188
+ * Upload a member avatar.
189
+ *
190
+ * @since 5.0.0
191
+ *
192
+ * @param WP_REST_Request $request Full details about the request.
193
+ * @return WP_REST_Response|WP_Error
194
+ */
195
+ public function create_item( $request ) {
196
+ $request->set_param( 'context', 'edit' );
197
+
198
+ // Get the image file from $_FILES.
199
+ $files = $request->get_file_params();
200
+
201
+ if ( empty( $files ) ) {
202
+ return new WP_Error(
203
+ 'bp_rest_attachments_member_avatar_no_image_file',
204
+ __( 'Sorry, you need an image file to upload.', 'buddypress' ),
205
+ array(
206
+ 'status' => 500,
207
+ )
208
+ );
209
+ }
210
+
211
+ // Upload the avatar.
212
+ $avatar = $this->upload_avatar_from_file( $files );
213
+ if ( is_wp_error( $avatar ) ) {
214
+ return $avatar;
215
+ }
216
+
217
+ $retval = array(
218
+ $this->prepare_response_for_collection(
219
+ $this->prepare_item_for_response( $avatar, $request )
220
+ ),
221
+ );
222
+
223
+ $response = rest_ensure_response( $retval );
224
+
225
+ /**
226
+ * Fires after a member avatar is uploaded via the REST API.
227
+ *
228
+ * @since 5.0.0
229
+ *
230
+ * @param stdClass $avatar Avatar object.
231
+ * @param WP_REST_Response $response The response data.
232
+ * @param WP_REST_Request $request The request sent to the API.
233
+ */
234
+ do_action( 'bp_rest_attachments_member_avatar_create_item', $avatar, $response, $request );
235
+
236
+ return $response;
237
+ }
238
+
239
+ /**
240
+ * Checks if a given request has access to upload a member avatar.
241
+ *
242
+ * @since 5.0.0
243
+ *
244
+ * @param WP_REST_Request $request Full details about the request.
245
+ * @return bool|WP_Error
246
+ */
247
+ public function create_item_permissions_check( $request ) {
248
+ $retval = $this->get_item_permissions_check( $request );
249
+ $args = array();
250
+
251
+ if ( isset( $this->user->ID ) ) {
252
+ $args = array(
253
+ 'item_id' => (int) $this->user->ID,
254
+ 'object' => 'user',
255
+ );
256
+ }
257
+
258
+ if ( true === $retval && ! is_user_logged_in() ) {
259
+ $retval = new WP_Error(
260
+ 'bp_rest_authorization_required',
261
+ __( 'Sorry, you need to be logged in to perform this action.', 'buddypress' ),
262
+ array(
263
+ 'status' => rest_authorization_required_code(),
264
+ )
265
+ );
266
+ }
267
+
268
+ if ( true === $retval && bp_disable_avatar_uploads() ) {
269
+ $retval = new WP_Error(
270
+ 'bp_rest_attachments_member_avatar_disabled',
271
+ __( 'Sorry, member avatar upload is disabled.', 'buddypress' ),
272
+ array(
273
+ 'status' => 500,
274
+ )
275
+ );
276
+ }
277
+
278
+ if ( true === $retval && ! empty( $args ) && ! bp_attachments_current_user_can( 'edit_avatar', $args ) ) {
279
+ $retval = new WP_Error(
280
+ 'bp_rest_authorization_required',
281
+ __( 'Sorry, you are not authorized to perform this action.', 'buddypress' ),
282
+ array(
283
+ 'status' => rest_authorization_required_code(),
284
+ )
285
+ );
286
+ }
287
+
288
+ /**
289
+ * Filter the member avatar `create_item` permissions check.
290
+ *
291
+ * @since 5.0.0
292
+ *
293
+ * @param bool|WP_Error $retval Returned value.
294
+ * @param WP_REST_Request $request The request sent to the API.
295
+ */
296
+ return apply_filters( 'bp_rest_attachments_member_avatar_create_item_permissions_check', $retval, $request );
297
+ }
298
+
299
+ /**
300
+ * Delete an existing member avatar.
301
+ *
302
+ * @since 5.0.0
303
+ *
304
+ * @param WP_REST_Request $request Full details about the request.
305
+ * @return WP_REST_Response|WP_Error
306
+ */
307
+ public function delete_item( $request ) {
308
+ $request->set_param( 'context', 'edit' );
309
+ $user_id = (int) $this->user->ID;
310
+
311
+ if ( ! bp_get_user_has_avatar( $user_id ) ) {
312
+ return new WP_Error(
313
+ 'bp_rest_attachments_member_avatar_no_uploaded_avatar',
314
+ __( 'Sorry, there are no uploaded avatars for this user on this site.', 'buddypress' ),
315
+ array(
316
+ 'status' => 404,
317
+ )
318
+ );
319
+ }
320
+
321
+ $args = array();
322
+
323
+ foreach ( array( 'full', 'thumb' ) as $type ) {
324
+ $args[ $type ] = bp_core_fetch_avatar(
325
+ array(
326
+ 'object' => $this->object,
327
+ 'type' => $type,
328
+ 'item_id' => $user_id,
329
+ 'html' => false,
330
+ )
331
+ );
332
+ }
333
+
334
+ // Get the avatar object before deleting it.
335
+ $avatar = $this->get_avatar_object( $args );
336
+
337
+ $deleted = bp_core_delete_existing_avatar(
338
+ array(
339
+ 'object' => $this->object,
340
+ 'item_id' => $user_id,
341
+ )
342
+ );
343
+
344
+ if ( ! $deleted ) {
345
+ return new WP_Error(
346
+ 'bp_rest_attachments_member_avatar_delete_failed',
347
+ __( 'Sorry, there was a problem deleting the avatar.', 'buddypress' ),
348
+ array(
349
+ 'status' => 500,
350
+ )
351
+ );
352
+ }
353
+
354
+ // Build the response.
355
+ $response = new WP_REST_Response();
356
+ $response->set_data(
357
+ array(
358
+ 'deleted' => true,
359
+ 'previous' => $avatar,
360
+ )
361
+ );
362
+
363
+ /**
364
+ * Fires after a member avatar is deleted via the REST API.
365
+ *
366
+ * @since 5.0.0
367
+ *
368
+ * @param WP_REST_Response $response The response data.
369
+ * @param WP_REST_Request $request The request sent to the API.
370
+ */
371
+ do_action( 'bp_rest_attachments_member_avatar_delete_item', $response, $request );
372
+
373
+ return $response;
374
+ }
375
+
376
+ /**
377
+ * Checks if a given request has access to delete member avatar.
378
+ *
379
+ * @since 5.0.0
380
+ *
381
+ * @param WP_REST_Request $request Full details about the request.
382
+ * @return bool|WP_Error
383
+ */
384
+ public function delete_item_permissions_check( $request ) {
385
+ $retval = $this->create_item_permissions_check( $request );
386
+
387
+ /**
388
+ * Filter the member avatar `delete_item` permissions check.
389
+ *
390
+ * @since 5.0.0
391
+ *
392
+ * @param bool|WP_Error $retval Returned value.
393
+ * @param WP_REST_Request $request The request sent to the API.
394
+ */
395
+ return apply_filters( 'bp_rest_attachments_member_avatar_delete_item_permissions_check', $retval, $request );
396
+ }
397
+
398
+ /**
399
+ * Prepares avatar data to return as an object.
400
+ *
401
+ * @since 5.0.0
402
+ *
403
+ * @param stdClass|string $avatar Avatar object or string with url or image with html.
404
+ * @param WP_REST_Request $request Full details about the request.
405
+ * @return WP_REST_Response
406
+ */
407
+ public function prepare_item_for_response( $avatar, $request ) {
408
+ $data = array(
409
+ 'full' => $avatar->full,
410
+ 'thumb' => $avatar->thumb,
411
+ );
412
+
413
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
414
+ $data = $this->add_additional_fields_to_object( $data, $request );
415
+ $data = $this->filter_response_by_context( $data, $context );
416
+
417
+ // @todo add prepare_links
418
+ $response = rest_ensure_response( $data );
419
+
420
+ /**
421
+ * Filter a member avatar value returned from the API.
422
+ *
423
+ * @since 5.0.0
424
+ *
425
+ * @param WP_REST_Response $response Response.
426
+ * @param WP_REST_Request $request Request used to generate the response.
427
+ * @param stdClass|string $avatar Avatar object or string with url or image with html.
428
+ */
429
+ return apply_filters( 'bp_rest_attachments_member_avatar_prepare_value', $response, $request, $avatar );
430
+ }
431
+
432
+ /**
433
+ * Get the member avatar schema, conforming to JSON Schema.
434
+ *
435
+ * @since 5.0.0
436
+ *
437
+ * @return array
438
+ */
439
+ public function get_item_schema() {
440
+ $schema = array(
441
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
442
+ 'title' => 'bp_attachments_member_avatar',
443
+ 'type' => 'object',
444
+ 'properties' => array(
445
+ 'full' => array(
446
+ 'context' => array( 'view', 'edit' ),
447
+ 'description' => __( 'Full size of the image file.', 'buddypress' ),
448
+ 'type' => 'string',
449
+ 'format' => 'uri',
450
+ 'readonly' => true,
451
+ ),
452
+ 'thumb' => array(
453
+ 'context' => array( 'view', 'edit' ),
454
+ 'description' => __( 'Thumb size of the image file.', 'buddypress' ),
455
+ 'type' => 'string',
456
+ 'format' => 'uri',
457
+ 'readonly' => true,
458
+ ),
459
+ ),
460
+ );
461
+
462
+ /**
463
+ * Filters the member avatar schema.
464
+ *
465
+ * @param string $schema The endpoint schema.
466
+ */
467
+ return apply_filters( 'bp_rest_attachments_member_avatar_schema', $this->add_additional_fields_schema( $schema ) );
468
+ }
469
+
470
+ /**
471
+ * Get the query params for the `get_item`.
472
+ *
473
+ * @since 5.0.0
474
+ *
475
+ * @return array
476
+ */
477
+ public function get_item_collection_params() {
478
+ $params = parent::get_collection_params();
479
+ $params['context']['default'] = 'view';
480
+
481
+ // Removing unused params.
482
+ unset( $params['search'], $params['page'], $params['per_page'] );
483
+
484
+ $params['html'] = array(
485
+ 'description' => __( 'Whether to return an <img> HTML element, vs a raw URL to an avatar.', 'buddypress' ),
486
+ 'default' => false,
487
+ 'type' => 'boolean',
488
+ 'sanitize_callback' => 'rest_sanitize_boolean',
489
+ 'validate_callback' => 'rest_validate_request_arg',
490
+ );
491
+
492
+ $params['alt'] = array(
493
+ 'description' => __( 'The alt attribute for the <img> element.', 'buddypress' ),
494
+ 'default' => '',
495
+ 'type' => 'string',
496
+ 'sanitize_callback' => 'sanitize_text_field',
497
+ 'validate_callback' => 'rest_validate_request_arg',
498
+ );
499
+
500
+ $params['no_grav'] = array(
501
+ 'description' => __( 'Whether to disable the default Gravatar fallback.', 'buddypress' ),
502
+ 'default' => false,
503
+ 'type' => 'boolean',
504
+ 'sanitize_callback' => 'rest_sanitize_boolean',
505
+ 'validate_callback' => 'rest_validate_request_arg',
506
+ );
507
+
508
+ /**
509
+ * Filters the item collection query params.
510
+ *
511
+ * @param array $params Query params.
512
+ */
513
+ return apply_filters( 'bp_rest_attachments_member_avatar_collection_params', $params );
514
+ }
515
+ }
bp-core/classes/class-bp-rest-components-endpoint.php ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Components_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Components endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Components_Endpoint extends WP_REST_Controller {
17
+
18
+ /**
19
+ * Constructor.
20
+ *
21
+ * @since 5.0.0
22
+ */
23
+ public function __construct() {
24
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
25
+ $this->rest_base = 'components';
26
+ }
27
+
28
+ /**
29
+ * Register the component routes.
30
+ *
31
+ * @since 5.0.0
32
+ */
33
+ public function register_routes() {
34
+ register_rest_route(
35
+ $this->namespace,
36
+ '/' . $this->rest_base,
37
+ array(
38
+ array(
39
+ 'methods' => WP_REST_Server::READABLE,
40
+ 'callback' => array( $this, 'get_items' ),
41
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
42
+ 'args' => $this->get_collection_params(),
43
+ ),
44
+ array(
45
+ 'methods' => WP_REST_Server::EDITABLE,
46
+ 'callback' => array( $this, 'update_item' ),
47
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
48
+ 'args' => array(
49
+ 'name' => array(
50
+ 'type' => 'string',
51
+ 'required' => true,
52
+ 'description' => __( 'Name of the component.', 'buddypress' ),
53
+ 'arg_options' => array(
54
+ 'sanitize_callback' => 'sanitize_key',
55
+ ),
56
+ ),
57
+ 'action' => array(
58
+ 'description' => __( 'Whether to activate or deactivate the component.', 'buddypress' ),
59
+ 'type' => 'string',
60
+ 'enum' => array( 'activate', 'deactivate' ),
61
+ 'required' => true,
62
+ 'arg_options' => array(
63
+ 'sanitize_callback' => 'sanitize_key',
64
+ ),
65
+ ),
66
+ ),
67
+ ),
68
+ 'schema' => array( $this, 'get_item_schema' ),
69
+ )
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Retrieve components.
75
+ *
76
+ * @since 5.0.0
77
+ *
78
+ * @param WP_REST_Request $request Full details about the request.
79
+ * @return WP_REST_Response
80
+ */
81
+ public function get_items( $request ) {
82
+ $args = array(
83
+ 'type' => $request['type'],
84
+ 'status' => $request['status'],
85
+ 'per_page' => $request['per_page'],
86
+ );
87
+
88
+ /**
89
+ * Filter the query arguments for the request.
90
+ *
91
+ * @since 5.0.0
92
+ *
93
+ * @param array $args Key value array of query var to query value.
94
+ * @param WP_REST_Request $request The request sent to the API.
95
+ */
96
+ $args = apply_filters( 'bp_rest_components_get_items_query_args', $args, $request );
97
+
98
+ $type = $args['type'];
99
+
100
+ // Get all components based on type.
101
+ $components = bp_core_get_components( $type );
102
+
103
+ // Active components.
104
+ $active_components = apply_filters( 'bp_active_components', bp_get_option( 'bp-active-components' ) );
105
+
106
+ // Core component is always active.
107
+ if ( 'optional' !== $type ) {
108
+ $active_components['core'] = $components['core'];
109
+ }
110
+
111
+ // Inactive components.
112
+ $inactive_components = array_diff( array_keys( $components ), array_keys( $active_components ) );
113
+
114
+ $current_components = array();
115
+ switch ( $args['status'] ) {
116
+ case 'all':
117
+ foreach ( $components as $name => $labels ) {
118
+ $current_components[] = $this->get_component_info( $name );
119
+ }
120
+ break;
121
+
122
+ case 'active':
123
+ foreach ( array_keys( $active_components ) as $component ) {
124
+ $current_components[] = $this->get_component_info( $component );
125
+ }
126
+ break;
127
+
128
+ case 'inactive':
129
+ foreach ( $inactive_components as $component ) {
130
+ $current_components[] = $this->get_component_info( $component );
131
+ }
132
+ break;
133
+ }
134
+
135
+ $retval = array();
136
+ foreach ( $current_components as $component ) {
137
+ $retval[] = $this->prepare_response_for_collection(
138
+ $this->prepare_item_for_response( $component, $request )
139
+ );
140
+ }
141
+
142
+ $response = rest_ensure_response( $retval );
143
+ $response = bp_rest_response_add_total_headers( $response, count( $current_components ), $args['per_page'] );
144
+
145
+ /**
146
+ * Fires after a list of components is fetched via the REST API.
147
+ *
148
+ * @since 5.0.0
149
+ *
150
+ * @param array $current_components Fetched components.
151
+ * @param WP_REST_Response $response The response data.
152
+ * @param WP_REST_Request $request The request sent to the API.
153
+ */
154
+ do_action( 'bp_rest_components_get_items', $current_components, $response, $request );
155
+
156
+ return $response;
157
+ }
158
+
159
+ /**
160
+ * Check if a given request has access to list components.
161
+ *
162
+ * @since 5.0.0
163
+ *
164
+ * @param WP_REST_Request $request Full data about the request.
165
+ * @return bool|WP_Error
166
+ */
167
+ public function get_items_permissions_check( $request ) {
168
+ $retval = true;
169
+
170
+ if ( ! ( is_user_logged_in() && bp_current_user_can( 'bp_moderate' ) ) ) {
171
+ $retval = new WP_Error(
172
+ 'bp_rest_authorization_required',
173
+ __( 'Sorry, you do not have access to list components.', 'buddypress' ),
174
+ array(
175
+ 'status' => rest_authorization_required_code(),
176
+ )
177
+ );
178
+ }
179
+
180
+ /**
181
+ * Filter the components `get_items` permissions check.
182
+ *
183
+ * @since 5.0.0
184
+ *
185
+ * @param bool|WP_Error $retval Returned value.
186
+ * @param WP_REST_Request $request The request sent to the API.
187
+ */
188
+ return apply_filters( 'bp_rest_components_get_items_permissions_check', $retval, $request );
189
+ }
190
+
191
+ /**
192
+ * Activate/Deactivate a component.
193
+ *
194
+ * @since 5.0.0
195
+ *
196
+ * @param WP_REST_Request $request Full details about the request.
197
+ * @return WP_REST_Response|WP_Error
198
+ */
199
+ public function update_item( $request ) {
200
+ $component = $request['name'];
201
+
202
+ if ( ! $this->component_exists( $component ) ) {
203
+ return new WP_Error(
204
+ 'bp_rest_component_nonexistent',
205
+ __( 'Sorry, this component does not exist.', 'buddypress' ),
206
+ array(
207
+ 'status' => 500,
208
+ )
209
+ );
210
+ }
211
+
212
+ $action = $request['action'];
213
+ if ( empty( $action ) || ! in_array( $action, [ 'activate', 'deactivate' ], true ) ) {
214
+ return new WP_Error(
215
+ 'bp_rest_component_invalid_action',
216
+ __( 'Sorry, this is not a valid action.', 'buddypress' ),
217
+ array(
218
+ 'status' => 500,
219
+ )
220
+ );
221
+ }
222
+
223
+ if ( 'activate' === $action ) {
224
+ if ( bp_is_active( $component ) ) {
225
+ return new WP_Error(
226
+ 'bp_rest_component_already_active',
227
+ __( 'Sorry, this component is already active.', 'buddypress' ),
228
+ array(
229
+ 'status' => 500,
230
+ )
231
+ );
232
+ }
233
+
234
+ $component_info = $this->activate_helper( $component );
235
+ } else {
236
+ if ( ! bp_is_active( $component ) ) {
237
+ return new WP_Error(
238
+ 'bp_rest_component_inactive',
239
+ __( 'Sorry, this component is not active.', 'buddypress' ),
240
+ array(
241
+ 'status' => 500,
242
+ )
243
+ );
244
+ }
245
+
246
+ if ( array_key_exists( $component, bp_core_get_components( 'required' ) ) ) {
247
+ return new WP_Error(
248
+ 'bp_rest_required_component',
249
+ __( 'Sorry, you cannot deactivate a required component.', 'buddypress' ),
250
+ array(
251
+ 'status' => 500,
252
+ )
253
+ );
254
+ }
255
+
256
+ $component_info = $this->deactivate_helper( $component );
257
+ }
258
+
259
+ $request->set_param( 'context', 'edit' );
260
+
261
+ $retval = array(
262
+ $this->prepare_response_for_collection(
263
+ $this->prepare_item_for_response( $component_info, $request )
264
+ ),
265
+ );
266
+
267
+ $response = rest_ensure_response( $retval );
268
+
269
+ /**
270
+ * Fires after a component is updated via the REST API.
271
+ *
272
+ * @since 5.0.0
273
+ *
274
+ * @param array $component_info Component info.
275
+ * @param WP_REST_Response $response The response data.
276
+ * @param WP_REST_Request $request The request sent to the API.
277
+ */
278
+ do_action( 'bp_rest_components_update_item', $component_info, $response, $request );
279
+
280
+ return $response;
281
+ }
282
+
283
+ /**
284
+ * Check if a given request has access to update a component.
285
+ *
286
+ * @since 5.0.0
287
+ *
288
+ * @param WP_REST_Request $request Full details about the request.
289
+ * @return bool|WP_Error
290
+ */
291
+ public function update_item_permissions_check( $request ) {
292
+ $retval = $this->get_items_permissions_check( $request );
293
+
294
+ /**
295
+ * Filter the components `update_item` permissions check.
296
+ *
297
+ * @since 5.0.0
298
+ *
299
+ * @param bool|WP_Error $retval Returned value.
300
+ * @param WP_REST_Request $request The request sent to the API.
301
+ */
302
+ return apply_filters( 'bp_rest_components_update_item_permissions_check', $retval, $request );
303
+ }
304
+
305
+ /**
306
+ * Prepares component data for return as an object.
307
+ *
308
+ * @since 5.0.0
309
+ *
310
+ * @param array $component The component and its values.
311
+ * @param WP_REST_Request $request Full details about the request.
312
+ * @return WP_REST_Response
313
+ */
314
+ public function prepare_item_for_response( $component, $request ) {
315
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
316
+ $data = $this->add_additional_fields_to_object( $component, $request );
317
+ $data = $this->filter_response_by_context( $data, $context );
318
+
319
+ // @todo add prepare_links
320
+ $response = rest_ensure_response( $data );
321
+
322
+ /**
323
+ * Filter a component value returned from the API.
324
+ *
325
+ * @since 5.0.0
326
+ *
327
+ * @param WP_REST_Response $response The Response data.
328
+ * @param WP_REST_Request $request Request used to generate the response.
329
+ * @param array $component The component and its values.
330
+ */
331
+ return apply_filters( 'bp_rest_components_prepare_value', $response, $request, $component );
332
+ }
333
+
334
+ /**
335
+ * Verify Component Status.
336
+ *
337
+ * @since 5.0.0
338
+ *
339
+ * @param string $name Component name.
340
+ * @return string
341
+ */
342
+ protected function verify_component_status( $name ) {
343
+ if ( 'core' === $name || bp_is_active( $name ) ) {
344
+ return __( 'active', 'buddypress' );
345
+ }
346
+
347
+ return __( 'inactive', 'buddypress' );
348
+ }
349
+
350
+ /**
351
+ * Deactivate component helper.
352
+ *
353
+ * @since 5.0.0
354
+ *
355
+ * @param string $component Component id.
356
+ * @return array
357
+ */
358
+ protected function deactivate_helper( $component ) {
359
+
360
+ $active_components =& buddypress()->active_components;
361
+
362
+ // Set for the rest of the page load.
363
+ unset( $active_components[ $component ] );
364
+
365
+ // Save in the db.
366
+ bp_update_option( 'bp-active-components', $active_components );
367
+
368
+ return $this->get_component_info( $component );
369
+ }
370
+
371
+ /**
372
+ * Activate component helper.
373
+ *
374
+ * @since 5.0.0
375
+ *
376
+ * @param string $component Component id.
377
+ * @return array
378
+ */
379
+ protected function activate_helper( $component ) {
380
+
381
+ $active_components =& buddypress()->active_components;
382
+
383
+ // Set for the rest of the page load.
384
+ $active_components[ $component ] = 1;
385
+
386
+ // Save in the db.
387
+ bp_update_option( 'bp-active-components', $active_components );
388
+
389
+ // Ensure that dbDelta() is defined.
390
+ if ( ! function_exists( 'dbDelta' ) ) {
391
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
392
+ }
393
+
394
+ // Run the setup, in case tables have to be created.
395
+ require_once buddypress()->plugin_dir . 'bp-core/admin/bp-core-admin-schema.php';
396
+
397
+ bp_core_install( $active_components );
398
+ bp_core_add_page_mappings( $active_components );
399
+
400
+ return $this->get_component_info( $component );
401
+ }
402
+
403
+ /**
404
+ * Get component info helper.
405
+ *
406
+ * @since 5.0.0
407
+ *
408
+ * @param string $component Component id.
409
+ * @return array
410
+ */
411
+ public function get_component_info( $component ) {
412
+
413
+ // Get all components.
414
+ $components = bp_core_get_components();
415
+
416
+ // Get specific component info.
417
+ $info = $components[ $component ];
418
+
419
+ // Return empty early.
420
+ if ( empty( $info ) ) {
421
+ return array();
422
+ }
423
+
424
+ return array(
425
+ 'name' => $component,
426
+ 'status' => $this->verify_component_status( $component ),
427
+ 'title' => $info['title'],
428
+ 'description' => $info['description'],
429
+ );
430
+ }
431
+
432
+ /**
433
+ * Does the component exist?
434
+ *
435
+ * @since 5.0.0
436
+ *
437
+ * @param string $component Component.
438
+ * @return bool
439
+ */
440
+ protected function component_exists( $component ) {
441
+ return in_array( $component, array_keys( bp_core_get_components() ), true );
442
+ }
443
+
444
+ /**
445
+ * Get the components schema, conforming to JSON Schema.
446
+ *
447
+ * @since 5.0.0
448
+ *
449
+ * @return array
450
+ */
451
+ public function get_item_schema() {
452
+ $schema = array(
453
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
454
+ 'title' => 'bp_components',
455
+ 'type' => 'object',
456
+ 'properties' => array(
457
+ 'name' => array(
458
+ 'context' => array( 'view', 'edit' ),
459
+ 'description' => __( 'Name of the object.', 'buddypress' ),
460
+ 'type' => 'string',
461
+ 'arg_options' => array(
462
+ 'sanitize_callback' => 'sanitize_key',
463
+ ),
464
+ ),
465
+ 'status' => array(
466
+ 'context' => array( 'view', 'edit' ),
467
+ 'description' => __( 'Whether the object is active or inactive.', 'buddypress' ),
468
+ 'type' => 'string',
469
+ 'enum' => array( 'active', 'inactive' ),
470
+ 'arg_options' => array(
471
+ 'sanitize_callback' => 'sanitize_key',
472
+ ),
473
+ ),
474
+ 'title' => array(
475
+ 'context' => array( 'view', 'edit' ),
476
+ 'description' => __( 'HTML title of the object.', 'buddypress' ),
477
+ 'type' => 'string',
478
+ 'arg_options' => array(
479
+ 'sanitize_callback' => 'sanitize_text_field',
480
+ ),
481
+ ),
482
+ 'description' => array(
483
+ 'context' => array( 'view', 'edit' ),
484
+ 'description' => __( 'HTML description of the object.', 'buddypress' ),
485
+ 'type' => 'string',
486
+ 'arg_options' => array(
487
+ 'sanitize_callback' => 'sanitize_text_field',
488
+ ),
489
+ ),
490
+ ),
491
+ );
492
+
493
+ /**
494
+ * Filters the components schema.
495
+ *
496
+ * @param string $schema The endpoint schema.
497
+ */
498
+ return apply_filters( 'bp_rest_components_schema', $this->add_additional_fields_schema( $schema ) );
499
+ }
500
+
501
+ /**
502
+ * Get the query params for collections.
503
+ *
504
+ * @since 5.0.0
505
+ *
506
+ * @return array
507
+ */
508
+ public function get_collection_params() {
509
+ $params = parent::get_collection_params();
510
+ $params['context']['default'] = 'view';
511
+
512
+ $params['status'] = array(
513
+ 'description' => __( 'Limit result set to items with a specific status.', 'buddypress' ),
514
+ 'default' => 'all',
515
+ 'type' => 'string',
516
+ 'enum' => array( 'all', 'active', 'inactive' ),
517
+ 'sanitize_callback' => 'sanitize_key',
518
+ 'validate_callback' => 'rest_validate_request_arg',
519
+ );
520
+
521
+ $params['type'] = array(
522
+ 'description' => __( 'Limit result set to items with a specific type.', 'buddypress' ),
523
+ 'default' => 'all',
524
+ 'type' => 'string',
525
+ 'enum' => array( 'all', 'optional', 'retired', 'required' ),
526
+ 'sanitize_callback' => 'sanitize_key',
527
+ 'validate_callback' => 'rest_validate_request_arg',
528
+ );
529
+
530
+ /**
531
+ * Filters the collection query params.
532
+ *
533
+ * @param array $params Query params.
534
+ */
535
+ return apply_filters( 'bp_rest_components_collection_params', $params );
536
+ }
537
+ }
bp-core/classes/class-bp-user-query.php CHANGED
@@ -374,7 +374,7 @@ class BP_User_Query {
374
  }
375
 
376
  // 'exclude' - User ids to exclude from the results.
377
- if ( false !== $exclude ) {
378
  $exclude_ids = implode( ',', wp_parse_id_list( $exclude ) );
379
  $sql['where'][] = "u.{$this->uid_name} NOT IN ({$exclude_ids})";
380
  }
374
  }
375
 
376
  // 'exclude' - User ids to exclude from the results.
377
+ if ( ! empty( $exclude ) ) {
378
  $exclude_ids = implode( ',', wp_parse_id_list( $exclude ) );
379
  $sql['where'][] = "u.{$this->uid_name} NOT IN ({$exclude_ids})";
380
  }
bp-core/classes/trait-attachments.php ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: Attachments Trait
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Attachments Trait
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ trait BP_REST_Attachments {
17
+
18
+ /**
19
+ * Returns the avatar object.
20
+ *
21
+ * @since 5.0.0
22
+ *
23
+ * @param array $args {
24
+ * An array of arguments to build the Avatar object.
25
+ *
26
+ * @type string $full The url to the full version of the avatar.
27
+ * @type string $thumb The url to the thumb version of the avatar.
28
+ * }
29
+ * @return object The avatar object.
30
+ */
31
+ protected function get_avatar_object( $args = array() ) {
32
+ $avatar_object = array_intersect_key(
33
+ $args,
34
+ array(
35
+ 'full' => '',
36
+ 'thumb' => '',
37
+ )
38
+ );
39
+
40
+ return (object) $avatar_object;
41
+ }
42
+
43
+ /**
44
+ * Avatar upload from File.
45
+ *
46
+ * @since 5.0.0
47
+ *
48
+ * @param array $files $_FILES superglobal.
49
+ * @return stdClass|WP_Error
50
+ */
51
+ protected function upload_avatar_from_file( $files ) {
52
+ $bp = buddypress();
53
+
54
+ // Set global variables.
55
+ if ( 'group' === $this->object ) {
56
+ $bp->groups->current_group = $this->group;
57
+ $upload_main_dir = 'groups_avatar_upload_dir';
58
+ } else {
59
+ $upload_main_dir = 'xprofile_avatar_upload_dir';
60
+ $bp->displayed_user = new stdClass();
61
+ $bp->displayed_user->id = (int) $this->user->ID;
62
+ }
63
+
64
+ $avatar_attachment = $this->avatar_instance;
65
+ $avatar_original = $avatar_attachment->upload( $files, $upload_main_dir );
66
+
67
+ // Bail early in case of an error.
68
+ if ( ! empty( $avatar_original['error'] ) ) {
69
+ return new WP_Error(
70
+ "bp_rest_attachments_{$this->object}_avatar_upload_error",
71
+ sprintf(
72
+ /* translators: %s is replaced with the error */
73
+ __( 'Upload failed! Error was: %s.', 'buddypress' ),
74
+ $avatar_original['error']
75
+ ),
76
+ array(
77
+ 'status' => 500,
78
+ )
79
+ );
80
+ }
81
+
82
+ // Get image and bail early if there is an error.
83
+ $image_file = $this->resize( $avatar_original['file'] );
84
+ if ( is_wp_error( $image_file ) ) {
85
+ return $image_file;
86
+ }
87
+
88
+ // If the uploaded image is smaller than the "full" dimensions, throw a warning.
89
+ if ( $avatar_attachment->is_too_small( $image_file ) ) {
90
+ return new WP_Error(
91
+ "bp_rest_attachments_{$this->object}_avatar_error",
92
+ sprintf(
93
+ /* translators: %1$s and %2$s is replaced with the correct sizes. */
94
+ __( 'You have selected an image that is smaller than recommended. For best results, upload a picture larger than %1$s x %2$s pixels.', 'buddypress' ),
95
+ bp_core_avatar_full_width(),
96
+ bp_core_avatar_full_height()
97
+ ),
98
+ array(
99
+ 'status' => 500,
100
+ )
101
+ );
102
+ }
103
+
104
+ // Delete existing image if one exists.
105
+ $this->delete_existing_image();
106
+
107
+ // Crop the profile photo accordingly and bail early in case of an error.
108
+ $cropped = $this->crop_image( $image_file );
109
+ if ( is_wp_error( $cropped ) ) {
110
+ return $cropped;
111
+ }
112
+
113
+ // Set the arguments for the avatar.
114
+ $args = array();
115
+ foreach ( [ 'full', 'thumb' ] as $key_type ) {
116
+
117
+ // Update path with an url.
118
+ $url = str_replace( bp_core_avatar_upload_path(), '', $cropped[ $key_type ] );
119
+
120
+ // Set image url to its size/type.
121
+ $args[ $key_type ] = bp_core_avatar_url() . $url;
122
+ }
123
+
124
+ // Build response object.
125
+ $avatar_object = $this->get_avatar_object( $args );
126
+
127
+ if ( file_exists( $avatar_original['file'] ) ) {
128
+ unlink( $avatar_original['file'] );
129
+ }
130
+
131
+ return $avatar_object;
132
+ }
133
+
134
+ /**
135
+ * Resize image.
136
+ *
137
+ * @since 5.0.0
138
+ *
139
+ * @param string $file Image to resize.
140
+ * @return string|WP_Error
141
+ */
142
+ protected function resize( $file ) {
143
+ $bp = buddypress();
144
+ $upload_path = bp_core_avatar_upload_path();
145
+
146
+ if ( ! isset( $bp->avatar_admin ) ) {
147
+ $bp->avatar_admin = new stdClass();
148
+ }
149
+
150
+ // The Avatar UI available width.
151
+ $ui_available_width = 0;
152
+
153
+ // Try to set the ui_available_width using the avatar_admin global.
154
+ if ( isset( $bp->avatar_admin->ui_available_width ) ) {
155
+ $ui_available_width = $bp->avatar_admin->ui_available_width;
156
+ }
157
+
158
+ $resized = $this->avatar_instance->shrink( $file, $ui_available_width );
159
+
160
+ // We only want to handle one image after resize.
161
+ if ( empty( $resized ) ) {
162
+ $image_file = $file;
163
+ $img_dir = str_replace( $upload_path, '', $file );
164
+ } else {
165
+ $image_file = $resized['path'];
166
+ $img_dir = str_replace( $upload_path, '', $resized['path'] );
167
+ unlink( $file );
168
+ }
169
+
170
+ // Check for WP_Error on what should be an image.
171
+ if ( is_wp_error( $img_dir ) ) {
172
+ return new WP_Error(
173
+ "bp_rest_attachments_{$this->object}_avatar_upload_error",
174
+ sprintf(
175
+ /* translators: %$1s is replaced with error message. */
176
+ __( 'Upload failed! Error was: %$1s', 'buddypress' ),
177
+ $img_dir->get_error_message()
178
+ ),
179
+ array(
180
+ 'status' => 500,
181
+ )
182
+ );
183
+ }
184
+
185
+ return $image_file;
186
+ }
187
+
188
+ /**
189
+ * Crop image.
190
+ *
191
+ * @since 5.0.0
192
+ *
193
+ * @param string $image_file Image to crop.
194
+ * @return array|WP_Error
195
+ */
196
+ protected function crop_image( $image_file ) {
197
+ $image = getimagesize( $image_file );
198
+ $avatar_to_crop = str_replace( bp_core_avatar_upload_path(), '', $image_file );
199
+
200
+ // Get avatar full width and height.
201
+ $full_height = bp_core_avatar_full_height();
202
+ $full_width = bp_core_avatar_full_width();
203
+
204
+ // Use as much as possible of the image.
205
+ $avatar_ratio = $full_width / $full_height;
206
+ $image_ratio = $image[0] / $image[1];
207
+
208
+ if ( $image_ratio >= $avatar_ratio ) {
209
+ // Uploaded image is wider than BP ratio, so we crop horizontally.
210
+ $crop_y = 0;
211
+ $crop_h = $image[1];
212
+
213
+ // Get the target width by multiplying unmodified image height by target ratio.
214
+ $crop_w = $avatar_ratio * $image[1];
215
+ $padding_w = round( ( $image[0] - $crop_w ) / 2 );
216
+ $crop_x = $padding_w;
217
+ } else {
218
+ // Uploaded image is narrower than BP ratio, so we crop vertically.
219
+ $crop_x = 0;
220
+ $crop_w = $image[0];
221
+
222
+ // Get the target height by multiplying unmodified image width by target ratio.
223
+ $crop_h = $avatar_ratio * $image[0];
224
+ $padding_h = round( ( $image[1] - $crop_h ) / 2 );
225
+ $crop_y = $padding_h;
226
+ }
227
+
228
+ add_filter( 'bp_attachments_current_user_can', '__return_true' );
229
+
230
+ // Crop the image.
231
+ $cropped = $this->avatar_instance->crop(
232
+ array(
233
+ 'object' => $this->object,
234
+ 'avatar_dir' => ( 'group' === $this->object ) ? 'group-avatars' : 'avatars',
235
+ 'item_id' => $this->get_item_id(),
236
+ 'original_file' => $avatar_to_crop,
237
+ 'crop_w' => $crop_w,
238
+ 'crop_h' => $crop_h,
239
+ 'crop_x' => $crop_x,
240
+ 'crop_y' => $crop_y,
241
+ )
242
+ );
243
+
244
+ remove_filter( 'bp_attachments_current_user_can', '__return_false' );
245
+
246
+ // Check for errors.
247
+ if ( empty( $cropped['full'] ) || empty( $cropped['thumb'] ) || is_wp_error( $cropped['full'] ) || is_wp_error( $cropped['thumb'] ) ) {
248
+ return new WP_Error(
249
+ "bp_rest_attachments_{$this->object}_avatar_crop_error",
250
+ sprintf(
251
+ /* translators: %$1s is replaced with object type. */
252
+ __( 'There was a problem cropping your %s photo.', 'buddypress' ),
253
+ $this->object
254
+ ),
255
+ array(
256
+ 'status' => 500,
257
+ )
258
+ );
259
+ }
260
+
261
+ return $cropped;
262
+ }
263
+
264
+ /**
265
+ * Delete group's existing avatar if one exists.
266
+ *
267
+ * @since 5.0.0
268
+ *
269
+ * @return void
270
+ */
271
+ protected function delete_existing_image() {
272
+ // Get existing avatar.
273
+ $existing_avatar = bp_core_fetch_avatar(
274
+ array(
275
+ 'object' => $this->object,
276
+ 'item_id' => $this->get_item_id(),
277
+ 'html' => false,
278
+ )
279
+ );
280
+
281
+ // Check if the avatar exists before deleting.
282
+ if ( ! empty( $existing_avatar ) ) {
283
+ bp_core_delete_existing_avatar(
284
+ array(
285
+ 'object' => $this->object,
286
+ 'item_id' => $this->get_item_id(),
287
+ )
288
+ );
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Get item id.
294
+ *
295
+ * @return int
296
+ */
297
+ protected function get_item_id() {
298
+ return ( 'group' === $this->object ) ? $this->group->id : $this->user->ID;
299
+ }
300
+ }
bp-core/deprecated/2.1.php CHANGED
@@ -334,7 +334,7 @@ function bp_core_load_buddybar_css() {
334
 
335
  wp_enqueue_style( 'bp-admin-bar', apply_filters( 'bp_core_buddybar_rtl_css', $stylesheet ), array(), bp_get_version() );
336
 
337
- wp_style_add_data( 'bp-admin-bar', 'rtl', true );
338
  if ( $min ) {
339
  wp_style_add_data( 'bp-admin-bar', 'suffix', $min );
340
  }
334
 
335
  wp_enqueue_style( 'bp-admin-bar', apply_filters( 'bp_core_buddybar_rtl_css', $stylesheet ), array(), bp_get_version() );
336
 
337
+ wp_style_add_data( 'bp-admin-bar', 'rtl', 'replace' );
338
  if ( $min ) {
339
  wp_style_add_data( 'bp-admin-bar', 'suffix', $min );
340
  }
bp-core/js/bp-api-request.js ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * jQuery.ajax wrapper for BP REST API requests.
3
+ *
4
+ * @since 5.0.0
5
+ * @output bp-core/js/bp-api-request.js
6
+ */
7
+ /* global bpApiSettings */
8
+ window.bp = window.bp || {};
9
+
10
+ ( function( wp, bp, $ ) {
11
+ // Bail if not set
12
+ if ( typeof bpApiSettings === 'undefined' ) {
13
+ return;
14
+ }
15
+
16
+ bp.isRestEnabled = true;
17
+
18
+ // Polyfill wp.apiRequest if WordPress < 4.9
19
+ bp.apiRequest = function( options ) {
20
+ if ( ! options.dataType ) {
21
+ options.dataType = 'json';
22
+ }
23
+
24
+ // WordPress is >= 4.9.0.
25
+ if ( wp.apiRequest ) {
26
+ return wp.apiRequest( options );
27
+
28
+ // WordPress is < 4.9.0.
29
+ } else {
30
+ var url = bpApiSettings.root;
31
+
32
+ if ( options.path ) {
33
+ url = url + options.path.replace( /^\//, '' );
34
+ }
35
+
36
+ options.url = url;
37
+ options.beforeSend = function( xhr ) {
38
+ xhr.setRequestHeader( 'X-WP-Nonce', bpApiSettings.nonce );
39
+ };
40
+
41
+ return $.ajax( options );
42
+ }
43
+ };
44
+
45
+ } )( window.wp || {}, window.bp, jQuery );
bp-core/js/bp-api-request.min.js ADDED
@@ -0,0 +1 @@
 
1
+ window.bp=window.bp||{},function(e,n,t){"undefined"!=typeof bpApiSettings&&(n.isRestEnabled=!0,n.apiRequest=function(n){if(n.dataType||(n.dataType="json"),e.apiRequest)return e.apiRequest(n);var i=bpApiSettings.root;return n.path&&(i+=n.path.replace(/^\//,"")),n.url=i,n.beforeSend=function(e){e.setRequestHeader("X-WP-Nonce",bpApiSettings.nonce)},t.ajax(n)})}(window.wp||{},window.bp,jQuery);
bp-friends/bp-friends-filters.php CHANGED
@@ -52,24 +52,28 @@ add_filter( 'bp_user_query_populate_extras', 'bp_friends_filter_user_query_popul
52
  * Registers Friends personal data exporter.
53
  *
54
  * @since 4.0.0
 
55
  *
56
  * @param array $exporters An array of personal data exporters.
57
  * @return array An array of personal data exporters.
58
  */
59
  function bp_friends_register_personal_data_exporters( $exporters ) {
60
  $exporters['buddypress-friends'] = array(
61
- 'exporter_friendly_name' => __( 'BuddyPress Friends', 'buddypress' ),
62
- 'callback' => 'bp_friends_personal_data_exporter',
 
63
  );
64
 
65
  $exporters['buddypress-friends-pending-sent-requests'] = array(
66
- 'exporter_friendly_name' => __( 'BuddyPress Friend Requests (Sent)', 'buddypress' ),
67
- 'callback' => 'bp_friends_pending_sent_requests_personal_data_exporter',
 
68
  );
69
 
70
  $exporters['buddypress-friends-pending-received-requests'] = array(
71
- 'exporter_friendly_name' => __( 'BuddyPress Friend Requests (Received)', 'buddypress' ),
72
- 'callback' => 'bp_friends_pending_received_requests_personal_data_exporter',
 
73
  );
74
 
75
  return $exporters;
52
  * Registers Friends personal data exporter.
53
  *
54
  * @since 4.0.0
55
+ * @since 5.0.0 adds an `exporter_bp_friendly_name` param to exporters.
56
  *
57
  * @param array $exporters An array of personal data exporters.
58
  * @return array An array of personal data exporters.
59
  */
60
  function bp_friends_register_personal_data_exporters( $exporters ) {
61
  $exporters['buddypress-friends'] = array(
62
+ 'exporter_friendly_name' => __( 'BuddyPress Friends', 'buddypress' ),
63
+ 'callback' => 'bp_friends_personal_data_exporter',
64
+ 'exporter_bp_friendly_name' => _x( 'Friends', 'BuddyPress Friends data exporter friendly name', 'buddypress' ),
65
  );
66
 
67
  $exporters['buddypress-friends-pending-sent-requests'] = array(
68
+ 'exporter_friendly_name' => __( 'BuddyPress Friend Requests (Sent)', 'buddypress' ),
69
+ 'callback' => 'bp_friends_pending_sent_requests_personal_data_exporter',
70
+ 'exporter_bp_friendly_name' => _x( 'Friend Requests (Sent)', 'BuddyPress Friend Requests data exporter friendly name', 'buddypress' ),
71
  );
72
 
73
  $exporters['buddypress-friends-pending-received-requests'] = array(
74
+ 'exporter_friendly_name' => __( 'BuddyPress Friend Requests (Received)', 'buddypress' ),
75
+ 'callback' => 'bp_friends_pending_received_requests_personal_data_exporter',
76
+ 'exporter_bp_friendly_name' => _x( 'Friend Requests (Received)', 'BuddyPress Friend Requests data exporter friendly name', 'buddypress' ),
77
  );
78
 
79
  return $exporters;
bp-friends/classes/class-bp-core-friends-widget.php CHANGED
@@ -161,7 +161,7 @@ class BP_Core_Friends_Widget extends WP_Widget {
161
 
162
  $instance['max_friends'] = absint( $new_instance['max_friends'] );
163
  $instance['friend_default'] = sanitize_text_field( $new_instance['friend_default'] );
164
- $instance['link_title'] = (bool) $new_instance['link_title'];
165
 
166
  return $instance;
167
  }
161
 
162
  $instance['max_friends'] = absint( $new_instance['max_friends'] );
163
  $instance['friend_default'] = sanitize_text_field( $new_instance['friend_default'] );
164
+ $instance['link_title'] = ! empty( $new_instance['link_title'] );
165
 
166
  return $instance;
167
  }
bp-groups/actions/create.php CHANGED
@@ -136,7 +136,7 @@ function groups_action_create_group() {
136
  }
137
  }
138
 
139
- groups_send_invites( bp_loggedin_user_id(), $bp->groups->new_group_id );
140
  }
141
 
142
  /**
@@ -337,4 +337,4 @@ function groups_action_sort_creation_steps() {
337
  * @since 2.3.0
338
  */
339
  do_action( 'groups_action_sort_creation_steps' );
340
- }
136
  }
137
  }
138
 
139
+ groups_send_invites( array( 'group_id' => $bp->groups->new_group_id ) );
140
  }
141
 
142
  /**
337
  * @since 2.3.0
338
  */
339
  do_action( 'groups_action_sort_creation_steps' );
340
+ }
bp-groups/actions/leave-group.php CHANGED
@@ -58,4 +58,35 @@ function groups_action_leave_group() {
58
  /** This filter is documented in bp-groups/bp-groups-actions.php */
59
  bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
60
  }
61
- add_action( 'bp_actions', 'groups_action_leave_group' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  /** This filter is documented in bp-groups/bp-groups-actions.php */
59
  bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
60
  }
61
+ add_action( 'bp_actions', 'groups_action_leave_group' );
62
+
63
+ /**
64
+ * Clean up requests/invites when a member leaves a group.
65
+ *
66
+ * @since 5.0.0
67
+ */
68
+ function groups_action_clean_up_invites_requests( $user_id, $group_id ) {
69
+
70
+ $invites_class = new BP_Groups_Invitation_Manager();
71
+ // Remove invitations/requests where the deleted user is the receiver.
72
+ $invites_class->delete( array(
73
+ 'user_id' => $user_id,
74
+ 'item_id' => $group_id,
75
+ 'type' => 'all'
76
+ ) );
77
+ /**
78
+ * Remove invitations where the deleted user is the sender.
79
+ * We'll use groups_uninvite_user() so that notifications will be cleaned up.
80
+ */
81
+ $pending_invites = groups_get_invites( array(
82
+ 'inviter_id' => $user_id,
83
+ 'item_id' => $group_id,
84
+ ) );
85
+
86
+ if ( $pending_invites ) {
87
+ foreach ( $pending_invites as $invite ) {
88
+ groups_uninvite_user( $invite->user_id, $group_id, $user_id );
89
+ }
90
+ }
91
+ }
92
+ add_action( 'bp_groups_member_after_delete', 'groups_action_clean_up_invites_requests', 10, 2 );
bp-groups/admin/css/admin-rtl.css CHANGED
@@ -140,6 +140,39 @@ table.bp-group-members .urole-column {
140
  padding-left: 20px;
141
  }
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  @media screen and (max-width: 782px) {
144
 
145
  .bp-groups-settings-section label {
140
  padding-left: 20px;
141
  }
142
 
143
+ #group-manage-members-ui .subnav-filters .filter.last {
144
+ float: left;
145
+ }
146
+
147
+ #group-manage-members-ui .subnav-filters .left-menu {
148
+ float: right;
149
+ }
150
+
151
+ #group-manage-members-ui .subnav-filters .group-members-paginate-button:last-child {
152
+ margin-left: 2em;
153
+ }
154
+
155
+ #group-manage-members-ui .subnav-filters .dashicons {
156
+ padding-top: 2px;
157
+ }
158
+
159
+ #group-manage-members-ui .uname-column .profile-photo {
160
+ margin-left: 1em;
161
+ }
162
+
163
+ #bp-no-group-members .bp-feedback.info {
164
+ background: #fff;
165
+ border-right: 4px solid #00a0d2;
166
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
167
+ margin: 5px 5px 2px;
168
+ padding: 1px 12px;
169
+ }
170
+
171
+ #bp-no-group-members .bp-feedback.info p {
172
+ margin: 0.5em 0;
173
+ padding: 2px;
174
+ }
175
+
176
  @media screen and (max-width: 782px) {
177
 
178
  .bp-groups-settings-section label {
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:medium none}#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{border:1px solid #e5e5e5;margin-top:6px;width:100%}#bp-groups-new-members-list{margin:0}.bp-groups-settings-section{margin-top:10px;line-height:2}.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-permalink{margin-left:24px}.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}.bp-group-admin-pagination-links .page-numbers{display:inline-block;min-width:12px;border:1px solid #ccc;padding:2px 4px 4px;background:#e5e5e5;line-height:1;font-weight:400;text-align:center;text-decoration:none}.bp-group-admin-pagination-links a.page-numbers:hover{text-decoration:underline}.bp-group-admin-pagination-links .page-numbers.current,.bp-group-admin-pagination-links .page-numbers.dots{border-color:#ddd;background:#f7f7f7;color:#a0a5aa}table.bp-group-members .uid-column{padding-right:20px;padding-left:20px}table.bp-group-members .uname-column{width:70%}table.bp-group-members .urole-column{padding-right:20px;padding-left:20px}@media screen and (max-width:782px){.bp-groups-settings-section label{margin:.25em 0}}
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:medium none}#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{border:1px solid #e5e5e5;margin-top:6px;width:100%}#bp-groups-new-members-list{margin:0}.bp-groups-settings-section{margin-top:10px;line-height:2}.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-permalink{margin-left:24px}.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}.bp-group-admin-pagination-links .page-numbers{display:inline-block;min-width:12px;border:1px solid #ccc;padding:2px 4px 4px;background:#e5e5e5;line-height:1;font-weight:400;text-align:center;text-decoration:none}.bp-group-admin-pagination-links a.page-numbers:hover{text-decoration:underline}.bp-group-admin-pagination-links .page-numbers.current,.bp-group-admin-pagination-links .page-numbers.dots{border-color:#ddd;background:#f7f7f7;color:#a0a5aa}table.bp-group-members .uid-column{padding-right:20px;padding-left:20px}table.bp-group-members .uname-column{width:70%}table.bp-group-members .urole-column{padding-right:20px;padding-left:20px}#group-manage-members-ui .subnav-filters .filter.last{float:left}#group-manage-members-ui .subnav-filters .left-menu{float:right}#group-manage-members-ui .subnav-filters .group-members-paginate-button:last-child{margin-left:2em}#group-manage-members-ui .subnav-filters .dashicons{padding-top:2px}#group-manage-members-ui .uname-column .profile-photo{margin-left:1em}#bp-no-group-members .bp-feedback.info{background:#fff;border-right:4px solid #00a0d2;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);margin:5px 5px 2px;padding:1px 12px}#bp-no-group-members .bp-feedback.info p{margin:.5em 0;padding:2px}@media screen and (max-width:782px){.bp-groups-settings-section label{margin:.25em 0}}
bp-groups/admin/css/admin.css CHANGED
@@ -140,6 +140,39 @@ table.bp-group-members .urole-column {
140
  padding-right: 20px;
141
  }
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  @media screen and (max-width: 782px) {
144
 
145
  .bp-groups-settings-section label {
140
  padding-right: 20px;
141
  }
142
 
143
+ #group-manage-members-ui .subnav-filters .filter.last {
144
+ float: right;
145
+ }
146
+
147
+ #group-manage-members-ui .subnav-filters .left-menu {
148
+ float: left;
149
+ }
150
+
151
+ #group-manage-members-ui .subnav-filters .group-members-paginate-button:last-child {
152
+ margin-right: 2em;
153
+ }
154
+
155
+ #group-manage-members-ui .subnav-filters .dashicons {
156
+ padding-top: 2px;
157
+ }
158
+
159
+ #group-manage-members-ui .uname-column .profile-photo {
160
+ margin-right: 1em;
161
+ }
162
+
163
+ #bp-no-group-members .bp-feedback.info {
164
+ background: #fff;
165
+ border-left: 4px solid #00a0d2;
166
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
167
+ margin: 5px 5px 2px;
168
+ padding: 1px 12px;
169
+ }
170
+
171
+ #bp-no-group-members .bp-feedback.info p {
172
+ margin: 0.5em 0;
173
+ padding: 2px;
174
+ }
175
+
176
  @media screen and (max-width: 782px) {
177
 
178
  .bp-groups-settings-section label {
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:medium none}#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{border:1px solid #e5e5e5;margin-top:6px;width:100%}#bp-groups-new-members-list{margin:0}.bp-groups-settings-section{margin-top:10px;line-height:2}.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-permalink{margin-right:24px}.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}.bp-group-admin-pagination-links .page-numbers{display:inline-block;min-width:12px;border:1px solid #ccc;padding:2px 4px 4px;background:#e5e5e5;line-height:1;font-weight:400;text-align:center;text-decoration:none}.bp-group-admin-pagination-links a.page-numbers:hover{text-decoration:underline}.bp-group-admin-pagination-links .page-numbers.current,.bp-group-admin-pagination-links .page-numbers.dots{border-color:#ddd;background:#f7f7f7;color:#a0a5aa}table.bp-group-members .uid-column{padding-left:20px;padding-right:20px}table.bp-group-members .uname-column{width:70%}table.bp-group-members .urole-column{padding-left:20px;padding-right:20px}@media screen and (max-width:782px){.bp-groups-settings-section label{margin:.25em 0}}
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:medium none}#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{border:1px solid #e5e5e5;margin-top:6px;width:100%}#bp-groups-new-members-list{margin:0}.bp-groups-settings-section{margin-top:10px;line-height:2}.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-permalink{margin-right:24px}.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}.bp-group-admin-pagination-links .page-numbers{display:inline-block;min-width:12px;border:1px solid #ccc;padding:2px 4px 4px;background:#e5e5e5;line-height:1;font-weight:400;text-align:center;text-decoration:none}.bp-group-admin-pagination-links a.page-numbers:hover{text-decoration:underline}.bp-group-admin-pagination-links .page-numbers.current,.bp-group-admin-pagination-links .page-numbers.dots{border-color:#ddd;background:#f7f7f7;color:#a0a5aa}table.bp-group-members .uid-column{padding-left:20px;padding-right:20px}table.bp-group-members .uname-column{width:70%}table.bp-group-members .urole-column{padding-left:20px;padding-right:20px}#group-manage-members-ui .subnav-filters .filter.last{float:right}#group-manage-members-ui .subnav-filters .left-menu{float:left}#group-manage-members-ui .subnav-filters .group-members-paginate-button:last-child{margin-right:2em}#group-manage-members-ui .subnav-filters .dashicons{padding-top:2px}#group-manage-members-ui .uname-column .profile-photo{margin-right:1em}#bp-no-group-members .bp-feedback.info{background:#fff;border-left:4px solid #00a0d2;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);margin:5px 5px 2px;padding:1px 12px}#bp-no-group-members .bp-feedback.info p{margin:.5em 0;padding:2px}@media screen and (max-width:782px){.bp-groups-settings-section label{margin:.25em 0}}
bp-groups/bp-groups-activity.php CHANGED
@@ -54,6 +54,15 @@ function groups_register_activity_actions() {
54
  array( 'activity', 'group', 'member', 'member_groups' )
55
  );
56
 
 
 
 
 
 
 
 
 
 
57
  /**
58
  * Fires at end of registration of the default activity actions for the Groups component.
59
  *
@@ -63,6 +72,27 @@ function groups_register_activity_actions() {
63
  }
64
  add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' );
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  /**
67
  * Format 'created_group' activity actions.
68
  *
@@ -75,7 +105,7 @@ add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' )
75
  function bp_groups_format_activity_action_created_group( $action, $activity ) {
76
  $user_link = bp_core_get_userlink( $activity->user_id );
77
 
78
- $group = groups_get_group( $activity->item_id );
79
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
80
 
81
  $action = sprintf( esc_html__( '%1$s created the group %2$s', 'buddypress'), $user_link, $group_link );
@@ -103,7 +133,7 @@ function bp_groups_format_activity_action_created_group( $action, $activity ) {
103
  function bp_groups_format_activity_action_joined_group( $action, $activity ) {
104
  $user_link = bp_core_get_userlink( $activity->user_id );
105
 
106
- $group = groups_get_group( $activity->item_id );
107
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
108
 
109
  $action = sprintf( esc_html__( '%1$s joined the group %2$s', 'buddypress' ), $user_link, $group_link );
@@ -142,7 +172,7 @@ function bp_groups_format_activity_action_joined_group( $action, $activity ) {
142
  function bp_groups_format_activity_action_group_details_updated( $action, $activity ) {
143
  $user_link = bp_core_get_userlink( $activity->user_id );
144
 
145
- $group = groups_get_group( $activity->item_id );
146
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
147
 
148
  /*
@@ -183,6 +213,38 @@ function bp_groups_format_activity_action_group_details_updated( $action, $activ
183
  return apply_filters( 'bp_groups_format_activity_action_joined_group', $action, $activity );
184
  }
185
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  /**
187
  * Fetch data related to groups at the beginning of an activity loop.
188
  *
@@ -440,12 +502,8 @@ function groups_record_activity( $args = '' ) {
440
 
441
  // Set the default for hide_sitewide by checking the status of the group.
442
  $hide_sitewide = false;
443
- if ( !empty( $args['item_id'] ) ) {
444
- if ( bp_get_current_group_id() == $args['item_id'] ) {
445
- $group = groups_get_current_group();
446
- } else {
447
- $group = groups_get_group( $args['item_id'] );
448
- }
449
 
450
  if ( isset( $group->status ) && 'public' != $group->status ) {
451
  $hide_sitewide = true;
@@ -470,6 +528,84 @@ function groups_record_activity( $args = '' ) {
470
  return bp_activity_add( $r );
471
  }
472
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  /**
474
  * Function used to determine if a user can comment on a group activity item.
475
  *
54
  array( 'activity', 'group', 'member', 'member_groups' )
55
  );
56
 
57
+ bp_activity_set_action(
58
+ $bp->groups->id,
59
+ 'activity_update',
60
+ __( 'Posted a status update in a Group', 'buddypress' ),
61
+ 'bp_groups_format_activity_action_group_activity_update',
62
+ __( 'Group Activity Updates', 'buddypress' ),
63
+ array( 'activity', 'group', 'member', 'member_groups' )
64
+ );
65
+
66
  /**
67
  * Fires at end of registration of the default activity actions for the Groups component.
68
  *
72
  }
73
  add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' );
74
 
75
+ /**
76
+ * Get the group object the activity belongs to.
77
+ *
78
+ * @since 5.0.0
79
+ *
80
+ * @param integer $group_id The group ID the activity is linked to.
81
+ * @return BP_Groups_Group The group object the activity belongs to.
82
+ */
83
+ function bp_groups_get_activity_group( $group_id = 0 ) {
84
+ // If displaying a specific group, check the activity belongs to it.
85
+ if ( bp_is_group() && bp_get_current_group_id() === (int) $group_id ) {
86
+ $group = groups_get_current_group();
87
+
88
+ // Otherwise get the group the activity belongs to.
89
+ } else {
90
+ $group = groups_get_group( $group_id );
91
+ }
92
+
93
+ return $group;
94
+ }
95
+
96
  /**
97
  * Format 'created_group' activity actions.
98
  *
105
  function bp_groups_format_activity_action_created_group( $action, $activity ) {
106
  $user_link = bp_core_get_userlink( $activity->user_id );
107
 
108
+ $group = bp_groups_get_activity_group( $activity->item_id );
109
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
110
 
111
  $action = sprintf( esc_html__( '%1$s created the group %2$s', 'buddypress'), $user_link, $group_link );
133
  function bp_groups_format_activity_action_joined_group( $action, $activity ) {
134
  $user_link = bp_core_get_userlink( $activity->user_id );
135
 
136
+ $group = bp_groups_get_activity_group( $activity->item_id );
137
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
138
 
139
  $action = sprintf( esc_html__( '%1$s joined the group %2$s', 'buddypress' ), $user_link, $group_link );
172
  function bp_groups_format_activity_action_group_details_updated( $action, $activity ) {
173
  $user_link = bp_core_get_userlink( $activity->user_id );
174
 
175
+ $group = bp_groups_get_activity_group( $activity->item_id );
176
  $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
177
 
178
  /*
213
  return apply_filters( 'bp_groups_format_activity_action_joined_group', $action, $activity );
214
  }
215
 
216
+ /**
217
+ * Format the action for activity updates posted in a Group.
218
+ *
219
+ * @since 5.0.0
220
+ *
221
+ * @param string $action Static activity action.
222
+ * @param object $activity Activity data object.
223
+ * @return string The formatted action for activity updates posted in a Group.
224
+ */
225
+ function bp_groups_format_activity_action_group_activity_update( $action, $activity ) {
226
+ $user_link = bp_core_get_userlink( $activity->user_id );
227
+ $group = bp_groups_get_activity_group( $activity->item_id );
228
+
229
+ $group_link = '<a href="' . esc_url( bp_get_group_permalink( $group ) ) . '">' . esc_html( $group->name ) . '</a>';
230
+
231
+ // Set the Activity update posted in a Group action.
232
+ $action = sprintf( esc_html__( '%1$s posted an update in the group %2$s', 'buddypress' ), $user_link, $group_link );
233
+
234
+ /** This filter is documented in wp-includes/deprecated.php */
235
+ $action = apply_filters_deprecated( 'groups_activity_new_update_action', array( $action ), '5.0.0', 'bp_groups_format_activity_action_group_activity_update' );
236
+
237
+ /**
238
+ * Filters the Group's activity update action.
239
+ *
240
+ * @since 5.0.0
241
+ *
242
+ * @param string $action The Group's activity update action.
243
+ * @param object $activity Activity data object.
244
+ */
245
+ return apply_filters( 'bp_groups_format_activity_action_group_activity_update', $action, $activity );
246
+ }
247
+
248
  /**
249
  * Fetch data related to groups at the beginning of an activity loop.
250
  *
502
 
503
  // Set the default for hide_sitewide by checking the status of the group.
504
  $hide_sitewide = false;
505
+ if ( ! empty( $args['item_id'] ) ) {
506
+ $group = bp_groups_get_activity_group( $args['item_id'] );
 
 
 
 
507
 
508
  if ( isset( $group->status ) && 'public' != $group->status ) {
509
  $hide_sitewide = true;
528
  return bp_activity_add( $r );
529
  }
530
 
531
+ /**
532
+ * Post an Activity status update affiliated with a group.
533
+ *
534
+ * @since 1.2.0
535
+ * @since 2.6.0 Added 'error_type' parameter to $args.
536
+ *
537
+ * @param array|string $args {
538
+ * Array of arguments.
539
+ * @type string $content The content of the update.
540
+ * @type int $user_id Optional. ID of the user posting the update. Default:
541
+ * ID of the logged-in user.
542
+ * @type int $group_id Optional. ID of the group to be affiliated with the
543
+ * update. Default: ID of the current group.
544
+ * }
545
+ * @return WP_Error|bool|int Returns the ID of the new activity item on success, or false on failure.
546
+ */
547
+ function groups_post_update( $args = '' ) {
548
+ $bp = buddypress();
549
+
550
+ $r = bp_parse_args( $args, array(
551
+ 'content' => false,
552
+ 'user_id' => bp_loggedin_user_id(),
553
+ 'group_id' => 0,
554
+ 'error_type' => 'bool'
555
+ ), 'groups_post_update' );
556
+
557
+ $group_id = (int) $r['group_id'];
558
+ if ( ! $group_id && ! empty( $bp->groups->current_group->id ) ) {
559
+ $group_id = (int) $bp->groups->current_group->id;
560
+ }
561
+
562
+ $content = $r['content'];
563
+ $user_id = (int) $r['user_id'];
564
+ if ( ! $content || ! strlen( trim( $content ) ) || ! $user_id || ! $group_id ) {
565
+ return false;
566
+ }
567
+
568
+ $bp->groups->current_group = groups_get_group( $group_id );
569
+
570
+ // Be sure the user is a member of the group before posting.
571
+ if ( ! bp_current_user_can( 'bp_moderate' ) && ! groups_is_user_member( $user_id, $group_id ) ) {
572
+ return false;
573
+ }
574
+
575
+ /**
576
+ * Filters the content for the new group activity update.
577
+ *
578
+ * @since 1.2.0
579
+ *
580
+ * @param string $content The content of the update.
581
+ */
582
+ $content_filtered = apply_filters( 'groups_activity_new_update_content', $content );
583
+
584
+ $activity_id = groups_record_activity( array(
585
+ 'user_id' => $user_id,
586
+ 'content' => $content_filtered,
587
+ 'type' => 'activity_update',
588
+ 'item_id' => $group_id,
589
+ 'error_type' => $r['error_type'],
590
+ ) );
591
+
592
+ groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
593
+
594
+ /**
595
+ * Fires after posting of an Activity status update affiliated with a group.
596
+ *
597
+ * @since 1.2.0
598
+ *
599
+ * @param string $content The content of the update.
600
+ * @param int $user_id ID of the user posting the update.
601
+ * @param int $group_id ID of the group being posted to.
602
+ * @param bool $activity_id Whether or not the activity recording succeeded.
603
+ */
604
+ do_action( 'bp_groups_posted_update', $content, $user_id, $group_id, $activity_id );
605
+
606
+ return $activity_id;
607
+ }
608
+
609
  /**
610
  * Function used to determine if a user can comment on a group activity item.
611
  *
bp-groups/bp-groups-admin.php CHANGED
@@ -202,7 +202,7 @@ function bp_groups_admin_load() {
202
  ) );
203
  wp_enqueue_style( 'bp_groups_admin_css', $bp->plugin_url . "bp-groups/admin/css/admin{$min}.css", array(), bp_get_version() );
204
 
205
- wp_style_add_data( 'bp_groups_admin_css', 'rtl', true );
206
  if ( $min ) {
207
  wp_style_add_data( 'bp_groups_admin_css', 'suffix', $min );
208
  }
@@ -891,6 +891,24 @@ function bp_groups_admin_edit_metabox_add_new_members( $item ) {
891
  * @param BP_Groups_Group $item The BP_Groups_Group object for the current group.
892
  */
893
  function bp_groups_admin_edit_metabox_members( $item ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894
 
895
  // Pull up a list of group members, so we can separate out the types
896
  // We'll also keep track of group members here to place them into a
202
  ) );
203
  wp_enqueue_style( 'bp_groups_admin_css', $bp->plugin_url . "bp-groups/admin/css/admin{$min}.css", array(), bp_get_version() );
204
 
205
+ wp_style_add_data( 'bp_groups_admin_css', 'rtl', 'replace' );
206
  if ( $min ) {
207
  wp_style_add_data( 'bp_groups_admin_css', 'suffix', $min );
208
  }
891
  * @param BP_Groups_Group $item The BP_Groups_Group object for the current group.
892
  */
893
  function bp_groups_admin_edit_metabox_members( $item ) {
894
+ // Use the BP REST API if it supported.
895
+ if ( bp_rest_api_is_available() && bp_groups_has_manage_group_members_templates() ) {
896
+ wp_enqueue_script( 'bp-group-manage-members' );
897
+ wp_localize_script(
898
+ 'bp-group-manage-members',
899
+ 'bpGroupManageMembersSettings',
900
+ bp_groups_get_group_manage_members_script_data( $item->id )
901
+ );
902
+
903
+ bp_get_template_part( 'common/js-templates/group-members/index' );
904
+
905
+ /**
906
+ * Echo out the JavaScript variable.
907
+ * This seems to be required by the autocompleter, leaving this here for now...
908
+ */
909
+ echo '<script type="text/javascript">var group_id = "' . esc_js( $item->id ) . '";</script>';
910
+ return;
911
+ }
912
 
913
  // Pull up a list of group members, so we can separate out the types
914
  // We'll also keep track of group members here to place them into a
bp-groups/bp-groups-cache.php CHANGED
@@ -254,6 +254,42 @@ function bp_groups_clear_user_group_cache_on_membership_save( BP_Groups_Member $
254
  add_action( 'groups_member_before_save', 'bp_groups_clear_user_group_cache_on_membership_save' );
255
  add_action( 'groups_member_before_remove', 'bp_groups_clear_user_group_cache_on_membership_save' );
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  /**
258
  * Clear group memberships cache on miscellaneous actions not covered by the 'after_save' hook.
259
  *
@@ -269,8 +305,6 @@ function bp_groups_clear_user_group_cache_on_other_events( $user_id, $group_id )
269
  wp_cache_delete( $membership->id, 'bp_groups_memberships' );
270
  }
271
  add_action( 'bp_groups_member_before_delete', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
272
- add_action( 'bp_groups_member_before_delete_invite', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
273
- add_action( 'groups_accept_invite', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
274
 
275
  /**
276
  * Reset cache incrementor for the Groups component.
254
  add_action( 'groups_member_before_save', 'bp_groups_clear_user_group_cache_on_membership_save' );
255
  add_action( 'groups_member_before_remove', 'bp_groups_clear_user_group_cache_on_membership_save' );
256
 
257
+ /**
258
+ * Clear caches on saving a group invitation or request.
259
+ * The save action is called when inserting a new record or using the save() method
260
+ * to update an existing record.
261
+ *
262
+ * @since 5.0.0
263
+ *
264
+ * @param BP_Invitation object $invitation Characteristics of the invitation just saved.
265
+ */
266
+ function bp_groups_clear_user_group_cache_on_invitation_save( BP_Invitation $invitation ) {
267
+ if ( sanitize_key( 'BP_Groups_Invitation_Manager' ) !== $invitation->class ) {
268
+ return;
269
+ }
270
+
271
+ wp_cache_delete( $invitation->id, 'bp_groups_invitations_as_memberships' );
272
+ }
273
+ add_action( 'bp_invitation_after_save', 'bp_groups_clear_user_group_cache_on_invitation_save', 10, 2 );
274
+
275
+ /**
276
+ * Clear caches on invitation deletion or update.
277
+ * This also catches changes like sending an invite or marking one as accepted.
278
+ *
279
+ * @since 5.0.0
280
+ *
281
+ * @param array $args Associative array of columns/values describing invitations about to be deleted.
282
+ */
283
+ function bp_groups_clear_user_group_cache_on_invitation_change( $args ) {
284
+ $args['fields' ] = 'ids';
285
+ $affected_invitation_ids = groups_get_invites( $args );
286
+ foreach ( $affected_invitation_ids as $invitation_id ) {
287
+ wp_cache_delete( $invitation_id, 'bp_groups_invitations_as_memberships' );
288
+ }
289
+ }
290
+ add_action( 'bp_invitation_before_delete', 'bp_groups_clear_user_group_cache_on_invitation_change' );
291
+ add_action( 'bp_invitation_before_update', 'bp_groups_clear_user_group_cache_on_invitation_change' );
292
+
293
  /**
294
  * Clear group memberships cache on miscellaneous actions not covered by the 'after_save' hook.
295
  *
305
  wp_cache_delete( $membership->id, 'bp_groups_memberships' );
306
  }
307
  add_action( 'bp_groups_member_before_delete', 'bp_groups_clear_user_group_cache_on_other_events', 10, 2 );
 
 
308
 
309
  /**
310
  * Reset cache incrementor for the Groups component.
bp-groups/bp-groups-cssjs.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Groups component CSS/JS
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage GroupsScripts
7
+ * @since 5.0.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Register Groups JavaScripts.
15
+ *
16
+ * @since 5.0.0
17
+ */
18
+ function bp_groups_register_scripts() {
19
+ wp_register_script(
20
+ 'bp-group-manage-members',
21
+ sprintf( '%1$sbp-groups/js/manage-members%2$s.js', buddypress()->plugin_url, bp_core_get_minified_asset_suffix() ),
22
+ array( 'json2', 'wp-backbone', 'bp-api-request' ),
23
+ bp_get_version(),
24
+ true
25
+ );
26
+ }
27
+ add_action( 'bp_enqueue_scripts', 'bp_groups_register_scripts', 1 );
28
+ add_action( 'bp_admin_enqueue_scripts', 'bp_groups_register_scripts', 1 );
29
+
30
+ /**
31
+ * Get JavaScript data for the Manage Group Members UI.
32
+ *
33
+ * @since 5.0.0
34
+ *
35
+ * @param integer $group_id Required. The Group ID whose members has to be managed.
36
+ * @return array The JavaScript data.
37
+ */
38
+ function bp_groups_get_group_manage_members_script_data( $group_id = 0 ) {
39
+ if ( ! $group_id ) {
40
+ return array();
41
+ } else {
42
+ $group_id = (int) $group_id;
43
+ }
44
+
45
+ $path = sprintf( '/%1$s/%2$s/%3$s/%4$s/members?exclude_admins=false',
46
+ bp_rest_namespace(),
47
+ bp_rest_version(),
48
+ buddypress()->groups->id,
49
+ $group_id
50
+ );
51
+
52
+ $preloaded_members = array();
53
+ if ( function_exists( 'rest_preload_api_request' ) ) {
54
+ $preloaded_members = rest_preload_api_request( '', $path );
55
+ }
56
+
57
+ return array(
58
+ 'path' => remove_query_arg( 'exclude_admins', $path ),
59
+ 'preloaded' => reset( $preloaded_members ),
60
+ 'roles' => bp_groups_get_group_roles(),
61
+ );
62
+ }
bp-groups/bp-groups-filters.php CHANGED
@@ -310,10 +310,7 @@ function bp_groups_user_can_filter( $retval, $user_id, $capability, $site_id, $a
310
  * currently be a member or be banned from the group.
311
  */
312
  $group = groups_get_group( $group_id );
313
- if ( in_array( bp_get_group_status( $group ), array( 'private', 'hidden' ), true )
314
- && ! groups_is_user_member( $user_id, $group->id )
315
- && ! groups_is_user_banned( $user_id, $group->id )
316
- ) {
317
  $retval = true;
318
  }
319
  break;
@@ -370,29 +367,34 @@ add_filter( 'bp_user_can', 'bp_groups_user_can_filter', 10, 5 );
370
  * Registers Groups personal data exporters.
371
  *
372
  * @since 4.0.0
 
373
  *
374
  * @param array $exporters An array of personal data exporters.
375
  * @return array An array of personal data exporters.
376
  */
377
  function bp_groups_register_personal_data_exporters( $exporters ) {
378
  $exporters['buddypress-groups-memberships'] = array(
379
- 'exporter_friendly_name' => __( 'BuddyPress Group Memberships', 'buddypress' ),
380
- 'callback' => 'bp_groups_memberships_personal_data_exporter',
 
381
  );
382
 
383
  $exporters['buddypress-groups-pending-requests'] = array(
384
- 'exporter_friendly_name' => __( 'BuddyPress Pending Group Membership Requests', 'buddypress' ),
385
- 'callback' => 'bp_groups_pending_requests_personal_data_exporter',
 
386
  );
387
 
388
  $exporters['buddypress-groups-pending-received-invitations'] = array(
389
- 'exporter_friendly_name' => __( 'BuddyPress Pending Group Invitations (Received)', 'buddypress' ),
390
- 'callback' => 'bp_groups_pending_received_invitations_personal_data_exporter',
 
391
  );
392
 
393
  $exporters['buddypress-groups-pending-sent-invitations'] = array(
394
- 'exporter_friendly_name' => __( 'BuddyPress Pending Group Invitations (Sent)', 'buddypress' ),
395
- 'callback' => 'bp_groups_pending_sent_invitations_personal_data_exporter',
 
396
  );
397
 
398
  return $exporters;
310
  * currently be a member or be banned from the group.
311
  */
312
  $group = groups_get_group( $group_id );
313
+ if ( ! groups_is_user_member( $user_id, $group->id ) && ! groups_is_user_banned( $user_id, $group->id ) ) {
 
 
 
314
  $retval = true;
315
  }
316
  break;
367
  * Registers Groups personal data exporters.
368
  *
369
  * @since 4.0.0
370
+ * @since 5.0.0 adds an `exporter_bp_friendly_name` param to exporters.
371
  *
372
  * @param array $exporters An array of personal data exporters.
373
  * @return array An array of personal data exporters.
374
  */
375
  function bp_groups_register_personal_data_exporters( $exporters ) {
376
  $exporters['buddypress-groups-memberships'] = array(
377
+ 'exporter_friendly_name' => __( 'BuddyPress Group Memberships', 'buddypress' ),
378
+ 'callback' => 'bp_groups_memberships_personal_data_exporter',
379
+ 'exporter_bp_friendly_name' => _x( 'Group Memberships', 'BuddyPress Group Memberships data exporter friendly name', 'buddypress' ),
380
  );
381
 
382
  $exporters['buddypress-groups-pending-requests'] = array(
383
+ 'exporter_friendly_name' => __( 'BuddyPress Pending Group Membership Requests', 'buddypress' ),
384
+ 'callback' => 'bp_groups_pending_requests_personal_data_exporter',
385
+ 'exporter_bp_friendly_name' => _x( 'Pending Group Membership Requests', 'BuddyPress Pending Group Membership Requests data exporter friendly name', 'buddypress' ),
386
  );
387
 
388
  $exporters['buddypress-groups-pending-received-invitations'] = array(
389
+ 'exporter_friendly_name' => __( 'BuddyPress Pending Group Invitations (Received)', 'buddypress' ),
390
+ 'callback' => 'bp_groups_pending_received_invitations_personal_data_exporter',
391
+ 'exporter_bp_friendly_name' => _x( 'Pending Group Invitations (Received)', 'BuddyPress Pending Group Invitations data exporter friendly name', 'buddypress' ),
392
  );
393
 
394
  $exporters['buddypress-groups-pending-sent-invitations'] = array(
395
+ 'exporter_friendly_name' => __( 'BuddyPress Pending Group Invitations (Sent)', 'buddypress' ),
396
+ 'callback' => 'bp_groups_pending_sent_invitations_personal_data_exporter',
397
+ 'exporter_bp_friendly_name' => _x( 'Pending Group Invitations (Sent)', 'BuddyPress Pending Group Invitations data exporter friendly name', 'buddypress' ),
398
  );
399
 
400
  return $exporters;
bp-groups/bp-groups-functions.php CHANGED
@@ -239,9 +239,10 @@ function groups_create_group( $args = '' ) {
239
  * @return bool True on success, false on failure.
240
  */
241
  function groups_edit_base_group_details( $args = array() ) {
 
242
 
243
  // Backward compatibility with old method of passing arguments.
244
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
245
  _deprecated_argument( __METHOD__, '2.9.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
246
 
247
  $old_args_keys = array(
@@ -251,7 +252,7 @@ function groups_edit_base_group_details( $args = array() ) {
251
  3 => 'notify_members',
252
  );
253
 
254
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
255
  }
256
 
257
  $r = bp_parse_args( $args, array(
@@ -689,9 +690,10 @@ function groups_get_group_mods( $group_id ) {
689
  * @return false|array Multi-d array of 'members' list and 'count'.
690
  */
691
  function groups_get_group_members( $args = array() ) {
 
692
 
693
  // Backward compatibility with old method of passing arguments.
694
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
695
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
696
 
697
  $old_args_keys = array(
@@ -704,7 +706,7 @@ function groups_get_group_members( $args = array() ) {
704
  6 => 'group_role',
705
  );
706
 
707
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
708
  }
709
 
710
  $r = bp_parse_args( $args, array(
@@ -720,7 +722,7 @@ function groups_get_group_members( $args = array() ) {
720
  ), 'groups_get_group_members' );
721
 
722
  // For legacy users. Use of BP_Groups_Member::get_all_for_group() is deprecated.
723
- if ( apply_filters( 'bp_use_legacy_group_member_query', false, __FUNCTION__, func_get_args() ) ) {
724
  $retval = BP_Groups_Member::get_all_for_group( $r['group_id'], $r['per_page'], $r['page'], $r['exclude_admins_mods'], $r['exclude_banned'], $r['exclude'] );
725
  } else {
726
 
@@ -949,6 +951,7 @@ function bp_get_user_groups( $user_id, $args = array() ) {
949
 
950
  $user_id = intval( $user_id );
951
 
 
952
  $membership_ids = wp_cache_get( $user_id, 'bp_groups_memberships_for_user' );
953
  if ( false === $membership_ids ) {
954
  $membership_ids = BP_Groups_Member::get_membership_ids_for_user( $user_id );
@@ -965,6 +968,45 @@ function bp_get_user_groups( $user_id, $args = array() ) {
965
  }
966
  }
967
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
968
  // Assemble filter array for use in `wp_list_filter()`.
969
  $filters = wp_array_slice_assoc( $r, array( 'is_confirmed', 'is_banned', 'is_admin', 'is_mod', 'invite_sent' ) );
970
  foreach ( $filters as $filter_name => $filter_value ) {
@@ -1006,6 +1048,36 @@ function bp_get_user_groups( $user_id, $args = array() ) {
1006
  $groups[ $group_id ] = $membership;
1007
  }
1008
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1009
  // By default, results are ordered by membership id.
1010
  if ( 'group_id' === $r['orderby'] ) {
1011
  ksort( $groups );
@@ -1111,6 +1183,50 @@ function groups_avatar_upload_dir( $group_id = 0 ) {
1111
 
1112
  /** Group Member Status Checks ************************************************/
1113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1114
  /**
1115
  * Check whether a user is an admin of a given group.
1116
  *
@@ -1209,24 +1325,17 @@ function groups_is_user_banned( $user_id, $group_id ) {
1209
  * Check whether a user has an outstanding invitation to a group.
1210
  *
1211
  * @since 2.6.0
 
1212
  *
1213
- * @param int $user_id ID of the user.
1214
- * @param int $group_id ID of the group.
 
 
 
1215
  * @return int|bool ID of the membership if the user is invited, otherwise false.
1216
  */
1217
- function groups_is_user_invited( $user_id, $group_id ) {
1218
- $is_invited = false;
1219
-
1220
- $user_groups = bp_get_user_groups( $user_id, array(
1221
- 'invite_sent' => true,
1222
- 'is_confirmed' => false,
1223
- ) );
1224
-
1225
- if ( isset( $user_groups[ $group_id ] ) ) {
1226
- $is_invited = $user_groups[ $group_id ]->id;
1227
- }
1228
-
1229
- return $is_invited;
1230
  }
1231
 
1232
  /**
@@ -1239,18 +1348,17 @@ function groups_is_user_invited( $user_id, $group_id ) {
1239
  * @return int|bool ID of the membership if the user is pending, otherwise false.
1240
  */
1241
  function groups_is_user_pending( $user_id, $group_id ) {
1242
- $is_pending = false;
1243
-
1244
- $user_groups = bp_get_user_groups( $user_id, array(
1245
- 'invite_sent' => false,
1246
- 'is_confirmed' => false,
1247
- ) );
1248
-
1249
- if ( isset( $user_groups[ $group_id ] ) ) {
1250
- $is_pending = $user_groups[ $group_id ]->id;
1251
  }
1252
 
1253
- return $is_pending;
 
 
 
 
 
 
1254
  }
1255
 
1256
  /**
@@ -1266,136 +1374,89 @@ function groups_is_user_creator( $user_id, $group_id ) {
1266
  return BP_Groups_Member::check_is_creator( $user_id, $group_id );
1267
  }
1268
 
1269
- /** Group Activity Posting ****************************************************/
1270
 
1271
  /**
1272
- * Post an Activity status update affiliated with a group.
1273
  *
1274
- * @since 1.2.0
1275
- * @since 2.6.0 Added 'error_type' parameter to $args.
1276
  *
1277
- * @param array|string $args {
1278
- * Array of arguments.
1279
- * @type string $content The content of the update.
1280
- * @type int $user_id Optional. ID of the user posting the update. Default:
1281
- * ID of the logged-in user.
1282
- * @type int $group_id Optional. ID of the group to be affiliated with the
1283
- * update. Default: ID of the current group.
 
1284
  * }
1285
- * @return WP_Error|bool|int Returns the ID of the new activity item on success, or false on failure.
1286
  */
1287
- function groups_post_update( $args = '' ) {
1288
- if ( ! bp_is_active( 'activity' ) ) {
1289
- return false;
1290
  }
1291
 
1292
- $bp = buddypress();
1293
-
1294
- $r = bp_parse_args( $args, array(
1295
- 'content' => false,
1296
- 'user_id' => bp_loggedin_user_id(),
1297
- 'group_id' => 0,
1298
- 'error_type' => 'bool'
1299
- ), 'groups_post_update' );
1300
- extract( $r, EXTR_SKIP );
1301
-
1302
- if ( empty( $group_id ) && !empty( $bp->groups->current_group->id ) )
1303
- $group_id = $bp->groups->current_group->id;
1304
-
1305
- if ( empty( $content ) || !strlen( trim( $content ) ) || empty( $user_id ) || empty( $group_id ) )
1306
- return false;
1307
-
1308
- $bp->groups->current_group = groups_get_group( $group_id );
1309
-
1310
- // Be sure the user is a member of the group before posting.
1311
- if ( !bp_current_user_can( 'bp_moderate' ) && !groups_is_user_member( $user_id, $group_id ) )
1312
- return false;
1313
-
1314
- // Record this in activity streams.
1315
- $activity_action = sprintf( esc_html__( '%1$s posted an update in the group %2$s', 'buddypress'), bp_core_get_userlink( $user_id ), '<a href="' . esc_url( bp_get_group_permalink( $bp->groups->current_group ) ) . '">' . esc_html( $bp->groups->current_group->name ) . '</a>' );
1316
- $activity_content = $content;
1317
-
1318
- /**
1319
- * Filters the action for the new group activity update.
1320
- *
1321
- * @since 1.2.0
1322
- *
1323
- * @param string $activity_action The new group activity update.
1324
- */
1325
- $action = apply_filters( 'groups_activity_new_update_action', $activity_action );
1326
-
1327
- /**
1328
- * Filters the content for the new group activity update.
1329
- *
1330
- * @since 1.2.0
1331
- *
1332
- * @param string $activity_content The content of the update.
1333
- */
1334
- $content_filtered = apply_filters( 'groups_activity_new_update_content', $activity_content );
1335
 
1336
- $activity_id = groups_record_activity( array(
1337
- 'user_id' => $user_id,
1338
- 'action' => $action,
1339
- 'content' => $content_filtered,
1340
- 'type' => 'activity_update',
1341
- 'item_id' => $group_id,
1342
- 'error_type' => $error_type
1343
- ) );
1344
 
1345
- groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
 
 
 
1346
 
1347
- /**
1348
- * Fires after posting of an Activity status update affiliated with a group.
1349
- *
1350
- * @since 1.2.0
1351
- *
1352
- * @param string $content The content of the update.
1353
- * @param int $user_id ID of the user posting the update.
1354
- * @param int $group_id ID of the group being posted to.
1355
- * @param bool $activity_id Whether or not the activity recording succeeded.
1356
- */
1357
- do_action( 'bp_groups_posted_update', $content, $user_id, $group_id, $activity_id );
1358
 
1359
- return $activity_id;
1360
  }
1361
 
1362
- /** Group Invitations *********************************************************/
1363
-
1364
  /**
1365
- * Get IDs of users with outstanding invites to a given group from a specified user.
1366
  *
1367
- * @since 1.0.0
1368
  *
1369
- * @param int $user_id ID of the inviting user.
1370
- * @param int|bool $limit Limit to restrict to.
1371
- * @param int|bool $page Optional. Page offset of results to return.
1372
- * @param string|array|bool $exclude Array of comma-separated list of group IDs
1373
- * to exclude from results.
1374
- * @return array $value IDs of users who have been invited to the group by the
1375
- * user but have not yet accepted.
1376
  */
1377
- function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = false, $exclude = false ) {
1378
-
1379
- if ( empty( $user_id ) )
1380
  $user_id = bp_loggedin_user_id();
 
1381
 
1382
- return BP_Groups_Member::get_invites( $user_id, $limit, $page, $exclude );
1383
  }
1384
 
1385
  /**
1386
- * Get the total group invite count for a user.
1387
  *
1388
- * @since 2.0.0
1389
  *
1390
  * @param int $user_id The user ID.
1391
- * @return int
 
1392
  */
1393
- function groups_get_invite_count_for_user( $user_id = 0 ) {
1394
  if ( empty( $user_id ) ) {
1395
  $user_id = bp_loggedin_user_id();
1396
  }
1397
 
1398
- return BP_Groups_Member::get_invite_count_for_user( $user_id );
 
 
 
 
 
 
1399
  }
1400
 
1401
  /**
@@ -1411,82 +1472,86 @@ function groups_get_invite_count_for_user( $user_id = 0 ) {
1411
  * ID of the logged-in user.
1412
  * @type string $date_modified Optional. Modified date for the invitation.
1413
  * Default: current date/time.
1414
- * @type bool $is_confirmed Optional. Whether the invitation should be
1415
- * marked confirmed. Default: false.
 
1416
  * }
1417
  * @return bool True on success, false on failure.
1418
  */
1419
  function groups_invite_user( $args = '' ) {
1420
 
1421
- $args = bp_parse_args( $args, array(
1422
  'user_id' => false,
1423
  'group_id' => false,
1424
  'inviter_id' => bp_loggedin_user_id(),
1425
  'date_modified' => bp_core_current_time(),
1426
- 'is_confirmed' => 0
 
1427
  ), 'groups_invite_user' );
1428
- extract( $args, EXTR_SKIP );
1429
 
1430
- if ( ! $user_id || ! $group_id || ! $inviter_id ) {
1431
- return false;
1432
- }
1433
-
1434
- // If the user has already requested membership, accept the request.
1435
- if ( $membership_id = groups_check_for_membership_request( $user_id, $group_id ) ) {
1436
- groups_accept_membership_request( $membership_id, $user_id, $group_id );
1437
-
1438
- // Otherwise, create a new invitation.
1439
- } elseif ( ! groups_is_user_member( $user_id, $group_id ) && ! groups_check_user_has_invite( $user_id, $group_id, 'all' ) ) {
1440
- $invite = new BP_Groups_Member;
1441
- $invite->group_id = $group_id;
1442
- $invite->user_id = $user_id;
1443
- $invite->date_modified = $date_modified;
1444
- $invite->inviter_id = $inviter_id;
1445
- $invite->is_confirmed = $is_confirmed;
1446
 
1447
- if ( !$invite->save() )
1448
- return false;
 
1449
 
1450
- /**
1451
- * Fires after the creation of a new group invite.
1452
- *
1453
- * @since 1.0.0
1454
- *
1455
- * @param array $args Array of parsed arguments for the group invite.
1456
- */
1457
- do_action( 'groups_invite_user', $args );
1458
- }
1459
 
1460
- return true;
1461
  }
1462
 
1463
  /**
1464
  * Uninvite a user from a group.
1465
  *
1466
- * Functionally, this is equivalent to removing a user from a group.
1467
- *
1468
  * @since 1.0.0
1469
  *
1470
  * @param int $user_id ID of the user.
1471
  * @param int $group_id ID of the group.
 
1472
  * @return bool True on success, false on failure.
1473
  */
1474
- function groups_uninvite_user( $user_id, $group_id ) {
1475
-
1476
- if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
1477
  return false;
 
1478
 
1479
- /**
1480
- * Fires after uninviting a user from a group.
1481
- *
1482
- * @since 1.0.0
1483
- *
1484
- * @param int $group_id ID of the group being uninvited from.
1485
- * @param int $user_id ID of the user being uninvited.
1486
- */
1487
- do_action( 'groups_uninvite_user', $group_id, $user_id );
1488
 
1489
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1490
  }
1491
 
1492
  /**
@@ -1501,137 +1566,154 @@ function groups_uninvite_user( $user_id, $group_id ) {
1501
  * @return bool True when the user is a member of the group, otherwise false.
1502
  */
1503
  function groups_accept_invite( $user_id, $group_id ) {
 
 
 
 
 
 
1504
 
1505
- // If the user is already a member (because BP at one point allowed two invitations to
1506
- // slip through), delete all existing invitations/requests and return true.
1507
- if ( groups_is_user_member( $user_id, $group_id ) ) {
1508
- if ( groups_check_user_has_invite( $user_id, $group_id ) ) {
1509
- groups_delete_invite( $user_id, $group_id );
1510
- }
1511
-
1512
- if ( groups_check_for_membership_request( $user_id, $group_id ) ) {
1513
- groups_delete_membership_request( null, $user_id, $group_id );
1514
- }
1515
-
1516
- return true;
1517
- }
1518
-
1519
- $member = new BP_Groups_Member( $user_id, $group_id );
1520
-
1521
- // Save the inviter ID so that we can pass it to the action below.
1522
- $inviter_id = $member->inviter_id;
1523
-
1524
- $member->accept_invite();
1525
-
1526
- if ( !$member->save() ) {
1527
- return false;
1528
- }
1529
-
1530
- // Remove request to join.
1531
- if ( $member->check_for_membership_request( $user_id, $group_id ) ) {
1532
- $member->delete_request( $user_id, $group_id );
1533
- }
1534
-
1535
- // Modify group meta.
1536
- groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
1537
-
1538
- /**
1539
- * Fires after a user has accepted a group invite.
1540
- *
1541
- * @since 1.0.0
1542
- * @since 2.8.0 The $inviter_id arg was added.
1543
- *
1544
- * @param int $user_id ID of the user who accepted the group invite.
1545
- * @param int $group_id ID of the group being accepted to.
1546
- * @param int $inviter_id ID of the user who invited this user to the group.
1547
- */
1548
- do_action( 'groups_accept_invite', $user_id, $group_id, $inviter_id );
1549
-
1550
- return true;
1551
  }
1552
 
1553
  /**
1554
  * Reject a group invitation.
1555
  *
1556
  * @since 1.0.0
 
 
 
 
 
1557
  *
1558
- * @param int $user_id ID of the user.
1559
- * @param int $group_id ID of the group.
1560
  * @return bool True on success, false on failure.
1561
  */
1562
- function groups_reject_invite( $user_id, $group_id ) {
1563
- if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
1564
  return false;
 
 
 
 
 
 
 
 
1565
 
1566
  /**
1567
  * Fires after a user rejects a group invitation.
1568
  *
1569
  * @since 1.0.0
 
1570
  *
1571
- * @param int $user_id ID of the user rejecting the invite.
1572
- * @param int $group_id ID of the group being rejected.
 
1573
  */
1574
- do_action( 'groups_reject_invite', $user_id, $group_id );
1575
 
1576
- return true;
1577
  }
1578
 
1579
  /**
1580
  * Delete a group invitation.
1581
  *
1582
  * @since 1.0.0
 
1583
  *
1584
  * @param int $user_id ID of the invited user.
1585
  * @param int $group_id ID of the group.
 
 
1586
  * @return bool True on success, false on failure.
1587
  */
1588
- function groups_delete_invite( $user_id, $group_id ) {
1589
- if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
1590
  return false;
 
 
 
 
 
 
 
 
1591
 
1592
  /**
1593
  * Fires after the deletion of a group invitation.
1594
  *
1595
  * @since 1.9.0
 
1596
  *
1597
  * @param int $user_id ID of the user whose invitation is being deleted.
1598
  * @param int $group_id ID of the group whose invitation is being deleted.
 
1599
  */
1600
- do_action( 'groups_delete_invite', $user_id, $group_id );
1601
 
1602
  return true;
1603
  }
1604
 
1605
  /**
1606
- * Send all pending invites by a single user to a specific group.
1607
  *
1608
  * @since 1.0.0
 
1609
  *
1610
- * @param int $user_id ID of the inviting user.
1611
- * @param int $group_id ID of the group.
 
 
 
 
 
 
1612
  */
1613
- function groups_send_invites( $user_id, $group_id ) {
 
 
 
1614
 
1615
- if ( empty( $user_id ) )
1616
- $user_id = bp_loggedin_user_id();
 
 
1617
 
1618
- // Send friend invites.
1619
- $invited_users = groups_get_invites_for_group( $user_id, $group_id );
1620
- $group = groups_get_group( $group_id );
 
 
 
 
 
 
 
1621
 
1622
- for ( $i = 0, $count = count( $invited_users ); $i < $count; ++$i ) {
1623
- $member = new BP_Groups_Member( $invited_users[$i], $group_id );
 
 
 
 
 
 
 
1624
 
1625
- // Skip if we've already sent an invite to this user.
1626
- if ( $member->invite_sent ) {
1627
- continue;
1628
- }
 
 
 
1629
 
1630
- // Send the actual invite.
1631
- groups_notification_group_invites( $group, $member, $user_id );
1632
 
1633
- $member->invite_sent = 1;
1634
- $member->save();
 
 
1635
  }
1636
 
1637
  /**
@@ -1644,11 +1726,11 @@ function groups_send_invites( $user_id, $group_id ) {
1644
  * @param array $invited_users Array of users being invited to the group.
1645
  * @param int $user_id ID of the inviting user.
1646
  */
1647
- do_action( 'groups_send_invites', $group_id, $invited_users, $user_id );
1648
  }
1649
 
1650
  /**
1651
- * Get IDs of users with outstanding invites to a given group from a specified user.
1652
  *
1653
  * @since 1.0.0
1654
  * @since 2.9.0 Added $sent as a parameter.
@@ -1666,6 +1748,22 @@ function groups_get_invites_for_group( $user_id, $group_id, $sent = null ) {
1666
  return BP_Groups_Group::get_invites( $user_id, $group_id, $sent );
1667
  }
1668
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1669
  /**
1670
  * Check to see whether a user has already been invited to a group.
1671
  *
@@ -1679,29 +1777,49 @@ function groups_get_invites_for_group( $user_id, $group_id, $sent = null ) {
1679
  * @param int $group_id ID of potential group.
1680
  * @param string $type Optional. Use 'sent' to check for sent invites,
1681
  * 'all' to check for all. Default: 'sent'.
1682
- * @return int|bool ID of the membership if found, otherwise false.
1683
  */
1684
  function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) {
1685
- $invite = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1686
 
1687
  $args = array(
1688
- 'is_confirmed' => false,
1689
- 'is_banned' => null,
1690
- 'is_admin' => null,
1691
- 'is_mod' => null,
1692
  );
1693
-
1694
- if ( 'sent' === $type ) {
1695
- $args['invite_sent'] = true;
1696
  }
1697
-
1698
- $user_groups = bp_get_user_groups( $user_id, $args );
1699
-
1700
- if ( isset( $user_groups[ $group_id ] ) && 0 !== $user_groups[ $group_id ]->inviter_id ) {
1701
- $invite = $user_groups[ $group_id ]->id;
1702
  }
1703
 
1704
- return $invite;
 
 
1705
  }
1706
 
1707
  /**
@@ -1878,42 +1996,50 @@ function groups_remove_member( $user_id, $group_id ) {
1878
  *
1879
  * @since 1.0.0
1880
  *
1881
- * @param int $requesting_user_id ID of the user requesting membership.
1882
- * @param int $group_id ID of the group.
 
 
 
 
 
 
1883
  * @return bool True on success, false on failure.
1884
  */
1885
- function groups_send_membership_request( $requesting_user_id, $group_id ) {
1886
-
1887
- // Prevent duplicate requests.
1888
- if ( groups_check_for_membership_request( $requesting_user_id, $group_id ) )
1889
- return false;
1890
 
1891
- // Check if the user is already a member or is banned.
1892
- if ( groups_is_user_member( $requesting_user_id, $group_id ) || groups_is_user_banned( $requesting_user_id, $group_id ) )
1893
- return false;
 
1894
 
1895
- // Check if the user is already invited - if so, simply accept invite.
1896
- if ( groups_check_user_has_invite( $requesting_user_id, $group_id ) ) {
1897
- groups_accept_invite( $requesting_user_id, $group_id );
1898
- return true;
1899
  }
1900
 
1901
- $requesting_user = new BP_Groups_Member;
1902
- $requesting_user->group_id = $group_id;
1903
- $requesting_user->user_id = $requesting_user_id;
1904
- $requesting_user->inviter_id = 0;
1905
- $requesting_user->is_admin = 0;
1906
- $requesting_user->user_title = '';
1907
- $requesting_user->date_modified = bp_core_current_time();
1908
- $requesting_user->is_confirmed = 0;
1909
- $requesting_user->comments = isset( $_POST['group-request-membership-comments'] ) ? $_POST['group-request-membership-comments'] : '';
 
 
 
 
1910
 
1911
- if ( $requesting_user->save() ) {
1912
- $admins = groups_get_group_admins( $group_id );
1913
 
1914
- // Saved okay, now send the email notification.
1915
- for ( $i = 0, $count = count( $admins ); $i < $count; ++$i )
1916
- groups_notification_new_membership_request( $requesting_user_id, $admins[$i]->user_id, $group_id, $requesting_user->id );
 
1917
 
1918
  /**
1919
  * Fires after the creation of a new membership request.
@@ -1923,11 +2049,11 @@ function groups_send_membership_request( $requesting_user_id, $group_id ) {
1923
  * @param int $requesting_user_id ID of the user requesting membership.
1924
  * @param array $admins Array of group admins.
1925
  * @param int $group_id ID of the group being requested to.
1926
- * @param int $requesting_user->id ID of the membership.
1927
  */
1928
- do_action( 'groups_membership_requested', $requesting_user_id, $admins, $group_id, $requesting_user->id );
1929
 
1930
- return true;
1931
  }
1932
 
1933
  return false;
@@ -1937,47 +2063,34 @@ function groups_send_membership_request( $requesting_user_id, $group_id ) {
1937
  * Accept a pending group membership request.
1938
  *
1939
  * @since 1.0.0
 
1940
  *
1941
- * @param int $membership_id ID of the membership object.
1942
- * @param int $user_id Optional. ID of the user who requested membership.
1943
  * Provide this value along with $group_id to override
1944
  * $membership_id.
1945
- * @param int $group_id Optional. ID of the group to which membership is being
1946
  * requested. Provide this value along with $user_id to
1947
  * override $membership_id.
1948
  * @return bool True on success, false on failure.
1949
  */
1950
  function groups_accept_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
1951
 
1952
- if ( !empty( $user_id ) && !empty( $group_id ) ) {
1953
- $membership = new BP_Groups_Member( $user_id, $group_id );
1954
- } else {
1955
- $membership = new BP_Groups_Member( false, false, $membership_id );
1956
  }
1957
 
1958
- $membership->accept_request();
1959
-
1960
- if ( !$membership->save() ) {
1961
  return false;
1962
  }
1963
 
1964
- // Check if the user has an outstanding invite, if so delete it.
1965
- if ( groups_check_user_has_invite( $membership->user_id, $membership->group_id ) ) {
1966
- groups_delete_invite( $membership->user_id, $membership->group_id );
1967
- }
1968
-
1969
- /**
1970
- * Fires after a group membership request has been accepted.
1971
- *
1972
- * @since 1.0.0
1973
- *
1974
- * @param int $user_id ID of the user who accepted membership.
1975
- * @param int $group_id ID of the group that was accepted membership to.
1976
- * @param bool $value If membership was accepted.
1977
- */
1978
- do_action( 'groups_membership_accepted', $membership->user_id, $membership->group_id, true );
1979
 
1980
- return true;
1981
  }
1982
 
1983
  /**
@@ -1985,7 +2098,7 @@ function groups_accept_membership_request( $membership_id, $user_id = 0, $group_
1985
  *
1986
  * @since 1.0.0
1987
  *
1988
- * @param int $membership_id ID of the membership object.
1989
  * @param int $user_id Optional. ID of the user who requested membership.
1990
  * Provide this value along with $group_id to override
1991
  * $membership_id.
@@ -1995,7 +2108,12 @@ function groups_accept_membership_request( $membership_id, $user_id = 0, $group_
1995
  * @return bool True on success, false on failure.
1996
  */
1997
  function groups_reject_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
1998
- if ( !$membership = groups_delete_membership_request( $membership_id, $user_id, $group_id ) ) {
 
 
 
 
 
1999
  return false;
2000
  }
2001
 
@@ -2008,7 +2126,7 @@ function groups_reject_membership_request( $membership_id, $user_id = 0, $group_
2008
  * @param int $group_id ID of the group that was rejected membership to.
2009
  * @param bool $value If membership was accepted.
2010
  */
2011
- do_action( 'groups_membership_rejected', $membership->user_id, $membership->group_id, false );
2012
 
2013
  return true;
2014
  }
@@ -2018,7 +2136,7 @@ function groups_reject_membership_request( $membership_id, $user_id = 0, $group_
2018
  *
2019
  * @since 1.2.0
2020
  *
2021
- * @param int $membership_id ID of the membership object.
2022
  * @param int $user_id Optional. ID of the user who requested membership.
2023
  * Provide this value along with $group_id to override
2024
  * $membership_id.
@@ -2028,15 +2146,37 @@ function groups_reject_membership_request( $membership_id, $user_id = 0, $group_
2028
  * @return false|BP_Groups_Member True on success, false on failure.
2029
  */
2030
  function groups_delete_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
2031
- if ( !empty( $user_id ) && !empty( $group_id ) )
2032
- $membership = new BP_Groups_Member( $user_id, $group_id );
2033
- else
2034
- $membership = new BP_Groups_Member( false, false, $membership_id );
2035
 
2036
- if ( ! BP_Groups_Member::delete_request( $membership->user_id, $membership->group_id ) )
2037
  return false;
 
 
 
 
 
 
 
2038
 
2039
- return $membership;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2040
  }
2041
 
2042
  /**
@@ -2046,23 +2186,64 @@ function groups_delete_membership_request( $membership_id, $user_id = 0, $group_
2046
  *
2047
  * @param int $user_id ID of the user.
2048
  * @param int $group_id ID of the group.
2049
- * @return int|bool ID of the membership if found, otherwise false.
2050
  */
2051
  function groups_check_for_membership_request( $user_id, $group_id ) {
2052
- $request = false;
 
 
2053
 
2054
- $user_groups = bp_get_user_groups( $user_id, array(
2055
- 'is_confirmed' => false,
2056
- 'is_banned' => false,
2057
- 'is_admin' => null,
2058
- 'is_mod' => null
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2059
  ) );
2060
 
2061
- if ( isset( $user_groups[ $group_id ] ) && 0 === $user_groups[ $group_id ]->inviter_id ) {
2062
- $request = $user_groups[ $group_id ]->id;
 
 
 
 
 
 
 
 
 
 
 
 
 
2063
  }
2064
 
2065
- return $request;
 
 
 
 
 
2066
  }
2067
 
2068
  /**
@@ -2073,14 +2254,20 @@ function groups_check_for_membership_request( $user_id, $group_id ) {
2073
  * @param int $group_id ID of the group.
2074
  * @return bool True on success, false on failure.
2075
  */
2076
- function groups_accept_all_pending_membership_requests( $group_id ) {
2077
- $user_ids = BP_Groups_Member::get_all_membership_request_user_ids( $group_id );
 
 
 
 
2078
 
2079
- if ( !$user_ids )
2080
  return false;
 
2081
 
2082
- foreach ( (array) $user_ids as $user_id )
2083
  groups_accept_membership_request( false, $user_id, $group_id );
 
2084
 
2085
  /**
2086
  * Fires after the acceptance of all pending membership requests to a group.
@@ -2756,14 +2943,14 @@ function bp_groups_pending_requests_personal_data_exporter( $email_address, $pag
2756
  );
2757
  }
2758
 
2759
- $requests = BP_Groups_Member::get_user_memberships( $user->ID, array(
2760
- 'type' => 'pending_request',
2761
  'page' => $page,
2762
  'per_page' => $number,
2763
  ) );
2764
 
2765
  foreach ( $requests as $request ) {
2766
- $group = groups_get_group( $request->group_id );
2767
 
2768
  $item_data = array(
2769
  array(
@@ -2822,14 +3009,14 @@ function bp_groups_pending_sent_invitations_personal_data_exporter( $email_addre
2822
  );
2823
  }
2824
 
2825
- $invitations = BP_Groups_Member::get_user_memberships( $user->ID, array(
2826
- 'type' => 'pending_sent_invitation',
2827
- 'page' => $page,
2828
- 'per_page' => $number,
2829
  ) );
2830
 
2831
  foreach ( $invitations as $invitation ) {
2832
- $group = groups_get_group( $invitation->group_id );
2833
 
2834
  $item_data = array(
2835
  array(
@@ -2892,14 +3079,14 @@ function bp_groups_pending_received_invitations_personal_data_exporter( $email_a
2892
  );
2893
  }
2894
 
2895
- $invitations = BP_Groups_Member::get_user_memberships( $user->ID, array(
2896
- 'type' => 'pending_received_invitation',
2897
  'page' => $page,
2898
  'per_page' => $number,
2899
  ) );
2900
 
2901
  foreach ( $invitations as $invitation ) {
2902
- $group = groups_get_group( $invitation->group_id );
2903
 
2904
  $item_data = array(
2905
  array(
@@ -2936,3 +3123,49 @@ function bp_groups_pending_received_invitations_personal_data_exporter( $email_a
2936
  'done' => $done,
2937
  );
2938
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  * @return bool True on success, false on failure.
240
  */
241
  function groups_edit_base_group_details( $args = array() ) {
242
+ $function_args = func_get_args();
243
 
244
  // Backward compatibility with old method of passing arguments.
245
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
246
  _deprecated_argument( __METHOD__, '2.9.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
247
 
248
  $old_args_keys = array(
252
  3 => 'notify_members',
253
  );
254
 
255
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
256
  }
257
 
258
  $r = bp_parse_args( $args, array(
690
  * @return false|array Multi-d array of 'members' list and 'count'.
691
  */
692
  function groups_get_group_members( $args = array() ) {
693
+ $function_args = func_get_args();
694
 
695
  // Backward compatibility with old method of passing arguments.
696
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
697
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
698
 
699
  $old_args_keys = array(
706
  6 => 'group_role',
707
  );
708
 
709
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
710
  }
711
 
712
  $r = bp_parse_args( $args, array(
722
  ), 'groups_get_group_members' );
723
 
724
  // For legacy users. Use of BP_Groups_Member::get_all_for_group() is deprecated.
725
+ if ( apply_filters( 'bp_use_legacy_group_member_query', false, __FUNCTION__, $function_args ) ) {
726
  $retval = BP_Groups_Member::get_all_for_group( $r['group_id'], $r['per_page'], $r['page'], $r['exclude_admins_mods'], $r['exclude_banned'], $r['exclude'] );
727
  } else {
728
 
951
 
952
  $user_id = intval( $user_id );
953
 
954
+ // Standard memberships
955
  $membership_ids = wp_cache_get( $user_id, 'bp_groups_memberships_for_user' );
956
  if ( false === $membership_ids ) {
957
  $membership_ids = BP_Groups_Member::get_membership_ids_for_user( $user_id );
968
  }
969
  }
970
 
971
+ // Prime the invitations- and requests-as-memberships cache
972
+ $invitation_ids = array();
973
+ if ( true !== $r['is_confirmed'] || false !== $r['invite_sent'] ) {
974
+ $invitation_ids = groups_get_invites( array(
975
+ 'user_id' => $user_id,
976
+ 'invite_sent' => 'all',
977
+ 'type' => 'all',
978
+ 'fields' => 'ids'
979
+ ) );
980
+
981
+ // Prime the invitations cache.
982
+ $uncached_invitation_ids = bp_get_non_cached_ids( $invitation_ids, 'bp_groups_invitations_as_memberships' );
983
+
984
+ $uncached_invitations = groups_get_invites( array(
985
+ 'ids' => $uncached_invitation_ids,
986
+ 'invite_sent' => 'all',
987
+ 'type' => 'all'
988
+ ) );
989
+ foreach ( $uncached_invitations as $uncached_invitation ) {
990
+ // Reshape the result as a membership db entry.
991
+ $invitation = new StdClass;
992
+ $invitation->id = $uncached_invitation->id;
993
+ $invitation->group_id = $uncached_invitation->item_id;
994
+ $invitation->user_id = $uncached_invitation->user_id;
995
+ $invitation->inviter_id = $uncached_invitation->inviter_id;
996
+ $invitation->is_admin = false;
997
+ $invitation->is_mod = false;
998
+ $invitation->user_title = '';
999
+ $invitation->date_modified = $uncached_invitation->date_modified;
1000
+ $invitation->comments = $uncached_invitation->content;
1001
+ $invitation->is_confirmed = false;
1002
+ $invitation->is_banned = false;
1003
+ $invitation->invite_sent = $uncached_invitation->invite_sent;
1004
+ wp_cache_set( $uncached_invitation->id, $invitation, 'bp_groups_invitations_as_memberships' );
1005
+ }
1006
+
1007
+ }
1008
+
1009
+
1010
  // Assemble filter array for use in `wp_list_filter()`.
1011
  $filters = wp_array_slice_assoc( $r, array( 'is_confirmed', 'is_banned', 'is_admin', 'is_mod', 'invite_sent' ) );
1012
  foreach ( $filters as $filter_name => $filter_value ) {
1048
  $groups[ $group_id ] = $membership;
1049
  }
1050
 
1051
+ // Populate group invitations array from cache, and normalize.
1052
+ foreach ( $invitation_ids as $invitation_id ) {
1053
+ $invitation = wp_cache_get( $invitation_id, 'bp_groups_invitations_as_memberships' );
1054
+
1055
+ // Sanity check.
1056
+ if ( ! isset( $invitation->group_id ) ) {
1057
+ continue;
1058
+ }
1059
+
1060
+ // Integer values.
1061
+ foreach ( $int_keys as $index ) {
1062
+ $invitation->{$index} = intval( $invitation->{$index} );
1063
+ }
1064
+
1065
+ // Boolean values.
1066
+ foreach ( $bool_keys as $index ) {
1067
+ $invitation->{$index} = (bool) $invitation->{$index};
1068
+ }
1069
+
1070
+ foreach ( $filters as $filter_name => $filter_value ) {
1071
+ if ( ! isset( $invitation->{$filter_name} ) || $filter_value != $invitation->{$filter_name} ) {
1072
+ continue 2;
1073
+ }
1074
+ }
1075
+
1076
+ $group_id = (int) $invitation->group_id;
1077
+
1078
+ $groups[ $group_id ] = $invitation;
1079
+ }
1080
+
1081
  // By default, results are ordered by membership id.
1082
  if ( 'group_id' === $r['orderby'] ) {
1083
  ksort( $groups );
1183
 
1184
  /** Group Member Status Checks ************************************************/
1185
 
1186
+ /**
1187
+ * Get the Group roles.
1188
+ *
1189
+ * @since 5.0.0
1190
+ *
1191
+ * @return array The list of Group role objects.
1192
+ */
1193
+ function bp_groups_get_group_roles() {
1194
+ return array(
1195
+ 'admin' => (object) array(
1196
+ 'id' => 'admin',
1197
+ 'name' => __( 'Administrator', 'buddypress' ),
1198
+ 'is_admin' => true,
1199
+ 'is_banned' => false,
1200
+ 'is_confirmed' => true,
1201
+ 'is_mod' => false,
1202
+ ),
1203
+ 'mod' => (object) array(
1204
+ 'id' => 'mod',
1205
+ 'name' => __( 'Moderator', 'buddypress' ),
1206
+ 'is_admin' => false,
1207
+ 'is_banned' => false,
1208
+ 'is_confirmed' => true,
1209
+ 'is_mod' => true,
1210
+ ),
1211
+ 'member' => (object) array(
1212
+ 'id' => 'member',
1213
+ 'name' => __( 'Member', 'buddypress' ),
1214
+ 'is_admin' => false,
1215
+ 'is_banned' => false,
1216
+ 'is_confirmed' => true,
1217
+ 'is_mod' => false,
1218
+ ),
1219
+ 'banned' => (object) array(
1220
+ 'id' => 'banned',
1221
+ 'name' => __( 'Banned', 'buddypress' ),
1222
+ 'is_admin' => false,
1223
+ 'is_banned' => true,
1224
+ 'is_confirmed' => true,
1225
+ 'is_mod' => false,
1226
+ ),
1227
+ );
1228
+ }
1229
+
1230
  /**
1231
  * Check whether a user is an admin of a given group.
1232
  *
1325
  * Check whether a user has an outstanding invitation to a group.
1326
  *
1327
  * @since 2.6.0
1328
+ * @since 5.0.0 Added $type parameter.
1329
  *
1330
+ * @param int $user_id ID of the user.
1331
+ * @param int $group_id ID of the group.
1332
+ * @param string $type If 'sent', results are limited to those invitations
1333
+ * that have actually been sent (non-draft).
1334
+ * Possible values: 'sent', 'draft', or 'all' Default: 'sent'.
1335
  * @return int|bool ID of the membership if the user is invited, otherwise false.
1336
  */
1337
+ function groups_is_user_invited( $user_id, $group_id, $type = 'sent' ) {
1338
+ return groups_check_has_invite_from_user( $user_id, $group_id, false, $type );
 
 
 
 
 
 
 
 
 
 
 
1339
  }
1340
 
1341
  /**
1348
  * @return int|bool ID of the membership if the user is pending, otherwise false.
1349
  */
1350
  function groups_is_user_pending( $user_id, $group_id ) {
1351
+ if ( empty( $user_id ) || empty( $group_id ) ) {
1352
+ return false;
 
 
 
 
 
 
 
1353
  }
1354
 
1355
+ $args = array(
1356
+ 'user_id' => $user_id,
1357
+ 'item_id' => $group_id,
1358
+ );
1359
+ $invites_class = new BP_Groups_Invitation_Manager();
1360
+
1361
+ return $invites_class->request_exists( $args );
1362
  }
1363
 
1364
  /**
1374
  return BP_Groups_Member::check_is_creator( $user_id, $group_id );
1375
  }
1376
 
1377
+ /** Group Invitations *********************************************************/
1378
 
1379
  /**
1380
+ * Get group objects for groups that a user is currently invited to.
1381
  *
1382
+ * @since 1.0.0
 
1383
  *
1384
+ * @param int $user_id ID of the invited user.
1385
+ * @param int|bool $limit Limit to restrict to.
1386
+ * @param int|bool $page Optional. Page offset of results to return.
1387
+ * @param string|array|bool $exclude Array of comma-separated list of group IDs
1388
+ * to exclude from results.
1389
+ * @return array {
1390
+ * @type array $groups Array of groups returned by paginated query.
1391
+ * @type int $total Count of groups matching query.
1392
  * }
 
1393
  */
1394
+ function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = false, $exclude = false ) {
1395
+ if ( empty( $user_id ) ) {
1396
+ $user_id = bp_loggedin_user_id();
1397
  }
1398
 
1399
+ $group_ids = groups_get_invited_to_group_ids( $user_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1400
 
1401
+ // Remove excluded groups.
1402
+ if ( $exclude ) {
1403
+ $group_ids = array_diff( $group_ids, wp_parse_id_list( $exclude ) );
1404
+ }
 
 
 
 
1405
 
1406
+ // Avoid passing an empty array.
1407
+ if ( ! $group_ids ) {
1408
+ $group_ids = array( 0 );
1409
+ }
1410
 
1411
+ // Get a filtered list of groups.
1412
+ $args = array(
1413
+ 'include' => $group_ids,
1414
+ 'show_hidden' => true,
1415
+ 'per_page' => $limit,
1416
+ 'page' => $page,
1417
+ );
1418
+ $groups = groups_get_groups( $args );
 
 
 
1419
 
1420
+ return array( 'groups' => $groups['groups'], 'total' => groups_get_invite_count_for_user( $user_id ) );
1421
  }
1422
 
 
 
1423
  /**
1424
+ * Get the total group invite count for a user.
1425
  *
1426
+ * @since 2.0.0
1427
  *
1428
+ * @param int $user_id The user ID.
1429
+ * @return int
 
 
 
 
 
1430
  */
1431
+ function groups_get_invite_count_for_user( $user_id = 0 ) {
1432
+ if ( empty( $user_id ) ) {
 
1433
  $user_id = bp_loggedin_user_id();
1434
+ }
1435
 
1436
+ return count( groups_get_invited_to_group_ids( $user_id ) );
1437
  }
1438
 
1439
  /**
1440
+ * Get an array of group IDs to which a user is invited.
1441
  *
1442
+ * @since 5.0.0
1443
  *
1444
  * @param int $user_id The user ID.
1445
+ *
1446
+ * @return array Array of group IDs.
1447
  */
1448
+ function groups_get_invited_to_group_ids( $user_id = 0 ) {
1449
  if ( empty( $user_id ) ) {
1450
  $user_id = bp_loggedin_user_id();
1451
  }
1452
 
1453
+ $group_ids = groups_get_invites( array(
1454
+ 'user_id' => $user_id,
1455
+ 'invite_sent' => 'sent',
1456
+ 'fields' => 'item_ids'
1457
+ ) );
1458
+
1459
+ return array_unique( $group_ids );
1460
  }
1461
 
1462
  /**
1472
  * ID of the logged-in user.
1473
  * @type string $date_modified Optional. Modified date for the invitation.
1474
  * Default: current date/time.
1475
+ * @type string $content Optional. Message to invitee.
1476
+ * @type bool $send_invite Optional. Whether the invitation should be
1477
+ * sent now. Default: false.
1478
  * }
1479
  * @return bool True on success, false on failure.
1480
  */
1481
  function groups_invite_user( $args = '' ) {
1482
 
1483
+ $r = bp_parse_args( $args, array(
1484
  'user_id' => false,
1485
  'group_id' => false,
1486
  'inviter_id' => bp_loggedin_user_id(),
1487
  'date_modified' => bp_core_current_time(),
1488
+ 'content' => '',
1489
+ 'send_invite' => 0
1490
  ), 'groups_invite_user' );
 
1491
 
1492
+ $inv_args = array(
1493
+ 'user_id' => $r['user_id'],
1494
+ 'item_id' => $r['group_id'],
1495
+ 'inviter_id' => $r['inviter_id'],
1496
+ 'date_modified' => $r['date_modified'],
1497
+ 'content' => $r['content'],
1498
+ 'send_invite' => $r['send_invite']
1499
+ );
 
 
 
 
 
 
 
 
1500
 
1501
+ // Create the unsent invitataion.
1502
+ $invites_class = new BP_Groups_Invitation_Manager();
1503
+ $created = $invites_class->add_invitation( $inv_args );
1504
 
1505
+ /**
1506
+ * Fires after the creation of a new group invite.
1507
+ *
1508
+ * @since 1.0.0
1509
+ *
1510
+ * @param array $r Array of parsed arguments for the group invite.
1511
+ * @param int|bool $created The ID of the invitation or false if it couldn't be created.
1512
+ */
1513
+ do_action( 'groups_invite_user', $r, $created );
1514
 
1515
+ return $created;
1516
  }
1517
 
1518
  /**
1519
  * Uninvite a user from a group.
1520
  *
 
 
1521
  * @since 1.0.0
1522
  *
1523
  * @param int $user_id ID of the user.
1524
  * @param int $group_id ID of the group.
1525
+ * @param int $inviter_id ID of the inviter.
1526
  * @return bool True on success, false on failure.
1527
  */
1528
+ function groups_uninvite_user( $user_id, $group_id, $inviter_id = false ) {
1529
+ if ( empty( $user_id ) || empty( $group_id ) ) {
 
1530
  return false;
1531
+ }
1532
 
1533
+ $invites_class = new BP_Groups_Invitation_Manager();
1534
+ $success = $invites_class->delete( array(
1535
+ 'user_id' => $user_id,
1536
+ 'item_id' => $group_id,
1537
+ 'inviter_id' => $inviter_id,
1538
+ ) );
 
 
 
1539
 
1540
+ if ( $success ) {
1541
+ /**
1542
+ * Fires after uninviting a user from a group.
1543
+ *
1544
+ * @since 1.0.0
1545
+ * @since 2.7.0 Added $inviter_id parameter
1546
+ *
1547
+ * @param int $group_id ID of the group being uninvited from.
1548
+ * @param int $user_id ID of the user being uninvited.
1549
+ * @param int $inviter_id ID of the inviter.
1550
+ */
1551
+ do_action( 'groups_uninvite_user', $group_id, $user_id, $inviter_id );
1552
+ }
1553
+
1554
+ return $success;
1555
  }
1556
 
1557
  /**
1566
  * @return bool True when the user is a member of the group, otherwise false.
1567
  */
1568
  function groups_accept_invite( $user_id, $group_id ) {
1569
+ $invites_class = new BP_Groups_Invitation_Manager();
1570
+ $args = array(
1571
+ 'user_id' => $user_id,
1572
+ 'item_id' => $group_id,
1573
+ 'invite_sent' => 'sent',
1574
+ );
1575
 
1576
+ return $invites_class->accept_invitation( $args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1577
  }
1578
 
1579
  /**
1580
  * Reject a group invitation.
1581
  *
1582
  * @since 1.0.0
1583
+ * @since 5.0.0 The $inviter_id arg was added.
1584
+ *
1585
+ * @param int $user_id ID of the user.
1586
+ * @param int $group_id ID of the group.
1587
+ * @param int $inviter_id ID of the inviter.
1588
  *
 
 
1589
  * @return bool True on success, false on failure.
1590
  */
1591
+ function groups_reject_invite( $user_id, $group_id, $inviter_id = false ) {
1592
+ if ( empty( $user_id ) || empty( $group_id ) ) {
1593
  return false;
1594
+ }
1595
+
1596
+ $invites_class = new BP_Groups_Invitation_Manager();
1597
+ $success = $invites_class->delete( array(
1598
+ 'user_id' => $user_id,
1599
+ 'item_id' => $group_id,
1600
+ 'inviter_id' => $inviter_id,
1601
+ ) );
1602
 
1603
  /**
1604
  * Fires after a user rejects a group invitation.
1605
  *
1606
  * @since 1.0.0
1607
+ * @since 5.0.0 The $inviter_id arg was added.
1608
  *
1609
+ * @param int $user_id ID of the user rejecting the invite.
1610
+ * @param int $group_id ID of the group being rejected.
1611
+ * @param int $inviter_id ID of the inviter.
1612
  */
1613
+ do_action( 'groups_reject_invite', $user_id, $group_id, $inviter_id );
1614
 
1615
+ return $success;
1616
  }
1617
 
1618
  /**
1619
  * Delete a group invitation.
1620
  *
1621
  * @since 1.0.0
1622
+ * @since 5.0.0 The $inviter_id arg was added.
1623
  *
1624
  * @param int $user_id ID of the invited user.
1625
  * @param int $group_id ID of the group.
1626
+ * @param int $inviter_id ID of the inviter.
1627
+ *
1628
  * @return bool True on success, false on failure.
1629
  */
1630
+ function groups_delete_invite( $user_id, $group_id, $inviter_id = false ) {
1631
+ if ( empty( $user_id ) || empty( $group_id ) ) {
1632
  return false;
1633
+ }
1634
+
1635
+ $invites_class = new BP_Groups_Invitation_Manager();
1636
+ $success = $invites_class->delete( array(
1637
+ 'user_id' => $user_id,
1638
+ 'item_id' => $group_id,
1639
+ 'inviter_id' => $inviter_id,
1640
+ ) );
1641
 
1642
  /**
1643
  * Fires after the deletion of a group invitation.
1644
  *
1645
  * @since 1.9.0
1646
+ * @since 5.0.0 The $inviter_id arg was added.
1647
  *
1648
  * @param int $user_id ID of the user whose invitation is being deleted.
1649
  * @param int $group_id ID of the group whose invitation is being deleted.
1650
+ * @param int $inviter_id ID of the inviter.
1651
  */
1652
+ do_action( 'groups_delete_invite', $user_id, $group_id, $inviter_id );
1653
 
1654
  return true;
1655
  }
1656
 
1657
  /**
1658
+ * Send some or all pending invites by a single user to a specific group.
1659
  *
1660
  * @since 1.0.0
1661
+ * @since 5.0.0 Parameters changed to associative array.
1662
  *
1663
+ * @param array $args {
1664
+ * An array of optional arguments.
1665
+ * @type int $user_id ID of the invited user.
1666
+ * @type string $invitee_email Email address of the invited user, if not a member of the site.
1667
+ * @type string $group_id ID of the group or an array of group IDs.
1668
+ * @type string $inviter_id ID of the user extending the invitation.
1669
+ * @type bool $force_resend Whether to resend the email & notification if one has already been sent.
1670
+ * }
1671
  */
1672
+ function groups_send_invites( $args = array() ) {
1673
+ // Backward compatibility with old method of passing arguments.
1674
+ if ( ! is_array( $args ) || func_num_args() > 1 ) {
1675
+ _deprecated_argument( __METHOD__, '5.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
1676
 
1677
+ $old_args_keys = array(
1678
+ 0 => 'inviter_id',
1679
+ 1 => 'group_id',
1680
+ );
1681
 
1682
+ $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
1683
+ }
1684
+
1685
+ $r = bp_parse_args( $args, array(
1686
+ 'user_id' => false,
1687
+ 'invitee_email' => '',
1688
+ 'group_id' => 0,
1689
+ 'inviter_id' => bp_loggedin_user_id(),
1690
+ 'force_resend' => false,
1691
+ ), 'groups_send_invitation' );
1692
 
1693
+ /*
1694
+ * We will generally only want to fetch unsent invitations.
1695
+ * If force_resend is true, then we need to fetch both sent and draft invites.
1696
+ */
1697
+ if ( $r['force_resend'] ) {
1698
+ $args['invite_sent'] = 'all';
1699
+ } else {
1700
+ $args['invite_sent'] = 'draft';
1701
+ }
1702
 
1703
+ $args = array(
1704
+ 'user_id' => $r['user_id'],
1705
+ 'invitee_email' => $r['invitee_email'],
1706
+ 'item_id' => $r['group_id'],
1707
+ 'inviter_id' => $r['inviter_id'],
1708
+ );
1709
+ $invites = groups_get_invites( $args );
1710
 
1711
+ $invited_users = array();
 
1712
 
1713
+ $invites_class = new BP_Groups_Invitation_Manager();
1714
+ foreach ( $invites as $invite ) {
1715
+ $invited_users[] = $invite->user_id;
1716
+ $invites_class->send_invitation_by_id( $invite->id );
1717
  }
1718
 
1719
  /**
1726
  * @param array $invited_users Array of users being invited to the group.
1727
  * @param int $user_id ID of the inviting user.
1728
  */
1729
+ do_action( 'groups_send_invites', $r['group_id'], $invited_users, $r['inviter_id'] );
1730
  }
1731
 
1732
  /**
1733
+ * Get IDs of users with outstanding invites to a given group.
1734
  *
1735
  * @since 1.0.0
1736
  * @since 2.9.0 Added $sent as a parameter.
1748
  return BP_Groups_Group::get_invites( $user_id, $group_id, $sent );
1749
  }
1750
 
1751
+ /**
1752
+ * Get invitations to a given group filtered by arguments.
1753
+ *
1754
+ * @since 5.0.0
1755
+ *
1756
+ * @param int $group_id ID of the group.
1757
+ * @param array $args Invitation arguments.
1758
+ * See BP_Invitation::get() for list.
1759
+ *
1760
+ * @return array $invites Matching BP_Invitation objects.
1761
+ */
1762
+ function groups_get_invites( $args = array() ) {
1763
+ $invites_class = new BP_Groups_Invitation_Manager();
1764
+ return $invites_class->get_invitations( $args );
1765
+ }
1766
+
1767
  /**
1768
  * Check to see whether a user has already been invited to a group.
1769
  *
1777
  * @param int $group_id ID of potential group.
1778
  * @param string $type Optional. Use 'sent' to check for sent invites,
1779
  * 'all' to check for all. Default: 'sent'.
1780
+ * @return int|bool ID of the first found membership if found, otherwise false.
1781
  */
1782
  function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) {
1783
+ return groups_check_has_invite_from_user( $user_id, $group_id, false, $type );
1784
+ }
1785
+
1786
+ /**
1787
+ * Check to see whether a user has already been invited to a group by a particular user.
1788
+ *
1789
+ * By default, the function checks for invitations that have been sent.
1790
+ * Entering 'all' as the $type parameter will return unsent invitations as
1791
+ * well (useful to make sure AJAX requests are not duplicated).
1792
+ *
1793
+ * @since 5.0.0
1794
+ *
1795
+ * @param int $user_id ID of potential group member.
1796
+ * @param int $group_id ID of potential group.
1797
+ * @param string $inviter_id Optional. Use 'sent' to check for sent invites,
1798
+ * 'all' to check for all. Default: 'sent'.
1799
+ * @param string $type Optional. Specify a user ID to limit to only invited from that user.
1800
+ * Default: 'false'.
1801
+ * @return int|bool ID of the first found membership if found, otherwise false.
1802
+ */
1803
+ function groups_check_has_invite_from_user( $user_id, $group_id, $inviter_id = false, $type = 'sent' ) {
1804
+ if ( empty( $user_id ) || empty( $group_id ) ) {
1805
+ return false;
1806
+ }
1807
 
1808
  $args = array(
1809
+ 'user_id' => $user_id,
1810
+ 'item_id' => $group_id,
1811
+ 'invite_sent' => 'sent',
 
1812
  );
1813
+ if ( $inviter_id ) {
1814
+ $args['inviter_id'] = $inviter_id;
 
1815
  }
1816
+ if ( $type === 'draft' || $type === 'all' ) {
1817
+ $args['invite_sent'] = $type;
 
 
 
1818
  }
1819
 
1820
+ $invites_class = new BP_Groups_Invitation_Manager();
1821
+
1822
+ return $invites_class->invitation_exists( $args );
1823
  }
1824
 
1825
  /**
1996
  *
1997
  * @since 1.0.0
1998
  *
1999
+ * @param array|string $args {
2000
+ * Array of arguments.
2001
+ * @type int $user_id ID of the user being invited.
2002
+ * @type int $group_id ID of the group to which the user is being invited.
2003
+ * @type string $content Optional. Message to invitee.
2004
+ * @type string $date_modified Optional. Modified date for the invitation.
2005
+ * Default: current date/time.
2006
+ * }
2007
  * @return bool True on success, false on failure.
2008
  */
2009
+ function groups_send_membership_request( $args = array() ) {
2010
+ // Backward compatibility with old method of passing arguments.
2011
+ if ( ! is_array( $args ) || func_num_args() > 1 ) {
2012
+ _deprecated_argument( __METHOD__, '5.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
 
2013
 
2014
+ $old_args_keys = array(
2015
+ 0 => 'user_id',
2016
+ 1 => 'group_id',
2017
+ );
2018
 
2019
+ $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
 
 
 
2020
  }
2021
 
2022
+ $r = bp_parse_args( $args, array(
2023
+ 'user_id' => false,
2024
+ 'group_id' => false,
2025
+ 'content' => '',
2026
+ 'date_modified' => bp_core_current_time(),
2027
+ ), 'groups_send_membership_request' );
2028
+
2029
+ $inv_args = array(
2030
+ 'user_id' => $r['user_id'],
2031
+ 'item_id' => $r['group_id'],
2032
+ 'content' => $r['content'],
2033
+ 'date_modified' => $r['date_modified'],
2034
+ );
2035
 
2036
+ $invites_class = new BP_Groups_Invitation_Manager();
2037
+ $request_id = $invites_class->add_request( $inv_args );
2038
 
2039
+ // If a new request was created, send the emails.
2040
+ if ( $request_id && is_int( $request_id ) ) {
2041
+ $invites_class->send_request_notification_by_id( $request_id );
2042
+ $admins = groups_get_group_admins( $r['group_id'] );
2043
 
2044
  /**
2045
  * Fires after the creation of a new membership request.
2049
  * @param int $requesting_user_id ID of the user requesting membership.
2050
  * @param array $admins Array of group admins.
2051
  * @param int $group_id ID of the group being requested to.
2052
+ * @param int $request_id ID of the request.
2053
  */
2054
+ do_action( 'groups_membership_requested', $r['user_id'], $admins, $r['group_id'], $request_id );
2055
 
2056
+ return $request_id;
2057
  }
2058
 
2059
  return false;
2063
  * Accept a pending group membership request.
2064
  *
2065
  * @since 1.0.0
2066
+ * @since 5.0.0 Deprecated $membership_id argument.
2067
  *
2068
+ * @param int $membership_id Deprecated 5.0.0.
2069
+ * @param int $user_id Required. ID of the user who requested membership.
2070
  * Provide this value along with $group_id to override
2071
  * $membership_id.
2072
+ * @param int $group_id Required. ID of the group to which membership is being
2073
  * requested. Provide this value along with $user_id to
2074
  * override $membership_id.
2075
  * @return bool True on success, false on failure.
2076
  */
2077
  function groups_accept_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
2078
 
2079
+ if ( ! empty( $membership_id ) ) {
2080
+ _deprecated_argument( __METHOD__, '5.0.0', sprintf( __( 'Argument `membership_id` passed to %1$s is deprecated. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
 
 
2081
  }
2082
 
2083
+ if ( ! $user_id || ! $group_id ) {
 
 
2084
  return false;
2085
  }
2086
 
2087
+ $invites_class = new BP_Groups_Invitation_Manager();
2088
+ $args = array(
2089
+ 'user_id' => $user_id,
2090
+ 'item_id' => $group_id,
2091
+ );
 
 
 
 
 
 
 
 
 
 
2092
 
2093
+ return $invites_class->accept_request( $args );
2094
  }
2095
 
2096
  /**
2098
  *
2099
  * @since 1.0.0
2100
  *
2101
+ * @param int $membership_id Deprecated 5.0.0.
2102
  * @param int $user_id Optional. ID of the user who requested membership.
2103
  * Provide this value along with $group_id to override
2104
  * $membership_id.
2108
  * @return bool True on success, false on failure.
2109
  */
2110
  function groups_reject_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
2111
+
2112
+ if ( ! empty( $membership_id ) ){
2113
+ _deprecated_argument( __METHOD__, '5.0.0', sprintf( __( 'Argument `membership_id` passed to %1$s is deprecated. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
2114
+ }
2115
+
2116
+ if ( ! groups_delete_membership_request( false, $user_id, $group_id ) ) {
2117
  return false;
2118
  }
2119
 
2126
  * @param int $group_id ID of the group that was rejected membership to.
2127
  * @param bool $value If membership was accepted.
2128
  */
2129
+ do_action( 'groups_membership_rejected', $user_id, $group_id, false );
2130
 
2131
  return true;
2132
  }
2136
  *
2137
  * @since 1.2.0
2138
  *
2139
+ * @param int $membership_id Deprecated 5.0.0.
2140
  * @param int $user_id Optional. ID of the user who requested membership.
2141
  * Provide this value along with $group_id to override
2142
  * $membership_id.
2146
  * @return false|BP_Groups_Member True on success, false on failure.
2147
  */
2148
  function groups_delete_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
2149
+ if ( ! empty( $membership_id ) ){
2150
+ _deprecated_argument( __METHOD__, '5.0.0', sprintf( __( 'Argument `membership_id` passed to %1$s is deprecated. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
2151
+ }
 
2152
 
2153
+ if ( empty( $user_id ) || empty( $group_id ) ) {
2154
  return false;
2155
+ }
2156
+
2157
+ $invites_class = new BP_Groups_Invitation_Manager();
2158
+ $success = $invites_class->delete_requests( array(
2159
+ 'user_id' => $user_id,
2160
+ 'item_id' => $group_id
2161
+ ) );
2162
 
2163
+ return $success;
2164
+ }
2165
+
2166
+ /**
2167
+ * Get group membership requests filtered by arguments.
2168
+ *
2169
+ * @since 5.0.0
2170
+ *
2171
+ * @param int $group_id ID of the group.
2172
+ * @param array $args Invitation arguments.
2173
+ * See BP_Invitation::get() for list.
2174
+ *
2175
+ * @return array $requests Matching BP_Invitation objects.
2176
+ */
2177
+ function groups_get_requests( $args = array() ) {
2178
+ $invites_class = new BP_Groups_Invitation_Manager();
2179
+ return $invites_class->get_requests( $args );
2180
  }
2181
 
2182
  /**
2186
  *
2187
  * @param int $user_id ID of the user.
2188
  * @param int $group_id ID of the group.
2189
+ * @return int|bool ID of the request if found, otherwise false.
2190
  */
2191
  function groups_check_for_membership_request( $user_id, $group_id ) {
2192
+ if ( empty( $user_id ) || empty( $group_id ) ) {
2193
+ return false;
2194
+ }
2195
 
2196
+ $args = array(
2197
+ 'user_id' => $user_id,
2198
+ 'item_id' => $group_id,
2199
+ );
2200
+ $invites_class = new BP_Groups_Invitation_Manager();
2201
+
2202
+ return $invites_class->request_exists( $args );
2203
+ }
2204
+
2205
+ /**
2206
+ * Get an array of group IDs to which a user has requested membership.
2207
+ *
2208
+ * @since 5.0.0
2209
+ *
2210
+ * @param int $user_id The user ID.
2211
+ *
2212
+ * @return array Array of group IDs.
2213
+ */
2214
+ function groups_get_membership_requested_group_ids( $user_id = 0 ) {
2215
+ if ( ! $user_id ) {
2216
+ $user_id = bp_loggedin_user_id();
2217
+ }
2218
+
2219
+ $group_ids = groups_get_requests( array(
2220
+ 'user_id' => $user_id,
2221
+ 'fields' => 'item_ids'
2222
  ) );
2223
 
2224
+ return $group_ids;
2225
+ }
2226
+
2227
+ /**
2228
+ * Get an array of group IDs to which a user has requested membership.
2229
+ *
2230
+ * @since 5.0.0
2231
+ *
2232
+ * @param int $user_id The user ID.
2233
+ *
2234
+ * @return array Array of group IDs.
2235
+ */
2236
+ function groups_get_membership_requested_user_ids( $group_id = 0 ) {
2237
+ if ( ! $group_id ) {
2238
+ $group_id = bp_get_current_group_id();
2239
  }
2240
 
2241
+ $requests = groups_get_requests( array(
2242
+ 'item_id' => $group_id,
2243
+ 'fields' => 'user_ids'
2244
+ ) );
2245
+
2246
+ return $requests;
2247
  }
2248
 
2249
  /**
2254
  * @param int $group_id ID of the group.
2255
  * @return bool True on success, false on failure.
2256
  */
2257
+ function groups_accept_all_pending_membership_requests( $group_id = 0 ) {
2258
+ if ( ! $group_id ) {
2259
+ $group_id = bp_get_current_group_id();
2260
+ }
2261
+
2262
+ $user_ids = groups_get_membership_requested_user_ids( $group_id );
2263
 
2264
+ if ( ! $user_ids ) {
2265
  return false;
2266
+ }
2267
 
2268
+ foreach ( (array) $user_ids as $user_id ) {
2269
  groups_accept_membership_request( false, $user_id, $group_id );
2270
+ }
2271
 
2272
  /**
2273
  * Fires after the acceptance of all pending membership requests to a group.
2943
  );
2944
  }
2945
 
2946
+ $requests = groups_get_requests( array(
2947
+ 'user_id' => $user->ID,
2948
  'page' => $page,
2949
  'per_page' => $number,
2950
  ) );
2951
 
2952
  foreach ( $requests as $request ) {
2953
+ $group = groups_get_group( $request->item_id );
2954
 
2955
  $item_data = array(
2956
  array(
3009
  );
3010
  }
3011
 
3012
+ $invitations = groups_get_invites( array(
3013
+ 'inviter_id' => $user->ID,
3014
+ 'page' => $page,
3015
+ 'per_page' => $number,
3016
  ) );
3017
 
3018
  foreach ( $invitations as $invitation ) {
3019
+ $group = groups_get_group( $invitation->item_id );
3020
 
3021
  $item_data = array(
3022
  array(
3079
  );
3080
  }
3081
 
3082
+ $invitations = groups_get_invites( array(
3083
+ 'user_id' => $user->ID,
3084
  'page' => $page,
3085
  'per_page' => $number,
3086
  ) );
3087
 
3088
  foreach ( $invitations as $invitation ) {
3089
+ $group = groups_get_group( $invitation->item_id );
3090
 
3091
  $item_data = array(
3092
  array(
3123
  'done' => $done,
3124
  );
3125
  }
3126
+
3127
+ /**
3128
+ * Migrate invitations and requests from pre-5.0 group_members table to invitations table.
3129
+ *
3130
+ * @since 5.0.0
3131
+ */
3132
+ function bp_groups_migrate_invitations() {
3133
+ global $wpdb;
3134
+ $bp = buddypress();
3135
+
3136
+ $records = $wpdb->get_results( "SELECT id, group_id, user_id, inviter_id, date_modified, comments, invite_sent FROM {$bp->groups->table_name_members} WHERE is_confirmed = 0 AND is_banned = 0" );
3137
+ if ( empty( $records ) ) {
3138
+ return;
3139
+ }
3140
+
3141
+ $processed = array();
3142
+ $values = array();
3143
+ foreach ( $records as $record ) {
3144
+ $values[] = $wpdb->prepare(
3145
+ "(%d, %d, %s, %s, %d, %d, %s, %s, %s, %d, %d)",
3146
+ (int) $record->user_id,
3147
+ (int) $record->inviter_id,
3148
+ '',
3149
+ 'bp_groups_invitation_manager',
3150
+ (int) $record->group_id,
3151
+ 0,
3152
+ ( 0 === (int) $record->inviter_id ) ? 'request' : 'invite',
3153
+ $record->comments,
3154
+ $record->date_modified,
3155
+ (int) $record->invite_sent,
3156
+ 0
3157
+ );
3158
+ $processed[] = (int) $record->id;
3159
+ }
3160
+
3161
+ $table_name = BP_Invitation_Manager::get_table_name();
3162
+ $query = "INSERT INTO {$table_name} (user_id, inviter_id, invitee_email, class, item_id, secondary_item_id, type, content, date_modified, invite_sent, accepted) VALUES ";
3163
+ $query .= implode(', ', $values );
3164
+ $query .= ';';
3165
+ $wpdb->query( $query );
3166
+
3167
+ $ids_to_delete = implode( ',', $processed );
3168
+ if ( $ids_to_delete ) {
3169
+ $wpdb->query( "DELETE FROM {$bp->groups->table_name_members} WHERE ID IN ($ids_to_delete)" );
3170
+ }
3171
+ }
bp-groups/bp-groups-notifications.php CHANGED
@@ -143,6 +143,15 @@ function groups_notification_new_membership_request( $requesting_user_id = 0, $a
143
  'notification_type' => 'groups-membership-request',
144
  );
145
 
 
 
 
 
 
 
 
 
 
146
  $group = groups_get_group( $group_id );
147
  $args = array(
148
  'tokens' => array(
@@ -151,10 +160,10 @@ function groups_notification_new_membership_request( $requesting_user_id = 0, $a
151
  'group.name' => $group->name,
152
  'group.id' => $group_id,
153
  'group-requests.url' => esc_url( bp_get_group_permalink( $group ) . 'admin/membership-requests' ),
154
- 'membership.id' => $membership_id,
155
  'profile.url' => esc_url( bp_core_get_user_domain( $requesting_user_id ) ),
156
  'requesting-user.id' => $requesting_user_id,
157
  'requesting-user.name' => bp_core_get_user_displayname( $requesting_user_id ),
 
158
  'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
159
  ),
160
  );
@@ -289,20 +298,20 @@ add_action( 'groups_promoted_member', 'groups_notification_promoted_member', 10,
289
  *
290
  * @since 1.0.0
291
  *
292
- * @param BP_Groups_Group $group Group object.
293
- * @param BP_Groups_Member $member Member object.
294
- * @param int $inviter_user_id ID of the user who sent the invite.
295
  */
296
  function groups_notification_group_invites( &$group, &$member, $inviter_user_id ) {
297
 
298
- // Bail if member has already been invited.
299
- if ( ! empty( $member->invite_sent ) ) {
300
- return;
301
- }
302
-
303
  // @todo $inviter_ud may be used for caching, test without it
304
  $inviter_ud = bp_core_get_core_userdata( $inviter_user_id );
305
- $invited_user_id = $member->user_id;
 
 
 
 
 
306
 
307
  // Trigger a BuddyPress Notification.
308
  if ( bp_is_active( 'notifications' ) ) {
@@ -326,18 +335,30 @@ function groups_notification_group_invites( &$group, &$member, $inviter_user_id
326
  'notification_type' => 'groups-invitation',
327
  );
328
 
 
 
 
 
 
 
 
 
 
 
329
  $args = array(
330
  'tokens' => array(
331
- 'group' => $group,
332
- 'group.url' => bp_get_group_permalink( $group ),
333
- 'group.name' => $group->name,
334
- 'inviter.name' => bp_core_get_userlink( $inviter_user_id, true, false, true ),
335
- 'inviter.url' => bp_core_get_user_domain( $inviter_user_id ),
336
- 'inviter.id' => $inviter_user_id,
337
- 'invites.url' => esc_url( $invited_link . '/invites/' ),
338
- 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
 
339
  ),
340
  );
 
341
  bp_send_email( 'groups-invitation', (int) $invited_user_id, $args );
342
  }
343
 
@@ -941,6 +962,23 @@ function bp_groups_delete_group_delete_all_notifications( $group_id ) {
941
  }
942
  add_action( 'groups_delete_group', 'bp_groups_delete_group_delete_all_notifications', 10 );
943
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
944
  /**
945
  * When a demotion takes place, delete any corresponding promotion notifications.
946
  *
143
  'notification_type' => 'groups-membership-request',
144
  );
145
 
146
+ $request_message = '';
147
+ $requests = groups_get_requests( $args = array(
148
+ 'user_id' => $requesting_user_id,
149
+ 'item_id' => $group_id,
150
+ ) );
151
+ if ( $requests ) {
152
+ $request_message = current( $requests )->content;
153
+ }
154
+
155
  $group = groups_get_group( $group_id );
156
  $args = array(
157
  'tokens' => array(
160
  'group.name' => $group->name,
161
  'group.id' => $group_id,
162
  'group-requests.url' => esc_url( bp_get_group_permalink( $group ) . 'admin/membership-requests' ),
 
163
  'profile.url' => esc_url( bp_core_get_user_domain( $requesting_user_id ) ),
164
  'requesting-user.id' => $requesting_user_id,
165
  'requesting-user.name' => bp_core_get_user_displayname( $requesting_user_id ),
166
+ 'request.message' => $request_message,
167
  'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
168
  ),
169
  );
298
  *
299
  * @since 1.0.0
300
  *
301
+ * @param BP_Groups_Group $group Group object.
302
+ * @param BP_Groups_Member|int $member Member object or invited_user_id.
303
+ * @param int $inviter_user_id ID of the user who sent the invite.
304
  */
305
  function groups_notification_group_invites( &$group, &$member, $inviter_user_id ) {
306
 
 
 
 
 
 
307
  // @todo $inviter_ud may be used for caching, test without it
308
  $inviter_ud = bp_core_get_core_userdata( $inviter_user_id );
309
+
310
+ if ( $member instanceof BP_Groups_Member ) {
311
+ $invited_user_id = $member->user_id;
312
+ } else if ( is_int( $member ) ) {
313
+ $invited_user_id = $member;
314
+ }
315
 
316
  // Trigger a BuddyPress Notification.
317
  if ( bp_is_active( 'notifications' ) ) {
335
  'notification_type' => 'groups-invitation',
336
  );
337
 
338
+ $invite_message = '';
339
+ $invitations = groups_get_invites( $args = array(
340
+ 'user_id' => $invited_user_id,
341
+ 'item_id' => $group->id,
342
+ 'inviter_id' => $inviter_user_id,
343
+ ) );
344
+ if ( $invitations ) {
345
+ $invite_message = current( $invitations )->content;
346
+ }
347
+
348
  $args = array(
349
  'tokens' => array(
350
+ 'group' => $group,
351
+ 'group.url' => bp_get_group_permalink( $group ),
352
+ 'group.name' => $group->name,
353
+ 'inviter.name' => bp_core_get_userlink( $inviter_user_id, true, false, true ),
354
+ 'inviter.url' => bp_core_get_user_domain( $inviter_user_id ),
355
+ 'inviter.id' => $inviter_user_id,
356
+ 'invites.url' => esc_url( $invited_link . '/invites/' ),
357
+ 'invite.message' => $invite_message,
358
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
359
  ),
360
  );
361
+
362
  bp_send_email( 'groups-invitation', (int) $invited_user_id, $args );
363
  }
364
 
962
  }
963
  add_action( 'groups_delete_group', 'bp_groups_delete_group_delete_all_notifications', 10 );
964
 
965
+ /**
966
+ * Remove Group invite notification when a user is uninvited.
967
+ *
968
+ * @since 5.0.0
969
+ *
970
+ * @param int $group_id ID of the group being uninvited from.
971
+ * @param int $user_id ID of the user being uninvited.
972
+ */
973
+ function bp_groups_uninvite_user_delete_group_invite_notification( $group_id = 0, $user_id = 0 ) {
974
+ if ( ! bp_is_active( 'notifications' ) || ! $group_id || ! $user_id ) {
975
+ return;
976
+ }
977
+
978
+ bp_notifications_delete_notifications_by_item_id( $user_id, $group_id, buddypress()->groups->id, 'group_invite' );
979
+ }
980
+ add_action( 'groups_uninvite_user', 'bp_groups_uninvite_user_delete_group_invite_notification', 10, 2 );
981
+
982
  /**
983
  * When a demotion takes place, delete any corresponding promotion notifications.
984
  *
bp-groups/bp-groups-template.php CHANGED
@@ -875,6 +875,32 @@ function bp_group_avatar_mini( $group = false ) {
875
  ) );
876
  }
877
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
878
  /** Group cover image *********************************************************/
879
 
880
  /**
@@ -889,6 +915,36 @@ function bp_group_use_cover_image_header() {
889
  return (bool) bp_is_active( 'groups', 'cover_image' ) && ! bp_disable_group_cover_image_uploads() && bp_attachments_is_wp_version_supported();
890
  }
891
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
  /**
893
  * Output the 'last active' string for the current group in the loop.
894
  *
@@ -5430,6 +5486,12 @@ function bp_group_request_reject_link() {
5430
  function bp_get_group_request_reject_link() {
5431
  global $requests_template;
5432
 
 
 
 
 
 
 
5433
  /**
5434
  * Filters the URL to use to reject a membership request.
5435
  *
@@ -5437,7 +5499,7 @@ function bp_group_request_reject_link() {
5437
  *
5438
  * @param string $value URL to use to reject a membership request.
5439
  */
5440
- return apply_filters( 'bp_get_group_request_reject_link', wp_nonce_url( trailingslashit( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/reject/' . $requests_template->request->membership_id ), 'groups_reject_membership_request' ) );
5441
  }
5442
 
5443
  /**
@@ -5454,6 +5516,12 @@ function bp_group_request_accept_link() {
5454
  function bp_get_group_request_accept_link() {
5455
  global $requests_template;
5456
 
 
 
 
 
 
 
5457
  /**
5458
  * Filters the URL to use to accept a membership request.
5459
  *
@@ -5461,7 +5529,7 @@ function bp_group_request_accept_link() {
5461
  *
5462
  * @param string $value URL to use to accept a membership request.
5463
  */
5464
- return apply_filters( 'bp_get_group_request_accept_link', wp_nonce_url( trailingslashit( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/accept/' . $requests_template->request->membership_id ), 'groups_accept_membership_request' ) );
5465
  }
5466
 
5467
  /**
@@ -6161,3 +6229,15 @@ function bp_groups_get_profile_stats( $args = '' ) {
6161
  */
6162
  return apply_filters( 'bp_groups_get_profile_stats', $r['output'], $r );
6163
  }
 
 
 
 
 
 
 
 
 
 
 
 
875
  ) );
876
  }
877
 
878
+ /**
879
+ * Returns the group avatar URL.
880
+ *
881
+ * @since 5.0.0
882
+ *
883
+ * @param object|bool $group Optional. Group object. Default current group in loop.
884
+ * @param string $type Optional. The type of the avatar ('full' or 'thumb'). Default 'full'.
885
+ * @return string The avatar URL.
886
+ */
887
+ function bp_get_group_avatar_url( $group = false, $type = 'full' ) {
888
+ $group_id = bp_get_group_id( $group );
889
+
890
+ if ( ! $group_id ) {
891
+ return '';
892
+ }
893
+
894
+ return bp_core_fetch_avatar(
895
+ array(
896
+ 'type' => $type,
897
+ 'object' => 'group',
898
+ 'item_id' => $group_id,
899
+ 'html' => false,
900
+ )
901
+ );
902
+ }
903
+
904
  /** Group cover image *********************************************************/
905
 
906
  /**
915
  return (bool) bp_is_active( 'groups', 'cover_image' ) && ! bp_disable_group_cover_image_uploads() && bp_attachments_is_wp_version_supported();
916
  }
917
 
918
+ /**
919
+ * Returns the group cover image URL.
920
+ *
921
+ * @since 5.0.0
922
+ *
923
+ * @param object|bool $group Optional. Group object. Default current group in loop.
924
+ * @return string The cover image URL or empty string if not found.
925
+ */
926
+ function bp_get_group_cover_url( $group = false ) {
927
+ $group_id = bp_get_group_id( $group );
928
+
929
+ if ( ! $group_id ) {
930
+ return '';
931
+ }
932
+
933
+ $cover_url = bp_attachments_get_attachment(
934
+ 'url',
935
+ array(
936
+ 'object_dir' => 'groups',
937
+ 'item_id' => $group_id,
938
+ )
939
+ );
940
+
941
+ if ( ! $cover_url ) {
942
+ return '';
943
+ }
944
+
945
+ return $cover_url;
946
+ }
947
+
948
  /**
949
  * Output the 'last active' string for the current group in the loop.
950
  *
5486
  function bp_get_group_request_reject_link() {
5487
  global $requests_template;
5488
 
5489
+ $link = add_query_arg( array(
5490
+ '_wpnonce' => wp_create_nonce( 'groups_reject_membership_request' ),
5491
+ 'user_id' => $requests_template->request->user_id,
5492
+ 'action' => 'reject'
5493
+ ), trailingslashit( bp_get_group_permalink( groups_get_current_group() ) ) . 'admin/membership-requests/' );
5494
+
5495
  /**
5496
  * Filters the URL to use to reject a membership request.
5497
  *
5499
  *
5500
  * @param string $value URL to use to reject a membership request.
5501
  */
5502
+ return apply_filters( 'bp_get_group_request_reject_link', $link );
5503
  }
5504
 
5505
  /**
5516
  function bp_get_group_request_accept_link() {
5517
  global $requests_template;
5518
 
5519
+ $link = add_query_arg( array(
5520
+ '_wpnonce' => wp_create_nonce( 'groups_accept_membership_request' ),
5521
+ 'user_id' => $requests_template->request->user_id,
5522
+ 'action' => 'accept'
5523
+ ), trailingslashit( bp_get_group_permalink( groups_get_current_group() ) ) . 'admin/membership-requests/' );
5524
+
5525
  /**
5526
  * Filters the URL to use to accept a membership request.
5527
  *
5529
  *
5530
  * @param string $value URL to use to accept a membership request.
5531
  */
5532
+ return apply_filters( 'bp_get_group_request_accept_link', $link );
5533
  }
5534
 
5535
  /**
6229
  */
6230
  return apply_filters( 'bp_groups_get_profile_stats', $r['output'], $r );
6231
  }
6232
+
6233
+ /**
6234
+ * Check if the active template pack includes the Group Membership management UI templates.
6235
+ *
6236
+ * @since 5.0.0
6237
+ *
6238
+ * @return boolean True if the active template pack includes the Group Membership management UI templates.
6239
+ * False otherwise.
6240
+ */
6241
+ function bp_groups_has_manage_group_members_templates() {
6242
+ return file_exists( bp_locate_template( 'common/js-templates/group-members/index.php' ) );
6243
+ }
bp-groups/classes/class-bp-group-member-query.php CHANGED
@@ -231,7 +231,61 @@ class BP_Group_Member_Query extends BP_User_Query {
231
  $sql['orderby'] = "ORDER BY date_modified";
232
  $sql['order'] = 'first_joined' === $this->query_vars['type'] ? 'ASC' : 'DESC';
233
 
234
- $this->group_member_ids = $wpdb->get_col( "{$sql['select']} {$sql['where']} {$sql['orderby']} {$sql['order']}" );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
  /**
237
  * Filters the member IDs for the current group member query.
@@ -330,6 +384,45 @@ class BP_Group_Member_Query extends BP_User_Query {
330
  }
331
  }
332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  // Don't filter other BP_User_Query objects on the same page.
334
  remove_action( 'bp_user_query_populate_extras', array( $this, 'populate_group_member_extras' ), 10 );
335
  }
231
  $sql['orderby'] = "ORDER BY date_modified";
232
  $sql['order'] = 'first_joined' === $this->query_vars['type'] ? 'ASC' : 'DESC';
233
 
234
+ $group_member_ids = $wpdb->get_col( "{$sql['select']} {$sql['where']} {$sql['orderby']} {$sql['order']}" );
235
+
236
+ $invited_member_ids = array();
237
+
238
+ // If appropriate, fetch invitations and add them to the results.
239
+ if ( ! $is_confirmed || ! is_null( $this->query_vars['invite_sent'] ) || ! is_null( $this->query_vars['inviter_id'] ) ) {
240
+ $invite_args = array(
241
+ 'item_id' => $this->query_vars['group_id'],
242
+ 'fields' => 'user_ids',
243
+ 'type' => 'all',
244
+ );
245
+
246
+ if ( ! is_null( $this->query_vars['invite_sent'] ) ) {
247
+ $invite_args['invite_sent'] = ! empty( $this->query_vars['invite_sent'] ) ? 'sent' : 'draft';
248
+ }
249
+
250
+ // If inviter_id.
251
+ if ( ! is_null( $this->query_vars['inviter_id'] ) ) {
252
+ $inviter_id = $this->query_vars['inviter_id'];
253
+
254
+ // Empty: inviter_id = 0. (pass false, 0, or empty array).
255
+ if ( empty( $inviter_id ) ) {
256
+ $invite_args['type'] = 'request';
257
+
258
+ /*
259
+ * The string 'any' matches any non-zero value (inviter_id != 0).
260
+ * These are invitations, not requests.
261
+ */
262
+ } elseif ( 'any' === $inviter_id ) {
263
+ $invite_args['type'] = 'invite';
264
+
265
+ // Assume that a list of inviter IDs has been passed.
266
+ } else {
267
+ $invite_args['type'] = 'invite';
268
+ // Parse and sanitize.
269
+ $inviter_ids = wp_parse_id_list( $inviter_id );
270
+ if ( ! empty( $inviter_ids ) ) {
271
+ $invite_args['inviter_id'] = $inviter_ids;
272
+ }
273
+ }
274
+ }
275
+
276
+ /*
277
+ * If first_joined is the "type" of query, sort the oldest
278
+ * requests and invitations to the top.
279
+ */
280
+ if ( 'first_joined' === $this->query_vars['type'] ) {
281
+ $invite_args['order_by'] = 'date_modified';
282
+ $invite_args['sort_order'] = 'ASC';
283
+ }
284
+
285
+ $invited_member_ids = groups_get_invites( $invite_args );
286
+ }
287
+
288
+ $this->group_member_ids = array_merge( $group_member_ids, $invited_member_ids );
289
 
290
  /**
291
  * Filters the member IDs for the current group member query.
384
  }
385
  }
386
 
387
+ // Add accurate invitation info from the invitations table.
388
+ $invites = groups_get_invites( array(
389
+ 'user_id' => $user_ids_sql,
390
+ 'item_id' => $this->query_vars['group_id'],
391
+ 'type' => 'all',
392
+ ) );
393
+ foreach ( $invites as $invite ) {
394
+ if ( isset( $this->results[ $invite->user_id ] ) ) {
395
+ $this->results[ $invite->user_id ]->comments = $invite->content;
396
+ $this->results[ $invite->user_id ]->is_confirmed = 0;
397
+ $this->results[ $invite->user_id ]->invitation_id = $invite->id;
398
+ $this->results[ $invite->user_id ]->invite_sent = (int) $invite->invite_sent;
399
+ $this->results[ $invite->user_id ]->inviter_id = $invite->inviter_id;
400
+
401
+ // Backfill properties that are not being set above.
402
+ if ( ! isset( $this->results[ $invite->user_id ]->user_id ) ) {
403
+ $this->results[ $invite->user_id ]->user_id = $invite->user_id;
404
+ }
405
+ if ( ! isset( $this->results[ $invite->user_id ]->is_admin ) ) {
406
+ $this->results[ $invite->user_id ]->is_admin = 0;
407
+ }
408
+ if ( ! isset( $this->results[ $invite->user_id ]->is_mod ) ) {
409
+ $this->results[ $invite->user_id ]->is_mod = 0;
410
+ }
411
+ if ( ! isset( $this->results[ $invite->user_id ]->is_banned ) ) {
412
+ $this->results[ $invite->user_id ]->is_banned = 0;
413
+ }
414
+ if ( ! isset( $this->results[ $invite->user_id ]->date_modified ) ) {
415
+ $this->results[ $invite->user_id ]->date_modified = $invite->date_modified;
416
+ }
417
+ if ( ! isset( $this->results[ $invite->user_id ]->user_title ) ) {
418
+ $this->results[ $invite->user_id ]->user_title = '';
419
+ }
420
+ if ( ! isset( $this->results[ $invite->user_id ]->membership_id ) ) {
421
+ $this->results[ $invite->user_id ]->membership_id = 0;
422
+ }
423
+ }
424
+ }
425
+
426
  // Don't filter other BP_User_Query objects on the same page.
427
  remove_action( 'bp_user_query_populate_extras', array( $this, 'populate_group_member_extras' ), 10 );
428
  }
bp-groups/classes/class-bp-groups-component.php CHANGED
@@ -128,7 +128,8 @@ class BP_Groups_Component extends BP_Component {
128
  'template',
129
  'adminbar',
130
  'functions',
131
- 'notifications'
 
132
  );
133
 
134
  // Conditional includes.
@@ -793,7 +794,7 @@ class BP_Groups_Component extends BP_Component {
793
  $title = _x( 'Groups', 'My Account Groups', 'buddypress' );
794
  $pending = _x( 'No Pending Invites', 'My Account Groups sub nav', 'buddypress' );
795
 
796
- if ( ! empty( $count['total'] ) ) {
797
  $title = sprintf(
798
  /* translators: %s: Group invitation count for the current user */
799
  _x( 'Groups %s', 'My Account Groups nav', 'buddypress' ),
@@ -921,4 +922,28 @@ class BP_Groups_Component extends BP_Component {
921
  'public' => false,
922
  ) );
923
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
924
  }
128
  'template',
129
  'adminbar',
130
  'functions',
131
+ 'notifications',
132
+ 'cssjs',
133
  );
134
 
135
  // Conditional includes.
794
  $title = _x( 'Groups', 'My Account Groups', 'buddypress' );
795
  $pending = _x( 'No Pending Invites', 'My Account Groups sub nav', 'buddypress' );
796
 
797
+ if ( $count ) {
798
  $title = sprintf(
799
  /* translators: %s: Group invitation count for the current user */
800
  _x( 'Groups %s', 'My Account Groups nav', 'buddypress' ),
922
  'public' => false,
923
  ) );
924
  }
925
+
926
+ /**
927
+ * Init the BP REST API.
928
+ *
929
+ * @since 5.0.0
930
+ */
931
+ public function rest_api_init() {
932
+ $controller = new BP_REST_Groups_Endpoint();
933
+ $controller->register_routes();
934
+
935
+ $controller = new BP_REST_Group_Membership_Endpoint();
936
+ $controller->register_routes();
937
+
938
+ $controller = new BP_REST_Group_Invites_Endpoint();
939
+ $controller->register_routes();
940
+
941
+ $controller = new BP_REST_Group_Membership_Request_Endpoint();
942
+ $controller->register_routes();
943
+
944
+ $controller = new BP_REST_Attachments_Group_Avatar_Endpoint();
945
+ $controller->register_routes();
946
+
947
+ parent::rest_api_init();
948
+ }
949
  }
bp-groups/classes/class-bp-groups-group-members-template.php CHANGED
@@ -93,9 +93,10 @@ class BP_Groups_Group_Members_Template {
93
  * }
94
  */
95
  public function __construct( $args = array() ) {
 
96
 
97
  // Backward compatibility with old method of passing arguments.
98
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
99
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
100
 
101
  $old_args_keys = array(
@@ -108,7 +109,7 @@ class BP_Groups_Group_Members_Template {
108
  6 => 'group_role',
109
  );
110
 
111
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
112
  }
113
 
114
  $r = bp_parse_args( $args, array(
93
  * }
94
  */
95
  public function __construct( $args = array() ) {
96
+ $function_args = func_get_args();
97
 
98
  // Backward compatibility with old method of passing arguments.
99
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
100
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
101
 
102
  $old_args_keys = array(
109
  6 => 'group_role',
110
  );
111
 
112
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
113
  }
114
 
115
  $r = bp_parse_args( $args, array(
bp-groups/classes/class-bp-groups-group.php CHANGED
@@ -771,17 +771,20 @@ class BP_Groups_Group {
771
  * yet accepted.
772
  */
773
  public static function get_invites( $user_id, $group_id, $sent = null ) {
774
- global $wpdb;
775
-
776
- $bp = buddypress();
777
- $sql = $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d and is_confirmed = 0 AND inviter_id = %d", $group_id, $user_id );
778
-
779
- // Query for a specific invite sent status.
780
- if ( ! is_null( $sent ) ) {
781
- $sql .= $wpdb->prepare( ' AND invite_sent = %d', $sent );
782
  }
783
 
784
- return $wpdb->get_col( $sql );
 
 
 
 
 
785
  }
786
 
787
  /**
@@ -959,18 +962,20 @@ class BP_Groups_Group {
959
  * }
960
  */
961
  public static function get_membership_requests( $group_id, $limit = null, $page = null ) {
962
- global $wpdb;
963
-
964
- if ( !empty( $limit ) && !empty( $page ) ) {
965
- $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
 
 
 
 
966
  }
967
 
968
- $bp = buddypress();
969
-
970
- $paged_requests = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0{$pag_sql}", $group_id ) );
971
- $total_requests = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) );
972
 
973
- return array( 'requests' => $paged_requests, 'total' => $total_requests );
974
  }
975
 
976
  /**
@@ -1046,8 +1051,10 @@ class BP_Groups_Group {
1046
  public static function get( $args = array() ) {
1047
  global $wpdb;
1048
 
 
 
1049
  // Backward compatibility with old method of passing arguments.
1050
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
1051
  _deprecated_argument( __METHOD__, '1.7', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
1052
 
1053
  $old_args_keys = array(
@@ -1062,7 +1069,7 @@ class BP_Groups_Group {
1062
  8 => 'show_hidden',
1063
  );
1064
 
1065
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
1066
  }
1067
 
1068
  $defaults = array(
@@ -1635,11 +1642,15 @@ class BP_Groups_Group {
1635
  * failure.
1636
  */
1637
  public static function delete_all_invites( $group_id ) {
1638
- global $wpdb;
 
 
1639
 
1640
- $bp = buddypress();
1641
 
1642
- return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE group_id = %d AND invite_sent = 1", $group_id ) );
 
 
1643
  }
1644
 
1645
  /**
771
  * yet accepted.
772
  */
773
  public static function get_invites( $user_id, $group_id, $sent = null ) {
774
+ if ( 0 === $sent ) {
775
+ $sent_arg = 'draft';
776
+ } else if ( 1 === $sent ) {
777
+ $sent_arg = 'sent';
778
+ } else {
779
+ $sent_arg = 'all';
 
 
780
  }
781
 
782
+ return groups_get_invites( array(
783
+ 'item_id' => $group_id,
784
+ 'inviter_id' => $user_id,
785
+ 'invite_sent' => $sent_arg,
786
+ 'fields' => 'user_ids',
787
+ ) );
788
  }
789
 
790
  /**
962
  * }
963
  */
964
  public static function get_membership_requests( $group_id, $limit = null, $page = null ) {
965
+ $args = array(
966
+ 'item_id' => $group_id
967
+ );
968
+ if ( $limit ) {
969
+ $args['per_page'] = $limit;
970
+ }
971
+ if ( $page ) {
972
+ $args['page'] = $page;
973
  }
974
 
975
+ $requests = groups_get_requests( $args );
976
+ $total = count( groups_get_membership_requested_user_ids( $group_id ) );
 
 
977
 
978
+ return array( 'requests' => $requests, 'total' => $total );
979
  }
980
 
981
  /**
1051
  public static function get( $args = array() ) {
1052
  global $wpdb;
1053
 
1054
+ $function_args = func_get_args();
1055
+
1056
  // Backward compatibility with old method of passing arguments.
1057
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
1058
  _deprecated_argument( __METHOD__, '1.7', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
1059
 
1060
  $old_args_keys = array(
1069
  8 => 'show_hidden',
1070
  );
1071
 
1072
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
1073
  }
1074
 
1075
  $defaults = array(
1642
  * failure.
1643
  */
1644
  public static function delete_all_invites( $group_id ) {
1645
+ if ( empty( $group_id ) ) {
1646
+ return false;
1647
+ }
1648
 
1649
+ $invites_class = new BP_Groups_Invitation_Manager();
1650
 
1651
+ return $invites_class->delete( array(
1652
+ 'item_id' => $group_id,
1653
+ ) );
1654
  }
1655
 
1656
  /**
bp-groups/classes/class-bp-groups-invitation-manager.php ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Group invitations class.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Core
7
+ * @since 5.0.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Group invitations class.
15
+ *
16
+ * An extension of the core Invitations class that adapts the
17
+ * core logic to accommodate group invitation behavior.
18
+ *
19
+ * @since 5.0.0
20
+ */
21
+ class BP_Groups_Invitation_Manager extends BP_Invitation_Manager {
22
+ /**
23
+ * Construct parameters.
24
+ *
25
+ * @since 5.0.0
26
+ *
27
+ * @param array|string $args.
28
+ */
29
+ public function __construct( $args = '' ) {
30
+ parent::__construct();
31
+ }
32
+
33
+ /**
34
+ * This is where custom actions are added to run when notifications of an
35
+ * invitation or request need to be generated & sent.
36
+ *
37
+ * @since 5.0.0
38
+ *
39
+ * @param int $id The ID of the invitation to mark as sent.
40
+ * @return bool True on success, false on failure.
41
+ */
42
+ public function run_send_action( BP_Invitation $invitation ) {
43
+ // Notify group admins of the pending request
44
+ if ( 'request' === $invitation->type ) {
45
+ $admins = groups_get_group_admins( $invitation->item_id );
46
+
47
+ foreach ( $admins as $admin ) {
48
+ groups_notification_new_membership_request( $invitation->user_id, $admin->user_id, $invitation->item_id, $invitation->id );
49
+ }
50
+ return true;
51
+
52
+ // Notify the invitee of the invitation.
53
+ } else {
54
+ $group = groups_get_group( $invitation->item_id );
55
+ groups_notification_group_invites( $group, $invitation->user_id, $invitation->inviter_id );
56
+ return true;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * This is where custom actions are added to run when an invitation
62
+ * or request is accepted.
63
+ *
64
+ * @since 5.0.0
65
+ *
66
+ * @param string $type Are we accepting an invitation or request?
67
+ * @param array $r Parameters that describe the invitation being accepted.
68
+ * @return bool True on success, false on failure.
69
+ */
70
+ public function run_acceptance_action( $type = 'invite', $r ) {
71
+ // If the user is already a member (because BP at one point allowed two invitations to
72
+ // slip through), return early.
73
+ if ( groups_is_user_member( $r['user_id'], $r['item_id'] ) ) {
74
+ return true;
75
+ }
76
+
77
+ // Create the new membership
78
+ $member = new BP_Groups_Member( $r['user_id'], $r['item_id'] );
79
+
80
+ if ( 'request' === $type ) {
81
+ $member->accept_request();
82
+ } else {
83
+ $member->accept_invite();
84
+ }
85
+
86
+ if ( ! $member->save() ) {
87
+ return false;
88
+ }
89
+
90
+ if ( 'request' === $type ) {
91
+ /**
92
+ * Fires after a group membership request has been accepted.
93
+ *
94
+ * @since 1.0.0
95
+ *
96
+ * @param int $user_id ID of the user who accepted membership.
97
+ * @param int $group_id ID of the group that was accepted membership to.
98
+ * @param bool $value If membership was accepted.
99
+ */
100
+ do_action( 'groups_membership_accepted', $r['user_id'], $r['item_id'], true );
101
+ } else {
102
+ // Get an inviter_id from the invitation.
103
+ $invites = groups_get_invites( $r );
104
+ $inviter_id = 0;
105
+ if ( $invites ) {
106
+ $inviter_id = current( $invites )->inviter_id;
107
+ }
108
+
109
+ /**
110
+ * Fires after a user has accepted a group invite.
111
+ *
112
+ * @since 1.0.0
113
+ * @since 2.8.0 The $inviter_id arg was added.
114
+ *
115
+ * @param int $user_id ID of the user who accepted the group invite.
116
+ * @param int $group_id ID of the group being accepted to.
117
+ * @param int $inviter_id ID of the user who invited this user to the group.
118
+ */
119
+ do_action( 'groups_accept_invite', $r['user_id'], $r['item_id'], $inviter_id );
120
+ }
121
+
122
+ // Modify group meta.
123
+ groups_update_groupmeta( $r['item_id'], 'last_activity', bp_core_current_time() );
124
+
125
+ return true;
126
+ }
127
+
128
+ /**
129
+ * With group invitations, we don't need to keep the old record, so we delete rather than
130
+ * mark invitations as "accepted."
131
+ *
132
+ * @since 5.0.0
133
+ *
134
+ * @see BP_Invitation::mark_accepted_by_data()
135
+ * for a description of arguments.
136
+ *
137
+ * @param array $args.
138
+ */
139
+ public function mark_accepted( $args ) {
140
+ // Delete all existing invitations/requests to this group for this user.
141
+ $this->delete( array(
142
+ 'user_id' => $args['user_id'],
143
+ 'item_id' => $args['item_id'],
144
+ 'type' => 'all'
145
+ ) );
146
+ }
147
+
148
+ /**
149
+ * Should this invitation be created?
150
+ *
151
+ * @since 5.0.0
152
+ *
153
+ * @param array $args.
154
+ * @return bool
155
+ */
156
+ public function allow_invitation( $args ) {
157
+ // Does the inviter have this capability?
158
+ if ( ! bp_user_can( $args['inviter_id'], 'groups_send_invitation', array( 'group_id' => $args['item_id'] ) ) ) {
159
+ return false;
160
+ }
161
+
162
+ // Is the invited user eligible to receive an invitation?
163
+ if ( ! bp_user_can( $args['user_id'], 'groups_receive_invitation', array( 'group_id' => $args['item_id'] ) ) ) {
164
+ return false;
165
+ }
166
+
167
+ // Prevent duplicated invitations.
168
+ if ( groups_check_has_invite_from_user( $args['user_id'], $args['item_id'], $args['inviter_id'], 'all' ) ) {
169
+ return false;
170
+ }
171
+
172
+ return true;
173
+ }
174
+
175
+ /**
176
+ * Should this request be created?
177
+ *
178
+ * @since 5.0.0
179
+ *
180
+ * @param array $args.
181
+ * @return bool.
182
+ */
183
+ public function allow_request( $args ) {
184
+ // Does the requester have this capability? (Also checks for duplicates.)
185
+ if ( ! bp_user_can( $args['user_id'], 'groups_request_membership', array( 'group_id' => $args['item_id'] ) ) ) {
186
+ return false;
187
+ }
188
+
189
+ return true;
190
+ }
191
+ }
bp-groups/classes/class-bp-groups-invite-template.php CHANGED
@@ -78,9 +78,10 @@ class BP_Groups_Invite_Template {
78
  * @param array $args
79
  */
80
  public function __construct( $args = array() ) {
 
81
 
82
  // Backward compatibility with old method of passing arguments.
83
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
84
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
85
 
86
  $old_args_keys = array(
@@ -88,7 +89,7 @@ class BP_Groups_Invite_Template {
88
  1 => 'group_id',
89
  );
90
 
91
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
92
  }
93
 
94
  $r = bp_parse_args( $args, array(
78
  * @param array $args
79
  */
80
  public function __construct( $args = array() ) {
81
+ $function_args = func_get_args();
82
 
83
  // Backward compatibility with old method of passing arguments.
84
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
85
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
86
 
87
  $old_args_keys = array(
89
  1 => 'group_id',
90
  );
91
 
92
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
93
  }
94
 
95
  $r = bp_parse_args( $args, array(
bp-groups/classes/class-bp-groups-list-table.php CHANGED
@@ -417,12 +417,20 @@ class BP_Groups_List_Table extends WP_List_Table {
417
  * @return array Array of sortable column names.
418
  */
419
  public function get_sortable_columns() {
420
- return array(
 
 
 
 
 
 
 
 
421
  'gid' => array( 'gid', false ),
422
  'comment' => array( 'name', false ),
423
  'members' => array( 'members', false ),
424
  'last_active' => array( 'last_active', false ),
425
- );
426
  }
427
 
428
  /**
417
  * @return array Array of sortable column names.
418
  */
419
  public function get_sortable_columns() {
420
+
421
+ /**
422
+ * Filters the column names for the sortable columns.
423
+ *
424
+ * @since 5.0.0
425
+ *
426
+ * @param array $value Array of keys and their values.
427
+ */
428
+ return apply_filters( 'bp_groups_list_table_get_sortable_columns', array(
429
  'gid' => array( 'gid', false ),
430
  'comment' => array( 'name', false ),
431
  'members' => array( 'members', false ),
432
  'last_active' => array( 'last_active', false ),
433
+ ) );
434
  }
435
 
436
  /**
bp-groups/classes/class-bp-groups-member.php CHANGED
@@ -767,7 +767,7 @@ class BP_Groups_Member {
767
  }
768
 
769
  /**
770
- * Get a user's outstanding group invitations.
771
  *
772
  * @since 1.6.0
773
  *
@@ -784,22 +784,7 @@ class BP_Groups_Member {
784
  * }
785
  */
786
  public static function get_invites( $user_id, $limit = false, $page = false, $exclude = false ) {
787
- global $wpdb;
788
-
789
- $pag_sql = ( !empty( $limit ) && !empty( $page ) ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
790
-
791
- if ( !empty( $exclude ) ) {
792
- $exclude = implode( ',', wp_parse_id_list( $exclude ) );
793
- $exclude_sql = " AND g.id NOT IN ({$exclude})";
794
- } else {
795
- $exclude_sql = '';
796
- }
797
-
798
- $bp = buddypress();
799
-
800
- $paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d {$exclude_sql} ORDER BY m.date_modified ASC {$pag_sql}", $user_id ) );
801
-
802
- return array( 'groups' => $paged_groups, 'total' => self::get_invite_count_for_user( $user_id ) );
803
  }
804
 
805
  /**
@@ -811,18 +796,7 @@ class BP_Groups_Member {
811
  * @return int
812
  */
813
  public static function get_invite_count_for_user( $user_id = 0 ) {
814
- global $wpdb;
815
-
816
- $bp = buddypress();
817
-
818
- $count = wp_cache_get( $user_id, 'bp_group_invite_count' );
819
-
820
- if ( false === $count ) {
821
- $count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d", $user_id ) );
822
- wp_cache_set( $user_id, $count, 'bp_group_invite_count' );
823
- }
824
-
825
- return $count;
826
  }
827
 
828
  /**
@@ -862,15 +836,27 @@ class BP_Groups_Member {
862
 
863
  switch ( $r['type'] ) {
864
  case 'pending_request' :
865
- $sql['where'] = $wpdb->prepare( "user_id = %d AND is_confirmed = 0 AND inviter_id = 0", $user_id );
 
 
 
 
866
  break;
867
 
868
  case 'pending_received_invitation' :
869
- $sql['where'] = $wpdb->prepare( "user_id = %d AND is_confirmed = 0 AND inviter_id != 0", $user_id );
 
 
 
 
870
  break;
871
 
872
  case 'pending_sent_invitation' :
873
- $sql['where'] = $wpdb->prepare( "inviter_id = %d AND is_confirmed = 0", $user_id );
 
 
 
 
874
  break;
875
 
876
  case 'membership' :
@@ -912,20 +898,7 @@ class BP_Groups_Member {
912
  * @return int|null The ID of the invitation if found; null if not found.
913
  */
914
  public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) {
915
- global $wpdb;
916
-
917
- if ( empty( $user_id ) )
918
- return false;
919
-
920
- $bp = buddypress();
921
- $sql = "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id != 0";
922
-
923
- if ( 'sent' == $type )
924
- $sql .= " AND invite_sent = 1";
925
-
926
- $query = $wpdb->get_var( $wpdb->prepare( $sql, $user_id, $group_id ) );
927
-
928
- return is_numeric( $query ) ? (int) $query : $query;
929
  }
930
 
931
  /**
@@ -935,38 +908,27 @@ class BP_Groups_Member {
935
  *
936
  * @global WPDB $wpdb
937
  *
938
- * @param int $user_id ID of the user.
939
- * @param int $group_id ID of the group.
 
 
 
940
  * @return int Number of records deleted.
941
  */
942
- public static function delete_invite( $user_id, $group_id ) {
943
- global $wpdb;
944
-
945
- if ( empty( $user_id ) ) {
946
- return false;
947
- }
948
-
949
  /**
950
  * Fires before a group invitation is deleted.
951
  *
952
  * @since 2.6.0
 
953
  *
954
  * @param int $user_id ID of the user.
955
  * @param int $group_id ID of the group.
 
956
  */
957
- do_action( 'bp_groups_member_before_delete_invite', $user_id, $group_id );
958
-
959
- $table_name = buddypress()->groups->table_name_members;
960
 
961
- $sql = "DELETE FROM {$table_name}
962
- WHERE user_id = %d
963
- AND group_id = %d
964
- AND is_confirmed = 0
965
- AND inviter_id != 0";
966
-
967
- $prepared = $wpdb->prepare( $sql, $user_id, $group_id );
968
-
969
- return $wpdb->query( $prepared );
970
  }
971
 
972
  /**
@@ -979,14 +941,7 @@ class BP_Groups_Member {
979
  * @return int Number of records deleted.
980
  */
981
  public static function delete_request( $user_id, $group_id ) {
982
- global $wpdb;
983
-
984
- if ( empty( $user_id ) )
985
- return false;
986
-
987
- $bp = buddypress();
988
-
989
- return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id = 0 AND invite_sent = 0", $user_id, $group_id ) );
990
  }
991
 
992
  /**
@@ -1104,14 +1059,7 @@ class BP_Groups_Member {
1104
  * @return int Database ID of the membership if found; int 0 on failure.
1105
  */
1106
  public static function check_for_membership_request( $user_id, $group_id ) {
1107
- global $wpdb;
1108
-
1109
- if ( empty( $user_id ) )
1110
- return false;
1111
-
1112
- $bp = buddypress();
1113
-
1114
- return $wpdb->query( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND is_banned = 0 AND inviter_id = 0", $user_id, $group_id ) );
1115
  }
1116
 
1117
  /**
@@ -1292,11 +1240,7 @@ class BP_Groups_Member {
1292
  * @return array IDs of users with outstanding membership requests.
1293
  */
1294
  public static function get_all_membership_request_user_ids( $group_id ) {
1295
- global $wpdb;
1296
-
1297
- $bp = buddypress();
1298
-
1299
- 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 ) ) );
1300
  }
1301
 
1302
  /**
767
  }
768
 
769
  /**
770
+ * Get group objects for groups that a user is currently invited to.
771
  *
772
  * @since 1.6.0
773
  *
784
  * }
785
  */
786
  public static function get_invites( $user_id, $limit = false, $page = false, $exclude = false ) {
787
+ return groups_get_invites_for_user( $user_id, $limit, $page, $exclude );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
  }
789
 
790
  /**
796
  * @return int
797
  */
798
  public static function get_invite_count_for_user( $user_id = 0 ) {
799
+ return groups_get_invite_count_for_user( $user_id );
 
 
 
 
 
 
 
 
 
 
 
800
  }
801
 
802
  /**
836
 
837
  switch ( $r['type'] ) {
838
  case 'pending_request' :
839
+ return groups_get_requests( array(
840
+ 'user_id' => $user_id,
841
+ 'page' => $r['page'],
842
+ 'per_page' => $r['per_page'],
843
+ ) );
844
  break;
845
 
846
  case 'pending_received_invitation' :
847
+ return groups_get_invites( array(
848
+ 'user_id' => $user_id,
849
+ 'page' => $r['page'],
850
+ 'per_page' => $r['per_page'],
851
+ ) );
852
  break;
853
 
854
  case 'pending_sent_invitation' :
855
+ return groups_get_invites( array(
856
+ 'inviter_id' => $user_id,
857
+ 'page' => $r['page'],
858
+ 'per_page' => $r['per_page'],
859
+ ) );
860
  break;
861
 
862
  case 'membership' :
898
  * @return int|null The ID of the invitation if found; null if not found.
899
  */
900
  public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) {
901
+ return groups_is_user_invited( $user_id, $group_id, $type );
 
 
 
 
 
 
 
 
 
 
 
 
 
902
  }
903
 
904
  /**
908
  *
909
  * @global WPDB $wpdb
910
  *
911
+ * @param int $user_id ID of the user.
912
+ * @param int $group_id ID of the group.
913
+ * @param int $inviter_id ID of the inviter. Specify if you want to delete
914
+ * a specific invite. Leave false if you want to
915
+ * delete all invites to this group.
916
  * @return int Number of records deleted.
917
  */
918
+ public static function delete_invite( $user_id, $group_id, $inviter_id = false ) {
 
 
 
 
 
 
919
  /**
920
  * Fires before a group invitation is deleted.
921
  *
922
  * @since 2.6.0
923
+ * @since 5.0.0 Added $inviter_id
924
  *
925
  * @param int $user_id ID of the user.
926
  * @param int $group_id ID of the group.
927
+ * @param int $inviter_id ID of the inviter.
928
  */
929
+ do_action( 'bp_groups_member_before_delete_invite', $user_id, $group_id, $inviter_id );
 
 
930
 
931
+ return groups_delete_invite( $user_id, $group_id, $inviter_id );
 
 
 
 
 
 
 
 
932
  }
933
 
934
  /**
941
  * @return int Number of records deleted.
942
  */
943
  public static function delete_request( $user_id, $group_id ) {
944
+ return groups_delete_membership_request( false, $user_id, $group_id );
 
 
 
 
 
 
 
945
  }
946
 
947
  /**
1059
  * @return int Database ID of the membership if found; int 0 on failure.
1060
  */
1061
  public static function check_for_membership_request( $user_id, $group_id ) {
1062
+ return groups_is_user_pending( $user_id, $group_id );
 
 
 
 
 
 
 
1063
  }
1064
 
1065
  /**
1240
  * @return array IDs of users with outstanding membership requests.
1241
  */
1242
  public static function get_all_membership_request_user_ids( $group_id ) {
1243
+ return groups_get_membership_requested_user_ids( $group_id );
 
 
 
 
1244
  }
1245
 
1246
  /**
bp-groups/classes/class-bp-groups-membership-requests-template.php CHANGED
@@ -85,9 +85,10 @@ class BP_Groups_Membership_Requests_Template {
85
  * }
86
  */
87
  public function __construct( $args = array() ) {
 
88
 
89
  // Backward compatibility with old method of passing arguments.
90
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
91
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
92
 
93
  $old_args_keys = array(
@@ -96,7 +97,7 @@ class BP_Groups_Membership_Requests_Template {
96
  2 => 'max',
97
  );
98
 
99
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
100
  }
101
 
102
  $r = bp_parse_args( $args, array(
85
  * }
86
  */
87
  public function __construct( $args = array() ) {
88
+ $function_args = func_get_args();
89
 
90
  // Backward compatibility with old method of passing arguments.
91
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
92
  _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
93
 
94
  $old_args_keys = array(
97
  2 => 'max',
98
  );
99
 
100
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
101
  }
102
 
103
  $r = bp_parse_args( $args, array(
bp-groups/classes/class-bp-groups-template.php CHANGED
@@ -128,9 +128,10 @@ class BP_Groups_Template {
128
  * }
129
  */
130
  function __construct( $args = array() ){
 
131
 
132
  // Backward compatibility with old method of passing arguments.
133
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
134
  _deprecated_argument( __METHOD__, '1.7', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
135
 
136
  $old_args_keys = array(
@@ -148,7 +149,7 @@ class BP_Groups_Template {
148
  11 => 'page_arg',
149
  );
150
 
151
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
152
  }
153
 
154
  $defaults = array(
128
  * }
129
  */
130
  function __construct( $args = array() ){
131
+ $function_args = func_get_args();
132
 
133
  // Backward compatibility with old method of passing arguments.
134
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
135
  _deprecated_argument( __METHOD__, '1.7', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
136
 
137
  $old_args_keys = array(
149
  11 => 'page_arg',
150
  );
151
 
152
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
153
  }
154
 
155
  $defaults = array(
bp-groups/classes/class-bp-groups-widget.php CHANGED
@@ -102,8 +102,13 @@ class BP_Groups_Widget extends WP_Widget {
102
 
103
  echo $before_title . $title . $after_title;
104
 
 
105
  $max_groups = ! empty( $instance['max_groups'] ) ? (int) $instance['max_groups'] : 5;
106
 
 
 
 
 
107
  $group_args = array(
108
  'user_id' => $user_id,
109
  'type' => $instance['group_default'],
@@ -183,10 +188,12 @@ class BP_Groups_Widget extends WP_Widget {
183
  public function update( $new_instance, $old_instance ) {
184
  $instance = $old_instance;
185
 
 
 
186
  $instance['title'] = strip_tags( $new_instance['title'] );
187
- $instance['max_groups'] = strip_tags( $new_instance['max_groups'] );
188
  $instance['group_default'] = strip_tags( $new_instance['group_default'] );
189
- $instance['link_title'] = (bool) $new_instance['link_title'];
190
 
191
  return $instance;
192
  }
@@ -208,8 +215,10 @@ class BP_Groups_Widget extends WP_Widget {
208
  );
209
  $instance = bp_parse_args( (array) $instance, $defaults, 'groups_widget_form' );
210
 
 
 
211
  $title = strip_tags( $instance['title'] );
212
- $max_groups = strip_tags( $instance['max_groups'] );
213
  $group_default = strip_tags( $instance['group_default'] );
214
  $link_title = (bool) $instance['link_title'];
215
  ?>
@@ -218,7 +227,7 @@ class BP_Groups_Widget extends WP_Widget {
218
 
219
  <p><label for="<?php echo $this->get_field_id('link_title') ?>"><input type="checkbox" name="<?php echo $this->get_field_name('link_title') ?>" id="<?php echo $this->get_field_id('link_title') ?>" value="1" <?php checked( $link_title ) ?> /> <?php _e( 'Link widget title to Groups directory', 'buddypress' ) ?></label></p>
220
 
221
- <p><label for="<?php echo $this->get_field_id( 'max_groups' ); ?>"><?php _e('Max groups to show:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_groups' ); ?>" name="<?php echo $this->get_field_name( 'max_groups' ); ?>" type="text" value="<?php echo esc_attr( $max_groups ); ?>" style="width: 30%" /></label></p>
222
 
223
  <p>
224
  <label for="<?php echo $this->get_field_id( 'group_default' ); ?>"><?php _e('Default groups to show:', 'buddypress'); ?></label>
102
 
103
  echo $before_title . $title . $after_title;
104
 
105
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
106
  $max_groups = ! empty( $instance['max_groups'] ) ? (int) $instance['max_groups'] : 5;
107
 
108
+ if ( $max_groups > $max_limit ) {
109
+ $max_groups = $max_limit;
110
+ }
111
+
112
  $group_args = array(
113
  'user_id' => $user_id,
114
  'type' => $instance['group_default'],
188
  public function update( $new_instance, $old_instance ) {
189
  $instance = $old_instance;
190
 
191
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
192
+
193
  $instance['title'] = strip_tags( $new_instance['title'] );
194
+ $instance['max_groups'] = $new_instance['max_groups'] > $max_limit ? $max_limit : intval( $new_instance['max_groups'] );
195
  $instance['group_default'] = strip_tags( $new_instance['group_default'] );
196
+ $instance['link_title'] = ! empty( $new_instance['link_title'] );
197
 
198
  return $instance;
199
  }
215
  );
216
  $instance = bp_parse_args( (array) $instance, $defaults, 'groups_widget_form' );
217
 
218
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
219
+
220
  $title = strip_tags( $instance['title'] );
221
+ $max_groups = $instance['max_groups'] > $max_limit ? $max_limit : intval( $instance['max_groups'] );
222
  $group_default = strip_tags( $instance['group_default'] );
223
  $link_title = (bool) $instance['link_title'];
224
  ?>
227
 
228
  <p><label for="<?php echo $this->get_field_id('link_title') ?>"><input type="checkbox" name="<?php echo $this->get_field_name('link_title') ?>" id="<?php echo $this->get_field_id('link_title') ?>" value="1" <?php checked( $link_title ) ?> /> <?php _e( 'Link widget title to Groups directory', 'buddypress' ) ?></label></p>
229
 
230
+ <p><label for="<?php echo $this->get_field_id( 'max_groups' ); ?>"><?php _e( 'Max groups to show:', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_groups' ); ?>" name="<?php echo $this->get_field_name( 'max_groups' ); ?>" type="number" min="1" max="<?php echo esc_attr( $max_limit ); ?>" value="<?php echo esc_attr( $max_groups ); ?>" style="width: 30%" /></label></p>
231
 
232
  <p>
233
  <label for="<?php echo $this->get_field_id( 'group_default' ); ?>"><?php _e('Default groups to show:', 'buddypress'); ?></label>
bp-groups/classes/class-bp-rest-group-invites-endpoint.php ADDED
@@ -0,0 +1,1037 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Group_Invites_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Group Invites endpoints.
13
+ *
14
+ * Use /groups/{group_id}/invites
15
+ * Use /groups/{group_id}/invites/{user_id}
16
+ *
17
+ * @since 5.0.0
18
+ */
19
+ class BP_REST_Group_Invites_Endpoint extends WP_REST_Controller {
20
+
21
+ /**
22
+ * Reuse some parts of the BP_REST_Groups_Endpoint class.
23
+ *
24
+ * @since 5.0.0
25
+ *
26
+ * @var BP_REST_Groups_Endpoint
27
+ */
28
+ protected $groups_endpoint;
29
+
30
+ /**
31
+ * Constructor.
32
+ *
33
+ * @since 5.0.0
34
+ */
35
+ public function __construct() {
36
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
37
+ $this->rest_base = buddypress()->groups->id . '/invites';
38
+ $this->groups_endpoint = new BP_REST_Groups_Endpoint();
39
+ $this->group_members_endpoint = new BP_REST_Group_Membership_Endpoint();
40
+ }
41
+
42
+ /**
43
+ * Register the component routes.
44
+ *
45
+ * @since 5.0.0
46
+ */
47
+ public function register_routes() {
48
+ register_rest_route(
49
+ $this->namespace,
50
+ '/' . $this->rest_base,
51
+ array(
52
+ array(
53
+ 'methods' => WP_REST_Server::READABLE,
54
+ 'callback' => array( $this, 'get_items' ),
55
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
56
+ 'args' => $this->get_collection_params(),
57
+ ),
58
+ array(
59
+ 'methods' => WP_REST_Server::CREATABLE,
60
+ 'callback' => array( $this, 'create_item' ),
61
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
62
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
63
+
64
+ ),
65
+ 'schema' => array( $this, 'get_item_schema' ),
66
+ )
67
+ );
68
+
69
+ register_rest_route(
70
+ $this->namespace,
71
+ '/' . $this->rest_base . '/(?P<invite_id>[\d]+)',
72
+ array(
73
+ 'args' => array(
74
+ 'invite_id' => array(
75
+ 'description' => __( 'A unique numeric ID for the group invitation.', 'buddypress' ),
76
+ 'type' => 'integer',
77
+ ),
78
+ ),
79
+ array(
80
+ 'methods' => WP_REST_Server::READABLE,
81
+ 'callback' => array( $this, 'get_item' ),
82
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
83
+ 'args' => array(
84
+ 'context' => $this->get_context_param(
85
+ array(
86
+ 'default' => 'view',
87
+ )
88
+ ),
89
+ ),
90
+ ),
91
+ array(
92
+ 'methods' => WP_REST_Server::EDITABLE,
93
+ 'callback' => array( $this, 'update_item' ),
94
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
95
+ ),
96
+ array(
97
+ 'methods' => WP_REST_Server::DELETABLE,
98
+ 'callback' => array( $this, 'delete_item' ),
99
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
100
+ ),
101
+ 'schema' => array( $this, 'get_item_schema' ),
102
+ )
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Retrieve group invitations.
108
+ *
109
+ * @since 5.0.0
110
+ *
111
+ * @param WP_REST_Request $request Full details about the request.
112
+ * @return WP_REST_Response
113
+ */
114
+ public function get_items( $request ) {
115
+ $args = array(
116
+ 'item_id' => $request['group_id'],
117
+ 'user_id' => $request['user_id'],
118
+ 'invite_sent' => $request['invite_sent'],
119
+ 'per_page' => $request['per_page'],
120
+ 'page' => $request['page'],
121
+ );
122
+
123
+ /**
124
+ * Inviter_id is a special case, because 0 can be meaningful for requests,
125
+ * but if it is zero for invitations, we can safely ignore it and should.
126
+ * So, only apply non-zero inviter_ids.
127
+ */
128
+ if ( $request['inviter_id'] ) {
129
+ $args['inviter_id'] = $request['inviter_id'];
130
+ }
131
+
132
+ // If the query is not restricted by group, user or inviter, limit it to the current user, if not an admin.
133
+ if ( ! $args['item_id'] && ! $args['user_id'] && ! $args['inviter_id'] && ! bp_current_user_can( 'bp_moderate' ) ) {
134
+ $args['user_id'] = bp_loggedin_user_id();
135
+ }
136
+
137
+ /**
138
+ * Filter the query arguments for the request.
139
+ *
140
+ * @since 5.0.0
141
+ *
142
+ * @param array $args Key value array of query var to query value.
143
+ * @param WP_REST_Request $request The request sent to the API.
144
+ */
145
+ $args = apply_filters( 'bp_rest_group_invites_get_items_query_args', $args, $request );
146
+
147
+ // Get invites.
148
+ $invites_data = groups_get_invites( $args );
149
+
150
+ $retval = array();
151
+ foreach ( $invites_data as $invitation ) {
152
+ if ( $invitation instanceof BP_Invitation ) {
153
+ $retval[] = $this->prepare_response_for_collection(
154
+ $this->prepare_item_for_response( $invitation, $request )
155
+ );
156
+ }
157
+ }
158
+
159
+ $response = rest_ensure_response( $retval );
160
+ $response = bp_rest_response_add_total_headers( $response, count( $invites_data ), $args['per_page'] );
161
+
162
+ /**
163
+ * Fires after a list of group invites are fetched via the REST API.
164
+ *
165
+ * @since 5.0.0
166
+ *
167
+ * @param array $invites_data Invited users from the group.
168
+ * @param WP_REST_Response $response The response data.
169
+ * @param WP_REST_Request $request The request sent to the API.
170
+ */
171
+ do_action( 'bp_rest_group_invites_get_items', $invites_data, $response, $request );
172
+
173
+ return $response;
174
+ }
175
+
176
+ /**
177
+ * Check if a given request has access to group invitations.
178
+ *
179
+ * @since 5.0.0
180
+ *
181
+ * @param WP_REST_Request $request Full details about the request.
182
+ * @return bool|WP_Error
183
+ */
184
+ public function get_items_permissions_check( $request ) {
185
+ $retval = true;
186
+ $user_id = bp_loggedin_user_id();
187
+ $user_id_arg = $request['user_id'];
188
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
189
+ $inviter = bp_rest_get_user( $request['inviter_id'] );
190
+
191
+ // If the query is not restricted by group or user, limit it to the current user, if not an admin.
192
+ if ( ! $request['group_id'] && ! $request['user_id'] && ! bp_current_user_can( 'bp_moderate' ) ) {
193
+ $user_id_arg = $user_id;
194
+ }
195
+ $user = bp_rest_get_user( $user_id_arg );
196
+
197
+ if ( ! $user_id ) {
198
+ $retval = new WP_Error(
199
+ 'bp_rest_authorization_required',
200
+ __( 'Sorry, you need to be logged in to see the group invitations.', 'buddypress' ),
201
+ array(
202
+ 'status' => rest_authorization_required_code(),
203
+ )
204
+ );
205
+ }
206
+
207
+ // If a group ID has been passed, check that it is valid.
208
+ if ( true === $retval && $request['group_id'] && ! $group instanceof BP_Groups_Group ) {
209
+ $retval = new WP_Error(
210
+ 'bp_rest_group_invalid_id',
211
+ __( 'Invalid group id.', 'buddypress' ),
212
+ array(
213
+ 'status' => 404,
214
+ )
215
+ );
216
+ }
217
+
218
+ // If a user ID has been passed, check that it is valid.
219
+ if ( true === $retval && $user_id_arg && ! $user instanceof WP_User ) {
220
+ $retval = new WP_Error(
221
+ 'bp_rest_member_invalid_id',
222
+ __( 'Invalid member id.', 'buddypress' ),
223
+ array(
224
+ 'status' => 404,
225
+ )
226
+ );
227
+ }
228
+
229
+ // If an inviter ID has been passed, check that it is valid.
230
+ if ( true === $retval && $request['inviter_id'] && ! $inviter instanceof WP_User ) {
231
+ $retval = new WP_Error(
232
+ 'bp_rest_member_invalid_id',
233
+ __( 'Invalid member id.', 'buddypress' ),
234
+ array(
235
+ 'status' => 404,
236
+ )
237
+ );
238
+
239
+ }
240
+
241
+ /**
242
+ * Users can see invitations if they
243
+ * - are a site admin
244
+ * - are a group admin of the subject group (group_id must be specified)
245
+ * - are the invite recipient (user_id must be specified)
246
+ * - are the inviter (inviter_id must be specified)
247
+ * So, the request must be scoped if the user is not a site admin.
248
+ */
249
+ if ( true === $retval
250
+ && ! bp_current_user_can( 'bp_moderate' )
251
+ && ( $request['group_id'] && ! $this->can_see( $request['group_id'] ) )
252
+ && $user_id_arg !== $user_id
253
+ && $request['inviter_id'] !== $user_id
254
+ ) {
255
+ $retval = new WP_Error(
256
+ 'bp_rest_group_invites_cannot_get_items',
257
+ __( 'Sorry, you are not allowed to fetch group invitations with those arguments.', 'buddypress' ),
258
+ array(
259
+ 'status' => 500,
260
+ )
261
+ );
262
+ }
263
+
264
+ /**
265
+ * Filter the group invites `get_items` permissions check.
266
+ *
267
+ * @since 5.0.0
268
+ *
269
+ * @param bool|WP_Error $retval Whether the request can continue.
270
+ * @param WP_REST_Request $request The request sent to the API.
271
+ */
272
+ return apply_filters( 'bp_rest_group_invites_get_items_permissions_check', $retval, $request );
273
+ }
274
+
275
+ /**
276
+ * Fetch a specific group invitation by ID.
277
+ *
278
+ * @since 5.0.0
279
+ *
280
+ * @param WP_REST_Request $request Full data about the request.
281
+ * @return WP_REST_Response|WP_Error
282
+ */
283
+ public function get_item( $request ) {
284
+ $invite = $this->fetch_single_invite( $request['invite_id'] );
285
+ $retval = $this->prepare_response_for_collection(
286
+ $this->prepare_item_for_response( $invite, $request )
287
+ );
288
+
289
+ $response = rest_ensure_response( $retval );
290
+
291
+ /**
292
+ * Fires after a membership request is fetched via the REST API.
293
+ *
294
+ * @since 5.0.0
295
+ *
296
+ * @param BP_Invitation $invite Invitation object.
297
+ * @param WP_REST_Response $response The response data.
298
+ * @param WP_REST_Request $request The request sent to the API.
299
+ */
300
+ do_action( 'bp_rest_group_invite_get_item', $invite, $response, $request );
301
+
302
+ return $response;
303
+ }
304
+
305
+ /**
306
+ * Check if a given request has access to fetch group invitation.
307
+ *
308
+ * @since 5.0.0
309
+ *
310
+ * @param WP_REST_Request $request Full details about the request.
311
+ * @return bool|WP_Error
312
+ */
313
+ public function get_item_permissions_check( $request ) {
314
+ $user_id = bp_loggedin_user_id();
315
+ $invite = $this->fetch_single_invite( $request['invite_id'] );
316
+ $retval = true;
317
+
318
+ if ( ! $user_id ) {
319
+ $retval = new WP_Error(
320
+ 'bp_rest_authorization_required',
321
+ __( 'Sorry, you need to be logged in to see the group invitations.', 'buddypress' ),
322
+ array(
323
+ 'status' => rest_authorization_required_code(),
324
+ )
325
+ );
326
+ }
327
+
328
+ if ( true === $retval && ! $invite ) {
329
+ $retval = new WP_Error(
330
+ 'bp_rest_group_invite_invalid_id',
331
+ __( 'Invalid group invitation id.', 'buddypress' ),
332
+ array(
333
+ 'status' => 404,
334
+ )
335
+ );
336
+ }
337
+
338
+ /**
339
+ * Users can see a specific invitation if they
340
+ * - are a site admin
341
+ * - are a group admin of the subject group
342
+ * - are the invite recipient
343
+ * - are the inviter
344
+ */
345
+ if ( true === $retval
346
+ && ! bp_current_user_can( 'bp_moderate' )
347
+ && ! $this->can_see( $invite->item_id )
348
+ && ! in_array( $user_id, array( $invite->user_id, $invite->inviter_id ), true ) ) {
349
+ $retval = new WP_Error(
350
+ 'bp_rest_group_invites_cannot_get_item',
351
+ __( 'Sorry, you are not allowed to fetch an invitation.', 'buddypress' ),
352
+ array(
353
+ 'status' => 500,
354
+ )
355
+ );
356
+ }
357
+
358
+ /**
359
+ * Filter the group membership request `get_item` permissions check.
360
+ *
361
+ * @since 5.0.0
362
+ *
363
+ * @param bool|WP_Error $retval Whether the request can continue.
364
+ * @param WP_REST_Request $request The request sent to the API.
365
+ */
366
+ return apply_filters( 'bp_rest_group_invites_get_item_permissions_check', $retval, $request );
367
+ }
368
+
369
+ /**
370
+ * Invite a member to a group.
371
+ *
372
+ * @since 5.0.0
373
+ *
374
+ * @param WP_REST_Request $request Full data about the request.
375
+ * @return WP_REST_Response|WP_Error
376
+ */
377
+ public function create_item( $request ) {
378
+ $inviter_id_arg = $request['inviter_id'] ? $request['inviter_id'] : bp_loggedin_user_id();
379
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
380
+ $user = bp_rest_get_user( $request['user_id'] );
381
+ $inviter = bp_rest_get_user( $inviter_id_arg );
382
+
383
+ $invite_id = groups_invite_user(
384
+ array(
385
+ 'user_id' => $user->ID,
386
+ 'group_id' => $group->id,
387
+ 'inviter_id' => $inviter->ID,
388
+ 'send_invite' => isset( $request['invite_sent'] ) ? (bool) $request['invite_sent'] : 1,
389
+ 'content' => $request['message'],
390
+ )
391
+ );
392
+
393
+ if ( ! $invite_id ) {
394
+ return new WP_Error(
395
+ 'bp_rest_group_invite_cannot_create_item',
396
+ __( 'Could not invite member to the group.', 'buddypress' ),
397
+ array(
398
+ 'status' => 500,
399
+ )
400
+ );
401
+ }
402
+
403
+ $invite = new BP_Invitation( $invite_id );
404
+
405
+ // Set context.
406
+ $request->set_param( 'context', 'edit' );
407
+
408
+ $retval = array(
409
+ $this->prepare_response_for_collection(
410
+ $this->prepare_item_for_response( $invite, $request )
411
+ ),
412
+ );
413
+
414
+ $response = rest_ensure_response( $retval );
415
+
416
+ /**
417
+ * Fires after a member is invited to a group via the REST API.
418
+ *
419
+ * @since 5.0.0
420
+ *
421
+ * @param BP_Invitation $invite The invitation object.
422
+ * @param WP_User $user The invited user.
423
+ * @param WP_User $inviter The inviter user.
424
+ * @param BP_Groups_Group $group The group object.
425
+ * @param WP_REST_Response $response The response data.
426
+ * @param WP_REST_Request $request The request sent to the API.
427
+ */
428
+ do_action( 'bp_rest_group_invites_create_item', $invite, $user, $inviter, $group, $response, $request );
429
+
430
+ return $response;
431
+ }
432
+
433
+ /**
434
+ * Checks if a given request has access to invite a member to a group.
435
+ *
436
+ * @since 5.0.0
437
+ *
438
+ * @param WP_REST_Request $request Full details about the request.
439
+ * @return bool|WP_Error
440
+ */
441
+ public function create_item_permissions_check( $request ) {
442
+ $inviter_id_arg = $request['inviter_id'] ? $request['inviter_id'] : bp_loggedin_user_id();
443
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
444
+ $user = bp_rest_get_user( $request['user_id'] );
445
+ $inviter = bp_rest_get_user( $inviter_id_arg );
446
+ $retval = true;
447
+
448
+ if ( ! is_user_logged_in() ) {
449
+ $retval = new WP_Error(
450
+ 'bp_rest_authorization_required',
451
+ __( 'Sorry, you need to be logged in to create an invitation.', 'buddypress' ),
452
+ array(
453
+ 'status' => rest_authorization_required_code(),
454
+ )
455
+ );
456
+ }
457
+
458
+ if ( true === $retval && empty( $group->id ) ) {
459
+ $retval = new WP_Error(
460
+ 'bp_rest_group_invalid_id',
461
+ __( 'Invalid group id.', 'buddypress' ),
462
+ array(
463
+ 'status' => 404,
464
+ )
465
+ );
466
+ }
467
+
468
+ if ( true === $retval && ( empty( $user->ID ) || empty( $inviter->ID ) || $user->ID === $inviter->ID ) ) {
469
+ $retval = new WP_Error(
470
+ 'bp_rest_member_invalid_id',
471
+ __( 'Invalid member id.', 'buddypress' ),
472
+ array(
473
+ 'status' => 404,
474
+ )
475
+ );
476
+ }
477
+
478
+ // Only a site admin or the user herself can extend invites.
479
+ if ( true === $retval && ! bp_current_user_can( 'bp_moderate' ) && bp_loggedin_user_id() !== $inviter_id_arg ) {
480
+ $retval = new WP_Error(
481
+ 'bp_rest_group_invite_cannot_create_item',
482
+ __( 'Sorry, you are not allowed to create the invitation as requested.', 'buddypress' ),
483
+ array(
484
+ 'status' => 500,
485
+ )
486
+ );
487
+ }
488
+
489
+ /**
490
+ * Filter the group invites `create_item` permissions check.
491
+ *
492
+ * @since 5.0.0
493
+ *
494
+ * @param bool|WP_Error $retval Whether the request can continue.
495
+ * @param WP_REST_Request $request The request sent to the API.
496
+ */
497
+ return apply_filters( 'bp_rest_group_invites_create_item_permissions_check', $retval, $request );
498
+ }
499
+
500
+ /**
501
+ * Accept a group invitation.
502
+ *
503
+ * @since 5.0.0
504
+ *
505
+ * @param WP_REST_Request $request Full details about the request.
506
+ * @return WP_REST_Response|WP_Error
507
+ */
508
+ public function update_item( $request ) {
509
+ $invite = $this->fetch_single_invite( $request['invite_id'] );
510
+ $accept = groups_accept_invite( $invite->user_id, $invite->item_id );
511
+ if ( ! $accept ) {
512
+ return new WP_Error(
513
+ 'bp_rest_group_invite_cannot_update_item',
514
+ __( 'Could not accept group invitation.', 'buddypress' ),
515
+ array(
516
+ 'status' => 500,
517
+ )
518
+ );
519
+ }
520
+
521
+ // Setting context.
522
+ $request->set_param( 'context', 'edit' );
523
+
524
+ $accepted_member = new BP_Groups_Member( $invite->user_id, $invite->item_id );
525
+
526
+ $retval = array(
527
+ $this->prepare_response_for_collection(
528
+ $this->group_members_endpoint->prepare_item_for_response( $accepted_member, $request )
529
+ ),
530
+ );
531
+
532
+ $response = rest_ensure_response( $retval );
533
+ $group = $this->groups_endpoint->get_group_object( $invite->item_id );
534
+
535
+ /**
536
+ * Fires after a group invite is accepted via the REST API.
537
+ *
538
+ * @since 5.0.0
539
+ *
540
+ * @param BP_Groups_Member $accepted_member Accepted group member.
541
+ * @param BP_Groups_Group $group The group object.
542
+ * @param WP_REST_Response $response The response data.
543
+ * @param WP_REST_Request $request The request sent to the API.
544
+ */
545
+ do_action( 'bp_rest_group_invites_update_item', $accepted_member, $group, $response, $request );
546
+
547
+ return $response;
548
+ }
549
+
550
+ /**
551
+ * Check if a given request has access to accept a group invitation.
552
+ *
553
+ * @since 5.0.0
554
+ *
555
+ * @param WP_REST_Request $request Full details about the request.
556
+ * @return bool|WP_Error
557
+ */
558
+ public function update_item_permissions_check( $request ) {
559
+ $retval = true;
560
+ $user_id = bp_loggedin_user_id();
561
+ $invite = $this->fetch_single_invite( $request['invite_id'] );
562
+
563
+ if ( ! $user_id ) {
564
+ $retval = new WP_Error(
565
+ 'bp_rest_authorization_required',
566
+ __( 'Sorry, you need to be logged in to see the group invitations.', 'buddypress' ),
567
+ array(
568
+ 'status' => rest_authorization_required_code(),
569
+ )
570
+ );
571
+ }
572
+
573
+ if ( true === $retval && ! $invite ) {
574
+ $retval = new WP_Error(
575
+ 'bp_rest_group_invite_invalid_id',
576
+ __( 'Invalid group invitation id.', 'buddypress' ),
577
+ array(
578
+ 'status' => 404,
579
+ )
580
+ );
581
+ }
582
+
583
+ // Only the invitee or a site admin should be able to accept an invitation.
584
+ if ( true === $retval
585
+ && ! bp_current_user_can( 'bp_moderate' )
586
+ && $user_id !== $invite->user_id ) {
587
+ $retval = new WP_Error(
588
+ 'bp_rest_group_invite_cannot_update_item',
589
+ __( 'Sorry, you are not allowed to accept the invitation as requested.', 'buddypress' ),
590
+ array(
591
+ 'status' => 500,
592
+ )
593
+ );
594
+ }
595
+
596
+ /**
597
+ * Filter the group invites `update_item` permissions check.
598
+ *
599
+ * @since 5.0.0
600
+ *
601
+ * @param bool|WP_Error $retval Whether the request can continue.
602
+ * @param WP_REST_Request $request The request sent to the API.
603
+ */
604
+ return apply_filters( 'bp_rest_group_invites_update_item_permissions_check', $retval, $request );
605
+ }
606
+
607
+ /**
608
+ * Remove (reject/delete) a group invitation.
609
+ *
610
+ * @since 5.0.0
611
+ *
612
+ * @param WP_REST_Request $request Full details about the request.
613
+ * @return WP_REST_Response|WP_Error
614
+ */
615
+ public function delete_item( $request ) {
616
+ // Setting context.
617
+ $request->set_param( 'context', 'edit' );
618
+
619
+ $user_id = bp_loggedin_user_id();
620
+ $invite = $this->fetch_single_invite( $request['invite_id'] );
621
+
622
+ // Set the invite response before it is deleted.
623
+ $previous = $this->prepare_item_for_response( $invite, $request );
624
+
625
+ /**
626
+ * If this change is being initiated by the invited user,
627
+ * use the `reject` function.
628
+ */
629
+ if ( $user_id === $invite->user_id ) {
630
+ $deleted = groups_reject_invite( $invite->user_id, $invite->item_id, $invite->inviter_id );
631
+ /**
632
+ * Otherwise, this change is being initiated by a group admin, site admin,
633
+ * or the inviter, and we should use the `uninvite` function.
634
+ */
635
+ } else {
636
+ $deleted = groups_uninvite_user( $invite->user_id, $invite->item_id, $invite->inviter_id );
637
+ }
638
+
639
+ if ( ! $deleted ) {
640
+ return new WP_Error(
641
+ 'bp_rest_group_invite_cannot_delete_item',
642
+ __( 'Could not delete group invitation.', 'buddypress' ),
643
+ array(
644
+ 'status' => 500,
645
+ )
646
+ );
647
+ }
648
+
649
+ // Build the response.
650
+ $response = new WP_REST_Response();
651
+ $response->set_data(
652
+ array(
653
+ 'deleted' => true,
654
+ 'previous' => $previous->get_data(),
655
+ )
656
+ );
657
+
658
+ $user = bp_rest_get_user( $invite->user_id );
659
+ $group = $this->groups_endpoint->get_group_object( $invite->item_id );
660
+
661
+ /**
662
+ * Fires after a group invite is deleted via the REST API.
663
+ *
664
+ * @since 5.0.0
665
+ *
666
+ * @param WP_User $user The invited user.
667
+ * @param BP_Groups_Group $group The group object.
668
+ * @param WP_REST_Response $response The response data.
669
+ * @param WP_REST_Request $request The request sent to the API.
670
+ */
671
+ do_action( 'bp_rest_group_invites_delete_item', $user, $group, $response, $request );
672
+
673
+ return $response;
674
+ }
675
+
676
+ /**
677
+ * Check if a given request has access to delete a group invitation.
678
+ *
679
+ * @since 5.0.0
680
+ *
681
+ * @param WP_REST_Request $request Full details about the request.
682
+ * @return bool|WP_Error
683
+ */
684
+ public function delete_item_permissions_check( $request ) {
685
+ $retval = true;
686
+ $user_id = bp_loggedin_user_id();
687
+ $invite = $this->fetch_single_invite( $request['invite_id'] );
688
+
689
+ if ( ! $user_id ) {
690
+ $retval = new WP_Error(
691
+ 'bp_rest_authorization_required',
692
+ __( 'Sorry, you need to be logged in to see the group invitations.', 'buddypress' ),
693
+ array(
694
+ 'status' => rest_authorization_required_code(),
695
+ )
696
+ );
697
+ }
698
+
699
+ if ( true === $retval && ! $invite ) {
700
+ $retval = new WP_Error(
701
+ 'bp_rest_group_invite_invalid_id',
702
+ __( 'Invalid group invitation id.', 'buddypress' ),
703
+ array(
704
+ 'status' => 404,
705
+ )
706
+ );
707
+ }
708
+
709
+ // The inviter, the invitee, group admins, and site admins can all delete invites.
710
+ if ( true === $retval
711
+ && ! bp_current_user_can( 'bp_moderate' )
712
+ && ! in_array( $user_id, array( $invite->user_id, $invite->inviter_id ), true )
713
+ && ! groups_is_user_admin( $user_id, $invite->item_id )
714
+ ) {
715
+ $retval = new WP_Error(
716
+ 'bp_rest_group_invite_cannot_delete_item',
717
+ __( 'Sorry, you are not allowed to delete the invitation as requested.', 'buddypress' ),
718
+ array(
719
+ 'status' => 500,
720
+ )
721
+ );
722
+ }
723
+
724
+ /**
725
+ * Filter the group invites `delete_item` permissions check.
726
+ *
727
+ * @since 5.0.0
728
+ *
729
+ * @param bool|WP_Error $retval Whether the request can continue.
730
+ * @param WP_REST_Request $request The request sent to the API.
731
+ */
732
+ return apply_filters( 'bp_rest_group_invites_delete_item_permissions_check', $retval, $request );
733
+ }
734
+
735
+ /**
736
+ * Prepares group invitation data to return as an object.
737
+ *
738
+ * @since 5.0.0
739
+ *
740
+ * @param BP_Invitation $invite Invite object.
741
+ * @param WP_REST_Request $request Full details about the request.
742
+ * @return WP_REST_Response
743
+ */
744
+ public function prepare_item_for_response( $invite, $request ) {
745
+ $data = array(
746
+ 'id' => $invite->id,
747
+ 'user_id' => $invite->user_id,
748
+ 'invite_sent' => $invite->invite_sent,
749
+ 'inviter_id' => $invite->inviter_id,
750
+ 'group_id' => $invite->item_id,
751
+ 'date_modified' => bp_rest_prepare_date_response( $invite->date_modified ),
752
+ 'type' => $invite->type,
753
+ 'message' => array(
754
+ 'raw' => $invite->content,
755
+ 'rendered' => apply_filters( 'the_content', $invite->content ),
756
+ ),
757
+ );
758
+
759
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
760
+ $data = $this->add_additional_fields_to_object( $data, $request );
761
+ $data = $this->filter_response_by_context( $data, $context );
762
+ $response = rest_ensure_response( $data );
763
+
764
+ $response->add_links( $this->prepare_links( $invite ) );
765
+
766
+ /**
767
+ * Filter a group invite value returned from the API.
768
+ *
769
+ * @since 5.0.0
770
+ *
771
+ * @param WP_REST_Response $response The response data.
772
+ * @param WP_REST_Request $request Request used to generate the response.
773
+ * @param BP_Invitation $invite The invite object.
774
+ */
775
+ return apply_filters( 'bp_rest_group_invites_prepare_value', $response, $request, $invite );
776
+ }
777
+
778
+ /**
779
+ * Prepare links for the request.
780
+ *
781
+ * @since 5.0.0
782
+ *
783
+ * @param BP_Invitation $invite Invite object.
784
+ * @return array Links for the given plugin.
785
+ */
786
+ protected function prepare_links( $invite ) {
787
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
788
+ $url = $base . $invite->id;
789
+
790
+ // Entity meta.
791
+ $links = array(
792
+ 'self' => array(
793
+ 'href' => rest_url( $url ),
794
+ ),
795
+ 'collection' => array(
796
+ 'href' => rest_url( $base ),
797
+ ),
798
+ 'user' => array(
799
+ 'href' => rest_url( bp_rest_get_user_url( $invite->user_id ) ),
800
+ 'embeddable' => true,
801
+ ),
802
+ );
803
+
804
+ /**
805
+ * Filter links prepared for the REST response.
806
+ *
807
+ * @since 5.0.0
808
+ *
809
+ * @param array $links The prepared links of the REST response.
810
+ * @param stdClass $invite Invite object.
811
+ */
812
+ return apply_filters( 'bp_rest_group_invites_prepare_links', $links, $invite );
813
+ }
814
+
815
+ /**
816
+ * Check access.
817
+ *
818
+ * @param int $group_id Group ID.
819
+ * @return bool
820
+ */
821
+ protected function can_see( $group_id ) {
822
+ $user_id = bp_loggedin_user_id();
823
+
824
+ if ( ! groups_is_user_admin( $user_id, $group_id ) && ! groups_is_user_mod( $user_id, $group_id ) ) {
825
+ return false;
826
+ }
827
+
828
+ return true;
829
+ }
830
+
831
+ /**
832
+ * Helper function to fetch a single group invite.
833
+ *
834
+ * @since 5.0.0
835
+ *
836
+ * @param int $invite_id The ID of the invitation you wish to fetch.
837
+ *
838
+ * @return BP_Invitation|bool $invite Invitation if found, false otherwise.
839
+ */
840
+ public function fetch_single_invite( $invite_id = 0 ) {
841
+ $invites = groups_get_invites( array( 'id' => $invite_id ) );
842
+ if ( $invites ) {
843
+ return current( $invites );
844
+ } else {
845
+ return false;
846
+ }
847
+ }
848
+
849
+ /**
850
+ * Edit the type of the some properties for the CREATABLE & EDITABLE methods.
851
+ *
852
+ * @since 5.0.0
853
+ *
854
+ * @param string $method Optional. HTTP method of the request.
855
+ * @return array Endpoint arguments.
856
+ */
857
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
858
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
859
+ $key = 'get_item';
860
+
861
+ if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) {
862
+ $key = 'create_item';
863
+ $args['message']['type'] = 'string';
864
+ $args['message']['description'] = __( 'The optional message to send to the invited user.', 'buddypress' );
865
+ $args['send_invite'] = $args['invite_sent'];
866
+ $args['inviter_id']['default'] = bp_loggedin_user_id();
867
+ $args['group_id']['required'] = true;
868
+ $args['user_id']['required'] = true;
869
+
870
+ // Remove arguments not needed for the CREATABLE transport method.
871
+ unset( $args['message']['properties'], $args['invite_sent'], $args['date_modified'], $args['type'] );
872
+
873
+ $args['send_invite']['description'] = __( 'Whether the invite should be sent to the invitee.', 'buddypress' );
874
+ $args['send_invite']['default'] = true;
875
+
876
+ if ( WP_REST_Server::EDITABLE === $method ) {
877
+ $key = 'update_item';
878
+ }
879
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
880
+ $key = 'delete_item';
881
+ }
882
+
883
+ /**
884
+ * Filters the method query arguments.
885
+ *
886
+ * @since 5.0.0
887
+ *
888
+ * @param array $args Query arguments.
889
+ * @param string $method HTTP method of the request.
890
+ */
891
+ return apply_filters( "bp_rest_group_invites_{$key}_query_arguments", $args, $method );
892
+ }
893
+
894
+ /**
895
+ * Get the group invite schema, conforming to JSON Schema.
896
+ *
897
+ * @since 5.0.0
898
+ *
899
+ * @return array
900
+ */
901
+ public function get_item_schema() {
902
+ $schema = array(
903
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
904
+ 'title' => 'bp_group_invites',
905
+ 'type' => 'object',
906
+ 'properties' => array(
907
+ 'id' => array(
908
+ 'context' => array( 'view', 'edit' ),
909
+ 'description' => __( 'A unique numeric ID for the BP Invitation object.', 'buddypress' ),
910
+ 'type' => 'integer',
911
+ 'readonly' => true,
912
+ ),
913
+ 'user_id' => array(
914
+ 'context' => array( 'view', 'edit' ),
915
+ 'description' => __( 'The ID of the user who is invited to join the Group.', 'buddypress' ),
916
+ 'type' => 'integer',
917
+ ),
918
+ 'invite_sent' => array(
919
+ 'context' => array( 'view', 'edit' ),
920
+ 'description' => __( 'Whether the invite has been sent to the invitee.', 'buddypress' ),
921
+ 'type' => 'boolean',
922
+ ),
923
+ 'inviter_id' => array(
924
+ 'context' => array( 'view', 'edit' ),
925
+ 'description' => __( 'The ID of the user who made the invite.', 'buddypress' ),
926
+ 'type' => 'integer',
927
+ ),
928
+ 'group_id' => array(
929
+ 'context' => array( 'view', 'edit' ),
930
+ 'description' => __( 'The ID of the group to which the user has been invited.', 'buddypress' ),
931
+ 'type' => 'integer',
932
+ ),
933
+ 'date_modified' => array(
934
+ 'context' => array( 'view', 'edit' ),
935
+ 'description' => __( "The date the object was created or last updated, in the site's timezone.", 'buddypress' ),
936
+ 'type' => 'string',
937
+ 'format' => 'date-time',
938
+ ),
939
+ 'type' => array(
940
+ 'context' => array( 'view', 'edit' ),
941
+ 'description' => __( 'Invitation or request.', 'buddypress' ),
942
+ 'type' => 'string',
943
+ 'enum' => array( 'invite', 'request' ),
944
+ 'default' => 'invite',
945
+ ),
946
+ 'message' => array(
947
+ 'context' => array( 'view', 'edit' ),
948
+ 'description' => __( 'The raw and rendered versions for the content of the message.', 'buddypress' ),
949
+ 'type' => 'object',
950
+ 'arg_options' => array(
951
+ 'sanitize_callback' => null,
952
+ 'validate_callback' => null,
953
+ ),
954
+ 'properties' => array(
955
+ 'raw' => array(
956
+ 'description' => __( 'Content for the object, as it exists in the database.', 'buddypress' ),
957
+ 'type' => 'string',
958
+ 'context' => array( 'view', 'edit' ),
959
+ ),
960
+ 'rendered' => array(
961
+ 'description' => __( 'HTML content for the object, transformed for display.', 'buddypress' ),
962
+ 'type' => 'string',
963
+ 'context' => array( 'view', 'edit' ),
964
+ 'readonly' => true,
965
+ ),
966
+ ),
967
+ ),
968
+
969
+ ),
970
+ );
971
+
972
+ /**
973
+ * Filters the group invites schema.
974
+ *
975
+ * @param array $schema The endpoint schema.
976
+ */
977
+ return apply_filters( 'bp_rest_group_invites_schema', $this->add_additional_fields_schema( $schema ) );
978
+ }
979
+
980
+ /**
981
+ * Get the query params for collections of group invites.
982
+ *
983
+ * @since 5.0.0
984
+ *
985
+ * @return array
986
+ */
987
+ public function get_collection_params() {
988
+ $params = parent::get_collection_params();
989
+ $params['context']['default'] = 'view';
990
+
991
+ // Remove the search param.
992
+ unset( $params['search'] );
993
+
994
+ $params['group_id'] = array(
995
+ 'description' => __( 'ID of the group to limit results to.', 'buddypress' ),
996
+ 'required' => false,
997
+ 'default' => 0,
998
+ 'type' => 'integer',
999
+ 'sanitize_callback' => 'absint',
1000
+ 'validate_callback' => 'rest_validate_request_arg',
1001
+ );
1002
+
1003
+ $params['user_id'] = array(
1004
+ 'description' => __( 'Return only invitations extended to this user.', 'buddypress' ),
1005
+ 'required' => false,
1006
+ 'default' => 0,
1007
+ 'type' => 'integer',
1008
+ 'sanitize_callback' => 'absint',
1009
+ 'validate_callback' => 'rest_validate_request_arg',
1010
+ );
1011
+
1012
+ $params['inviter_id'] = array(
1013
+ 'description' => __( 'Return only invitations extended by this user.', 'buddypress' ),
1014
+ 'required' => false,
1015
+ 'default' => 0,
1016
+ 'type' => 'integer',
1017
+ 'sanitize_callback' => 'absint',
1018
+ 'validate_callback' => 'rest_validate_request_arg',
1019
+ );
1020
+
1021
+ $params['invite_sent'] = array(
1022
+ 'description' => __( 'Limit result set to invites that have been sent, not sent, or include all.', 'buddypress' ),
1023
+ 'default' => 'sent',
1024
+ 'type' => 'string',
1025
+ 'sanitize_callback' => 'sanitize_text_field',
1026
+ 'validate_callback' => 'rest_validate_request_arg',
1027
+ 'enum' => array( 'draft', 'sent', 'all' ),
1028
+ );
1029
+
1030
+ /**
1031
+ * Filters the collection query params.
1032
+ *
1033
+ * @param array $params Query params.
1034
+ */
1035
+ return apply_filters( 'bp_rest_group_invites_collection_params', $params );
1036
+ }
1037
+ }
bp-groups/classes/class-bp-rest-group-membership-endpoint.php ADDED
@@ -0,0 +1,950 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Group_Membership_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Group membership endpoints.
13
+ *
14
+ * Use /groups/{group_id}/members
15
+ * Use /groups/{group_id}/members/{user_id}
16
+ *
17
+ * @since 5.0.0
18
+ */
19
+ class BP_REST_Group_Membership_Endpoint extends WP_REST_Controller {
20
+
21
+ /**
22
+ * Reuse some parts of the BP_REST_Groups_Endpoint class.
23
+ *
24
+ * @since 5.0.0
25
+ *
26
+ * @var BP_REST_Groups_Endpoint
27
+ */
28
+ protected $groups_endpoint;
29
+
30
+ /**
31
+ * Reuse some parts of the BP_REST_Members_Endpoint class.
32
+ *
33
+ * @since 5.0.0
34
+ *
35
+ * @var BP_REST_Members_Endpoint
36
+ */
37
+ protected $members_endpoint;
38
+
39
+ /**
40
+ * Constructor.
41
+ *
42
+ * @since 5.0.0
43
+ */
44
+ public function __construct() {
45
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
46
+ $this->rest_base = buddypress()->groups->id;
47
+ $this->groups_endpoint = new BP_REST_Groups_Endpoint();
48
+ $this->members_endpoint = new BP_REST_Members_Endpoint();
49
+ }
50
+
51
+ /**
52
+ * Register the component routes.
53
+ *
54
+ * @since 5.0.0
55
+ */
56
+ public function register_routes() {
57
+ register_rest_route(
58
+ $this->namespace,
59
+ '/' . $this->rest_base . '/(?P<group_id>[\d]+)/members',
60
+ array(
61
+ 'args' => array(
62
+ 'group_id' => array(
63
+ 'description' => __( 'A unique numeric ID for the Group.', 'buddypress' ),
64
+ 'type' => 'integer',
65
+ ),
66
+ ),
67
+ array(
68
+ 'methods' => WP_REST_Server::READABLE,
69
+ 'callback' => array( $this, 'get_items' ),
70
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
71
+ 'args' => $this->get_collection_params(),
72
+ ),
73
+ array(
74
+ 'methods' => WP_REST_Server::CREATABLE,
75
+ 'callback' => array( $this, 'create_item' ),
76
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
77
+ 'args' => $this->get_endpoint_args_for_method( WP_REST_Server::CREATABLE ),
78
+ ),
79
+ 'schema' => array( $this, 'get_item_schema' ),
80
+ )
81
+ );
82
+
83
+ register_rest_route(
84
+ $this->namespace,
85
+ '/' . $this->rest_base . '/(?P<group_id>[\d]+)/members/(?P<user_id>[\d]+)',
86
+ array(
87
+ 'args' => array(
88
+ 'group_id' => array(
89
+ 'description' => __( 'A unique numeric ID for the Group.', 'buddypress' ),
90
+ 'type' => 'integer',
91
+ ),
92
+ 'user_id' => array(
93
+ 'description' => __( 'A unique numeric ID for the Group Member.', 'buddypress' ),
94
+ 'type' => 'integer',
95
+ ),
96
+ ),
97
+ array(
98
+ 'methods' => WP_REST_Server::EDITABLE,
99
+ 'callback' => array( $this, 'update_item' ),
100
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
101
+ 'args' => $this->get_endpoint_args_for_method( WP_REST_Server::EDITABLE ),
102
+ ),
103
+ array(
104
+ 'methods' => WP_REST_Server::DELETABLE,
105
+ 'callback' => array( $this, 'delete_item' ),
106
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
107
+ 'args' => $this->get_endpoint_args_for_method( WP_REST_Server::DELETABLE ),
108
+ ),
109
+ 'schema' => array( $this, 'get_item_schema' ),
110
+ )
111
+ );
112
+ }
113
+
114
+ /**
115
+ * Retrieve group members.
116
+ *
117
+ * @since 5.0.0
118
+ *
119
+ * @param WP_REST_Request $request Full details about the request.
120
+ * @return WP_REST_Response
121
+ */
122
+ public function get_items( $request ) {
123
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
124
+
125
+ $args = array(
126
+ 'group_id' => $group->id,
127
+ 'group_role' => $request['roles'],
128
+ 'type' => $request['status'],
129
+ 'per_page' => $request['per_page'],
130
+ 'page' => $request['page'],
131
+ 'search_terms' => $request['search'],
132
+ 'exclude' => $request['exclude'],
133
+ 'exclude_admins_mods' => (bool) $request['exclude_admins'],
134
+ 'exclude_banned' => (bool) $request['exclude_banned'],
135
+ );
136
+
137
+ if ( empty( $args['exclude'] ) ) {
138
+ $args['exclude'] = false;
139
+ }
140
+
141
+ /**
142
+ * Filter the query arguments for the request.
143
+ *
144
+ * @since 5.0.0
145
+ *
146
+ * @param array $args Key value array of query var to query value.
147
+ * @param WP_REST_Request $request The request sent to the API.
148
+ */
149
+ $args = apply_filters( 'bp_rest_group_members_get_items_query_args', $args, $request );
150
+
151
+ // Get our members.
152
+ $members = groups_get_group_members( $args );
153
+
154
+ $retval = array();
155
+ foreach ( $members['members'] as $member ) {
156
+ $retval[] = $this->prepare_response_for_collection(
157
+ $this->prepare_item_for_response( $member, $request )
158
+ );
159
+ }
160
+
161
+ $response = rest_ensure_response( $retval );
162
+ $response = bp_rest_response_add_total_headers( $response, $members['count'], $args['per_page'] );
163
+
164
+ /**
165
+ * Fires after a list of group members are fetched via the REST API.
166
+ *
167
+ * @since 5.0.0
168
+ *
169
+ * @param array $members Fetched group members.
170
+ * @param BP_Groups_Group $group The group object.
171
+ * @param WP_REST_Response $response The response data.
172
+ * @param WP_REST_Request $request The request sent to the API.
173
+ */
174
+ do_action( 'bp_rest_group_members_get_items', $members, $group, $response, $request );
175
+
176
+ return $response;
177
+ }
178
+
179
+ /**
180
+ * Check if a given request has access to group members.
181
+ *
182
+ * We are using the same permissions check done on group access.
183
+ *
184
+ * @since 5.0.0
185
+ *
186
+ * @param WP_REST_Request $request Full details about the request.
187
+ * @return bool|WP_Error
188
+ */
189
+ public function get_items_permissions_check( $request ) {
190
+ $retval = $this->groups_endpoint->get_item_permissions_check( $request );
191
+
192
+ /**
193
+ * Filter the group members `get_items` permissions check.
194
+ *
195
+ * @since 5.0.0
196
+ *
197
+ * @param bool|WP_Error $retval Returned value.
198
+ * @param WP_REST_Request $request The request sent to the API.
199
+ */
200
+ return apply_filters( 'bp_rest_group_members_get_items_permissions_check', $retval, $request );
201
+ }
202
+
203
+ /**
204
+ * Add member to a group.
205
+ *
206
+ * @since 5.0.0
207
+ *
208
+ * @param WP_REST_Request $request Full data about the request.
209
+ * @return WP_REST_Response|WP_Error
210
+ */
211
+ public function create_item( $request ) {
212
+ $user = bp_rest_get_user( $request['user_id'] );
213
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
214
+
215
+ if ( ! $request['context'] || 'view' === $request['context'] ) {
216
+ if ( ! groups_join_group( $group->id, $user->ID ) ) {
217
+ return new WP_Error(
218
+ 'bp_rest_group_member_failed_to_join',
219
+ __( 'Could not join the group.', 'buddypress' ),
220
+ array(
221
+ 'status' => 500,
222
+ )
223
+ );
224
+ }
225
+
226
+ // Set the group member.
227
+ $group_member = new BP_Groups_Member( $user->ID, $group->id );
228
+ } else {
229
+ $role = $request['role'];
230
+ $group_id = $group->id;
231
+ $group_member = new BP_Groups_Member( $user->ID, $group_id );
232
+
233
+ // Add member to the group.
234
+ $group_member->group_id = $group_id;
235
+ $group_member->user_id = $user->ID;
236
+ $group_member->is_admin = 0;
237
+ $group_member->date_modified = bp_core_current_time();
238
+ $group_member->is_confirmed = 1;
239
+ $saved = $group_member->save();
240
+
241
+ if ( ! $saved ) {
242
+ return new WP_Error(
243
+ 'bp_rest_group_member_failed_to_join',
244
+ __( 'Could not add member to the group.', 'buddypress' ),
245
+ array(
246
+ 'status' => 500,
247
+ )
248
+ );
249
+ }
250
+
251
+ // If new role set, promote it too.
252
+ if ( $saved && 'member' !== $role ) {
253
+ // Make sure to update the group role.
254
+ if ( groups_promote_member( $user->ID, $group_id, $role ) ) {
255
+ $group_member = new BP_Groups_Member( $user->ID, $group_id );
256
+ }
257
+ }
258
+ }
259
+
260
+ // Setting context.
261
+ $request->set_param( 'context', 'edit' );
262
+
263
+ $retval = array(
264
+ $this->prepare_response_for_collection(
265
+ $this->prepare_item_for_response( $group_member, $request )
266
+ ),
267
+ );
268
+
269
+ $response = rest_ensure_response( $retval );
270
+
271
+ /**
272
+ * Fires after a member is added to a group via the REST API.
273
+ *
274
+ * @since 5.0.0
275
+ *
276
+ * @param WP_User $user The user.
277
+ * @param BP_Groups_Member $group_member The group member object.
278
+ * @param BP_Groups_Group $group The group object.
279
+ * @param WP_REST_Response $response The response data.
280
+ * @param WP_REST_Request $request The request sent to the API.
281
+ */
282
+ do_action( 'bp_rest_group_members_create_item', $user, $group_member, $group, $response, $request );
283
+
284
+ return $response;
285
+ }
286
+
287
+ /**
288
+ * Checks if a given request has access to join a group.
289
+ *
290
+ * @since 5.0.0
291
+ *
292
+ * @param WP_REST_Request $request Full details about the request.
293
+ * @return bool|WP_Error
294
+ */
295
+ public function create_item_permissions_check( $request ) {
296
+ $retval = true;
297
+
298
+ if ( ! is_user_logged_in() ) {
299
+ $retval = new WP_Error(
300
+ 'bp_rest_authorization_required',
301
+ __( 'Sorry, you need to be logged in to join a group.', 'buddypress' ),
302
+ array(
303
+ 'status' => rest_authorization_required_code(),
304
+ )
305
+ );
306
+ }
307
+
308
+ $user = bp_rest_get_user( $request['user_id'] );
309
+
310
+ if ( true === $retval && ! $user instanceof WP_User ) {
311
+ $retval = new WP_Error(
312
+ 'bp_rest_group_member_invalid_id',
313
+ __( 'Invalid group member id.', 'buddypress' ),
314
+ array(
315
+ 'status' => 404,
316
+ )
317
+ );
318
+ }
319
+
320
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
321
+ if ( true === $retval && ! $group instanceof BP_Groups_Group ) {
322
+ $retval = new WP_Error(
323
+ 'bp_rest_group_invalid_id',
324
+ __( 'Invalid group id.', 'buddypress' ),
325
+ array(
326
+ 'status' => 404,
327
+ )
328
+ );
329
+ }
330
+
331
+ // Site administrators can do anything.
332
+ if ( true === $retval && bp_current_user_can( 'bp_moderate' ) ) {
333
+ $retval = true;
334
+ } else {
335
+
336
+ $loggedin_user_id = bp_loggedin_user_id();
337
+ if ( $loggedin_user_id === $user->ID && 'view' === $request['context'] ) {
338
+
339
+ // Users may only freely join public groups.
340
+ if ( true === $retval && (
341
+ ! bp_current_user_can( 'groups_join_group', array( 'group_id' => $group->id ) )
342
+ || groups_is_user_member( $loggedin_user_id, $group->id ) // As soon as they are not already members.
343
+ || groups_is_user_banned( $loggedin_user_id, $group->id ) // And as soon as they are not banned from it.
344
+ ) ) {
345
+ $retval = new WP_Error(
346
+ 'bp_rest_group_member_failed_to_join',
347
+ __( 'Could not join the group.', 'buddypress' ),
348
+ array(
349
+ 'status' => 500,
350
+ )
351
+ );
352
+ }
353
+
354
+ if ( true === $retval ) {
355
+ $retval = true;
356
+ }
357
+ } else {
358
+ $retval = false;
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Filter the group members `create_item` permissions check.
364
+ *
365
+ * @since 5.0.0
366
+ *
367
+ * @param bool|WP_Error $retval Returned value.
368
+ * @param WP_REST_Request $request The request sent to the API.
369
+ */
370
+ return apply_filters( 'bp_rest_group_members_create_item_permissions_check', $retval, $request );
371
+ }
372
+
373
+ /**
374
+ * Update user status on a group (add, remove, promote, demote or ban).
375
+ *
376
+ * @since 5.0.0
377
+ *
378
+ * @param WP_REST_Request $request Full details about the request.
379
+ * @return WP_REST_Response|WP_Error
380
+ */
381
+ public function update_item( $request ) {
382
+ $user = bp_rest_get_user( $request['user_id'] );
383
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
384
+ $action = $request['action'];
385
+ $role = $request['role'];
386
+ $group_id = $group->id;
387
+ $group_member = new BP_Groups_Member( $user->ID, $group_id );
388
+
389
+ if ( 'promote' === $action ) {
390
+ if ( ! $group_member->promote( $role ) ) {
391
+ return new WP_Error(
392
+ 'bp_rest_group_member_failed_to_promote',
393
+ __( 'Could not promote member.', 'buddypress' ),
394
+ array(
395
+ 'status' => 500,
396
+ )
397
+ );
398
+ }
399
+ } elseif ( 'demote' === $action && 'member' !== $role ) {
400
+ if ( ! $group_member->promote( $role ) ) {
401
+ return new WP_Error(
402
+ 'bp_rest_group_member_failed_to_demote',
403
+ __( 'Could not demote member.', 'buddypress' ),
404
+ array(
405
+ 'status' => 500,
406
+ )
407
+ );
408
+ }
409
+ } elseif ( in_array( $action, [ 'demote', 'ban', 'unban' ], true ) ) {
410
+ if ( ! $group_member->$action() ) {
411
+ return new WP_Error(
412
+ 'bp_rest_group_member_failed_to_' . $action,
413
+ sprintf(
414
+ /* translators: %1$s is replaced with the action */
415
+ __( 'Could not %s member from the group.', 'buddypress' ),
416
+ esc_attr( $action )
417
+ ),
418
+ array(
419
+ 'status' => 500,
420
+ )
421
+ );
422
+ }
423
+ }
424
+
425
+ // Setting context.
426
+ $request->set_param( 'context', 'edit' );
427
+
428
+ $retval = array(
429
+ $this->prepare_response_for_collection(
430
+ $this->prepare_item_for_response( $group_member, $request )
431
+ ),
432
+ );
433
+
434
+ $response = rest_ensure_response( $retval );
435
+
436
+ /**
437
+ * Fires after a group member is updated via the REST API.
438
+ *
439
+ * @since 5.0.0
440
+ *
441
+ * @param WP_User $user The updated member.
442
+ * @param BP_Groups_Member $group_member The group member object.
443
+ * @param BP_Groups_Group $group The group object.
444
+ * @param WP_REST_Response $response The response data.
445
+ * @param WP_REST_Request $request The request sent to the API.
446
+ */
447
+ do_action( 'bp_rest_group_members_update_item', $user, $group_member, $group, $response, $request );
448
+
449
+ return $response;
450
+ }
451
+
452
+ /**
453
+ * Check if a given request has access to update a group member.
454
+ *
455
+ * @since 5.0.0
456
+ *
457
+ * @param WP_REST_Request $request Full details about the request.
458
+ * @return WP_Error|bool
459
+ */
460
+ public function update_item_permissions_check( $request ) {
461
+ $retval = true;
462
+
463
+ if ( ! is_user_logged_in() ) {
464
+ $retval = new WP_Error(
465
+ 'bp_rest_authorization_required',
466
+ __( 'Sorry, you need to be logged in to make an update.', 'buddypress' ),
467
+ array(
468
+ 'status' => rest_authorization_required_code(),
469
+ )
470
+ );
471
+ }
472
+
473
+ $user = bp_rest_get_user( $request['user_id'] );
474
+
475
+ if ( true === $retval && ! $user instanceof WP_User ) {
476
+ $retval = new WP_Error(
477
+ 'bp_rest_group_member_invalid_id',
478
+ __( 'Invalid group member id.', 'buddypress' ),
479
+ array(
480
+ 'status' => 404,
481
+ )
482
+ );
483
+ }
484
+
485
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
486
+ if ( true === $retval && ! $group instanceof BP_Groups_Group ) {
487
+ $retval = new WP_Error(
488
+ 'bp_rest_group_invalid_id',
489
+ __( 'Invalid group id.', 'buddypress' ),
490
+ array(
491
+ 'status' => 404,
492
+ )
493
+ );
494
+ }
495
+
496
+ // Site administrators can do anything.
497
+ if ( true === $retval && bp_current_user_can( 'bp_moderate' ) ) {
498
+ $retval = true;
499
+ } else {
500
+
501
+ $loggedin_user_id = bp_loggedin_user_id();
502
+ if ( true === $retval && in_array( $request['action'], [ 'ban', 'unban', 'promote', 'demote' ], true ) ) {
503
+ if ( ! groups_is_user_admin( $loggedin_user_id, $group->id ) && ! groups_is_user_mod( $loggedin_user_id, $group->id ) ) {
504
+ $retval = new WP_Error(
505
+ 'bp_rest_group_member_cannot_' . $request['action'],
506
+ sprintf(
507
+ /* translators: %1$s is replaced with the action. */
508
+ __( 'Sorry, you are not allowed to %s this group member.', 'buddypress' ),
509
+ esc_attr( $request['action'] )
510
+ ),
511
+ array(
512
+ 'status' => rest_authorization_required_code(),
513
+ )
514
+ );
515
+ } else {
516
+ $retval = true;
517
+ }
518
+ }
519
+ }
520
+
521
+ /**
522
+ * Filter the group members `update_item` permissions check.
523
+ *
524
+ * @since 5.0.0
525
+ *
526
+ * @param bool|WP_Error $retval Returned value.
527
+ * @param WP_REST_Request $request The request sent to the API.
528
+ */
529
+ return apply_filters( 'bp_rest_group_members_update_item_permissions_check', $retval, $request );
530
+ }
531
+
532
+ /**
533
+ * Delete a group membership.
534
+ *
535
+ * @since 5.0.0
536
+ *
537
+ * @param WP_REST_Request $request Full details about the request.
538
+ * @return WP_REST_Response|WP_Error
539
+ */
540
+ public function delete_item( $request ) {
541
+ // Setting context.
542
+ $request->set_param( 'context', 'edit' );
543
+
544
+ // Get the Group member before it's removed.
545
+ $member = new BP_Groups_Member( $request['user_id'], $request['group_id'] );
546
+ $previous = $this->prepare_item_for_response( $member, $request );
547
+
548
+ if ( ! $member->remove() ) {
549
+ return new WP_Error(
550
+ 'bp_rest_group_member_failed_to_remove',
551
+ __( 'Could not remove member from this group.', 'buddypress' ),
552
+ array(
553
+ 'status' => 500,
554
+ )
555
+ );
556
+ }
557
+
558
+ // Build the response.
559
+ $response = new WP_REST_Response();
560
+ $response->set_data(
561
+ array(
562
+ 'removed' => true,
563
+ 'previous' => $previous->get_data(),
564
+ )
565
+ );
566
+
567
+ $user = bp_rest_get_user( $request['user_id'] );
568
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
569
+
570
+ /**
571
+ * Fires after a group member is deleted via the REST API.
572
+ *
573
+ * @since 5.0.0
574
+ *
575
+ * @param WP_User $user The updated member.
576
+ * @param BP_Groups_Member $member The group member object.
577
+ * @param BP_Groups_Group $group The group object.
578
+ * @param WP_REST_Response $response The response data.
579
+ * @param WP_REST_Request $request The request sent to the API.
580
+ */
581
+ do_action( 'bp_rest_group_members_delete_item', $user, $member, $group, $response, $request );
582
+
583
+ return $response;
584
+ }
585
+
586
+ /**
587
+ * Check if a given request has access to delete a group member.
588
+ *
589
+ * @since 5.0.0
590
+ *
591
+ * @param WP_REST_Request $request Full details about the request.
592
+ * @return WP_Error|bool
593
+ */
594
+ public function delete_item_permissions_check( $request ) {
595
+ $retval = true;
596
+
597
+ if ( ! is_user_logged_in() ) {
598
+ $retval = new WP_Error(
599
+ 'bp_rest_authorization_required',
600
+ __( 'Sorry, you need to be logged in to view a group membership.', 'buddypress' ),
601
+ array(
602
+ 'status' => rest_authorization_required_code(),
603
+ )
604
+ );
605
+ }
606
+
607
+ $user = bp_rest_get_user( $request['user_id'] );
608
+
609
+ if ( true === $retval && ! $user instanceof WP_User ) {
610
+ return new WP_Error(
611
+ 'bp_rest_group_member_invalid_id',
612
+ __( 'Invalid group member id.', 'buddypress' ),
613
+ array(
614
+ 'status' => 404,
615
+ )
616
+ );
617
+ }
618
+
619
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
620
+ if ( true === $retval && ! $group instanceof BP_Groups_Group ) {
621
+ $retval = new WP_Error(
622
+ 'bp_rest_group_invalid_id',
623
+ __( 'Invalid group id.', 'buddypress' ),
624
+ array(
625
+ 'status' => 404,
626
+ )
627
+ );
628
+ }
629
+
630
+ // Site administrators can do anything.
631
+ if ( true === $retval && bp_current_user_can( 'bp_moderate' ) ) {
632
+ $retval = true;
633
+ } elseif ( true === $retval ) {
634
+
635
+ $loggedin_user_id = bp_loggedin_user_id();
636
+
637
+ if ( $user->ID !== $loggedin_user_id ) {
638
+ if ( true === $retval && ! groups_is_user_admin( $loggedin_user_id, $group->id ) && ! groups_is_user_mod( $loggedin_user_id, $group->id ) ) {
639
+ $retval = new WP_Error(
640
+ 'bp_rest_authorization_required',
641
+ __( 'Sorry, you need to be logged in to view a group membership.', 'buddypress' ),
642
+ array(
643
+ 'status' => rest_authorization_required_code(),
644
+ )
645
+ );
646
+ }
647
+ } else {
648
+ // Special case for self-removal: don't allow if it'd leave a group with no admins.
649
+ $user = bp_rest_get_user( $request['user_id'] );
650
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
651
+ $loggedin_user_id = bp_loggedin_user_id();
652
+
653
+ $group_admins = groups_get_group_admins( $group->id );
654
+ if ( true === $retval && 1 === count( $group_admins ) && $loggedin_user_id === $group_admins[0]->user_id && $user->ID === $loggedin_user_id ) {
655
+ $retval = new WP_Error(
656
+ 'bp_rest_authorization_required',
657
+ __( 'Sorry, you need to be logged in to view a group membership.', 'buddypress' ),
658
+ array(
659
+ 'status' => rest_authorization_required_code(),
660
+ )
661
+ );
662
+ }
663
+ }
664
+ }
665
+
666
+ /**
667
+ * Filter the group members `delete_item` permissions check.
668
+ *
669
+ * @since 5.0.0
670
+ *
671
+ * @param bool|WP_Error $retval Returned value.
672
+ * @param WP_REST_Request $request The request sent to the API.
673
+ */
674
+ return apply_filters( 'bp_rest_group_members_delete_item_permissions_check', $retval, $request );
675
+ }
676
+
677
+ /**
678
+ * Prepares group member data for return as an object.
679
+ *
680
+ * @since 5.0.0
681
+ *
682
+ * @param BP_Groups_Member $group_member Group member object.
683
+ * @param WP_REST_Request $request Full details about the request.
684
+ * @return WP_REST_Response
685
+ */
686
+ public function prepare_item_for_response( $group_member, $request ) {
687
+ $user = bp_rest_get_user( $group_member->user_id );
688
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
689
+ $member_data = $this->members_endpoint->user_data( $user, $context );
690
+
691
+ // Merge both info.
692
+ $data = array_merge(
693
+ $member_data,
694
+ array(
695
+ 'is_mod' => (bool) $group_member->is_mod,
696
+ 'is_admin' => (bool) $group_member->is_admin,
697
+ 'is_banned' => (bool) $group_member->is_banned,
698
+ 'is_confirmed' => (bool) $group_member->is_confirmed,
699
+ 'date_modified' => bp_rest_prepare_date_response( $group_member->date_modified ),
700
+ )
701
+ );
702
+
703
+ $data = $this->add_additional_fields_to_object( $data, $request );
704
+ $data = $this->filter_response_by_context( $data, $context );
705
+ $response = rest_ensure_response( $data );
706
+
707
+ $response->add_links( $this->prepare_links( $user ) );
708
+
709
+ /**
710
+ * Filter a group member value returned from the API.
711
+ *
712
+ * @since 5.0.0
713
+ *
714
+ * @param WP_REST_Response $response The response data.
715
+ * @param WP_REST_Request $request Request used to generate the response.
716
+ * @param BP_Groups_Member $group_member Group member object.
717
+ */
718
+ return apply_filters( 'bp_rest_group_members_prepare_value', $response, $request, $group_member );
719
+ }
720
+
721
+ /**
722
+ * Prepare links for the request.
723
+ *
724
+ * @since 5.0.0
725
+ *
726
+ * @param WP_User $user User object.
727
+ * @return array
728
+ */
729
+ protected function prepare_links( $user ) {
730
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
731
+ $url = $base . $user->ID;
732
+
733
+ // Entity meta.
734
+ $links = array(
735
+ 'self' => array(
736
+ 'href' => rest_url( $url ),
737
+ ),
738
+ 'collection' => array(
739
+ 'href' => rest_url( $base ),
740
+ ),
741
+ );
742
+
743
+ /**
744
+ * Filter links prepared for the REST response.
745
+ *
746
+ * @since 5.0.0
747
+ *
748
+ * @param array $links The prepared links of the REST response.
749
+ * @param WP_User $user User object.
750
+ */
751
+ return apply_filters( 'bp_rest_group_members_prepare_links', $links, $user );
752
+ }
753
+
754
+ /**
755
+ * GET arguments for the endpoint's CREATABLE, EDITABLE & DELETABLE methods.
756
+ *
757
+ * @since 5.0.0
758
+ *
759
+ * @param string $method Optional. HTTP method of the request.
760
+ * @return array Endpoint arguments.
761
+ */
762
+ public function get_endpoint_args_for_method( $method = WP_REST_Server::CREATABLE ) {
763
+ $key = 'get_item';
764
+ $args = array(
765
+ 'context' => $this->get_context_param(
766
+ array(
767
+ 'default' => 'edit',
768
+ )
769
+ ),
770
+ );
771
+
772
+ if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) {
773
+ $group_roles = array_diff( array_keys( bp_groups_get_group_roles() ), array( 'banned' ) );
774
+
775
+ $args['role'] = array(
776
+ 'description' => __( 'Group role to assign the user to.', 'buddypress' ),
777
+ 'default' => 'member',
778
+ 'type' => 'string',
779
+ 'enum' => $group_roles,
780
+ 'sanitize_callback' => 'sanitize_key',
781
+ 'validate_callback' => 'rest_validate_request_arg',
782
+ );
783
+
784
+ if ( WP_REST_Server::CREATABLE === $method ) {
785
+ $key = 'create_item';
786
+ $schema = $this->get_item_schema();
787
+ $args['user_id'] = array_merge(
788
+ $schema['properties']['id'],
789
+ array(
790
+ 'description' => __( 'A unique numeric ID for the Member to add to the Group.', 'buddypress' ),
791
+ 'default' => bp_loggedin_user_id(),
792
+ 'readonly' => false,
793
+ )
794
+ );
795
+ }
796
+
797
+ if ( WP_REST_Server::EDITABLE === $method ) {
798
+ $key = 'update_item';
799
+ $args['action'] = array(
800
+ 'description' => __( 'Action used to update a group member.', 'buddypress' ),
801
+ 'default' => 'promote',
802
+ 'type' => 'string',
803
+ 'enum' => array( 'promote', 'demote', 'ban', 'unban' ),
804
+ 'sanitize_callback' => 'sanitize_key',
805
+ 'validate_callback' => 'rest_validate_request_arg',
806
+ );
807
+ }
808
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
809
+ $key = 'delete_item';
810
+ }
811
+
812
+ /**
813
+ * Filters the method query arguments.
814
+ *
815
+ * @since 5.0.0
816
+ *
817
+ * @param array $args Query arguments.
818
+ * @param string $method HTTP method of the request.
819
+ */
820
+ return apply_filters( "bp_rest_group_members_{$key}_query_arguments", $args, $method );
821
+ }
822
+
823
+ /**
824
+ * Get the group member schema, conforming to JSON Schema.
825
+ *
826
+ * @since 5.0.0
827
+ *
828
+ * @return array
829
+ */
830
+ public function get_item_schema() {
831
+
832
+ // Get schema from members.
833
+ $schema = $this->members_endpoint->get_item_schema();
834
+
835
+ // Set title to this endpoint.
836
+ $schema['title'] = 'bp_group_members';
837
+
838
+ $schema['properties']['is_mod'] = array(
839
+ 'context' => array( 'view', 'edit' ),
840
+ 'description' => __( '`1` if this member is a Group moderator, `0` otherwise.', 'buddypress' ),
841
+ 'type' => 'integer',
842
+ 'enum' => array( 0, 1 ),
843
+ );
844
+
845
+ $schema['properties']['is_banned'] = array(
846
+ 'context' => array( 'view', 'edit' ),
847
+ 'description' => __( '`1` if this member has been banned from the Group, `0` otherwise.', 'buddypress' ),
848
+ 'type' => 'integer',
849
+ 'enum' => array( 0, 1 ),
850
+ );
851
+
852
+ $schema['properties']['is_admin'] = array(
853
+ 'context' => array( 'view', 'edit' ),
854
+ 'description' => __( '`1` if this member is a Group administrator, `0` otherwise.', 'buddypress' ),
855
+ 'type' => 'integer',
856
+ 'enum' => array( 0, 1 ),
857
+ );
858
+
859
+ $schema['properties']['is_confirmed'] = array(
860
+ 'context' => array( 'view', 'edit' ),
861
+ 'description' => __( '`1` if the membership of this user has been confirmed, `0` otherwise.', 'buddypress' ),
862
+ 'type' => 'integer',
863
+ 'enum' => array( 0, 1 ),
864
+ );
865
+
866
+ $schema['properties']['date_modified'] = array(
867
+ 'context' => array( 'view', 'edit' ),
868
+ 'description' => __( "The date of the last time the membership of this user was modified, in the site's timezone.", 'buddypress' ),
869
+ 'type' => 'string',
870
+ 'format' => 'date-time',
871
+ );
872
+
873
+ /**
874
+ * Filters the group membership schema.
875
+ *
876
+ * @param array $schema The endpoint schema.
877
+ */
878
+ return apply_filters( 'bp_rest_group_members_schema', $this->add_additional_fields_schema( $schema ) );
879
+ }
880
+
881
+ /**
882
+ * Get the query params for collections of group memberships.
883
+ *
884
+ * @since 5.0.0
885
+ *
886
+ * @return array
887
+ */
888
+ public function get_collection_params() {
889
+ $params = parent::get_collection_params();
890
+ $params['context']['default'] = 'view';
891
+ $statuses = array( 'last_joined', 'first_joined', 'alphabetical' );
892
+
893
+ if ( bp_is_active( 'activity' ) ) {
894
+ $statuses[] = 'group_activity';
895
+ }
896
+
897
+ $params['status'] = array(
898
+ 'description' => __( 'Sort the order of results by the status of the group members.', 'buddypress' ),
899
+ 'default' => 'last_joined',
900
+ 'type' => 'string',
901
+ 'enum' => $statuses,
902
+ 'sanitize_callback' => 'sanitize_key',
903
+ 'validate_callback' => 'rest_validate_request_arg',
904
+ );
905
+
906
+ $params['roles'] = array(
907
+ 'description' => __( 'Ensure result set includes specific Group roles.', 'buddypress' ),
908
+ 'default' => array(),
909
+ 'type' => 'array',
910
+ 'items' => array(
911
+ 'type' => 'string',
912
+ 'enum' => array_keys( bp_groups_get_group_roles() ),
913
+ ),
914
+ 'sanitize_callback' => 'bp_rest_sanitize_string_list',
915
+ 'validate_callback' => 'rest_validate_request_arg',
916
+ );
917
+
918
+ $params['exclude'] = array(
919
+ 'description' => __( 'Ensure result set excludes specific member IDs.', 'buddypress' ),
920
+ 'default' => array(),
921
+ 'type' => 'array',
922
+ 'items' => array( 'type' => 'integer' ),
923
+ 'sanitize_callback' => 'wp_parse_id_list',
924
+ 'validate_callback' => 'rest_validate_request_arg',
925
+ );
926
+
927
+ $params['exclude_admins'] = array(
928
+ 'description' => __( 'Whether results should exclude group admins and mods.', 'buddypress' ),
929
+ 'default' => true,
930
+ 'type' => 'boolean',
931
+ 'sanitize_callback' => 'rest_sanitize_boolean',
932
+ 'validate_callback' => 'rest_validate_request_arg',
933
+ );
934
+
935
+ $params['exclude_banned'] = array(
936
+ 'description' => __( 'Whether results should exclude banned group members.', 'buddypress' ),
937
+ 'default' => true,
938
+ 'type' => 'boolean',
939
+ 'sanitize_callback' => 'rest_sanitize_boolean',
940
+ 'validate_callback' => 'rest_validate_request_arg',
941
+ );
942
+
943
+ /**
944
+ * Filters the collection query params.
945
+ *
946
+ * @param array $params Query params.
947
+ */
948
+ return apply_filters( 'bp_rest_group_members_collection_params', $params );
949
+ }
950
+ }
bp-groups/classes/class-bp-rest-group-membership-request-endpoint.php ADDED
@@ -0,0 +1,906 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Group_Membership_Request_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Group Membership Request Endpoint.
13
+ *
14
+ * Use /groups/{group_id}/membership-request
15
+ * Use /groups/membership-request/{request_id}
16
+ * Use /groups/{group_id}/membership-request/{user_id}
17
+ *
18
+ * @since 5.0.0
19
+ */
20
+ class BP_REST_Group_Membership_Request_Endpoint extends WP_REST_Controller {
21
+
22
+ /**
23
+ * Reuse some parts of the BP_REST_Groups_Endpoint class.
24
+ *
25
+ * @since 5.0.0
26
+ *
27
+ * @var BP_REST_Groups_Endpoint
28
+ */
29
+ protected $groups_endpoint;
30
+
31
+ /**
32
+ * Reuse some parts of the BP_REST_Group_Invites_Endpoint class.
33
+ *
34
+ * @since 5.0.0
35
+ *
36
+ * @var BP_REST_Group_Invites_Endpoint
37
+ */
38
+ protected $invites_endpoint;
39
+
40
+ /**
41
+ * Constructor.
42
+ *
43
+ * @since 5.0.0
44
+ */
45
+ public function __construct() {
46
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
47
+ $this->rest_base = buddypress()->groups->id . '/membership-requests';
48
+ $this->groups_endpoint = new BP_REST_Groups_Endpoint();
49
+ $this->group_members_endpoint = new BP_REST_Group_Membership_Endpoint();
50
+ $this->invites_endpoint = new BP_REST_Group_Invites_Endpoint();
51
+ }
52
+
53
+ /**
54
+ * Register the component routes.
55
+ *
56
+ * @since 5.0.0
57
+ */
58
+ public function register_routes() {
59
+ register_rest_route(
60
+ $this->namespace,
61
+ '/' . $this->rest_base,
62
+ array(
63
+ array(
64
+ 'methods' => WP_REST_Server::READABLE,
65
+ 'callback' => array( $this, 'get_items' ),
66
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
67
+ 'args' => $this->get_collection_params(),
68
+ ),
69
+ array(
70
+ 'methods' => WP_REST_Server::CREATABLE,
71
+ 'callback' => array( $this, 'create_item' ),
72
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
73
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
74
+ ),
75
+ 'schema' => array( $this, 'get_item_schema' ),
76
+ )
77
+ );
78
+
79
+ register_rest_route(
80
+ $this->namespace,
81
+ '/' . $this->rest_base . '/(?P<request_id>[\d]+)',
82
+ array(
83
+ 'args' => array(
84
+ 'request_id' => array(
85
+ 'description' => __( 'A unique numeric ID for the group membership request.', 'buddypress' ),
86
+ 'type' => 'integer',
87
+ ),
88
+ ),
89
+ array(
90
+ 'methods' => WP_REST_Server::READABLE,
91
+ 'callback' => array( $this, 'get_item' ),
92
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
93
+ 'args' => array(
94
+ 'context' => $this->get_context_param(
95
+ array(
96
+ 'default' => 'view',
97
+ )
98
+ ),
99
+ ),
100
+ ),
101
+ array(
102
+ 'methods' => WP_REST_Server::EDITABLE,
103
+ 'callback' => array( $this, 'update_item' ),
104
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
105
+ ),
106
+ array(
107
+ 'methods' => WP_REST_Server::DELETABLE,
108
+ 'callback' => array( $this, 'delete_item' ),
109
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
110
+ ),
111
+ 'schema' => array( $this, 'get_item_schema' ),
112
+ )
113
+ );
114
+ }
115
+
116
+ /**
117
+ * Fetch pending group membership requests.
118
+ *
119
+ * @since 5.0.0
120
+ *
121
+ * @param WP_REST_Request $request Full data about the request.
122
+ * @return WP_REST_Response|WP_Error
123
+ */
124
+ public function get_items( $request ) {
125
+ $args = array(
126
+ 'item_id' => $request['group_id'],
127
+ 'user_id' => $request['user_id'],
128
+ 'per_page' => $request['per_page'],
129
+ 'page' => $request['page'],
130
+ );
131
+
132
+ // If the query is not restricted by group or user, limit it to the current user, if not an admin.
133
+ if ( ! $args['item_id'] && ! $args['user_id'] && ! bp_current_user_can( 'bp_moderate' ) ) {
134
+ $args['user_id'] = bp_loggedin_user_id();
135
+ }
136
+
137
+ /**
138
+ * Filter the query arguments for the request.
139
+ *
140
+ * @since 5.0.0
141
+ *
142
+ * @param array $args Key value array of query var to query value.
143
+ * @param WP_REST_Request $request The request sent to the API.
144
+ */
145
+ $args = apply_filters( 'bp_rest_group_membership_requests_get_items_query_args', $args, $request );
146
+
147
+ $group_requests = groups_get_requests( $args );
148
+
149
+ $retval = array();
150
+ foreach ( $group_requests as $group_request ) {
151
+ $retval[] = $this->prepare_response_for_collection(
152
+ $this->prepare_item_for_response( $group_request, $request )
153
+ );
154
+ }
155
+
156
+ $response = rest_ensure_response( $retval );
157
+ $response = bp_rest_response_add_total_headers( $response, count( $group_requests ), $args['per_page'] );
158
+
159
+ /**
160
+ * Fires after a list of group membership request is fetched via the REST API.
161
+ *
162
+ * @since 5.0.0
163
+ *
164
+ * @param array of BP_Invitations $group_requests List of membership requests.
165
+ * @param WP_REST_Response $response The response data.
166
+ * @param WP_REST_Request $request The request sent to the API.
167
+ */
168
+ do_action( 'bp_rest_group_membership_requests_get_items', $group_requests, $response, $request );
169
+
170
+ return $response;
171
+ }
172
+
173
+ /**
174
+ * Check if a given request has access to fetch group membership requests.
175
+ *
176
+ * @since 5.0.0
177
+ *
178
+ * @param WP_REST_Request $request Full details about the request.
179
+ * @return bool|WP_Error
180
+ */
181
+ public function get_items_permissions_check( $request ) {
182
+ $retval = true;
183
+ $user_id = bp_loggedin_user_id();
184
+ $user_id_arg = $request['user_id'];
185
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
186
+
187
+ // If the query is not restricted by group or user, limit it to the current user, if not an admin.
188
+ if ( ! $request['group_id'] && ! $request['user_id'] && ! bp_current_user_can( 'bp_moderate' ) ) {
189
+ $user_id_arg = $user_id;
190
+ }
191
+ $user = bp_rest_get_user( $user_id_arg );
192
+
193
+ if ( ! $user_id ) {
194
+ $retval = new WP_Error(
195
+ 'bp_rest_authorization_required',
196
+ __( 'Sorry, you need to be logged in to view membership requests.', 'buddypress' ),
197
+ array(
198
+ 'status' => rest_authorization_required_code(),
199
+ )
200
+ );
201
+ }
202
+
203
+ // If a group ID has been passed, check that it is valid.
204
+ if ( true === $retval && $request['group_id'] && ! $group instanceof BP_Groups_Group ) {
205
+ $retval = new WP_Error(
206
+ 'bp_rest_group_invalid_id',
207
+ __( 'Invalid group id.', 'buddypress' ),
208
+ array(
209
+ 'status' => 404,
210
+ )
211
+ );
212
+ }
213
+
214
+ // If a user ID has been passed, check that it is valid.
215
+ if ( true === $retval && $user_id_arg && ! $user instanceof WP_User ) {
216
+ $retval = new WP_Error(
217
+ 'bp_rest_member_invalid_id',
218
+ __( 'Invalid member id.', 'buddypress' ),
219
+ array(
220
+ 'status' => 404,
221
+ )
222
+ );
223
+ }
224
+
225
+ // Site administrators can do anything. Otherwise, the user must manage the subject group or be the requester.
226
+ if ( true === $retval
227
+ && ! bp_current_user_can( 'bp_moderate' )
228
+ && ! ( $request['group_id'] && groups_is_user_admin( $user_id, $request['group_id'] ) )
229
+ && $user_id_arg !== $user_id ) {
230
+ $retval = new WP_Error(
231
+ 'bp_rest_group_membership_requests_cannot_get_items',
232
+ __( 'Sorry, you are not allowed to view membership requests.', 'buddypress' ),
233
+ array(
234
+ 'status' => 500,
235
+ )
236
+ );
237
+ }
238
+
239
+ /**
240
+ * Filter the `get_items` permissions check.
241
+ *
242
+ * @since 5.0.0
243
+ *
244
+ * @param bool|WP_Error $retval Whether the request can continue.
245
+ * @param WP_REST_Request $request The request sent to the API.
246
+ */
247
+ return apply_filters( 'bp_rest_group_membership_requests_get_items_permissions_check', $retval, $request );
248
+ }
249
+
250
+ /**
251
+ * Fetch a sepcific pending group membership request by ID.
252
+ *
253
+ * @since 5.0.0
254
+ *
255
+ * @param WP_REST_Request $request Full data about the request.
256
+ * @return WP_REST_Response|WP_Error
257
+ */
258
+ public function get_item( $request ) {
259
+ $group_request = $this->fetch_single_membership_request( $request['request_id'] );
260
+ $retval = $this->prepare_response_for_collection(
261
+ $this->prepare_item_for_response( $group_request, $request )
262
+ );
263
+
264
+ $response = rest_ensure_response( $retval );
265
+
266
+ /**
267
+ * Fires after a membership request is fetched via the REST API.
268
+ *
269
+ * @since 5.0.0
270
+ *
271
+ * @param BP_Invitation $group_request Membership request object.
272
+ * @param WP_REST_Response $response The response data.
273
+ * @param WP_REST_Request $request The request sent to the API.
274
+ */
275
+ do_action( 'bp_rest_group_membership_requests_get_item', $group_request, $response, $request );
276
+
277
+ return $response;
278
+ }
279
+
280
+ /**
281
+ * Check if a given request has access to fetch group membership request.
282
+ *
283
+ * @since 5.0.0
284
+ *
285
+ * @param WP_REST_Request $request Full details about the request.
286
+ * @return bool|WP_Error
287
+ */
288
+ public function get_item_permissions_check( $request ) {
289
+ $retval = true;
290
+ $user_id = bp_loggedin_user_id();
291
+ $group_request = $this->fetch_single_membership_request( $request['request_id'] );
292
+
293
+ if ( ! $user_id ) {
294
+ $retval = new WP_Error(
295
+ 'bp_rest_authorization_required',
296
+ __( 'Sorry, you need to be logged in to get a membership.', 'buddypress' ),
297
+ array(
298
+ 'status' => rest_authorization_required_code(),
299
+ )
300
+ );
301
+ }
302
+
303
+ if ( true === $retval && ! $group_request ) {
304
+ $retval = new WP_Error(
305
+ 'bp_rest_group_membership_requests_invalid_id',
306
+ __( 'Invalid group membership request id.', 'buddypress' ),
307
+ array(
308
+ 'status' => 404,
309
+ )
310
+ );
311
+ }
312
+
313
+ if ( true === $retval
314
+ && ! bp_current_user_can( 'bp_moderate' )
315
+ && $user_id !== $group_request->user_id
316
+ && ! groups_is_user_admin( $user_id, $group_request->item_id ) ) {
317
+ $retval = new WP_Error(
318
+ 'bp_rest_group_membership_requests_cannot_get_item',
319
+ __( 'Sorry, you are not allowed to view a membership request.', 'buddypress' ),
320
+ array(
321
+ 'status' => 500,
322
+ )
323
+ );
324
+ }
325
+
326
+ /**
327
+ * Filter the group membership request `get_item` permissions check.
328
+ *
329
+ * @since 5.0.0
330
+ *
331
+ * @param bool|WP_Error $retval Whether the request can continue.
332
+ * @param WP_REST_Request $request The request sent to the API.
333
+ */
334
+ return apply_filters( 'bp_rest_group_membership_requests_get_item_permissions_check', $retval, $request );
335
+ }
336
+
337
+ /**
338
+ * Request membership to a group.
339
+ *
340
+ * @since 5.0.0
341
+ *
342
+ * @param WP_REST_Request $request Full data about the request.
343
+ * @return WP_REST_Response|WP_Error
344
+ */
345
+ public function create_item( $request ) {
346
+ $user_id_arg = $request['user_id'] ? $request['user_id'] : bp_loggedin_user_id();
347
+ $user = bp_rest_get_user( $user_id_arg );
348
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
349
+
350
+ // Avoid duplicate requests.
351
+ if ( groups_check_for_membership_request( $user->ID, $group->id ) ) {
352
+ return new WP_Error(
353
+ 'bp_rest_group_membership_requests_duplicate_request',
354
+ __( 'There is already a request to this member.', 'buddypress' ),
355
+ array(
356
+ 'status' => 500,
357
+ )
358
+ );
359
+ }
360
+
361
+ $request_id = groups_send_membership_request(
362
+ array(
363
+ 'group_id' => $group->id,
364
+ 'user_id' => $user->ID,
365
+ 'content' => $request['message'],
366
+ )
367
+ );
368
+
369
+ if ( ! $request_id ) {
370
+ return new WP_Error(
371
+ 'bp_rest_group_membership_requests_cannot_create_item',
372
+ __( 'Could not send membership request to this group.', 'buddypress' ),
373
+ array(
374
+ 'status' => 500,
375
+ )
376
+ );
377
+ }
378
+
379
+ // Setting context.
380
+ $request->set_param( 'context', 'edit' );
381
+
382
+ $invite = new BP_Invitation( $request_id );
383
+
384
+ $retval = array(
385
+ $this->prepare_response_for_collection(
386
+ $this->prepare_item_for_response( $invite, $request )
387
+ ),
388
+ );
389
+
390
+ $response = rest_ensure_response( $retval );
391
+
392
+ /**
393
+ * Fires after a group membership request is made via the REST API.
394
+ *
395
+ * @since 5.0.0
396
+ *
397
+ * @param WP_User $user The user.
398
+ * @param BP_Invitation $invite The invitation object.
399
+ * @param BP_Groups_Group $group The group object.
400
+ * @param WP_REST_Response $response The response data.
401
+ * @param WP_REST_Request $request The request sent to the API.
402
+ */
403
+ do_action( 'bp_rest_group_membership_requests_create_item', $user, $invite, $group, $response, $request );
404
+
405
+ return $response;
406
+ }
407
+
408
+ /**
409
+ * Checks if a given request has access to make a group membership request.
410
+ *
411
+ * @since 5.0.0
412
+ *
413
+ * @param WP_REST_Request $request Full details about the request.
414
+ * @return bool|WP_Error
415
+ */
416
+ public function create_item_permissions_check( $request ) {
417
+ $retval = true;
418
+ $user_id = bp_loggedin_user_id();
419
+ $user_id_arg = $request['user_id'] ? $request['user_id'] : bp_loggedin_user_id();
420
+ $user = bp_rest_get_user( $user_id_arg );
421
+ $group = $this->groups_endpoint->get_group_object( $request['group_id'] );
422
+
423
+ // User must be logged in.
424
+ if ( ! is_user_logged_in() ) {
425
+ $retval = new WP_Error(
426
+ 'bp_rest_authorization_required',
427
+ __( 'Sorry, you need to be logged in to create a membership request.', 'buddypress' ),
428
+ array(
429
+ 'status' => rest_authorization_required_code(),
430
+ )
431
+ );
432
+ }
433
+
434
+ // Check for valid user.
435
+ if ( true === $retval && ! $user instanceof WP_User ) {
436
+ $retval = new WP_Error(
437
+ 'bp_rest_group_member_invalid_id',
438
+ __( 'Invalid user id.', 'buddypress' ),
439
+ array(
440
+ 'status' => 404,
441
+ )
442
+ );
443
+ }
444
+
445
+ // Check for valid group.
446
+ if ( true === $retval && ! $group instanceof BP_Groups_Group ) {
447
+ $retval = new WP_Error(
448
+ 'bp_rest_group_invalid_id',
449
+ __( 'Invalid group id.', 'buddypress' ),
450
+ array(
451
+ 'status' => 404,
452
+ )
453
+ );
454
+ }
455
+
456
+ // Normal users can only extend invitations on their own behalf.
457
+ if ( true === $retval
458
+ && ! bp_current_user_can( 'bp_moderate' )
459
+ && $user_id !== $user_id_arg ) {
460
+ $retval = new WP_Error(
461
+ 'bp_rest_group_membership_requests_cannot_create_item',
462
+ __( 'User may not extend requests on behalf of another user.', 'buddypress' ),
463
+ array(
464
+ 'status' => 500,
465
+ )
466
+ );
467
+ }
468
+
469
+ /**
470
+ * Filter the group membership request `create_item` permissions check.
471
+ *
472
+ * @since 5.0.0
473
+ *
474
+ * @param bool|WP_Error $retval Returned value.
475
+ * @param WP_REST_Request $request The request sent to the API.
476
+ */
477
+ return apply_filters( 'bp_rest_group_membership_requests_create_item_permissions_check', $retval, $request );
478
+ }
479
+
480
+ /**
481
+ * Accept or reject a pending group membership request.
482
+ *
483
+ * @since 5.0.0
484
+ *
485
+ * @param WP_REST_Request $request Full data about the request.
486
+ * @return WP_REST_Response|WP_Error
487
+ */
488
+ public function update_item( $request ) {
489
+ $group_request = $this->fetch_single_membership_request( $request['request_id'] );
490
+ $success = groups_accept_membership_request( false, $group_request->user_id, $group_request->item_id );
491
+ if ( ! $success ) {
492
+ return new WP_Error(
493
+ 'bp_rest_group_member_request_cannot_update_item',
494
+ __( 'There was an error accepting the membership request.', 'buddypress' ),
495
+ array(
496
+ 'status' => 500,
497
+ )
498
+ );
499
+ }
500
+
501
+ // Setting context.
502
+ $request->set_param( 'context', 'edit' );
503
+
504
+ $g_member = new BP_Groups_Member( $group_request->user_id, $group_request->item_id );
505
+
506
+ $retval = array(
507
+ $this->prepare_response_for_collection(
508
+ $this->group_members_endpoint->prepare_item_for_response( $g_member, $request )
509
+ ),
510
+ );
511
+
512
+ $response = rest_ensure_response( $retval );
513
+ $group = $this->groups_endpoint->get_group_object( $group_request->item_id );
514
+
515
+ /**
516
+ * Fires after a group membership request is accepted/rejected via the REST API.
517
+ *
518
+ * @since 5.0.0
519
+ *
520
+ * @param BP_Groups_Member $g_member The groups member object.
521
+ * @param BP_Groups_Group $group The group object.
522
+ * @param WP_REST_Response $response The response data.
523
+ * @param WP_REST_Request $request The request sent to the API.
524
+ */
525
+ do_action( 'bp_rest_group_membership_requests_update_item', $g_member, $group, $response, $request );
526
+
527
+ return $response;
528
+ }
529
+
530
+ /**
531
+ * Checks if a given request has access to accept a group membership request.
532
+ *
533
+ * @since 5.0.0
534
+ *
535
+ * @param WP_REST_Request $request Full details about the request.
536
+ * @return bool|WP_Error
537
+ */
538
+ public function update_item_permissions_check( $request ) {
539
+ $retval = true;
540
+ $user_id = bp_loggedin_user_id();
541
+ $group_request = $this->fetch_single_membership_request( $request['request_id'] );
542
+
543
+ if ( ! $user_id ) {
544
+ $retval = new WP_Error(
545
+ 'bp_rest_authorization_required',
546
+ __( 'Sorry, you need to be logged in to make an update.', 'buddypress' ),
547
+ array(
548
+ 'status' => rest_authorization_required_code(),
549
+ )
550
+ );
551
+ }
552
+
553
+ if ( true === $retval && ! $group_request ) {
554
+ $retval = new WP_Error(
555
+ 'bp_rest_group_membership_requests_invalid_id',
556
+ __( 'Invalid group membership request id.', 'buddypress' ),
557
+ array(
558
+ 'status' => 404,
559
+ )
560
+ );
561
+ }
562
+
563
+ if ( true === $retval
564
+ && ! bp_current_user_can( 'bp_moderate' )
565
+ && ! groups_is_user_admin( $user_id, $group_request->item_id ) ) {
566
+ $retval = new WP_Error(
567
+ 'bp_rest_group_member_request_cannot_update_item',
568
+ __( 'User is not allowed to approve membership requests to this group.', 'buddypress' ),
569
+ array(
570
+ 'status' => 500,
571
+ )
572
+ );
573
+ }
574
+
575
+ /**
576
+ * Filter the group membership request `update_item` permissions check.
577
+ *
578
+ * @since 5.0.0
579
+ *
580
+ * @param bool|WP_Error $retval Whether the request can continue.
581
+ * @param WP_REST_Request $request The request sent to the API.
582
+ */
583
+ return apply_filters( 'bp_rest_group_membership_requests_update_item_permissions_check', $retval, $request );
584
+ }
585
+
586
+ /**
587
+ * Reject a pending group membership request.
588
+ *
589
+ * @since 5.0.0
590
+ *
591
+ * @param WP_REST_Request $request Full data about the request.
592
+ * @return WP_REST_Response|WP_Error
593
+ */
594
+ public function delete_item( $request ) {
595
+
596
+ // Setting context.
597
+ $request->set_param( 'context', 'edit' );
598
+
599
+ // Get invite.
600
+ $group_request = $this->fetch_single_membership_request( $request['request_id'] );
601
+
602
+ // Set the invite response before it is deleted.
603
+ $previous = $this->prepare_item_for_response( $group_request, $request );
604
+
605
+ /**
606
+ * If this change is being initiated by the requesting user,
607
+ * use the `delete` function.
608
+ */
609
+ if ( bp_loggedin_user_id() === $group_request->user_id ) {
610
+ $success = groups_delete_membership_request( false, $group_request->user_id, $group_request->item_id );
611
+ /**
612
+ * Otherwise, this change is being initiated by a group admin or site admin,
613
+ * and we should use the `reject` function.
614
+ */
615
+ } else {
616
+ $success = groups_reject_membership_request( false, $group_request->user_id, $group_request->item_id );
617
+ }
618
+
619
+ if ( ! $success ) {
620
+ return new WP_Error(
621
+ 'bp_rest_group_membership_requests_cannot_delete_item',
622
+ __( 'There was an error rejecting the membership request.', 'buddypress' ),
623
+ array(
624
+ 'status' => 500,
625
+ )
626
+ );
627
+ }
628
+
629
+ // Build the response.
630
+ $response = new WP_REST_Response();
631
+ $response->set_data(
632
+ array(
633
+ 'deleted' => true,
634
+ 'previous' => $previous->get_data(),
635
+ )
636
+ );
637
+
638
+ $user = bp_rest_get_user( $group_request->user_id );
639
+ $group = $this->groups_endpoint->get_group_object( $group_request->item_id );
640
+
641
+ /**
642
+ * Fires after a group membership request is rejected via the REST API.
643
+ *
644
+ * @since 5.0.0
645
+ *
646
+ * @param WP_User $user The user.
647
+ * @param BP_Groups_Group $group The group object.
648
+ * @param WP_REST_Response $response The response data.
649
+ * @param WP_REST_Request $request The request sent to the API.
650
+ */
651
+ do_action( 'bp_rest_group_membership_requests_delete_item', $user, $group, $response, $request );
652
+
653
+ return $response;
654
+ }
655
+
656
+ /**
657
+ * Checks if a given request has access to reject a group membership request.
658
+ *
659
+ * @since 5.0.0
660
+ *
661
+ * @param WP_REST_Request $request Full details about the request.
662
+ * @return bool|WP_Error
663
+ */
664
+ public function delete_item_permissions_check( $request ) {
665
+ $retval = true;
666
+ $user_id = bp_loggedin_user_id();
667
+ $group_request = $this->fetch_single_membership_request( $request['request_id'] );
668
+
669
+ if ( ! $user_id ) {
670
+ $retval = new WP_Error(
671
+ 'bp_rest_authorization_required',
672
+ __( 'Sorry, you need to be logged in to delete a request.', 'buddypress' ),
673
+ array(
674
+ 'status' => rest_authorization_required_code(),
675
+ )
676
+ );
677
+ }
678
+
679
+ if ( true === $retval && ! $group_request ) {
680
+ $retval = new WP_Error(
681
+ 'bp_rest_group_membership_requests_invalid_id',
682
+ __( 'Invalid group membership request id.', 'buddypress' ),
683
+ array(
684
+ 'status' => 404,
685
+ )
686
+ );
687
+ }
688
+
689
+ if ( true === $retval
690
+ && ! bp_current_user_can( 'bp_moderate' )
691
+ && $user_id !== $group_request->user_id
692
+ && ! groups_is_user_admin( $user_id, $group_request->item_id ) ) {
693
+ $retval = new WP_Error(
694
+ 'bp_rest_group_membership_requests_cannot_delete_item',
695
+ __( 'User is not allowed to delete this membership request.', 'buddypress' ),
696
+ array(
697
+ 'status' => 500,
698
+ )
699
+ );
700
+ }
701
+
702
+ /**
703
+ * Filter the group membership request `delete_item` permissions check.
704
+ *
705
+ * @since 5.0.0
706
+ *
707
+ * @param bool|WP_Error $retval Whether the request may proceed.
708
+ * @param WP_REST_Request $request The request sent to the API.
709
+ */
710
+ return apply_filters( 'bp_rest_group_membership_requests_delete_item_permissions_check', $retval, $request );
711
+ }
712
+
713
+ /**
714
+ * Prepares group invitation data to return as an object.
715
+ *
716
+ * @since 5.0.0
717
+ *
718
+ * @param BP_Invitation $invite Invite object.
719
+ * @param WP_REST_Request $request Full details about the request.
720
+ * @return WP_REST_Response
721
+ */
722
+ public function prepare_item_for_response( $invite, $request ) {
723
+ $data = array(
724
+ 'id' => $invite->id,
725
+ 'user_id' => $invite->user_id,
726
+ 'invite_sent' => $invite->invite_sent,
727
+ 'inviter_id' => $invite->inviter_id,
728
+ 'group_id' => $invite->item_id,
729
+ 'date_modified' => bp_rest_prepare_date_response( $invite->date_modified ),
730
+ 'type' => $invite->type,
731
+ 'message' => array(
732
+ 'raw' => $invite->content,
733
+ 'rendered' => apply_filters( 'the_content', $invite->content ),
734
+ ),
735
+ );
736
+
737
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
738
+ $data = $this->add_additional_fields_to_object( $data, $request );
739
+ $data = $this->filter_response_by_context( $data, $context );
740
+ $response = rest_ensure_response( $data );
741
+
742
+ $response->add_links( $this->prepare_links( $invite ) );
743
+
744
+ /**
745
+ * Filter a group invite value returned from the API.
746
+ *
747
+ * @since 5.0.0
748
+ *
749
+ * @param WP_REST_Response $response The response data.
750
+ * @param WP_REST_Request $request Request used to generate the response.
751
+ * @param BP_Invitation $invite The invite object.
752
+ */
753
+ return apply_filters( 'bp_rest_group_membership_requests_prepare_value', $response, $request, $invite );
754
+ }
755
+
756
+ /**
757
+ * Prepare links for the request.
758
+ *
759
+ * @since 5.0.0
760
+ *
761
+ * @param BP_Invitation $invite Invite object.
762
+ * @return array Links for the given plugin.
763
+ */
764
+ protected function prepare_links( $invite ) {
765
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
766
+ $url = $base . $invite->id;
767
+
768
+ // Entity meta.
769
+ $links = array(
770
+ 'self' => array(
771
+ 'href' => rest_url( $url ),
772
+ ),
773
+ 'collection' => array(
774
+ 'href' => rest_url( $base ),
775
+ ),
776
+ 'user' => array(
777
+ 'href' => rest_url( bp_rest_get_user_url( $invite->user_id ) ),
778
+ 'embeddable' => true,
779
+ ),
780
+ );
781
+
782
+ /**
783
+ * Filter links prepared for the REST response.
784
+ *
785
+ * @since 5.0.0
786
+ *
787
+ * @param array $links The prepared links of the REST response.
788
+ * @param BP_Invitation $invite Invite object.
789
+ */
790
+ return apply_filters( 'bp_rest_group_membership_requests_prepare_links', $links, $invite );
791
+ }
792
+
793
+ /**
794
+ * Helper function to fetch a single group invite.
795
+ *
796
+ * @since 5.0.0
797
+ *
798
+ * @param int $request_id The ID of the request you wish to fetch.
799
+ * @return BP_Invitation|bool $group_request Membership request if found, false otherwise.
800
+ */
801
+ public function fetch_single_membership_request( $request_id = 0 ) {
802
+ $group_requests = groups_get_requests( array( 'id' => $request_id ) );
803
+ if ( $group_requests ) {
804
+ return current( $group_requests );
805
+ } else {
806
+ return false;
807
+ }
808
+ }
809
+
810
+ /**
811
+ * Endpoint args.
812
+ *
813
+ * @since 5.0.0
814
+ *
815
+ * @param string $method Optional. HTTP method of the request.
816
+ * @return array Endpoint arguments.
817
+ */
818
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
819
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
820
+ $key = 'get_item';
821
+
822
+ if ( WP_REST_Server::CREATABLE === $method ) {
823
+ $key = 'create_item';
824
+
825
+ $args['message']['type'] = 'string';
826
+ $args['message']['description'] = __( 'The optional message to send to the invited user.', 'buddypress' );
827
+ $args['group_id']['required'] = true;
828
+ $args['user_id']['default'] = bp_loggedin_user_id();
829
+
830
+ // Remove arguments not needed for the CREATABLE transport method.
831
+ unset( $args['message']['properties'], $args['date_modified'], $args['type'] );
832
+
833
+ } elseif ( WP_REST_Server::EDITABLE === $method ) {
834
+ $key = 'update_item';
835
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
836
+ $key = 'delete_item';
837
+ }
838
+
839
+ /**
840
+ * Filters the method query arguments.
841
+ *
842
+ * @since 5.0.0
843
+ *
844
+ * @param array $args Query arguments.
845
+ * @param string $method HTTP method of the request.
846
+ */
847
+ return apply_filters( "bp_rest_group_membership_requests_{$key}_query_arguments", $args, $method );
848
+ }
849
+
850
+ /**
851
+ * Get the group membership request schema, conforming to JSON Schema.
852
+ *
853
+ * @since 5.0.0
854
+ *
855
+ * @return array
856
+ */
857
+ public function get_item_schema() {
858
+
859
+ // Get schema from the membership endpoint.
860
+ $schema = $this->invites_endpoint->get_item_schema();
861
+
862
+ // Set title to this endpoint.
863
+ $schema['title'] = 'bp_group_membership_request';
864
+
865
+ // Adapt some item schema property descriptions to this endpoint.
866
+ $schema['properties']['user_id']['description'] = __( 'The ID of the user who requested a Group membership.', 'buddypress' );
867
+ $schema['properties']['group_id']['description'] = __( 'The ID of the group the user requested a membership for.', 'buddypress' );
868
+ $schema['properties']['type']['default'] = 'request';
869
+
870
+ // Remove unused properties.
871
+ unset( $schema['properties']['invite_sent'], $schema['properties']['inviter_id'] );
872
+
873
+ /**
874
+ * Filters the group membership request schema.
875
+ *
876
+ * @param array $schema The endpoint schema.
877
+ */
878
+ return apply_filters( 'bp_rest_group_membership_requests_schema', $this->add_additional_fields_schema( $schema ) );
879
+ }
880
+
881
+ /**
882
+ * Get the query params for collections of group invites.
883
+ *
884
+ * @since 5.0.0
885
+ *
886
+ * @return array
887
+ */
888
+ public function get_collection_params() {
889
+ $params = $this->invites_endpoint->get_collection_params();
890
+ $params['context']['default'] = 'view';
891
+
892
+ // Adapt some item schema property descriptions to this endpoint.
893
+ $params['user_id']['description'] = __( 'Return only Membership requests made by a specific user.', 'buddypress' );
894
+ $params['group_id']['description'] = __( 'The ID of the group the user requested a membership for.', 'buddypress' );
895
+
896
+ // Remove unused properties.
897
+ unset( $params['invite_sent'], $params['inviter_id'] );
898
+
899
+ /**
900
+ * Filters the collection query params.
901
+ *
902
+ * @param array $params Query params.
903
+ */
904
+ return apply_filters( 'bp_rest_group_membership_requests_collection_params', $params );
905
+ }
906
+ }
bp-groups/classes/class-bp-rest-groups-endpoint.php ADDED
@@ -0,0 +1,1216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Groups_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Groups endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Groups_Endpoint extends WP_REST_Controller {
17
+
18
+ /**
19
+ * Constructor.
20
+ *
21
+ * @since 5.0.0
22
+ */
23
+ public function __construct() {
24
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
25
+ $this->rest_base = buddypress()->groups->id;
26
+ }
27
+
28
+ /**
29
+ * Register the component routes.
30
+ *
31
+ * @since 5.0.0
32
+ */
33
+ public function register_routes() {
34
+ register_rest_route(
35
+ $this->namespace,
36
+ '/' . $this->rest_base,
37
+ array(
38
+ array(
39
+ 'methods' => WP_REST_Server::READABLE,
40
+ 'callback' => array( $this, 'get_items' ),
41
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
42
+ 'args' => $this->get_collection_params(),
43
+ ),
44
+ array(
45
+ 'methods' => WP_REST_Server::CREATABLE,
46
+ 'callback' => array( $this, 'create_item' ),
47
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
48
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
49
+ ),
50
+ 'schema' => array( $this, 'get_item_schema' ),
51
+ )
52
+ );
53
+
54
+ register_rest_route(
55
+ $this->namespace,
56
+ '/' . $this->rest_base . '/(?P<id>[\d]+)',
57
+ array(
58
+ 'args' => array(
59
+ 'id' => array(
60
+ 'description' => __( 'A unique numeric ID for the Group.', 'buddypress' ),
61
+ 'type' => 'integer',
62
+ ),
63
+ ),
64
+ array(
65
+ 'methods' => WP_REST_Server::READABLE,
66
+ 'callback' => array( $this, 'get_item' ),
67
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
68
+ 'args' => array(
69
+ 'context' => $this->get_context_param(
70
+ array(
71
+ 'default' => 'view',
72
+ )
73
+ ),
74
+ ),
75
+ ),
76
+ array(
77
+ 'methods' => WP_REST_Server::EDITABLE,
78
+ 'callback' => array( $this, 'update_item' ),
79
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
80
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
81
+ ),
82
+ array(
83
+ 'methods' => WP_REST_Server::DELETABLE,
84
+ 'callback' => array( $this, 'delete_item' ),
85
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
86
+ ),
87
+ 'schema' => array( $this, 'get_item_schema' ),
88
+ )
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Retrieve groups.
94
+ *
95
+ * @since 5.0.0
96
+ *
97
+ * @param WP_REST_Request $request Full details about the request.
98
+ * @return WP_REST_Request List of groups object data.
99
+ */
100
+ public function get_items( $request ) {
101
+ $args = array(
102
+ 'type' => $request['type'],
103
+ 'order' => $request['order'],
104
+ 'fields' => $request['fields'],
105
+ 'orderby' => $request['orderby'],
106
+ 'user_id' => $request['user_id'],
107
+ 'include' => $request['include'],
108
+ 'parent_id' => $request['parent_id'],
109
+ 'exclude' => $request['exclude'],
110
+ 'search_terms' => $request['search'],
111
+ 'meta_query' => $request['meta'], // phpcs:ignore
112
+ 'group_type' => $request['group_type'],
113
+ 'show_hidden' => $request['show_hidden'],
114
+ 'per_page' => $request['per_page'],
115
+ 'status' => $request['status'],
116
+ 'page' => $request['page'],
117
+ );
118
+
119
+ if ( empty( $request['parent_id'] ) ) {
120
+ $args['parent_id'] = null;
121
+ }
122
+
123
+ /**
124
+ * Filter the query arguments for the request.
125
+ *
126
+ * @since 5.0.0
127
+ *
128
+ * @param array $args Key value array of query var to query value.
129
+ * @param WP_REST_Request $request The request sent to the API.
130
+ */
131
+ $args = apply_filters( 'bp_rest_groups_get_items_query_args', $args, $request );
132
+
133
+ // Actually, query it.
134
+ $groups = groups_get_groups( $args );
135
+
136
+ $retval = array();
137
+ foreach ( $groups['groups'] as $group ) {
138
+ $retval[] = $this->prepare_response_for_collection(
139
+ $this->prepare_item_for_response( $group, $request )
140
+ );
141
+ }
142
+
143
+ $response = rest_ensure_response( $retval );
144
+ $response = bp_rest_response_add_total_headers( $response, $groups['total'], $args['per_page'] );
145
+
146
+ /**
147
+ * Fires after a list of groups is fetched via the REST API.
148
+ *
149
+ * @since 5.0.0
150
+ *
151
+ * @param array $groups Fetched groups.
152
+ * @param WP_REST_Response $response The response data.
153
+ * @param WP_REST_Request $request The request sent to the API.
154
+ */
155
+ do_action( 'bp_rest_groups_get_items', $groups, $response, $request );
156
+
157
+ return $response;
158
+ }
159
+
160
+ /**
161
+ * Check if a given request has access to group items.
162
+ *
163
+ * @since 5.0.0
164
+ *
165
+ * @param WP_REST_Request $request Full details about the request.
166
+ * @return bool|WP_Error
167
+ */
168
+ public function get_items_permissions_check( $request ) {
169
+ $retval = true;
170
+
171
+ if ( ! $this->can_see_hidden_groups( $request ) ) {
172
+ $retval = new WP_Error(
173
+ 'bp_rest_authorization_required',
174
+ __( 'Sorry, you cannot view hidden groups.', 'buddypress' ),
175
+ array(
176
+ 'status' => rest_authorization_required_code(),
177
+ )
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Filter the groups `get_items` permissions check.
183
+ *
184
+ * @since 5.0.0
185
+ *
186
+ * @param bool|WP_Error $retval Returned value.
187
+ * @param WP_REST_Request $request The request sent to the API.
188
+ */
189
+ return apply_filters( 'bp_rest_groups_get_items_permissions_check', $retval, $request );
190
+ }
191
+
192
+ /**
193
+ * Retrieve a group.
194
+ *
195
+ * @since 5.0.0
196
+ *
197
+ * @param WP_REST_Request $request Full details about the request.
198
+ * @return WP_REST_Response
199
+ */
200
+ public function get_item( $request ) {
201
+ $group = $this->get_group_object( $request );
202
+
203
+ $retval = array(
204
+ $this->prepare_response_for_collection(
205
+ $this->prepare_item_for_response( $group, $request )
206
+ ),
207
+ );
208
+
209
+ $response = rest_ensure_response( $retval );
210
+
211
+ /**
212
+ * Fires after a group is fetched via the REST API.
213
+ *
214
+ * @since 5.0.0
215
+ *
216
+ * @param BP_Groups_Group $group Fetched group.
217
+ * @param WP_REST_Response $response The response data.
218
+ * @param WP_REST_Request $request The request sent to the API.
219
+ */
220
+ do_action( 'bp_rest_groups_get_item', $group, $response, $request );
221
+
222
+ return $response;
223
+ }
224
+
225
+ /**
226
+ * Check if a given request has access to get information about a specific group.
227
+ *
228
+ * @since 5.0.0
229
+ *
230
+ * @param WP_REST_Request $request Full details about the request.
231
+ * @return WP_Error|bool
232
+ */
233
+ public function get_item_permissions_check( $request ) {
234
+ $retval = true;
235
+ $group = $this->get_group_object( $request );
236
+
237
+ if ( empty( $group->id ) ) {
238
+ $retval = new WP_Error(
239
+ 'bp_rest_group_invalid_id',
240
+ __( 'Invalid group id.', 'buddypress' ),
241
+ array(
242
+ 'status' => 404,
243
+ )
244
+ );
245
+ }
246
+
247
+ if ( true === $retval && ! $this->can_see( $group ) ) {
248
+ $retval = new WP_Error(
249
+ 'bp_rest_authorization_required',
250
+ __( 'Sorry, you cannot view the group.', 'buddypress' ),
251
+ array(
252
+ 'status' => rest_authorization_required_code(),
253
+ )
254
+ );
255
+ }
256
+
257
+ /**
258
+ * Filter the groups `get_item` permissions check.
259
+ *
260
+ * @since 5.0.0
261
+ *
262
+ * @param bool|WP_Error $retval Returned value.
263
+ * @param WP_REST_Request $request The request sent to the API.
264
+ */
265
+ return apply_filters( 'bp_rest_groups_get_item_permissions_check', $retval, $request );
266
+ }
267
+
268
+ /**
269
+ * Create a group.
270
+ *
271
+ * @since 5.0.0
272
+ *
273
+ * @param WP_REST_Request $request Full data about the request.
274
+ * @return WP_REST_Response|WP_Error
275
+ */
276
+ public function create_item( $request ) {
277
+
278
+ // Setting context.
279
+ $request->set_param( 'context', 'edit' );
280
+
281
+ // If no group name.
282
+ if ( empty( $request['name'] ) ) {
283
+ return new WP_Error(
284
+ 'bp_rest_create_group_empty_name',
285
+ __( 'Please, enter the name of group.', 'buddypress' ),
286
+ array(
287
+ 'status' => 500,
288
+ )
289
+ );
290
+ }
291
+
292
+ $group_id = groups_create_group( $this->prepare_item_for_database( $request ) );
293
+
294
+ if ( ! is_numeric( $group_id ) ) {
295
+ return new WP_Error(
296
+ 'bp_rest_user_cannot_create_group',
297
+ __( 'Cannot create new group.', 'buddypress' ),
298
+ array(
299
+ 'status' => 500,
300
+ )
301
+ );
302
+ }
303
+
304
+ $group = $this->get_group_object( $group_id );
305
+ $fields_update = $this->update_additional_fields_for_object( $group, $request );
306
+
307
+ if ( is_wp_error( $fields_update ) ) {
308
+ return $fields_update;
309
+ }
310
+
311
+ $retval = array(
312
+ $this->prepare_response_for_collection(
313
+ $this->prepare_item_for_response( $group, $request )
314
+ ),
315
+ );
316
+
317
+ $response = rest_ensure_response( $retval );
318
+
319
+ /**
320
+ * Fires after a group is created via the REST API.
321
+ *
322
+ * @since 5.0.0
323
+ *
324
+ * @param BP_Groups_Group $group The created group.
325
+ * @param WP_REST_Response $response The response data.
326
+ * @param WP_REST_Request $request The request sent to the API.
327
+ */
328
+ do_action( 'bp_rest_groups_create_item', $group, $response, $request );
329
+
330
+ return $response;
331
+ }
332
+
333
+ /**
334
+ * Checks if a given request has access to create a group.
335
+ *
336
+ * @since 5.0.0
337
+ *
338
+ * @param WP_REST_Request $request Full details about the request.
339
+ * @return bool|WP_Error
340
+ */
341
+ public function create_item_permissions_check( $request ) {
342
+ $retval = true;
343
+
344
+ if ( ! ( is_user_logged_in() && bp_user_can_create_groups() ) ) {
345
+ $retval = new WP_Error(
346
+ 'bp_rest_authorization_required',
347
+ __( 'Sorry, you are not allowed to create groups.', 'buddypress' ),
348
+ array(
349
+ 'status' => rest_authorization_required_code(),
350
+ )
351
+ );
352
+ }
353
+
354
+ /**
355
+ * Filter the groups `create_item` permissions check.
356
+ *
357
+ * @since 5.0.0
358
+ *
359
+ * @param bool|WP_Error $retval Returned value.
360
+ * @param WP_REST_Request $request The request sent to the API.
361
+ */
362
+ return apply_filters( 'bp_rest_groups_create_item_permissions_check', $retval, $request );
363
+ }
364
+
365
+ /**
366
+ * Update a group.
367
+ *
368
+ * @since 5.0.0
369
+ *
370
+ * @param WP_REST_Request $request Full details about the request.
371
+ * @return WP_REST_Response|WP_Error
372
+ */
373
+ public function update_item( $request ) {
374
+ // Setting context.
375
+ $request->set_param( 'context', 'edit' );
376
+
377
+ $group_id = groups_create_group( $this->prepare_item_for_database( $request ) );
378
+
379
+ if ( ! is_numeric( $group_id ) ) {
380
+ return new WP_Error(
381
+ 'bp_rest_user_cannot_update_group',
382
+ __( 'Cannot update existing group.', 'buddypress' ),
383
+ array(
384
+ 'status' => 500,
385
+ )
386
+ );
387
+ }
388
+
389
+ $group = $this->get_group_object( $group_id );
390
+ $fields_update = $this->update_additional_fields_for_object( $group, $request );
391
+
392
+ if ( is_wp_error( $fields_update ) ) {
393
+ return $fields_update;
394
+ }
395
+
396
+ $retval = array(
397
+ $this->prepare_response_for_collection(
398
+ $this->prepare_item_for_response( $group, $request )
399
+ ),
400
+ );
401
+
402
+ $response = rest_ensure_response( $retval );
403
+
404
+ /**
405
+ * Fires after a group is updated via the REST API.
406
+ *
407
+ * @since 5.0.0
408
+ *
409
+ * @param BP_Groups_Group $group The updated group.
410
+ * @param WP_REST_Response $response The response data.
411
+ * @param WP_REST_Request $request The request sent to the API.
412
+ */
413
+ do_action( 'bp_rest_groups_update_item', $group, $response, $request );
414
+
415
+ return $response;
416
+ }
417
+
418
+ /**
419
+ * Check if a given request has access to update a group.
420
+ *
421
+ * @since 5.0.0
422
+ *
423
+ * @param WP_REST_Request $request Full details about the request.
424
+ * @return bool|WP_Error
425
+ */
426
+ public function update_item_permissions_check( $request ) {
427
+ $retval = true;
428
+
429
+ if ( ! is_user_logged_in() ) {
430
+ $retval = new WP_Error(
431
+ 'bp_rest_authorization_required',
432
+ __( 'Sorry, you need to be logged in to update this group.', 'buddypress' ),
433
+ array(
434
+ 'status' => rest_authorization_required_code(),
435
+ )
436
+ );
437
+ }
438
+
439
+ $group = $this->get_group_object( $request );
440
+
441
+ if ( true === $retval && empty( $group->id ) ) {
442
+ $retval = new WP_Error(
443
+ 'bp_rest_group_invalid_id',
444
+ __( 'Invalid group id.', 'buddypress' ),
445
+ array(
446
+ 'status' => 404,
447
+ )
448
+ );
449
+ }
450
+
451
+ // If group author does not match logged_in user, block update.
452
+ if ( true === $retval && ! $this->can_user_delete_or_update( $group ) ) {
453
+ $retval = new WP_Error(
454
+ 'bp_rest_authorization_required',
455
+ __( 'Sorry, you are not allowed to update this group.', 'buddypress' ),
456
+ array(
457
+ 'status' => rest_authorization_required_code(),
458
+ )
459
+ );
460
+ }
461
+
462
+ /**
463
+ * Filter the groups `update_item` permissions check.
464
+ *
465
+ * @since 5.0.0
466
+ *
467
+ * @param bool|WP_Error $retval Returned value.
468
+ * @param WP_REST_Request $request The request sent to the API.
469
+ */
470
+ return apply_filters( 'bp_rest_groups_update_item_permissions_check', $retval, $request );
471
+ }
472
+
473
+ /**
474
+ * Delete a group.
475
+ *
476
+ * @since 5.0.0
477
+ *
478
+ * @param WP_REST_Request $request Full details about the request.
479
+ * @return WP_REST_Response|WP_Error
480
+ */
481
+ public function delete_item( $request ) {
482
+ // Setting context.
483
+ $request->set_param( 'context', 'edit' );
484
+
485
+ // Get the group before it's deleted.
486
+ $group = $this->get_group_object( $request );
487
+ $previous = $this->prepare_item_for_response( $group, $request );
488
+
489
+ if ( ! groups_delete_group( $group->id ) ) {
490
+ return new WP_Error(
491
+ 'bp_rest_group_cannot_delete',
492
+ __( 'Could not delete the group.', 'buddypress' ),
493
+ array(
494
+ 'status' => 500,
495
+ )
496
+ );
497
+ }
498
+
499
+ // Build the response.
500
+ $response = new WP_REST_Response();
501
+ $response->set_data(
502
+ array(
503
+ 'deleted' => true,
504
+ 'previous' => $previous->get_data(),
505
+ )
506
+ );
507
+
508
+ /**
509
+ * Fires after a group is deleted via the REST API.
510
+ *
511
+ * @since 5.0.0
512
+ *
513
+ * @param object $group The deleted group.
514
+ * @param WP_REST_Response $response The response data.
515
+ * @param WP_REST_Request $request The request sent to the API.
516
+ */
517
+ do_action( 'bp_rest_groups_delete_item', $group, $response, $request );
518
+
519
+ return $response;
520
+ }
521
+
522
+ /**
523
+ * Check if a given request has access to delete a group.
524
+ *
525
+ * @since 5.0.0
526
+ *
527
+ * @param WP_REST_Request $request Full details about the request.
528
+ * @return bool|WP_Error
529
+ */
530
+ public function delete_item_permissions_check( $request ) {
531
+ $retval = true;
532
+
533
+ if ( ! is_user_logged_in() ) {
534
+ $retval = new WP_Error(
535
+ 'bp_rest_authorization_required',
536
+ __( 'Sorry, you need to be logged in to delete this group.', 'buddypress' ),
537
+ array(
538
+ 'status' => rest_authorization_required_code(),
539
+ )
540
+ );
541
+ }
542
+
543
+ $group = $this->get_group_object( $request );
544
+
545
+ if ( true === $retval && empty( $group->id ) ) {
546
+ $retval = new WP_Error(
547
+ 'bp_rest_group_invalid_id',
548
+ __( 'Invalid group id.', 'buddypress' ),
549
+ array(
550
+ 'status' => 404,
551
+ )
552
+ );
553
+ }
554
+
555
+ if ( true === $retval && ! $this->can_user_delete_or_update( $group ) ) {
556
+ $retval = new WP_Error(
557
+ 'bp_rest_authorization_required',
558
+ __( 'Sorry, you are not allowed to delete this group.', 'buddypress' ),
559
+ array(
560
+ 'status' => rest_authorization_required_code(),
561
+ )
562
+ );
563
+ }
564
+
565
+ /**
566
+ * Filter the groups `delete_item` permissions check.
567
+ *
568
+ * @since 5.0.0
569
+ *
570
+ * @param bool|WP_Error $retval Returned value.
571
+ * @param WP_REST_Request $request The request sent to the API.
572
+ */
573
+ return apply_filters( 'bp_rest_groups_delete_item_permissions_check', $retval, $request );
574
+ }
575
+
576
+ /**
577
+ * Prepares group data for return as an object.
578
+ *
579
+ * @since 5.0.0
580
+ *
581
+ * @param BP_Groups_Group $item Group object.
582
+ * @param WP_REST_Request $request Full details about the request.
583
+ * @return WP_REST_Response
584
+ */
585
+ public function prepare_item_for_response( $item, $request ) {
586
+ $data = array(
587
+ 'id' => $item->id,
588
+ 'creator_id' => bp_get_group_creator_id( $item ),
589
+ 'parent_id' => $item->parent_id,
590
+ 'date_created' => bp_rest_prepare_date_response( $item->date_created ),
591
+ 'description' => array(
592
+ 'raw' => $item->description,
593
+ 'rendered' => bp_get_group_description( $item ),
594
+ ),
595
+ 'enable_forum' => bp_group_is_forum_enabled( $item ),
596
+ 'link' => bp_get_group_permalink( $item ),
597
+ 'name' => bp_get_group_name( $item ),
598
+ 'slug' => bp_get_group_slug( $item ),
599
+ 'status' => bp_get_group_status( $item ),
600
+ 'avatar_urls' => array(),
601
+ 'admins' => array(),
602
+ 'mods' => array(),
603
+ 'total_member_count' => null,
604
+ 'last_activity' => null,
605
+ );
606
+
607
+ // Avatars.
608
+ $data['avatar_urls']['thumb'] = bp_core_fetch_avatar(
609
+ array(
610
+ 'html' => false,
611
+ 'object' => 'group',
612
+ 'item_id' => $item->id,
613
+ 'type' => 'thumb',
614
+ )
615
+ );
616
+
617
+ $data['avatar_urls']['full'] = bp_core_fetch_avatar(
618
+ array(
619
+ 'html' => false,
620
+ 'object' => 'group',
621
+ 'item_id' => $item->id,
622
+ 'type' => 'full',
623
+ )
624
+ );
625
+
626
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
627
+
628
+ // If this is the 'edit' context, fill in more details--similar to "populate_extras".
629
+ if ( 'edit' === $context ) {
630
+ $data['total_member_count'] = groups_get_groupmeta( $item->id, 'total_member_count' );
631
+ $data['last_activity'] = bp_rest_prepare_date_response( groups_get_groupmeta( $item->id, 'last_activity' ) );
632
+
633
+ // Add admins and moderators to their respective arrays.
634
+ $admin_mods = groups_get_group_members(
635
+ array(
636
+ 'group_id' => $item->id,
637
+ 'group_role' => array(
638
+ 'admin',
639
+ 'mod',
640
+ ),
641
+ )
642
+ );
643
+
644
+ foreach ( (array) $admin_mods['members'] as $user ) {
645
+ if ( ! empty( $user->is_admin ) ) {
646
+ $data['admins'][] = $user;
647
+ } else {
648
+ $data['mods'][] = $user;
649
+ }
650
+ }
651
+ }
652
+
653
+ $data = $this->add_additional_fields_to_object( $data, $request );
654
+ $data = $this->filter_response_by_context( $data, $context );
655
+ $response = rest_ensure_response( $data );
656
+
657
+ $response->add_links( $this->prepare_links( $item ) );
658
+
659
+ /**
660
+ * Filter a group value returned from the API.
661
+ *
662
+ * @since 5.0.0
663
+ *
664
+ * @param WP_REST_Response $response The response data.
665
+ * @param WP_REST_Request $request Request used to generate the response.
666
+ * @param BP_Groups_Group $item Group object.
667
+ */
668
+ return apply_filters( 'bp_rest_groups_prepare_value', $response, $request, $item );
669
+ }
670
+
671
+ /**
672
+ * Prepare a group for create or update.
673
+ *
674
+ * @since 5.0.0
675
+ *
676
+ * @param WP_REST_Request $request Request object.
677
+ * @return stdClass|WP_Error Object or WP_Error.
678
+ */
679
+ protected function prepare_item_for_database( $request ) {
680
+ $prepared_group = new stdClass();
681
+ $schema = $this->get_item_schema();
682
+ $group = $this->get_group_object( $request );
683
+
684
+ // Group ID.
685
+ if ( ! empty( $schema['properties']['id'] ) && ! empty( $group->id ) ) {
686
+ $prepared_group->group_id = $group->id;
687
+ }
688
+
689
+ // Group Creator ID.
690
+ if ( ! empty( $schema['properties']['creator_id'] ) && isset( $request['creator_id'] ) ) {
691
+ $prepared_group->creator_id = (int) $request['creator_id'];
692
+
693
+ // Fallback on the existing creator id in case of an update.
694
+ } elseif ( isset( $group->creator_id ) && $group->creator_id ) {
695
+ $prepared_group->creator_id = (int) $group->creator_id;
696
+
697
+ // Fallback on the current user otherwise.
698
+ } else {
699
+ $prepared_group->creator_id = bp_loggedin_user_id();
700
+ }
701
+
702
+ // Group Slug.
703
+ if ( ! empty( $schema['properties']['slug'] ) && isset( $request['slug'] ) ) {
704
+ $prepared_group->slug = $request['slug'];
705
+ }
706
+
707
+ // Group Name.
708
+ if ( ! empty( $schema['properties']['name'] ) && isset( $request['name'] ) ) {
709
+ $prepared_group->name = $request['name'];
710
+ }
711
+
712
+ // Do additional checks for the Group's slug.
713
+ if ( WP_REST_Server::CREATABLE === $request->get_method() || ( isset( $group->slug ) && isset( $prepared_group->slug ) && $group->slug !== $prepared_group->slug ) ) {
714
+ // Fallback on the group name if the slug is not defined.
715
+ if ( ! isset( $prepared_group->slug ) && ! isset( $group->slug ) ) {
716
+ $prepared_group->slug = $prepared_group->name;
717
+ }
718
+
719
+ // Make sure it is unique and sanitize it.
720
+ $prepared_group->slug = groups_check_slug( sanitize_title( esc_attr( $prepared_group->slug ) ) );
721
+ }
722
+
723
+ // Group description.
724
+ if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) {
725
+ if ( is_string( $request['description'] ) ) {
726
+ $prepared_group->description = $request['description'];
727
+ } elseif ( isset( $request['description']['raw'] ) ) {
728
+ $prepared_group->description = $request['description']['raw'];
729
+ }
730
+ }
731
+
732
+ // Group status.
733
+ if ( ! empty( $schema['properties']['status'] ) && isset( $request['status'] ) ) {
734
+ $prepared_group->status = $request['status'];
735
+ }
736
+
737
+ // Group Forum Enabled.
738
+ if ( ! empty( $schema['properties']['enable_forum'] ) && isset( $request['enable_forum'] ) ) {
739
+ $prepared_group->enable_forum = (bool) $request['enable_forum'];
740
+ }
741
+
742
+ // Group Parent ID.
743
+ if ( ! empty( $schema['properties']['parent_id'] ) && isset( $request['parent_id'] ) ) {
744
+ $prepared_group->parent_id = $request['parent_id'];
745
+ }
746
+
747
+ /**
748
+ * Filters a group before it is inserted or updated via the REST API.
749
+ *
750
+ * @since 5.0.0
751
+ *
752
+ * @param stdClass $prepared_group An object prepared for inserting or updating the database.
753
+ * @param WP_REST_Request $request Request object.
754
+ */
755
+ return apply_filters( 'bp_rest_groups_pre_insert_value', $prepared_group, $request );
756
+ }
757
+
758
+ /**
759
+ * Prepare links for the request.
760
+ *
761
+ * @since 5.0.0
762
+ *
763
+ * @param BP_Groups_Group $group Group object.
764
+ * @return array
765
+ */
766
+ protected function prepare_links( $group ) {
767
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
768
+
769
+ // Entity meta.
770
+ $links = array(
771
+ 'self' => array(
772
+ 'href' => rest_url( $base . $group->id ),
773
+ ),
774
+ 'collection' => array(
775
+ 'href' => rest_url( $base ),
776
+ ),
777
+ 'user' => array(
778
+ 'href' => rest_url( bp_rest_get_user_url( $group->creator_id ) ),
779
+ 'embeddable' => true,
780
+ ),
781
+ );
782
+
783
+ /**
784
+ * Filter links prepared for the REST response.
785
+ *
786
+ * @since 5.0.0
787
+ *
788
+ * @param array $links The prepared links of the REST response.
789
+ * @param BP_Groups_Group $group Group object.
790
+ */
791
+ return apply_filters( 'bp_rest_groups_prepare_links', $links, $group );
792
+ }
793
+
794
+ /**
795
+ * Can a user see a group?
796
+ *
797
+ * @since 5.0.0
798
+ *
799
+ * @param BP_Groups_Group $group Group object.
800
+ * @return bool
801
+ */
802
+ protected function can_see( $group ) {
803
+
804
+ // If it is not a hidden/private group, user can see it.
805
+ if ( 'public' === $group->status ) {
806
+ return true;
807
+ }
808
+
809
+ // Moderators.
810
+ if ( bp_current_user_can( 'bp_moderate' ) ) {
811
+ return true;
812
+ }
813
+
814
+ // User is a member of the group.
815
+ if ( groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
816
+ return true;
817
+ }
818
+
819
+ return false;
820
+ }
821
+
822
+ /**
823
+ * See if user can delete or update a group.
824
+ *
825
+ * @since 5.0.0
826
+ *
827
+ * @param BP_Groups_Group $group Group item.
828
+ * @return bool
829
+ */
830
+ protected function can_user_delete_or_update( $group ) {
831
+ return ( bp_current_user_can( 'bp_moderate' ) || bp_loggedin_user_id() === $group->creator_id );
832
+ }
833
+
834
+ /**
835
+ * Can this user see hidden groups?
836
+ *
837
+ * @since 5.0.0
838
+ *
839
+ * @param WP_REST_Request $request Full details about the request.
840
+ * @return bool
841
+ */
842
+ protected function can_see_hidden_groups( $request ) {
843
+ if ( $request['show_hidden'] ) {
844
+
845
+ if ( bp_current_user_can( 'bp_moderate' ) ) {
846
+ return true;
847
+ }
848
+
849
+ if ( is_user_logged_in() && isset( $request['user_id'] ) && absint( $request['user_id'] ) === bp_loggedin_user_id() ) {
850
+ return true;
851
+ }
852
+
853
+ return false;
854
+ }
855
+
856
+ return true;
857
+ }
858
+
859
+ /**
860
+ * Get group object.
861
+ *
862
+ * @since 5.0.0
863
+ *
864
+ * @param WP_REST_Request $request Full details about the request.
865
+ * @return bool|BP_Groups_Group
866
+ */
867
+ public function get_group_object( $request ) {
868
+ if ( ! empty( $request['group_id'] ) ) {
869
+ $group_id = (int) $request['group_id'];
870
+ } elseif ( is_numeric( $request ) ) {
871
+ $group_id = $request;
872
+ } else {
873
+ $group_id = (int) $request['id'];
874
+ }
875
+
876
+ $group = groups_get_group( $group_id );
877
+
878
+ if ( empty( $group ) || empty( $group->id ) ) {
879
+ return false;
880
+ }
881
+
882
+ return $group;
883
+ }
884
+
885
+ /**
886
+ * Edit some arguments for the endpoint's CREATABLE and EDITABLE methods.
887
+ *
888
+ * @since 5.0.0
889
+ *
890
+ * @param string $method Optional. HTTP method of the request.
891
+ * @return array Endpoint arguments.
892
+ */
893
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
894
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
895
+ $key = 'get_item';
896
+
897
+ if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) {
898
+ $key = 'create_item';
899
+ $args['description']['type'] = 'string';
900
+
901
+ if ( WP_REST_Server::EDITABLE === $method ) {
902
+ $key = 'update_item';
903
+ unset( $args['slug'] );
904
+ }
905
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
906
+ $key = 'delete_item';
907
+ }
908
+
909
+ /**
910
+ * Filters the method query arguments.
911
+ *
912
+ * @since 5.0.0
913
+ *
914
+ * @param array $args Query arguments.
915
+ * @param string $method HTTP method of the request.
916
+ */
917
+ return apply_filters( "bp_rest_groups_{$key}_query_arguments", $args, $method );
918
+ }
919
+
920
+ /**
921
+ * Get the group schema, conforming to JSON Schema.
922
+ *
923
+ * @since 5.0.0
924
+ *
925
+ * @return array
926
+ */
927
+ public function get_item_schema() {
928
+ $schema = array(
929
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
930
+ 'title' => 'bp_groups',
931
+ 'type' => 'object',
932
+ 'properties' => array(
933
+ 'id' => array(
934
+ 'context' => array( 'view', 'edit' ),
935
+ 'description' => __( 'A unique numeric ID for the Group.', 'buddypress' ),
936
+ 'readonly' => true,
937
+ 'type' => 'integer',
938
+ ),
939
+ 'creator_id' => array(
940
+ 'context' => array( 'view', 'edit' ),
941
+ 'description' => __( 'The ID of the user who created the Group.', 'buddypress' ),
942
+ 'type' => 'integer',
943
+ 'default' => bp_loggedin_user_id(),
944
+ ),
945
+ 'name' => array(
946
+ 'context' => array( 'view', 'edit' ),
947
+ 'description' => __( 'The name of the Group.', 'buddypress' ),
948
+ 'type' => 'string',
949
+ 'required' => true,
950
+ 'arg_options' => array(
951
+ 'sanitize_callback' => 'sanitize_text_field',
952
+ ),
953
+ ),
954
+ 'slug' => array(
955
+ 'context' => array( 'view', 'edit' ),
956
+ 'description' => __( 'The URL-friendly slug for the Group.', 'buddypress' ),
957
+ 'type' => 'string',
958
+ 'arg_options' => array(
959
+ 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database().
960
+ ),
961
+ ),
962
+ 'link' => array(
963
+ 'context' => array( 'view', 'edit' ),
964
+ 'description' => __( 'The permalink to the Group on the site.', 'buddypress' ),
965
+ 'type' => 'string',
966
+ 'format' => 'uri',
967
+ 'readonly' => true,
968
+ ),
969
+ 'description' => array(
970
+ 'context' => array( 'view', 'edit' ),
971
+ 'description' => __( 'The description of the Group.', 'buddypress' ),
972
+ 'type' => 'object',
973
+ 'required' => true,
974
+ 'arg_options' => array(
975
+ 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database().
976
+ 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database().
977
+ ),
978
+ 'properties' => array(
979
+ 'raw' => array(
980
+ 'description' => __( 'Content for the description of the Group, as it exists in the database.', 'buddypress' ),
981
+ 'type' => 'string',
982
+ 'context' => array( 'view', 'edit' ),
983
+ ),
984
+ 'rendered' => array(
985
+ 'description' => __( 'HTML content for the description of the Group, transformed for display.', 'buddypress' ),
986
+ 'type' => 'string',
987
+ 'context' => array( 'view', 'edit' ),
988
+ 'readonly' => true,
989
+ ),
990
+ ),
991
+ ),
992
+ 'status' => array(
993
+ 'context' => array( 'view', 'edit' ),
994
+ 'description' => __( 'The status of the Group.', 'buddypress' ),
995
+ 'type' => 'string',
996
+ 'enum' => buddypress()->groups->valid_status,
997
+ 'default' => 'public',
998
+ 'arg_options' => array(
999
+ 'sanitize_callback' => 'sanitize_key',
1000
+ ),
1001
+ ),
1002
+ 'enable_forum' => array(
1003
+ 'context' => array( 'view', 'edit' ),
1004
+ 'description' => __( 'Whether the Group has a forum or not.', 'buddypress' ),
1005
+ 'type' => 'boolean',
1006
+ ),
1007
+ 'parent_id' => array(
1008
+ 'context' => array( 'view', 'edit' ),
1009
+ 'description' => __( 'ID of the parent Group.', 'buddypress' ),
1010
+ 'type' => 'integer',
1011
+ ),
1012
+ 'date_created' => array(
1013
+ 'context' => array( 'view', 'edit' ),
1014
+ 'description' => __( "The date the Group was created, in the site's timezone.", 'buddypress' ),
1015
+ 'readonly' => true,
1016
+ 'type' => 'string',
1017
+ 'format' => 'date-time',
1018
+ ),
1019
+ 'admins' => array(
1020
+ 'context' => array( 'edit' ),
1021
+ 'description' => __( 'Group administrators.', 'buddypress' ),
1022
+ 'readonly' => true,
1023
+ 'type' => 'array',
1024
+ 'items' => array(
1025
+ 'type' => 'object',
1026
+ ),
1027
+ ),
1028
+ 'mods' => array(
1029
+ 'context' => array( 'edit' ),
1030
+ 'description' => __( 'Group moderators.', 'buddypress' ),
1031
+ 'readonly' => true,
1032
+ 'type' => 'array',
1033
+ 'items' => array(
1034
+ 'type' => 'object',
1035
+ ),
1036
+ ),
1037
+ 'total_member_count' => array(
1038
+ 'context' => array( 'edit' ),
1039
+ 'description' => __( 'Count of all Group members.', 'buddypress' ),
1040
+ 'readonly' => true,
1041
+ 'type' => 'integer',
1042
+ ),
1043
+ 'last_activity' => array(
1044
+ 'context' => array( 'edit' ),
1045
+ 'description' => __( "The date the Group was last active, in the site's timezone.", 'buddypress' ),
1046
+ 'type' => 'string',
1047
+ 'readonly' => true,
1048
+ 'format' => 'date-time',
1049
+ ),
1050
+ ),
1051
+ );
1052
+
1053
+ // Avatars.
1054
+ if ( true === buddypress()->avatar->show_avatars ) {
1055
+ $avatar_properties = array();
1056
+
1057
+ $avatar_properties['full'] = array(
1058
+ /* translators: Full image size for the group Avatar */
1059
+ 'description' => sprintf( __( 'Avatar URL with full image size (%1$d x %2$d pixels).', 'buddypress' ), number_format_i18n( bp_core_avatar_full_width() ), number_format_i18n( bp_core_avatar_full_height() ) ),
1060
+ 'type' => 'string',
1061
+ 'format' => 'uri',
1062
+ 'context' => array( 'view', 'edit' ),
1063
+ );
1064
+
1065
+ $avatar_properties['thumb'] = array(
1066
+ /* translators: Thumb imaze size for the group Avatar */
1067
+ 'description' => sprintf( __( 'Avatar URL with thumb image size (%1$d x %2$d pixels).', 'buddypress' ), number_format_i18n( bp_core_avatar_thumb_width() ), number_format_i18n( bp_core_avatar_thumb_height() ) ),
1068
+ 'type' => 'string',
1069
+ 'format' => 'uri',
1070
+ 'context' => array( 'view', 'edit' ),
1071
+ );
1072
+
1073
+ $schema['properties']['avatar_urls'] = array(
1074
+ 'description' => __( 'Avatar URLs for the group.', 'buddypress' ),
1075
+ 'type' => 'object',
1076
+ 'context' => array( 'view', 'edit' ),
1077
+ 'readonly' => true,
1078
+ 'properties' => $avatar_properties,
1079
+ );
1080
+ }
1081
+
1082
+ /**
1083
+ * Filters the group schema.
1084
+ *
1085
+ * @param array $schema The endpoint schema.
1086
+ */
1087
+ return apply_filters( 'bp_rest_group_schema', $this->add_additional_fields_schema( $schema ) );
1088
+ }
1089
+
1090
+ /**
1091
+ * Get the query params for collections of groups.
1092
+ *
1093
+ * @since 5.0.0
1094
+ *
1095
+ * @return array
1096
+ */
1097
+ public function get_collection_params() {
1098
+ $params = parent::get_collection_params();
1099
+ $params['context']['default'] = 'view';
1100
+
1101
+ $params['type'] = array(
1102
+ 'description' => __( 'Shorthand for certain orderby/order combinations.', 'buddypress' ),
1103
+ 'default' => 'active',
1104
+ 'type' => 'string',
1105
+ 'enum' => array( 'active', 'newest', 'alphabetical', 'random', 'popular' ),
1106
+ 'sanitize_callback' => 'sanitize_text_field',
1107
+ 'validate_callback' => 'rest_validate_request_arg',
1108
+ );
1109
+
1110
+ $params['order'] = array(
1111
+ 'description' => __( 'Order sort attribute ascending or descending.', 'buddypress' ),
1112
+ 'default' => 'desc',
1113
+ 'type' => 'string',
1114
+ 'enum' => array( 'asc', 'desc' ),
1115
+ 'sanitize_callback' => 'sanitize_key',
1116
+ 'validate_callback' => 'rest_validate_request_arg',
1117
+ );
1118
+
1119
+ $params['orderby'] = array(
1120
+ 'description' => __( 'Order Groups by which attribute.', 'buddypress' ),
1121
+ 'default' => 'date_created',
1122
+ 'type' => 'string',
1123
+ 'enum' => array( 'date_created', 'last_activity', 'total_member_count', 'name', 'random' ),
1124
+ 'sanitize_callback' => 'sanitize_key',
1125
+ 'validate_callback' => 'rest_validate_request_arg',
1126
+ );
1127
+
1128
+ $params['status'] = array(
1129
+ 'description' => __( 'Group statuses to limit results to.', 'buddypress' ),
1130
+ 'default' => array(),
1131
+ 'type' => 'array',
1132
+ 'items' => array(
1133
+ 'enum' => buddypress()->groups->valid_status,
1134
+ 'type' => 'string',
1135
+ ),
1136
+ 'sanitize_callback' => 'bp_rest_sanitize_string_list',
1137
+ 'validate_callback' => 'rest_validate_request_arg',
1138
+ );
1139
+
1140
+ $params['user_id'] = array(
1141
+ 'description' => __( 'Pass a user_id to limit to only Groups that this user is a member of.', 'buddypress' ),
1142
+ 'default' => 0,
1143
+ 'type' => 'integer',
1144
+ 'sanitize_callback' => 'absint',
1145
+ 'validate_callback' => 'rest_validate_request_arg',
1146
+ );
1147
+
1148
+ $params['parent_id'] = array(
1149
+ 'description' => __( 'Get Groups that are children of the specified Group(s) IDs.', 'buddypress' ),
1150
+ 'default' => array(),
1151
+ 'type' => 'array',
1152
+ 'items' => array( 'type' => 'integer' ),
1153
+ 'sanitize_callback' => 'wp_parse_id_list',
1154
+ 'validate_callback' => 'rest_validate_request_arg',
1155
+ );
1156
+
1157
+ // @todo Confirm what's the proper sanitization here.
1158
+ $params['meta'] = array(
1159
+ 'description' => __( 'Get Groups based on their meta data information.', 'buddypress' ),
1160
+ 'default' => array(),
1161
+ 'type' => 'array',
1162
+ 'items' => array( 'type' => 'string' ),
1163
+ 'validate_callback' => 'rest_validate_request_arg',
1164
+ );
1165
+
1166
+ $params['include'] = array(
1167
+ 'description' => __( 'Ensure result set includes Groups with specific IDs.', 'buddypress' ),
1168
+ 'default' => array(),
1169
+ 'type' => 'array',
1170
+ 'items' => array( 'type' => 'integer' ),
1171
+ 'sanitize_callback' => 'wp_parse_id_list',
1172
+ 'validate_callback' => 'rest_validate_request_arg',
1173
+ );
1174
+
1175
+ $params['exclude'] = array(
1176
+ 'description' => __( 'Ensure result set excludes Groups with specific IDs', 'buddypress' ),
1177
+ 'default' => array(),
1178
+ 'type' => 'array',
1179
+ 'items' => array( 'type' => 'integer' ),
1180
+ 'sanitize_callback' => 'wp_parse_id_list',
1181
+ 'validate_callback' => 'rest_validate_request_arg',
1182
+ );
1183
+
1184
+ $params['group_type'] = array(
1185
+ 'description' => __( 'Limit results set to a certain Group type.', 'buddypress' ),
1186
+ 'default' => '',
1187
+ 'type' => 'string',
1188
+ 'enum' => bp_groups_get_group_types(),
1189
+ 'sanitize_callback' => 'bp_rest_sanitize_group_types',
1190
+ 'validate_callback' => 'bp_rest_validate_group_types',
1191
+ );
1192
+
1193
+ $params['enable_forum'] = array(
1194
+ 'description' => __( 'Whether the Group has a forum enabled or not.', 'buddypress' ),
1195
+ 'default' => false,
1196
+ 'type' => 'boolean',
1197
+ 'sanitize_callback' => 'rest_sanitize_boolean',
1198
+ 'validate_callback' => 'rest_validate_request_arg',
1199
+ );
1200
+
1201
+ $params['show_hidden'] = array(
1202
+ 'description' => __( 'Whether results should include hidden Groups.', 'buddypress' ),
1203
+ 'default' => false,
1204
+ 'type' => 'boolean',
1205
+ 'sanitize_callback' => 'rest_sanitize_boolean',
1206
+ 'validate_callback' => 'rest_validate_request_arg',
1207
+ );
1208
+
1209
+ /**
1210
+ * Filters the collection query params.
1211
+ *
1212
+ * @param array $params Query params.
1213
+ */
1214
+ return apply_filters( 'bp_rest_groups_collection_params', $params );
1215
+ }
1216
+ }
bp-groups/js/manage-members.js ADDED
@@ -0,0 +1,549 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global bpGroupManageMembersSettings, _, Backbone */
2
+ /* @version 5.0.0 */
3
+
4
+ ( function( wp, bp, $ ) {
5
+
6
+ // Bail if not set
7
+ if ( typeof bpGroupManageMembersSettings === 'undefined' || ! bp.isRestEnabled ) {
8
+ return;
9
+ }
10
+
11
+ // Copy useful WP Objects into BP.
12
+ _.extend( bp, _.pick( wp, 'Backbone', 'template' ) );
13
+
14
+ bp.Models = bp.Models || {};
15
+ bp.Collections = bp.Collections || {};
16
+ bp.Views = bp.Views || {};
17
+
18
+ /**
19
+ * Model for the Member of the displayed group.
20
+ */
21
+ bp.Models.groupMember = Backbone.Model.extend( {
22
+ defaults: {
23
+ id: 0,
24
+ name: '',
25
+ avatar_urls : {},
26
+ is_admin: false,
27
+ is_banned: false,
28
+ is_confirmed: false,
29
+ is_mod: false,
30
+ link: ''
31
+ },
32
+ options : {
33
+ path: bpGroupManageMembersSettings.path,
34
+ type: 'POST',
35
+ data: {},
36
+ dataType: 'json'
37
+ },
38
+
39
+ initialize: function() {
40
+ // Make sure to reset data & path on model's sync.
41
+ this.on( 'sync', this.resetRequestOptions, this );
42
+ },
43
+
44
+ resetRequestOptions: function() {
45
+ this.options.data = {};
46
+ this.options.path = bpGroupManageMembersSettings.path;
47
+ },
48
+
49
+ sync: function( method, model, options ) {
50
+ options = options || {};
51
+ options.context = this;
52
+ var data = options.data || {};
53
+ this.options.path = this.options.path.concat( '/' + model.get( 'id' ) );
54
+
55
+ _.extend( options, this.options );
56
+ _.extend( options.data, data );
57
+
58
+ if ( 'delete' === method || 'update' === method ) {
59
+ if ( 'delete' === method ) {
60
+ options.headers = { 'X-HTTP-Method-Override': 'DELETE' };
61
+ } else {
62
+ options.headers = { 'X-HTTP-Method-Override': 'PUT' };
63
+ }
64
+
65
+ return bp.apiRequest( options );
66
+ }
67
+ },
68
+
69
+ parse: function( response ) {
70
+ if ( _.isArray( response ) ) {
71
+ response = _.first( response );
72
+ }
73
+
74
+ return response;
75
+ }
76
+ } );
77
+
78
+ /**
79
+ * Collection for the Members of the displayed group.
80
+ */
81
+ bp.Collections.groupMembers = Backbone.Collection.extend( {
82
+ model: bp.Models.groupMember,
83
+ options : {
84
+ path: bpGroupManageMembersSettings.path,
85
+ type: 'GET',
86
+ data: {},
87
+ dataType: 'json'
88
+ },
89
+
90
+ initialize: function() {
91
+ // Make sure to reset data on collection's reset.
92
+ this.on( 'reset', function() {
93
+ this.options.data = {};
94
+ }, this );
95
+ },
96
+
97
+ sync: function( method, collection, options ) {
98
+ options = options || {};
99
+ options.context = this;
100
+ var data = options.data || {};
101
+
102
+ _.extend( options, this.options );
103
+ _.extend( options.data, data );
104
+
105
+ if ( 'read' === method ) {
106
+ var self = this, success = options.success;
107
+ options.success = function( data, textStatus, request ) {
108
+ if ( ! _.isUndefined( request ) ) {
109
+ self.totalPages = parseInt( request.getResponseHeader( 'X-WP-TotalPages' ), 10 );
110
+ self.totalGroupMembers = parseInt( request.getResponseHeader( 'X-WP-Total' ), 10 );
111
+ }
112
+
113
+ self.currentPage = options.data.page || 1;
114
+
115
+ if ( success ) {
116
+ return success.apply( this, arguments );
117
+ }
118
+ };
119
+
120
+ return bp.apiRequest( options );
121
+ }
122
+ }
123
+ } );
124
+
125
+ // Extend wp.Backbone.View with .prepare().
126
+ bp.View = bp.View || bp.Backbone.View.extend( {
127
+ prepare: function() {
128
+ if ( ! _.isUndefined( this.model ) && _.isFunction( this.model.toJSON ) ) {
129
+ return this.model.toJSON();
130
+ } else {
131
+ return {};
132
+ }
133
+ }
134
+ } );
135
+
136
+ bp.Views.GroupMemberUpdatingInfo = bp.View.extend( {
137
+ tagName: 'p',
138
+ template : bp.template( 'bp-manage-members-updating' ),
139
+
140
+ initialize: function() {
141
+ this.model = new Backbone.Model( {
142
+ type: this.options.value
143
+ } );
144
+ }
145
+ } );
146
+
147
+ bp.Views.GroupMemberErrorInfo = bp.View.extend( {
148
+ tagName: 'p',
149
+ template : bp.template( 'bp-manage-members-error' ),
150
+
151
+ initialize: function() {
152
+ this.model = new Backbone.Model( {
153
+ message: this.options.value
154
+ } );
155
+ }
156
+ } );
157
+
158
+ bp.Views.GroupsMembersLabel = bp.Views.GroupMemberUpdatingInfo.extend( {
159
+ tagName: 'label',
160
+ template: bp.template( 'bp-manage-members-label' )
161
+ } );
162
+
163
+ bp.Views.GroupRolesDropDown = bp.View.extend( {
164
+ tagName: 'select',
165
+ filters: _.extend( { all: { name: 'All members' } }, bpGroupManageMembersSettings.roles ),
166
+
167
+ events: {
168
+ change: 'change'
169
+ },
170
+
171
+ initialize: function() {
172
+ if ( this.options.omits ) {
173
+ this.filters = _.omit( this.filters, this.options.omits );
174
+ }
175
+
176
+ // Build `<option>` elements.
177
+ this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
178
+ var optionOutput = $( '<option></option>' ).val( value ).html( filter.name )[0];
179
+
180
+ if ( this.options.currentRole && value === this.options.currentRole ) {
181
+ return {
182
+ el: $( optionOutput ).prop( 'selected', true )
183
+ };
184
+ } else {
185
+ return {
186
+ el: optionOutput
187
+ };
188
+ }
189
+ }, this ).pluck( 'el' ).value() );
190
+ },
191
+
192
+ change: function( event ) {
193
+ var role = $( event.target ).val(), queryArgs = { roles: [ role ] };
194
+
195
+ if ( ! this.collection ) {
196
+ return;
197
+ }
198
+
199
+ if ( 'all' === role ) {
200
+ // Unset the current role.
201
+ this.collection.currentRole = '';
202
+
203
+ queryArgs = { 'exclude_admins': false };
204
+ } else {
205
+ // Set the current role.
206
+ this.collection.currentRole = role;
207
+ }
208
+
209
+ // Reset the current page.
210
+ this.collection.currentPage = 1;
211
+
212
+ queryArgs.page = 1;
213
+ $( '#manage-members-search' ).val( '' );
214
+
215
+ this.collection.fetch( {
216
+ data: queryArgs,
217
+ reset: true
218
+ } );
219
+ }
220
+ } );
221
+
222
+ bp.Views.GroupMembersSearch = bp.View.extend( {
223
+ className: 'bp-dir-search-form',
224
+ tagName: 'form',
225
+ template: bp.template( 'bp-manage-members-search' ),
226
+
227
+ events: {
228
+ 'click #manage-members-search-submit' : 'searchMember'
229
+ },
230
+
231
+ searchMember: function( event ) {
232
+ event.preventDefault();
233
+
234
+ var searchTerms = $( '#manage-members-search' ).val(),
235
+ queryArgs = _.extend( this.collection.options.data, { search: searchTerms, page: 1 } );
236
+
237
+ // Reset the current page.
238
+ this.collection.currentPage = 1;
239
+
240
+ if ( ! this.collection.currentRole ) {
241
+ queryArgs.exclude_admins = false;
242
+ } else {
243
+ queryArgs.roles = [ this.collection.currentRole ];
244
+ }
245
+
246
+ this.collection.fetch( {
247
+ data: queryArgs,
248
+ reset: true
249
+ } );
250
+ }
251
+ } );
252
+
253
+ bp.Views.GroupsMembersPagination = bp.View.extend( {
254
+ className: 'bp-pagination',
255
+ template: bp.template( 'bp-manage-members-paginate' ),
256
+
257
+ events: {
258
+ 'click .group-members-paginate-button' : 'queryPage'
259
+ },
260
+
261
+ initialize: function() {
262
+ this.collection.on( 'reset', this.setPagination, this );
263
+ },
264
+
265
+ setPagination: function( collection ) {
266
+ var attributes = _.pick( collection, [ 'currentPage', 'totalGroupMembers', 'totalPages' ] );
267
+
268
+ if ( attributes.totalPages > 1 ) {
269
+ attributes.nextPage = attributes.currentPage + 1;
270
+ attributes.prevPage = attributes.currentPage - 1;
271
+ }
272
+
273
+ this.model = new Backbone.Model( attributes );
274
+ this.render();
275
+ },
276
+
277
+ queryPage: function( event ) {
278
+ event.preventDefault();
279
+
280
+ var page = $( event.currentTarget ).data( 'page' ),
281
+ searchTerms = $( '#manage-members-search' ).val(),
282
+ queryArgs = _.extend( this.collection.options.data, { search: searchTerms, page: page } );
283
+
284
+ if ( ! this.collection.currentRole ) {
285
+ queryArgs.exclude_admins = false;
286
+ } else {
287
+ queryArgs.roles = [ this.collection.currentRole ];
288
+ }
289
+
290
+ this.collection.fetch( {
291
+ data: queryArgs,
292
+ reset: true
293
+ } );
294
+ }
295
+ } );
296
+
297
+ bp.Views.GroupMembersNoMatches = bp.View.extend( {
298
+ tagName: 'tr',
299
+ template : bp.template( 'bp-manage-members-empty-row' )
300
+ } );
301
+
302
+ bp.Views.GroupMembersListRow = bp.View.extend( {
303
+ tagName: 'tr',
304
+ template : bp.template( 'bp-manage-members-row' ),
305
+
306
+ events: {
307
+ 'click .group-member-actions a' : 'doMemberAction',
308
+ 'change .group-member-edit select' : 'editMemberRole'
309
+ },
310
+
311
+ initialize: function() {
312
+ var roleProps = [ 'is_admin', 'is_banned', 'is_confirmed', 'is_mod' ],
313
+ self = this;
314
+
315
+ _.each( bpGroupManageMembersSettings.roles, function( props ) {
316
+ if ( _.isMatch( self.model.attributes, _.pick( props, roleProps ) ) ) {
317
+ self.model.set( 'role', _.pick( props, ['id', 'name'] ), { silent: true } );
318
+ }
319
+ } );
320
+
321
+ this.model.collection.on( 'reset', this.clearRow, this );
322
+ },
323
+
324
+ clearRow: function() {
325
+ this.views.view.remove();
326
+ },
327
+
328
+ renderEditForm: function() {
329
+ var userId = this.model.get( 'id' );
330
+
331
+ this.render();
332
+
333
+ this.views.set( '#edit-group-member-' + userId, [
334
+ new bp.Views.GroupsMembersLabel( { value: userId, attributes: { 'for': 'group-member' + userId + '-role' } } ),
335
+ new bp.Views.GroupRolesDropDown( { id: 'group-member' + userId + '-role', omits: [ 'all', 'banned' ], currentRole: this.model.get( 'role' ).id } ).render()
336
+ ] );
337
+ },
338
+
339
+ resetRow: function() {
340
+ this.model.set( 'editing', false );
341
+
342
+ return this.render();
343
+ },
344
+
345
+ getRoleObject: function( roleId ) {
346
+ var roles = bpGroupManageMembersSettings.roles;
347
+
348
+ if ( _.isUndefined( roles[ roleId ] ) ) {
349
+ return {};
350
+ }
351
+
352
+ return _.extend(
353
+ { role: _.pick( roles[ roleId ], ['id', 'name'] ) },
354
+ _.pick( roles[ roleId ], [ 'is_admin', 'is_banned', 'is_confirmed', 'is_mod' ] )
355
+ );
356
+ },
357
+
358
+ doMemberAction: function( event ) {
359
+ event.preventDefault();
360
+
361
+ var action = $( event.target ).data( 'action' ), self = this;
362
+
363
+ if ( 'edit' === action ) {
364
+ this.model.set( 'editing', true );
365
+ return this.renderEditForm();
366
+
367
+ } else if ( 'abort' === action ) {
368
+ return this.resetRow();
369
+
370
+ } else if ( 'ban' === action || 'unban' === action ) {
371
+ var newRole = ( 'ban' === action ) ? 'banned' : 'member', roleObject = this.getRoleObject( newRole );
372
+
373
+ if ( ! roleObject ) {
374
+ return this.resetRow();
375
+ } else {
376
+ this.model.set( 'managingBan', true );
377
+ this.render();
378
+ }
379
+
380
+ // Display user feedback.
381
+ this.views.set( '#edit-group-member-' + this.model.get( 'id' ), new bp.Views.GroupMemberUpdatingInfo( { value: action } ).render() );
382
+
383
+ // Update Group member's role.
384
+ this.model.save( roleObject, {
385
+ wait: true,
386
+ data: { action: action },
387
+ success: function( model) {
388
+ self.model.collection.remove( model );
389
+ return self.clearRow();
390
+ },
391
+ error: function( model, response ) {
392
+ self.views.set( '#edit-group-member-' + model.get( 'id' ), new bp.Views.GroupMemberErrorInfo( { value: response.responseJSON.message } ).render() );
393
+
394
+ // Make sure to reset request options.
395
+ model.resetRequestOptions();
396
+ model.set( 'managingBan', false );
397
+ }
398
+ } );
399
+ } else if ( 'remove' === action ) {
400
+ this.model.set( 'removing', true );
401
+ this.render();
402
+
403
+ // Display user feedback.
404
+ this.views.set( '#edit-group-member-' + this.model.get( 'id' ), new bp.Views.GroupMemberUpdatingInfo( { value: action } ).render() );
405
+
406
+ // Destroy the membership model.
407
+ this.model.destroy( {
408
+ wait: true,
409
+ data: {},
410
+ success: function() {
411
+ return self.clearRow();
412
+ },
413
+ error: function( model, response ) {
414
+ self.views.set( '#edit-group-member-' + model.get( 'id' ), new bp.Views.GroupMemberErrorInfo( { value: response.responseJSON.message } ).render() );
415
+
416
+ // Make sure to reset request options.
417
+ model.resetRequestOptions();
418
+ model.set( 'removing', false );
419
+ }
420
+ } );
421
+ }
422
+ },
423
+
424
+ editMemberRole: function( event ) {
425
+ var newRole = $( event.target ).val(), roleObject = this.getRoleObject( newRole ),
426
+ currentRole = this.model.get( 'role').id, roleAction = 'promote', self = this;
427
+
428
+ if ( newRole === this.model.get( 'role' ).id || ! roleObject ) {
429
+ return this.resetRow();
430
+ }
431
+
432
+ this.views.set( '#edit-group-member-' + this.model.get( 'id' ), new bp.Views.GroupMemberUpdatingInfo().render() );
433
+
434
+ if ( 'admin' === currentRole || ( 'mod' === currentRole && 'member' === newRole ) ) {
435
+ roleAction = 'demote';
436
+ }
437
+
438
+ // Update Group member's role
439
+ this.model.save( roleObject, {
440
+ wait: true,
441
+ data: {
442
+ action: roleAction,
443
+ role: newRole
444
+ },
445
+ success: function( model ) {
446
+ if ( self.model.collection.currentRole && newRole !== self.model.collection.currentRole ) {
447
+ self.model.collection.remove( model );
448
+ return self.clearRow();
449
+ } else {
450
+ return self.resetRow();
451
+ }
452
+ },
453
+ error: function( model, response ) {
454
+ self.views.set( '#edit-group-member-' + model.get( 'id' ), new bp.Views.GroupMemberErrorInfo( { value: response.responseJSON.message } ).render() );
455
+
456
+ // Make sure to reset request options.
457
+ model.resetRequestOptions();
458
+ model.set( 'editing', false );
459
+ }
460
+ } );
461
+ }
462
+ } );
463
+
464
+ bp.Views.GroupMembersListHeader = bp.View.extend( {
465
+ tagName: 'thead',
466
+ template : bp.template( 'bp-manage-members-header' )
467
+ } );
468
+
469
+ bp.Views.GroupMembersListTable = bp.View.extend( {
470
+ tagName: 'tbody',
471
+
472
+ initialize: function() {
473
+ var preloaded = bpGroupManageMembersSettings.preloaded || {},
474
+ models = [];
475
+
476
+ this.collection.on( 'reset', this.addListTableRows, this );
477
+
478
+ if ( preloaded.body && preloaded.body.length > 0 ) {
479
+ _.each( preloaded.body, function( member ) {
480
+ models.push( new bp.Models.groupMember( member ) );
481
+ } );
482
+
483
+ this.collection.currentPage = 1;
484
+ if ( preloaded.headers && preloaded.headers[ 'X-WP-TotalPages' ] ) {
485
+ this.collection.totalPages = parseInt( preloaded.headers[ 'X-WP-TotalPages' ], 10 );
486
+ }
487
+
488
+ if ( preloaded.headers && preloaded.headers[ 'X-WP-Total' ] ) {
489
+ this.collection.totalGroupMembers = parseInt( preloaded.headers[ 'X-WP-Total' ], 10 );
490
+ }
491
+
492
+ this.collection.reset( models );
493
+ } else {
494
+ this.collection.fetch( {
495
+ data: { 'exclude_admins': false },
496
+ reset: true
497
+ } );
498
+ }
499
+ },
500
+
501
+ addListTableRows: function( collection ) {
502
+ if ( this.views._views ) {
503
+ var noMembersRow = _.findWhere( this.views._views[''] , { id: 'bp-no-group-members' } );
504
+
505
+ if ( noMembersRow ) {
506
+ noMembersRow.remove();
507
+ }
508
+ }
509
+
510
+ if ( ! collection.length ) {
511
+ this.views.add( new bp.Views.GroupMembersNoMatches( { id: 'bp-no-group-members' } ) );
512
+ } else {
513
+ _.each( collection.models, function( member ) {
514
+ this.views.add( new bp.Views.GroupMembersListRow( { model: member } ) );
515
+ }, this );
516
+ }
517
+ }
518
+ } );
519
+
520
+ bp.Views.GroupMembersUI = bp.View.extend( {
521
+ className: 'group-members',
522
+
523
+ initialize: function() {
524
+ var groupMembers = new bp.Collections.groupMembers();
525
+
526
+ // Set filters.
527
+ this.views.set( '#group-roles-filter', [
528
+ new bp.Views.GroupsMembersLabel( { attributes: { 'for': 'group-members-role-filter' } } ),
529
+ new bp.Views.GroupRolesDropDown( { id: 'group-members-role-filter', collection: groupMembers } )
530
+ ] );
531
+
532
+ // Set the search form.
533
+ this.views.set( '#group-members-search-form', new bp.Views.GroupMembersSearch( { id: 'group-members-search', collection: groupMembers } ) );
534
+
535
+ // Set Paginate links.
536
+ this.views.set( '#group-members-pagination', new bp.Views.GroupsMembersPagination( { collection: groupMembers } ) );
537
+
538
+ // Set Group members list header and body.
539
+ this.views.set( '#group-members-list-table', [
540
+ new bp.Views.GroupMembersListHeader(),
541
+ new bp.Views.GroupMembersListTable( { collection: groupMembers } )
542
+ ] );
543
+ }
544
+ } );
545
+
546
+ // Inject the UI to manage Group Members into the DOM.
547
+ bp.manageGroupMembersUI = new bp.Views.GroupMembersUI( { el:'#group-manage-members-ui' } ).render();
548
+
549
+ } )( window.wp || {}, window.bp || {}, jQuery );
bp-groups/js/manage-members.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(e,t,i){"undefined"!=typeof bpGroupManageMembersSettings&&t.isRestEnabled&&(_.extend(t,_.pick(e,"Backbone","template")),t.Models=t.Models||{},t.Collections=t.Collections||{},t.Views=t.Views||{},t.Models.groupMember=Backbone.Model.extend({defaults:{id:0,name:"",avatar_urls:{},is_admin:!1,is_banned:!1,is_confirmed:!1,is_mod:!1,link:""},options:{path:bpGroupManageMembersSettings.path,type:"POST",data:{},dataType:"json"},initialize:function(){this.on("sync",this.resetRequestOptions,this)},resetRequestOptions:function(){this.options.data={},this.options.path=bpGroupManageMembersSettings.path},sync:function(e,i,s){(s=s||{}).context=this;var r=s.data||{};if(this.options.path=this.options.path.concat("/"+i.get("id")),_.extend(s,this.options),_.extend(s.data,r),"delete"===e||"update"===e)return s.headers="delete"===e?{"X-HTTP-Method-Override":"DELETE"}:{"X-HTTP-Method-Override":"PUT"},t.apiRequest(s)},parse:function(e){return _.isArray(e)&&(e=_.first(e)),e}}),t.Collections.groupMembers=Backbone.Collection.extend({model:t.Models.groupMember,options:{path:bpGroupManageMembersSettings.path,type:"GET",data:{},dataType:"json"},initialize:function(){this.on("reset",function(){this.options.data={}},this)},sync:function(e,i,s){(s=s||{}).context=this;var r=s.data||{};if(_.extend(s,this.options),_.extend(s.data,r),"read"===e){var o=this,n=s.success;return s.success=function(e,t,i){if(_.isUndefined(i)||(o.totalPages=parseInt(i.getResponseHeader("X-WP-TotalPages"),10),o.totalGroupMembers=parseInt(i.getResponseHeader("X-WP-Total"),10)),o.currentPage=s.data.page||1,n)return n.apply(this,arguments)},t.apiRequest(s)}}}),t.View=t.View||t.Backbone.View.extend({prepare:function(){return!_.isUndefined(this.model)&&_.isFunction(this.model.toJSON)?this.model.toJSON():{}}}),t.Views.GroupMemberUpdatingInfo=t.View.extend({tagName:"p",template:t.template("bp-manage-members-updating"),initialize:function(){this.model=new Backbone.Model({type:this.options.value})}}),t.Views.GroupMemberErrorInfo=t.View.extend({tagName:"p",template:t.template("bp-manage-members-error"),initialize:function(){this.model=new Backbone.Model({message:this.options.value})}}),t.Views.GroupsMembersLabel=t.Views.GroupMemberUpdatingInfo.extend({tagName:"label",template:t.template("bp-manage-members-label")}),t.Views.GroupRolesDropDown=t.View.extend({tagName:"select",filters:_.extend({all:{name:"All members"}},bpGroupManageMembersSettings.roles),events:{change:"change"},initialize:function(){this.options.omits&&(this.filters=_.omit(this.filters,this.options.omits)),this.$el.html(_.chain(this.filters).map(function(e,t){var s=i("<option></option>").val(t).html(e.name)[0];return this.options.currentRole&&t===this.options.currentRole?{el:i(s).prop("selected",!0)}:{el:s}},this).pluck("el").value())},change:function(e){var t=i(e.target).val(),s={roles:[t]};this.collection&&("all"===t?(this.collection.currentRole="",s={exclude_admins:!1}):this.collection.currentRole=t,this.collection.currentPage=1,s.page=1,i("#manage-members-search").val(""),this.collection.fetch({data:s,reset:!0}))}}),t.Views.GroupMembersSearch=t.View.extend({className:"bp-dir-search-form",tagName:"form",template:t.template("bp-manage-members-search"),events:{"click #manage-members-search-submit":"searchMember"},searchMember:function(e){e.preventDefault();var t=i("#manage-members-search").val(),s=_.extend(this.collection.options.data,{search:t,page:1});this.collection.currentPage=1,this.collection.currentRole?s.roles=[this.collection.currentRole]:s.exclude_admins=!1,this.collection.fetch({data:s,reset:!0})}}),t.Views.GroupsMembersPagination=t.View.extend({className:"bp-pagination",template:t.template("bp-manage-members-paginate"),events:{"click .group-members-paginate-button":"queryPage"},initialize:function(){this.collection.on("reset",this.setPagination,this)},setPagination:function(e){var t=_.pick(e,["currentPage","totalGroupMembers","totalPages"]);t.totalPages>1&&(t.nextPage=t.currentPage+1,t.prevPage=t.currentPage-1),this.model=new Backbone.Model(t),this.render()},queryPage:function(e){e.preventDefault();var t=i(e.currentTarget).data("page"),s=i("#manage-members-search").val(),r=_.extend(this.collection.options.data,{search:s,page:t});this.collection.currentRole?r.roles=[this.collection.currentRole]:r.exclude_admins=!1,this.collection.fetch({data:r,reset:!0})}}),t.Views.GroupMembersNoMatches=t.View.extend({tagName:"tr",template:t.template("bp-manage-members-empty-row")}),t.Views.GroupMembersListRow=t.View.extend({tagName:"tr",template:t.template("bp-manage-members-row"),events:{"click .group-member-actions a":"doMemberAction","change .group-member-edit select":"editMemberRole"},initialize:function(){var e=["is_admin","is_banned","is_confirmed","is_mod"],t=this;_.each(bpGroupManageMembersSettings.roles,function(i){_.isMatch(t.model.attributes,_.pick(i,e))&&t.model.set("role",_.pick(i,["id","name"]),{silent:!0})}),this.model.collection.on("reset",this.clearRow,this)},clearRow:function(){this.views.view.remove()},renderEditForm:function(){var e=this.model.get("id");this.render(),this.views.set("#edit-group-member-"+e,[new t.Views.GroupsMembersLabel({value:e,attributes:{for:"group-member"+e+"-role"}}),new t.Views.GroupRolesDropDown({id:"group-member"+e+"-role",omits:["all","banned"],currentRole:this.model.get("role").id}).render()])},resetRow:function(){return this.model.set("editing",!1),this.render()},getRoleObject:function(e){var t=bpGroupManageMembersSettings.roles;return _.isUndefined(t[e])?{}:_.extend({role:_.pick(t[e],["id","name"])},_.pick(t[e],["is_admin","is_banned","is_confirmed","is_mod"]))},doMemberAction:function(e){e.preventDefault();var s=i(e.target).data("action"),r=this;if("edit"===s)return this.model.set("editing",!0),this.renderEditForm();if("abort"===s)return this.resetRow();if("ban"===s||"unban"===s){var o="ban"===s?"banned":"member",n=this.getRoleObject(o);if(!n)return this.resetRow();this.model.set("managingBan",!0),this.render(),this.views.set("#edit-group-member-"+this.model.get("id"),new t.Views.GroupMemberUpdatingInfo({value:s}).render()),this.model.save(n,{wait:!0,data:{action:s},success:function(e){return r.model.collection.remove(e),r.clearRow()},error:function(e,i){r.views.set("#edit-group-member-"+e.get("id"),new t.Views.GroupMemberErrorInfo({value:i.responseJSON.message}).render()),e.resetRequestOptions(),e.set("managingBan",!1)}})}else"remove"===s&&(this.model.set("removing",!0),this.render(),this.views.set("#edit-group-member-"+this.model.get("id"),new t.Views.GroupMemberUpdatingInfo({value:s}).render()),this.model.destroy({wait:!0,data:{},success:function(){return r.clearRow()},error:function(e,i){r.views.set("#edit-group-member-"+e.get("id"),new t.Views.GroupMemberErrorInfo({value:i.responseJSON.message}).render()),e.resetRequestOptions(),e.set("removing",!1)}}))},editMemberRole:function(e){var s=i(e.target).val(),r=this.getRoleObject(s),o=this.model.get("role").id,n="promote",a=this;if(s===this.model.get("role").id||!r)return this.resetRow();this.views.set("#edit-group-member-"+this.model.get("id"),(new t.Views.GroupMemberUpdatingInfo).render()),("admin"===o||"mod"===o&&"member"===s)&&(n="demote"),this.model.save(r,{wait:!0,data:{action:n,role:s},success:function(e){return a.model.collection.currentRole&&s!==a.model.collection.currentRole?(a.model.collection.remove(e),a.clearRow()):a.resetRow()},error:function(e,i){a.views.set("#edit-group-member-"+e.get("id"),new t.Views.GroupMemberErrorInfo({value:i.responseJSON.message}).render()),e.resetRequestOptions(),e.set("editing",!1)}})}}),t.Views.GroupMembersListHeader=t.View.extend({tagName:"thead",template:t.template("bp-manage-members-header")}),t.Views.GroupMembersListTable=t.View.extend({tagName:"tbody",initialize:function(){var e=bpGroupManageMembersSettings.preloaded||{},i=[];this.collection.on("reset",this.addListTableRows,this),e.body&&e.body.length>0?(_.each(e.body,function(e){i.push(new t.Models.groupMember(e))}),this.collection.currentPage=1,e.headers&&e.headers["X-WP-TotalPages"]&&(this.collection.totalPages=parseInt(e.headers["X-WP-TotalPages"],10)),e.headers&&e.headers["X-WP-Total"]&&(this.collection.totalGroupMembers=parseInt(e.headers["X-WP-Total"],10)),this.collection.reset(i)):this.collection.fetch({data:{exclude_admins:!1},reset:!0})},addListTableRows:function(e){if(this.views._views){var i=_.findWhere(this.views._views[""],{id:"bp-no-group-members"});i&&i.remove()}e.length?_.each(e.models,function(e){this.views.add(new t.Views.GroupMembersListRow({model:e}))},this):this.views.add(new t.Views.GroupMembersNoMatches({id:"bp-no-group-members"}))}}),t.Views.GroupMembersUI=t.View.extend({className:"group-members",initialize:function(){var e=new t.Collections.groupMembers;this.views.set("#group-roles-filter",[new t.Views.GroupsMembersLabel({attributes:{for:"group-members-role-filter"}}),new t.Views.GroupRolesDropDown({id:"group-members-role-filter",collection:e})]),this.views.set("#group-members-search-form",new t.Views.GroupMembersSearch({id:"group-members-search",collection:e})),this.views.set("#group-members-pagination",new t.Views.GroupsMembersPagination({collection:e})),this.views.set("#group-members-list-table",[new t.Views.GroupMembersListHeader,new t.Views.GroupMembersListTable({collection:e})])}}),t.manageGroupMembersUI=new t.Views.GroupMembersUI({el:"#group-manage-members-ui"}).render())}(window.wp||{},window.bp||{},jQuery);
bp-groups/screens/single/admin/membership-requests.php CHANGED
@@ -23,34 +23,42 @@ function groups_screen_group_admin_requests() {
23
  return false;
24
  }
25
 
26
- $request_action = (string) bp_action_variable( 1 );
27
- $membership_id = (int) bp_action_variable( 2 );
 
28
 
29
- if ( !empty( $request_action ) && !empty( $membership_id ) ) {
30
- if ( 'accept' == $request_action && is_numeric( $membership_id ) ) {
31
 
32
  // Check the nonce first.
33
- if ( !check_admin_referer( 'groups_accept_membership_request' ) )
34
  return false;
 
35
 
36
  // Accept the membership request.
37
- if ( !groups_accept_membership_request( $membership_id ) )
38
  bp_core_add_message( __( 'There was an error accepting the membership request. Please try again.', 'buddypress' ), 'error' );
39
- else
40
  bp_core_add_message( __( 'Group membership request accepted', 'buddypress' ) );
 
41
 
42
- } elseif ( 'reject' == $request_action && is_numeric( $membership_id ) ) {
43
  /* Check the nonce first. */
44
- if ( !check_admin_referer( 'groups_reject_membership_request' ) )
45
  return false;
 
46
 
47
  // Reject the membership request.
48
- if ( !groups_reject_membership_request( $membership_id ) )
49
  bp_core_add_message( __( 'There was an error rejecting the membership request. Please try again.', 'buddypress' ), 'error' );
50
- else
51
  bp_core_add_message( __( 'Group membership request rejected', 'buddypress' ) );
 
52
  }
53
 
 
 
 
54
  /**
55
  * Fires before the redirect if a group membership request has been handled.
56
  *
@@ -58,9 +66,11 @@ function groups_screen_group_admin_requests() {
58
  *
59
  * @param int $id ID of the group that was edited.
60
  * @param string $request_action Membership request action being performed.
61
- * @param int $membership_id The key of the action_variables array that you want.
 
 
62
  */
63
- do_action( 'groups_group_request_managed', $bp->groups->current_group->id, $request_action, $membership_id );
64
  bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/' );
65
  }
66
 
@@ -82,4 +92,4 @@ function groups_screen_group_admin_requests() {
82
  */
83
  bp_core_load_template( apply_filters( 'groups_template_group_admin_requests', 'groups/single/home' ) );
84
  }
85
- add_action( 'bp_screens', 'groups_screen_group_admin_requests' );
23
  return false;
24
  }
25
 
26
+ $request_action = isset( $_GET['action'] ) ? $_GET['action'] : false;
27
+ $user_id = isset( $_GET['user_id'] ) ? (int) $_GET['user_id'] : false;
28
+ $group_id = bp_get_current_group_id();
29
 
30
+ if ( $request_action && $user_id && $group_id ) {
31
+ if ( 'accept' === $request_action ) {
32
 
33
  // Check the nonce first.
34
+ if ( ! check_admin_referer( 'groups_accept_membership_request' ) ) {
35
  return false;
36
+ }
37
 
38
  // Accept the membership request.
39
+ if ( ! groups_accept_membership_request( false, $user_id, $group_id ) ) {
40
  bp_core_add_message( __( 'There was an error accepting the membership request. Please try again.', 'buddypress' ), 'error' );
41
+ } else {
42
  bp_core_add_message( __( 'Group membership request accepted', 'buddypress' ) );
43
+ }
44
 
45
+ } elseif ( 'reject' === $request_action ) {
46
  /* Check the nonce first. */
47
+ if ( ! check_admin_referer( 'groups_reject_membership_request' ) ) {
48
  return false;
49
+ }
50
 
51
  // Reject the membership request.
52
+ if ( ! groups_reject_membership_request( false, $user_id, $group_id ) ) {
53
  bp_core_add_message( __( 'There was an error rejecting the membership request. Please try again.', 'buddypress' ), 'error' );
54
+ } else {
55
  bp_core_add_message( __( 'Group membership request rejected', 'buddypress' ) );
56
+ }
57
  }
58
 
59
+ // Was the member added to the group?
60
+ $membership_id = groups_is_user_member( $user_id, $group_id );
61
+
62
  /**
63
  * Fires before the redirect if a group membership request has been handled.
64
  *
66
  *
67
  * @param int $id ID of the group that was edited.
68
  * @param string $request_action Membership request action being performed.
69
+ * @param int $membership_id The membership ID of the new user; false if rejected.
70
+ * @param int $user_id The ID of the requesting user.
71
+ * @param int $group_id The ID of the requested group.
72
  */
73
+ do_action( 'groups_group_request_managed', $bp->groups->current_group->id, $request_action, $membership_id, $user_id, $group_id );
74
  bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/' );
75
  }
76
 
92
  */
93
  bp_core_load_template( apply_filters( 'groups_template_group_admin_requests', 'groups/single/home' ) );
94
  }
95
+ add_action( 'bp_screens', 'groups_screen_group_admin_requests' );
bp-groups/screens/single/send-invites.php CHANGED
@@ -31,7 +31,7 @@ function groups_screen_group_invite() {
31
  }
32
 
33
  // Send the invites.
34
- groups_send_invites( bp_loggedin_user_id(), $bp->groups->current_group->id );
35
  bp_core_add_message( __('Group invites sent.', 'buddypress') );
36
 
37
  /**
@@ -101,4 +101,4 @@ function groups_remove_group_invite() {
101
  bp_core_add_message( $message, $error );
102
  bp_core_redirect( $redirect );
103
  }
104
- add_action( 'bp_screens', 'groups_remove_group_invite' );
31
  }
32
 
33
  // Send the invites.
34
+ groups_send_invites( array( 'group_id' => $bp->groups->current_group->id ) );
35
  bp_core_add_message( __('Group invites sent.', 'buddypress') );
36
 
37
  /**
101
  bp_core_add_message( $message, $error );
102
  bp_core_redirect( $redirect );
103
  }
104
+ add_action( 'bp_screens', 'groups_remove_group_invite' );
bp-loader.php CHANGED
@@ -15,7 +15,7 @@
15
  * Description: BuddyPress adds community features to WordPress. Member Profiles, Activity Streams, Direct Messaging, Notifications, and more!
16
  * Author: The BuddyPress Community
17
  * Author URI: https://buddypress.org/
18
- * Version: 4.4.0
19
  * Text Domain: buddypress
20
  * Domain Path: /bp-languages/
21
  * License: GPLv2 or later (license.txt)
15
  * Description: BuddyPress adds community features to WordPress. Member Profiles, Activity Streams, Direct Messaging, Notifications, and more!
16
  * Author: The BuddyPress Community
17
  * Author URI: https://buddypress.org/
18
+ * Version: 5.0.0-beta1
19
  * Text Domain: buddypress
20
  * Domain Path: /bp-languages/
21
  * License: GPLv2 or later (license.txt)
bp-members/bp-members-functions.php CHANGED
@@ -609,6 +609,42 @@ function bp_core_get_active_member_count() {
609
  return apply_filters( 'bp_core_get_active_member_count', $count );
610
  }
611
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
  /**
613
  * Process a spammed or unspammed user.
614
  *
@@ -671,9 +707,7 @@ function bp_core_process_spammer_status( $user_id, $status, $do_wp_cleanup = tru
671
  }
672
 
673
  // Finally, mark this user as a spammer.
674
- if ( is_multisite() ) {
675
- update_user_status( $user_id, 'spam', $is_spam );
676
- }
677
  }
678
 
679
  // Update the user status.
@@ -1741,7 +1775,12 @@ function bp_core_signup_user( $user_login, $user_password, $user_email, $usermet
1741
  * signup data, xprofile data, etc).
1742
  */
1743
  if ( apply_filters( 'bp_core_signup_send_activation_key', true, $user_id, $user_email, $activation_key, $usermeta ) ) {
1744
- bp_core_signup_send_validation_email( $user_id, $user_email, $activation_key, $user_login );
 
 
 
 
 
1745
  }
1746
  }
1747
 
@@ -2158,13 +2197,14 @@ function bp_core_signup_avatar_upload_dir() {
2158
  *
2159
  * @since 1.2.2
2160
  * @since 2.5.0 Add the $user_login parameter.
 
2161
  *
2162
  * @param int|bool $user_id ID of the new user, false if BP_SIGNUPS_SKIP_USER_CREATION is true.
2163
- * @param string $user_email Email address of the new user.
2164
- * @param string $key Activation key.
2165
- * @param string $user_login Optional. The user login name.
2166
  */
2167
- function bp_core_signup_send_validation_email( $user_id, $user_email, $key, $user_login = '' ) {
2168
  $args = array(
2169
  'tokens' => array(
2170
  'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ),
@@ -2174,11 +2214,7 @@ function bp_core_signup_send_validation_email( $user_id, $user_email, $key, $use
2174
  ),
2175
  );
2176
 
2177
- if ( $user_id ) {
2178
- $to = $user_id;
2179
- } else {
2180
- $to = array( array( $user_email => $user_login ) );
2181
- }
2182
 
2183
  bp_send_email( 'core-user-registration', $to, $args );
2184
  }
@@ -2289,14 +2325,55 @@ function bp_core_wpsignup_redirect() {
2289
  return;
2290
  }
2291
 
2292
- $action = !empty( $_GET['action'] ) ? $_GET['action'] : '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2293
 
2294
- // Not at the WP core signup page and action is not register.
2295
- if ( ! empty( $_SERVER['SCRIPT_NAME'] ) && false === strpos( 'wp-signup.php', $_SERVER['SCRIPT_NAME'] ) && ( 'register' != $action ) ) {
2296
  return;
2297
  }
2298
 
2299
- bp_core_redirect( bp_get_signup_page() );
2300
  }
2301
  add_action( 'bp_init', 'bp_core_wpsignup_redirect' );
2302
 
609
  return apply_filters( 'bp_core_get_active_member_count', $count );
610
  }
611
 
612
+ /**
613
+ * Update the spam status of the member on multisite configs.
614
+ *
615
+ * @since 5.0.0
616
+ *
617
+ * @param int $user_id The user ID to spam or ham.
618
+ * @param int $value 0 to mark the user as `ham`, 1 to mark as `spam`.
619
+ * @return bool True if the spam status of the member changed.
620
+ * False otherwise.
621
+ */
622
+ function bp_core_update_member_status( $user_id = 0, $value = 0 ) {
623
+ if ( ! is_multisite() || ! $user_id ) {
624
+ return false;
625
+ }
626
+
627
+ /**
628
+ * The `update_user_status()` function is deprecated since WordPress 5.3.0.
629
+ * Continue to use it if WordPress current major version is lower than 5.3.
630
+ */
631
+ if ( bp_get_major_wp_version() < 5.3 ) {
632
+ return update_user_status( $user_id, 'spam', $value );
633
+ }
634
+
635
+ // Otherwise use the replacement function.
636
+ $user = wp_update_user( array(
637
+ 'ID' => $user_id,
638
+ 'spam' => $value,
639
+ ) );
640
+
641
+ if ( is_wp_error( $user ) ) {
642
+ return false;
643
+ }
644
+
645
+ return true;
646
+ }
647
+
648
  /**
649
  * Process a spammed or unspammed user.
650
  *
707
  }
708
 
709
  // Finally, mark this user as a spammer.
710
+ bp_core_update_member_status( $user_id, $is_spam );
 
 
711
  }
712
 
713
  // Update the user status.
1775
  * signup data, xprofile data, etc).
1776
  */
1777
  if ( apply_filters( 'bp_core_signup_send_activation_key', true, $user_id, $user_email, $activation_key, $usermeta ) ) {
1778
+ $salutation = $user_login;
1779
+ if ( isset( $usermeta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) {
1780
+ $salutation = $usermeta[ 'field_' . bp_xprofile_fullname_field_id() ];
1781
+ }
1782
+
1783
+ bp_core_signup_send_validation_email( $user_id, $user_email, $activation_key, $salutation );
1784
  }
1785
  }
1786
 
2197
  *
2198
  * @since 1.2.2
2199
  * @since 2.5.0 Add the $user_login parameter.
2200
+ * @since 5.0.0 Change $user_login parameter to more general $salutation.
2201
  *
2202
  * @param int|bool $user_id ID of the new user, false if BP_SIGNUPS_SKIP_USER_CREATION is true.
2203
+ * @param string $user_email Email address of the new user.
2204
+ * @param string $key Activation key.
2205
+ * @param string $salutation Optional. The name to be used as a salutation in the email.
2206
  */
2207
+ function bp_core_signup_send_validation_email( $user_id, $user_email, $key, $salutation = '' ) {
2208
  $args = array(
2209
  'tokens' => array(
2210
  'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ),
2214
  ),
2215
  );
2216
 
2217
+ $to = array( array( $user_email => $salutation ) );
 
 
 
 
2218
 
2219
  bp_send_email( 'core-user-registration', $to, $args );
2220
  }
2325
  return;
2326
  }
2327
 
2328
+ $is_wp_signup = false;
2329
+ if ( ! empty( $_SERVER['SCRIPT_NAME'] ) ) {
2330
+ $script_name_path = wp_parse_url( $_SERVER['SCRIPT_NAME'], PHP_URL_PATH );
2331
+
2332
+ if ( 'wp-signup.php' === basename( $script_name_path ) || ( 'wp-login.php' === basename( $script_name_path ) && ! empty( $_GET['action'] ) && 'register' === $_GET['action'] ) ) {
2333
+ $is_wp_signup = true;
2334
+ }
2335
+ }
2336
+
2337
+ // If this is not wp-signup.php, there's nothing to do here.
2338
+ if ( ! $is_wp_signup ) {
2339
+ return;
2340
+ }
2341
+
2342
+ /*
2343
+ * We redirect wp-signup.php to the registration page except when it's a site signup.
2344
+ * In that case, redirect to the BP site creation page if available, otherwise allow
2345
+ * access to wp-signup.php.
2346
+ */
2347
+ $redirect_to = bp_get_signup_page();
2348
+
2349
+ $is_site_creation = false;
2350
+
2351
+ $referer = wp_get_referer();
2352
+
2353
+ // A new site is being added.
2354
+ if ( isset( $_POST['stage'] ) && $_POST['stage'] === 'gimmeanotherblog' ) {
2355
+ $is_site_creation = true;
2356
+
2357
+ // We've arrived at wp-signup.php from my-sites.php.
2358
+ } elseif ( $referer ) {
2359
+ $referer_path = wp_parse_url( $referer, PHP_URL_PATH );
2360
+ $is_site_creation = false !== strpos( $referer_path, 'wp-admin/my-sites.php' );
2361
+ }
2362
+
2363
+ if ( $is_site_creation ) {
2364
+ if ( bp_is_active( 'blogs' ) ) {
2365
+ $redirect_to = trailingslashit( bp_get_blogs_directory_permalink() . 'create' );
2366
+ } else {
2367
+ // Perform no redirect in this case.
2368
+ $redirect_to = '';
2369
+ }
2370
+ }
2371
 
2372
+ if ( ! $redirect_to ) {
 
2373
  return;
2374
  }
2375
 
2376
+ bp_core_redirect( $redirect_to );
2377
  }
2378
  add_action( 'bp_init', 'bp_core_wpsignup_redirect' );
2379
 
bp-members/classes/class-bp-core-members-widget.php CHANGED
@@ -90,12 +90,15 @@ class BP_Core_Members_Widget extends WP_Widget {
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(
95
  'user_id' => 0,
96
  'type' => $settings['member_default'],
97
- 'per_page' => $settings['max_members'],
98
- 'max' => $settings['max_members'],
99
  'populate_extras' => true,
100
  'search_terms' => false,
101
  );
@@ -177,10 +180,12 @@ class BP_Core_Members_Widget extends WP_Widget {
177
  public function update( $new_instance, $old_instance ) {
178
  $instance = $old_instance;
179
 
 
 
180
  $instance['title'] = strip_tags( $new_instance['title'] );
181
- $instance['max_members'] = strip_tags( $new_instance['max_members'] );
182
  $instance['member_default'] = strip_tags( $new_instance['member_default'] );
183
- $instance['link_title'] = (bool) $new_instance['link_title'];
184
 
185
  return $instance;
186
  }
@@ -194,11 +199,12 @@ class BP_Core_Members_Widget extends WP_Widget {
194
  * @return void
195
  */
196
  public function form( $instance ) {
 
197
 
198
  // Get widget settings.
199
  $settings = $this->parse_settings( $instance );
200
  $title = strip_tags( $settings['title'] );
201
- $max_members = strip_tags( $settings['max_members'] );
202
  $member_default = strip_tags( $settings['member_default'] );
203
  $link_title = (bool) $settings['link_title']; ?>
204
 
@@ -219,7 +225,7 @@ class BP_Core_Members_Widget extends WP_Widget {
219
  <p>
220
  <label for="<?php echo $this->get_field_id( 'max_members' ); ?>">
221
  <?php esc_html_e( 'Max members to show:', 'buddypress' ); ?>
222
- <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="text" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" />
223
  </label>
224
  </p>
225
 
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
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
94
+ $max_members = $settings['max_members'] > $max_limit ? $max_limit : (int) $settings['max_members'];
95
+
96
  // Setup args for querying members.
97
  $members_args = array(
98
  'user_id' => 0,
99
  'type' => $settings['member_default'],
100
+ 'per_page' => $max_members,
101
+ 'max' => $max_members,
102
  'populate_extras' => true,
103
  'search_terms' => false,
104
  );
180
  public function update( $new_instance, $old_instance ) {
181
  $instance = $old_instance;
182
 
183
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
184
+
185
  $instance['title'] = strip_tags( $new_instance['title'] );
186
+ $instance['max_members'] = $new_instance['max_members'] > $max_limit ? $max_limit : intval( $new_instance['max_members'] );
187
  $instance['member_default'] = strip_tags( $new_instance['member_default'] );
188
+ $instance['link_title'] = ! empty( $new_instance['link_title'] );
189
 
190
  return $instance;
191
  }
199
  * @return void
200
  */
201
  public function form( $instance ) {
202
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
203
 
204
  // Get widget settings.
205
  $settings = $this->parse_settings( $instance );
206
  $title = strip_tags( $settings['title'] );
207
+ $max_members = $settings['max_members'] > $max_limit ? $max_limit : intval( $settings['max_members'] );
208
  $member_default = strip_tags( $settings['member_default'] );
209
  $link_title = (bool) $settings['link_title']; ?>
210
 
225
  <p>
226
  <label for="<?php echo $this->get_field_id( 'max_members' ); ?>">
227
  <?php esc_html_e( 'Max members to show:', 'buddypress' ); ?>
228
+ <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="number" min="1" max="<?php echo esc_attr( $max_limit ); ?>" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" />
229
  </label>
230
  </p>
231
 
bp-members/classes/class-bp-core-recently-active-widget.php CHANGED
@@ -63,12 +63,15 @@ class BP_Core_Recently_Active_Widget extends WP_Widget {
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(
68
  'user_id' => 0,
69
  'type' => 'active',
70
- 'per_page' => $settings['max_members'],
71
- 'max' => $settings['max_members'],
72
  'populate_extras' => true,
73
  'search_terms' => false,
74
  );
@@ -116,9 +119,12 @@ class BP_Core_Recently_Active_Widget extends WP_Widget {
116
  * @return array $instance The parsed options to be saved.
117
  */
118
  public function update( $new_instance, $old_instance ) {
119
- $instance = $old_instance;
 
 
 
120
  $instance['title'] = strip_tags( $new_instance['title'] );
121
- $instance['max_members'] = strip_tags( $new_instance['max_members'] );
122
 
123
  return $instance;
124
  }
@@ -132,11 +138,13 @@ class BP_Core_Recently_Active_Widget extends WP_Widget {
132
  * @return void
133
  */
134
  public function form( $instance ) {
 
135
 
136
  // Get widget settings.
137
  $settings = $this->parse_settings( $instance );
138
  $title = strip_tags( $settings['title'] );
139
- $max_members = strip_tags( $settings['max_members'] ); ?>
 
140
 
141
  <p>
142
  <label for="<?php echo $this->get_field_id( 'title' ); ?>">
@@ -148,7 +156,7 @@ class BP_Core_Recently_Active_Widget extends WP_Widget {
148
  <p>
149
  <label for="<?php echo $this->get_field_id( 'max_members' ); ?>">
150
  <?php esc_html_e( 'Max members to show:', 'buddypress' ); ?>
151
- <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="text" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" />
152
  </label>
153
  </p>
154
 
63
  echo $args['before_widget'];
64
  echo $args['before_title'] . $title . $args['after_title'];
65
 
66
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
67
+ $max_members = $settings['max_members'] > $max_limit ? $max_limit : (int) $settings['max_members'];
68
+
69
  // Setup args for querying members.
70
  $members_args = array(
71
  'user_id' => 0,
72
  'type' => 'active',
73
+ 'per_page' => $max_members,
74
+ 'max' => $max_members,
75
  'populate_extras' => true,
76
  'search_terms' => false,
77
  );
119
  * @return array $instance The parsed options to be saved.
120
  */
121
  public function update( $new_instance, $old_instance ) {
122
+ $instance = $old_instance;
123
+
124
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
125
+
126
  $instance['title'] = strip_tags( $new_instance['title'] );
127
+ $instance['max_members'] = $new_instance['max_members'] > $max_limit ? $max_limit : intval( $new_instance['max_members'] );
128
 
129
  return $instance;
130
  }
138
  * @return void
139
  */
140
  public function form( $instance ) {
141
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
142
 
143
  // Get widget settings.
144
  $settings = $this->parse_settings( $instance );
145
  $title = strip_tags( $settings['title'] );
146
+ $max_members = $settings['max_members'] > $max_limit ? $max_limit : intval( $settings['max_members'] );
147
+ ?>
148
 
149
  <p>
150
  <label for="<?php echo $this->get_field_id( 'title' ); ?>">
156
  <p>
157
  <label for="<?php echo $this->get_field_id( 'max_members' ); ?>">
158
  <?php esc_html_e( 'Max members to show:', 'buddypress' ); ?>
159
+ <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="number" min="1" max="<?php echo esc_attr( $max_limit ); ?>" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" />
160
  </label>
161
  </p>
162
 
bp-members/classes/class-bp-core-whos-online-widget.php CHANGED
@@ -62,12 +62,15 @@ class BP_Core_Whos_Online_Widget extends WP_Widget {
62
 
63
  echo $args['before_widget'] . $args['before_title'] . $title . $args['after_title'];
64
 
 
 
 
65
  // Setup args for querying members.
66
  $members_args = array(
67
  'user_id' => 0,
68
  'type' => 'online',
69
- 'per_page' => $settings['max_members'],
70
- 'max' => $settings['max_members'],
71
  'populate_extras' => true,
72
  'search_terms' => false,
73
  );
@@ -115,9 +118,12 @@ class BP_Core_Whos_Online_Widget extends WP_Widget {
115
  * @return array $instance The parsed options to be saved.
116
  */
117
  public function update( $new_instance, $old_instance ) {
118
- $instance = $old_instance;
 
 
 
119
  $instance['title'] = strip_tags( $new_instance['title'] );
120
- $instance['max_members'] = strip_tags( $new_instance['max_members'] );
121
 
122
  return $instance;
123
  }
@@ -131,11 +137,13 @@ class BP_Core_Whos_Online_Widget extends WP_Widget {
131
  * @return void
132
  */
133
  public function form( $instance ) {
 
134
 
135
  // Get widget settings.
136
  $settings = $this->parse_settings( $instance );
137
  $title = strip_tags( $settings['title'] );
138
- $max_members = strip_tags( $settings['max_members'] ); ?>
 
139
 
140
  <p>
141
  <label for="<?php echo $this->get_field_id( 'title' ); ?>">
@@ -147,7 +155,7 @@ class BP_Core_Whos_Online_Widget extends WP_Widget {
147
  <p>
148
  <label for="<?php echo $this->get_field_id( 'max_members' ); ?>">
149
  <?php esc_html_e( 'Max members to show:', 'buddypress' ); ?>
150
- <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="text" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" />
151
  </label>
152
  </p>
153
 
62
 
63
  echo $args['before_widget'] . $args['before_title'] . $title . $args['after_title'];
64
 
65
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
66
+ $max_members = $settings['max_members'] > $max_limit ? $max_limit : (int) $settings['max_members'];
67
+
68
  // Setup args for querying members.
69
  $members_args = array(
70
  'user_id' => 0,
71
  'type' => 'online',
72
+ 'per_page' => $max_members,
73
+ 'max' => $max_members,
74
  'populate_extras' => true,
75
  'search_terms' => false,
76
  );
118
  * @return array $instance The parsed options to be saved.
119
  */
120
  public function update( $new_instance, $old_instance ) {
121
+ $instance = $old_instance;
122
+
123
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
124
+
125
  $instance['title'] = strip_tags( $new_instance['title'] );
126
+ $instance['max_members'] = $new_instance['max_members'] > $max_limit ? $max_limit : intval( $new_instance['max_members'] );
127
 
128
  return $instance;
129
  }
137
  * @return void
138
  */
139
  public function form( $instance ) {
140
+ $max_limit = bp_get_widget_max_count_limit( __CLASS__ );
141
 
142
  // Get widget settings.
143
  $settings = $this->parse_settings( $instance );
144
  $title = strip_tags( $settings['title'] );
145
+ $max_members = $settings['max_members'] > $max_limit ? $max_limit : intval( $settings['max_members'] );
146
+ ?>
147
 
148
  <p>
149
  <label for="<?php echo $this->get_field_id( 'title' ); ?>">
155
  <p>
156
  <label for="<?php echo $this->get_field_id( 'max_members' ); ?>">
157
  <?php esc_html_e( 'Max members to show:', 'buddypress' ); ?>
158
+ <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="number" min="1" max="<?php echo esc_attr( $max_limit ); ?>" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" />
159
  </label>
160
  </p>
161
 
bp-members/classes/class-bp-members-admin.php CHANGED
@@ -624,7 +624,7 @@ class BP_Members_Admin {
624
 
625
  wp_enqueue_style( 'bp-members-css', $css, array(), bp_get_version() );
626
 
627
- wp_style_add_data( 'bp-members-css', 'rtl', true );
628
  if ( $min ) {
629
  wp_style_add_data( 'bp-members-css', 'suffix', $min );
630
  }
624
 
625
  wp_enqueue_style( 'bp-members-css', $css, array(), bp_get_version() );
626
 
627
+ wp_style_add_data( 'bp-members-css', 'rtl', 'replace' );
628
  if ( $min ) {
629
  wp_style_add_data( 'bp-members-css', 'suffix', $min );
630
  }
bp-members/classes/class-bp-members-component.php CHANGED
@@ -456,4 +456,26 @@ class BP_Members_Component extends BP_Component {
456
 
457
  parent::setup_cache_groups();
458
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  }
456
 
457
  parent::setup_cache_groups();
458
  }
459
+
460
+ /**
461
+ * Init the BP REST API.
462
+ *
463
+ * @since 5.0.0
464
+ */
465
+ public function rest_api_init() {
466
+ /**
467
+ * As the Members component is always loaded,
468
+ * let's register the Components endpoint here.
469
+ */
470
+ $controller = new BP_REST_Components_Endpoint();
471
+ $controller->register_routes();
472
+
473
+ $controller = new BP_REST_Members_Endpoint();
474
+ $controller->register_routes();
475
+
476
+ $controller = new BP_REST_Attachments_Member_Avatar_Endpoint();
477
+ $controller->register_routes();
478
+
479
+ parent::rest_api_init();
480
+ }
481
  }
bp-members/classes/class-bp-rest-members-endpoint.php ADDED
@@ -0,0 +1,811 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Members_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * BuddyPress Members endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Members_Endpoint extends WP_REST_Users_Controller {
17
+
18
+ /**
19
+ * Constructor.
20
+ *
21
+ * @since 5.0.0
22
+ */
23
+ public function __construct() {
24
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
25
+ $this->rest_base = 'members';
26
+ }
27
+
28
+ /**
29
+ * Retrieve users.
30
+ *
31
+ * @since 5.0.0
32
+ *
33
+ * @param WP_REST_Request $request Full details about the request.
34
+ * @return WP_REST_Response
35
+ */
36
+ public function get_items( $request ) {
37
+ $args = array(
38
+ 'type' => $request['type'],
39
+ 'user_id' => $request['user_id'],
40
+ 'user_ids' => $request['user_ids'],
41
+ 'xprofile_query' => $request['xprofile'],
42
+ 'include' => $request['include'],
43
+ 'exclude' => $request['exclude'],
44
+ 'member_type' => $request['member_type'],
45
+ 'search_terms' => $request['search'],
46
+ 'per_page' => $request['per_page'],
47
+ 'page' => $request['page'],
48
+ );
49
+
50
+ if ( empty( $request['user_ids'] ) ) {
51
+ $args['user_ids'] = false;
52
+ }
53
+
54
+ if ( empty( $request['exclude'] ) ) {
55
+ $args['exclude'] = false;
56
+ }
57
+
58
+ if ( empty( $request['include'] ) ) {
59
+ $args['include'] = false;
60
+ }
61
+
62
+ if ( empty( $request['xprofile'] ) ) {
63
+ $args['xprofile_query'] = false;
64
+ }
65
+
66
+ if ( empty( $request['member_type'] ) ) {
67
+ $args['member_type'] = '';
68
+ }
69
+
70
+ /**
71
+ * Filter the query arguments for the request.
72
+ *
73
+ * @since 5.0.0
74
+ *
75
+ * @param array $args Key value array of query var to query value.
76
+ * @param WP_REST_Request $request The request sent to the API.
77
+ */
78
+ $args = apply_filters( 'bp_rest_members_get_items_query_args', $args, $request );
79
+
80
+ // Actually, query it.
81
+ $member_query = new BP_User_Query( $args );
82
+ $members = array_values( $member_query->results );
83
+
84
+ $retval = array();
85
+ foreach ( $members as $member ) {
86
+ $retval[] = $this->prepare_response_for_collection(
87
+ $this->prepare_item_for_response( $member, $request )
88
+ );
89
+ }
90
+
91
+ $response = rest_ensure_response( $retval );
92
+ $response = bp_rest_response_add_total_headers( $response, $member_query->total_users, $args['per_page'] );
93
+
94
+ /**
95
+ * Fires after a list of members is fetched via the REST API.
96
+ *
97
+ * @since 5.0.0
98
+ *
99
+ * @param array $members Fetched members.
100
+ * @param WP_REST_Response $response The response data.
101
+ * @param WP_REST_Request $request The request sent to the API.
102
+ */
103
+ do_action( 'bp_rest_members_get_items', $members, $response, $request );
104
+
105
+ return $response;
106
+ }
107
+
108
+ /**
109
+ * Checks if a given request has access to get all users.
110
+ *
111
+ * @since 5.0.0
112
+ *
113
+ * @param WP_REST_Request $request Full details about the request.
114
+ * @return bool
115
+ */
116
+ public function get_items_permissions_check( $request ) {
117
+
118
+ /**
119
+ * Filter the members `get_items` permissions check.
120
+ *
121
+ * @since 5.0.0
122
+ *
123
+ * @param bool $retval Returned value.
124
+ * @param WP_REST_Request $request The request sent to the API.
125
+ */
126
+ return apply_filters( 'bp_rest_members_get_items_permissions_check', true, $request );
127
+ }
128
+
129
+ /**
130
+ * Checks if a given request has access to read a user.
131
+ *
132
+ * @since 5.0.0
133
+ *
134
+ * @param WP_REST_Request $request Full details about the request.
135
+ * @return bool|WP_Error
136
+ */
137
+ public function get_item_permissions_check( $request ) {
138
+ $retval = true;
139
+
140
+ if ( ! is_user_logged_in() ) {
141
+ $retval = new WP_Error(
142
+ 'bp_rest_authorization_required',
143
+ __( 'Sorry, you are not allowed to view members', 'buddypress' ),
144
+ array(
145
+ 'status' => rest_authorization_required_code(),
146
+ )
147
+ );
148
+ }
149
+
150
+ $user = bp_rest_get_user( $request['id'] );
151
+
152
+ if ( true === $retval && ! $user instanceof WP_User ) {
153
+ $retval = new WP_Error(
154
+ 'bp_rest_member_invalid_id',
155
+ __( 'Invalid member id.', 'buddypress' ),
156
+ array(
157
+ 'status' => 404,
158
+ )
159
+ );
160
+ }
161
+
162
+ if ( true === $retval && get_current_user_id() === $user->ID ) {
163
+ $retval = true;
164
+ } elseif ( true === $retval && 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) {
165
+ $retval = new WP_Error(
166
+ 'bp_rest_authorization_required',
167
+ __( 'Sorry, you are not allowed to view members.', 'buddypress' ),
168
+ array(
169
+ 'status' => rest_authorization_required_code(),
170
+ )
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Filter the members `get_item` permissions check.
176
+ *
177
+ * @since 5.0.0
178
+ *
179
+ * @param bool|WP_Error $retval Returned value.
180
+ * @param WP_REST_Request $request The request sent to the API.
181
+ */
182
+ return apply_filters( 'bp_rest_members_get_item_permissions_check', $retval, $request );
183
+ }
184
+
185
+ /**
186
+ * Checks if a given request has access create members.
187
+ *
188
+ * @since 5.0.0
189
+ *
190
+ * @param WP_REST_Request $request Full details about the request.
191
+ * @return bool|WP_Error
192
+ */
193
+ public function create_item_permissions_check( $request ) {
194
+ $retval = true;
195
+
196
+ if ( ! ( is_user_logged_in() && current_user_can( 'bp_moderate' ) ) ) {
197
+ $retval = new WP_Error(
198
+ 'bp_rest_authorization_required',
199
+ __( 'Sorry, you are not allowed to view members.', 'buddypress' ),
200
+ array(
201
+ 'status' => rest_authorization_required_code(),
202
+ )
203
+ );
204
+ }
205
+
206
+ /**
207
+ * Filter or override the members `create_item` permissions check.
208
+ *
209
+ * @since 5.0.0
210
+ *
211
+ * @param bool|WP_Error $retval Returned value.
212
+ * @param WP_REST_Request $request The request sent to the API.
213
+ */
214
+ return apply_filters( 'bp_rest_members_create_item_permissions_check', $retval, $request );
215
+ }
216
+
217
+ /**
218
+ * Check if a given request has access to update a member.
219
+ *
220
+ * @since 5.0.0
221
+ *
222
+ * @param WP_REST_Request $request Full details about the request.
223
+ * @return bool|WP_Error
224
+ */
225
+ public function update_item_permissions_check( $request ) {
226
+ $retval = true;
227
+ $user = bp_rest_get_user( $request['id'] );
228
+
229
+ if ( ! $user instanceof WP_User ) {
230
+ $retval = new WP_Error(
231
+ 'bp_rest_member_invalid_id',
232
+ __( 'Invalid member id.', 'buddypress' ),
233
+ array(
234
+ 'status' => 404,
235
+ )
236
+ );
237
+ }
238
+
239
+ $action = 'delete';
240
+ if ( 'DELETE' !== $request->get_method() ) {
241
+ $action = 'update';
242
+ }
243
+
244
+ if ( true === $retval && ! $this->can_manage_member( $user, $action ) ) {
245
+ $retval = new WP_Error(
246
+ 'bp_rest_authorization_required',
247
+ __( 'Sorry, you are not allowed to view members.', 'buddypress' ),
248
+ array(
249
+ 'status' => rest_authorization_required_code(),
250
+ )
251
+ );
252
+ }
253
+
254
+ /**
255
+ * Filter the members `update_item` permissions check.
256
+ *
257
+ * @since 5.0.0
258
+ *
259
+ * @param bool|WP_Error $retval Returned value.
260
+ * @param WP_REST_Request $request The request sent to the API.
261
+ */
262
+ return apply_filters( 'bp_rest_members_update_item_permissions_check', $retval, $request );
263
+ }
264
+
265
+ /**
266
+ * Check if a given request has access to delete a member.
267
+ *
268
+ * @since 5.0.0
269
+ *
270
+ * @param WP_REST_Request $request Full details about the request.
271
+ * @return bool|WP_Error
272
+ */
273
+ public function delete_item_permissions_check( $request ) {
274
+ $retval = $this->update_item_permissions_check( $request );
275
+
276
+ /**
277
+ * Filter the members `delete_item` permissions check.
278
+ *
279
+ * @since 5.0.0
280
+ *
281
+ * @param bool|WP_Error $retval Returned value.
282
+ * @param WP_REST_Request $request The request sent to the API.
283
+ */
284
+ return apply_filters( 'bp_rest_members_delete_item_permissions_check', $retval, $request );
285
+ }
286
+
287
+ /**
288
+ * Deleting the current user is not implemented into this endpoint.
289
+ *
290
+ * This action is specific to the User Settings endpoint.
291
+ *
292
+ * @since 5.0.0
293
+ *
294
+ * @param WP_REST_Request $request Full details about the request.
295
+ * @return WP_Error WP_Error object to inform it's not implemented.
296
+ */
297
+ public function delete_current_item_permissions_check( $request ) {
298
+ return new WP_Error(
299
+ 'bp_rest_invalid_method',
300
+ /* translators: %s: transport method name */
301
+ sprintf( __( '\'%s\' Transport Method not implemented.', 'buddypress' ), $request->get_method() ),
302
+ array(
303
+ 'status' => 405,
304
+ )
305
+ );
306
+ }
307
+
308
+ /**
309
+ * Deleting the current user is not implemented into this endpoint.
310
+ *
311
+ * This action is specific to the User Settings endpoint.
312
+ *
313
+ * @since 5.0.0
314
+ *
315
+ * @param WP_REST_Request $request Full details about the request.
316
+ * @return WP_Error WP_Error to inform it's not implemented.
317
+ */
318
+ public function delete_current_item( $request ) {
319
+ return new WP_Error(
320
+ 'bp_rest_invalid_method',
321
+ /* translators: %s: transport method name */
322
+ sprintf( __( '\'%s\' Transport method not implemented.', 'buddypress' ), $request->get_method() ),
323
+ array(
324
+ 'status' => 405,
325
+ )
326
+ );
327
+ }
328
+
329
+ /**
330
+ * Prepares a single user output for response.
331
+ *
332
+ * @since 5.0.0
333
+ *
334
+ * @param WP_User $user User object.
335
+ * @param WP_REST_Request $request Full details about the request.
336
+ * @return WP_REST_Response
337
+ */
338
+ public function prepare_item_for_response( $user, $request ) {
339
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
340
+ $data = $this->user_data( $user, $context );
341
+ $data = $this->add_additional_fields_to_object( $data, $request );
342
+ $data = $this->filter_response_by_context( $data, $context );
343
+ $response = rest_ensure_response( $data );
344
+
345
+ $response->add_links( $this->prepare_links( $user ) );
346
+
347
+ /**
348
+ * Filters user data returned from the API.
349
+ *
350
+ * @since 5.0.0
351
+ *
352
+ * @param WP_REST_Response $response The response object.
353
+ * @param WP_REST_Request $request The request object.
354
+ * @param WP_User $user WP_User object.
355
+ */
356
+ return apply_filters( 'bp_rest_members_prepare_value', $response, $request, $user );
357
+ }
358
+
359
+ /**
360
+ * Method to facilitate fetching of user data.
361
+ *
362
+ * This was abstracted to be used in other BuddyPress endpoints.
363
+ *
364
+ * @since 5.0.0
365
+ *
366
+ * @param WP_User $user User object.
367
+ * @param string $context The context of the request. Defaults to 'view'.
368
+ * @return array
369
+ */
370
+ public function user_data( $user, $context = 'view' ) {
371
+ $data = array(
372
+ 'id' => $user->ID,
373
+ 'name' => $user->display_name,
374
+ 'user_login' => $user->user_login,
375
+ 'link' => bp_core_get_user_domain( $user->ID, $user->user_nicename, $user->user_login ),
376
+ 'member_types' => bp_get_member_type( $user->ID, false ),
377
+ 'roles' => array(),
378
+ 'capabilities' => array(),
379
+ 'extra_capabilities' => array(),
380
+ 'registered_date' => '',
381
+ 'xprofile' => $this->xprofile_data( $user->ID ),
382
+ );
383
+
384
+ if ( 'edit' === $context ) {
385
+ $data['registered_date'] = bp_rest_prepare_date_response( $user->data->user_registered );
386
+ $data['roles'] = (array) array_values( $user->roles );
387
+ $data['capabilities'] = (array) array_keys( $user->allcaps );
388
+ $data['extra_capabilities'] = (array) array_keys( $user->caps );
389
+ }
390
+
391
+ // The name used for that user in @-mentions.
392
+ if ( bp_is_active( 'activity' ) ) {
393
+ $data['mention_name'] = bp_activity_get_user_mentionname( $user->ID );
394
+ }
395
+
396
+ // Avatars.
397
+ $data['avatar_urls'] = array(
398
+ 'full' => bp_core_fetch_avatar(
399
+ array(
400
+ 'item_id' => $user->ID,
401
+ 'html' => false,
402
+ 'type' => 'full',
403
+ )
404
+ ),
405
+ 'thumb' => bp_core_fetch_avatar(
406
+ array(
407
+ 'item_id' => $user->ID,
408
+ 'html' => false,
409
+ )
410
+ ),
411
+ );
412
+
413
+ // Fallback.
414
+ if ( false === $data['member_types'] ) {
415
+ $data['member_types'] = array();
416
+ }
417
+
418
+ return $data;
419
+ }
420
+
421
+ /**
422
+ * Prepares a single user for creation or update.
423
+ *
424
+ * @todo Improve sanitization and schema verification.
425
+ *
426
+ * @since 5.0.0
427
+ *
428
+ * @param WP_REST_Request $request Request object.
429
+ * @return stdClass
430
+ */
431
+ protected function prepare_item_for_database( $request ) {
432
+ $prepared_user = parent::prepare_item_for_database( $request );
433
+
434
+ // The parent class uses username instead of user_login.
435
+ if ( ! isset( $prepared_user->user_login ) && isset( $request['user_login'] ) ) {
436
+ $prepared_user->user_login = $request['user_login'];
437
+ }
438
+
439
+ /**
440
+ * Filters an user object before it is inserted or updated via the REST API.
441
+ *
442
+ * @since 5.0.0
443
+ *
444
+ * @param stdClass $prepared_user An object prepared for inserting or updating the database.
445
+ * @param WP_REST_Request $request Request object.
446
+ */
447
+ return apply_filters( 'bp_rest_members_pre_insert_value', $prepared_user, $request );
448
+ }
449
+
450
+ /**
451
+ * Get XProfile info from the user.
452
+ *
453
+ * @since 5.0.0
454
+ *
455
+ * @param int $user_id User ID.
456
+ * @return array
457
+ */
458
+ protected function xprofile_data( $user_id ) {
459
+ $data = array();
460
+
461
+ // Get XProfile groups, only if the component is active.
462
+ if ( bp_is_active( 'xprofile' ) ) {
463
+ $fields_endpoint = new BP_REST_XProfile_Fields_Endpoint();
464
+
465
+ $groups = bp_xprofile_get_groups(
466
+ array(
467
+ 'user_id' => $user_id,
468
+ 'fetch_fields' => true,
469
+ 'fetch_field_data' => true,
470
+ )
471
+ );
472
+
473
+ foreach ( $groups as $group ) {
474
+ $data['groups'][ $group->id ] = array(
475
+ 'name' => $group->name,
476
+ );
477
+
478
+ foreach ( $group->fields as $item ) {
479
+ $data['groups'][ $group->id ]['fields'][ $item->id ] = array(
480
+ 'name' => $item->name,
481
+ 'value' => array(
482
+ 'raw' => $item->data->value,
483
+ 'unserialized' => $fields_endpoint->get_profile_field_unserialized_value( $item->data->value ),
484
+ 'rendered' => $fields_endpoint->get_profile_field_rendered_value( $item->data->value, $item ),
485
+ ),
486
+ );
487
+ }
488
+ }
489
+ } else {
490
+ $data = array( __( 'No extended profile data available as the component is inactive', 'buddypress' ) );
491
+ }
492
+
493
+ return $data;
494
+ }
495
+
496
+ /**
497
+ * Can user manage (delete/update) a member?
498
+ *
499
+ * @since 5.0.0
500
+ *
501
+ * @param WP_User $user User object.
502
+ * @param string $action The action to perform (update or delete).
503
+ * @return bool
504
+ */
505
+ protected function can_manage_member( $user, $action = 'delete' ) {
506
+ $capability = 'delete_user';
507
+ if ( 'update' === $action ) {
508
+ $capability = 'edit_user';
509
+ }
510
+
511
+ return ( current_user_can( 'bp_moderate' ) || current_user_can( $capability, $user->ID ) );
512
+ }
513
+
514
+ /**
515
+ * Updates the values of additional fields added to a data object.
516
+ *
517
+ * This function makes sure updating the field value thanks to the `id` property of
518
+ * the created/updated object type is consistent accross BuddyPress components.
519
+ *
520
+ * @since 5.0.0
521
+ *
522
+ * @param WP_User $object The WordPress user object.
523
+ * @param WP_REST_Request $request Full details about the request.
524
+ * @return bool|WP_Error True on success, WP_Error object if a field cannot be updated.
525
+ */
526
+ protected function update_additional_fields_for_object( $object, $request ) {
527
+ if ( ! isset( $object->data ) ) {
528
+ return new WP_Error( 'invalid_user', __( 'The data for the user was not found.', 'buddypress' ) );
529
+ }
530
+
531
+ $member = $object->data;
532
+ $member->id = $member->ID;
533
+
534
+ return WP_REST_Controller::update_additional_fields_for_object( $member, $request );
535
+ }
536
+
537
+ /**
538
+ * Make sure to retrieve the needed arguments for the endpoint CREATABLE method.
539
+ *
540
+ * @since 5.0.0
541
+ *
542
+ * @param string $method Optional. HTTP method of the request.
543
+ * @return array Endpoint arguments.
544
+ */
545
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
546
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
547
+ $key = 'get_item';
548
+
549
+ if ( WP_REST_Server::CREATABLE === $method ) {
550
+ $key = 'create_item';
551
+
552
+ // We don't need the mention name to create a user.
553
+ unset( $args['mention_name'] );
554
+
555
+ // But we absolutely need the email.
556
+ $args['email'] = array(
557
+ 'description' => __( 'The email address for the member.', 'buddypress' ),
558
+ 'type' => 'string',
559
+ 'format' => 'email',
560
+ 'context' => array( 'edit' ),
561
+ 'required' => true,
562
+ );
563
+ } elseif ( WP_REST_Server::EDITABLE === $method ) {
564
+ $key = 'update_item';
565
+
566
+ /**
567
+ * 1. The mention name or user login are not updatable.
568
+ * 2. The password belongs to the Settings endpoint parameter.
569
+ */
570
+ unset( $args['mention_name'], $args['user_login'], $args['password'] );
571
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
572
+ $key = 'delete_item';
573
+ }
574
+
575
+ /**
576
+ * Filters the method query arguments.
577
+ *
578
+ * @since 5.0.0
579
+ *
580
+ * @param array $args Query arguments.
581
+ * @param string $method HTTP method of the request.
582
+ */
583
+ return apply_filters( "bp_rest_members_{$key}_query_arguments", $args, $method );
584
+ }
585
+
586
+ /**
587
+ * Get the members schema, conforming to JSON Schema.
588
+ *
589
+ * @since 5.0.0
590
+ *
591
+ * @return array
592
+ */
593
+ public function get_item_schema() {
594
+ $schema = array(
595
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
596
+ 'title' => 'bp_members',
597
+ 'type' => 'object',
598
+ 'properties' => array(
599
+ 'id' => array(
600
+ 'description' => __( 'Unique identifier for the member.', 'buddypress' ),
601
+ 'type' => 'integer',
602
+ 'context' => array( 'embed', 'view', 'edit' ),
603
+ 'readonly' => true,
604
+ ),
605
+ 'name' => array(
606
+ 'description' => __( 'Display name for the member.', 'buddypress' ),
607
+ 'type' => 'string',
608
+ 'context' => array( 'embed', 'view', 'edit' ),
609
+ 'arg_options' => array(
610
+ 'sanitize_callback' => 'sanitize_text_field',
611
+ ),
612
+ ),
613
+ 'mention_name' => array(
614
+ 'description' => __( 'The name used for that user in @-mentions.', 'buddypress' ),
615
+ 'type' => 'string',
616
+ 'context' => array( 'embed', 'view', 'edit' ),
617
+ 'arg_options' => array(
618
+ 'sanitize_callback' => 'sanitize_text_field',
619
+ ),
620
+ ),
621
+ 'link' => array(
622
+ 'description' => __( 'Profile URL of the member.', 'buddypress' ),
623
+ 'type' => 'string',
624
+ 'format' => 'uri',
625
+ 'context' => array( 'embed', 'view', 'edit' ),
626
+ 'readonly' => true,
627
+ ),
628
+ 'user_login' => array(
629
+ 'description' => __( 'An alphanumeric identifier for the member.', 'buddypress' ),
630
+ 'type' => 'string',
631
+ 'context' => array( 'embed', 'view', 'edit' ),
632
+ 'required' => true,
633
+ 'arg_options' => array(
634
+ 'sanitize_callback' => array( $this, 'check_username' ),
635
+ ),
636
+ ),
637
+ 'member_types' => array(
638
+ 'description' => __( 'Member types associated with the member.', 'buddypress' ),
639
+ 'type' => 'object',
640
+ 'context' => array( 'embed', 'view', 'edit' ),
641
+ 'readonly' => true,
642
+ ),
643
+ 'registered_date' => array(
644
+ 'description' => __( 'Registration date for the member.', 'buddypress' ),
645
+ 'type' => 'string',
646
+ 'format' => 'date-time',
647
+ 'context' => array( 'edit' ),
648
+ 'readonly' => true,
649
+ ),
650
+ 'password' => array(
651
+ 'description' => __( 'Password for the member (never included).', 'buddypress' ),
652
+ 'type' => 'string',
653
+ 'context' => array(), // Password is never displayed.
654
+ 'required' => true,
655
+ 'arg_options' => array(
656
+ 'sanitize_callback' => array( $this, 'check_user_password' ),
657
+ ),
658
+ ),
659
+ 'roles' => array(
660
+ 'description' => __( 'Roles assigned to the member.', 'buddypress' ),
661
+ 'type' => 'array',
662
+ 'context' => array( 'edit' ),
663
+ 'items' => array(
664
+ 'type' => 'string',
665
+ ),
666
+ ),
667
+ 'capabilities' => array(
668
+ 'description' => __( 'All capabilities assigned to the user.', 'buddypress' ),
669
+ 'type' => 'object',
670
+ 'context' => array( 'edit' ),
671
+ 'readonly' => true,
672
+ ),
673
+ 'extra_capabilities' => array(
674
+ 'description' => __( 'Any extra capabilities assigned to the user.', 'buddypress' ),
675
+ 'type' => 'object',
676
+ 'context' => array( 'edit' ),
677
+ 'readonly' => true,
678
+ ),
679
+ 'xprofile' => array(
680
+ 'description' => __( 'Member XProfile groups and its fields.', 'buddypress' ),
681
+ 'type' => 'array',
682
+ 'context' => array( 'view', 'edit' ),
683
+ 'readonly' => true,
684
+ ),
685
+ ),
686
+ );
687
+
688
+ // Avatars.
689
+ if ( true === buddypress()->avatar->show_avatars ) {
690
+ $avatar_properties = array();
691
+
692
+ $avatar_properties['full'] = array(
693
+ /* translators: Full image size for the member Avatar */
694
+ 'description' => sprintf( __( 'Avatar URL with full image size (%1$d x %2$d pixels).', 'buddypress' ), number_format_i18n( bp_core_avatar_full_width() ), number_format_i18n( bp_core_avatar_full_height() ) ),
695
+ 'type' => 'string',
696
+ 'format' => 'uri',
697
+ 'context' => array( 'embed', 'view', 'edit' ),
698
+ );
699
+
700
+ $avatar_properties['thumb'] = array(
701
+ /* translators: Thumb imaze size for the member Avatar */
702
+ 'description' => sprintf( __( 'Avatar URL with thumb image size (%1$d x %2$d pixels).', 'buddypress' ), number_format_i18n( bp_core_avatar_thumb_width() ), number_format_i18n( bp_core_avatar_thumb_height() ) ),
703
+ 'type' => 'string',
704
+ 'format' => 'uri',
705
+ 'context' => array( 'embed', 'view', 'edit' ),
706
+ );
707
+
708
+ $schema['properties']['avatar_urls'] = array(
709
+ 'description' => __( 'Avatar URLs for the member.', 'buddypress' ),
710
+ 'type' => 'object',
711
+ 'context' => array( 'embed', 'view', 'edit' ),
712
+ 'readonly' => true,
713
+ 'properties' => $avatar_properties,
714
+ );
715
+ }
716
+
717
+ /**
718
+ * Filters the members schema.
719
+ *
720
+ * @param array $schema The endpoint schema.
721
+ */
722
+ return apply_filters( 'bp_rest_members_schema', $this->add_additional_fields_schema( $schema ) );
723
+ }
724
+
725
+ /**
726
+ * Get the query params for collections.
727
+ *
728
+ * @since 5.0.0
729
+ *
730
+ * @return array
731
+ */
732
+ public function get_collection_params() {
733
+ $params = array_intersect_key(
734
+ parent::get_collection_params(),
735
+ array(
736
+ 'context' => true,
737
+ 'page' => true,
738
+ 'per_page' => true,
739
+ 'search' => true,
740
+ )
741
+ );
742
+
743
+ $params['type'] = array(
744
+ 'description' => __( 'Shorthand for certain orderby/order combinations.', 'buddypress' ),
745
+ 'default' => 'newest',
746
+ 'type' => 'string',
747
+ 'enum' => array( 'active', 'newest', 'alphabetical', 'random', 'online', 'popular' ),
748
+ 'sanitize_callback' => 'sanitize_key',
749
+ 'validate_callback' => 'rest_validate_request_arg',
750
+ );
751
+
752
+ $params['user_id'] = array(
753
+ 'description' => __( 'Limit results to friends of a user.', 'buddypress' ),
754
+ 'default' => 0,
755
+ 'type' => 'integer',
756
+ 'sanitize_callback' => 'absint',
757
+ 'validate_callback' => 'rest_validate_request_arg',
758
+ );
759
+
760
+ $params['user_ids'] = array(
761
+ 'description' => __( 'Pass IDs of users to limit result set.', 'buddypress' ),
762
+ 'default' => array(),
763
+ 'type' => 'array',
764
+ 'items' => array( 'type' => 'integer' ),
765
+ 'sanitize_callback' => 'wp_parse_id_list',
766
+ 'validate_callback' => 'rest_validate_request_arg',
767
+ );
768
+
769
+ $params['include'] = array(
770
+ 'description' => __( 'Ensure result set include specific IDs.', 'buddypress' ),
771
+ 'default' => array(),
772
+ 'type' => 'array',
773
+ 'items' => array( 'type' => 'integer' ),
774
+ 'sanitize_callback' => 'wp_parse_id_list',
775
+ 'validate_callback' => 'rest_validate_request_arg',
776
+ );
777
+
778
+ $params['exclude'] = array(
779
+ 'description' => __( 'Ensure result set excludes specific IDs.', 'buddypress' ),
780
+ 'default' => array(),
781
+ 'type' => 'array',
782
+ 'items' => array( 'type' => 'integer' ),
783
+ 'sanitize_callback' => 'wp_parse_id_list',
784
+ 'validate_callback' => 'rest_validate_request_arg',
785
+ );
786
+
787
+ $params['member_type'] = array(
788
+ 'description' => __( 'Limit results set to certain type(s).', 'buddypress' ),
789
+ 'default' => array(),
790
+ 'type' => 'array',
791
+ 'items' => array( 'type' => 'string' ),
792
+ 'sanitize_callback' => 'bp_rest_sanitize_string_list',
793
+ 'validate_callback' => 'rest_validate_request_arg',
794
+ );
795
+
796
+ $params['xprofile'] = array(
797
+ 'description' => __( 'Limit results set to a certain XProfile field.', 'buddypress' ),
798
+ 'default' => '',
799
+ 'type' => 'string',
800
+ 'sanitize_callback' => 'sanitize_key',
801
+ 'validate_callback' => 'rest_validate_request_arg',
802
+ );
803
+
804
+ /**
805
+ * Filters the collection query params.
806
+ *
807
+ * @param array $params Query params.
808
+ */
809
+ return apply_filters( 'bp_rest_members_collection_params', $params );
810
+ }
811
+ }
bp-members/classes/class-bp-signup.php CHANGED
@@ -639,7 +639,12 @@ class BP_Signup {
639
 
640
  // Send the validation email.
641
  } else {
642
- bp_core_signup_send_validation_email( false, $signup->user_email, $signup->activation_key, $signup->user_login );
 
 
 
 
 
643
  }
644
  }
645
 
639
 
640
  // Send the validation email.
641
  } else {
642
+ $salutation = $signup->user_login;
643
+ if ( isset( $meta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) {
644
+ $salutation = $meta[ 'field_' . bp_xprofile_fullname_field_id() ];
645
+ }
646
+
647
+ bp_core_signup_send_validation_email( false, $signup->user_email, $signup->activation_key, $salutation );
648
  }
649
  }
650
 
bp-messages/bp-messages-cssjs.php CHANGED
@@ -42,7 +42,7 @@ function messages_add_autocomplete_css() {
42
 
43
  wp_enqueue_style( 'bp-messages-autocomplete', "{$url}autocomplete/jquery.autocompletefb{$min}.css", array(), bp_get_version() );
44
 
45
- wp_style_add_data( 'bp-messages-autocomplete', 'rtl', true );
46
  if ( $min ) {
47
  wp_style_add_data( 'bp-messages-autocomplete', 'suffix', $min );
48
  }
42
 
43
  wp_enqueue_style( 'bp-messages-autocomplete', "{$url}autocomplete/jquery.autocompletefb{$min}.css", array(), bp_get_version() );
44
 
45
+ wp_style_add_data( 'bp-messages-autocomplete', 'rtl', 'replace' );
46
  if ( $min ) {
47
  wp_style_add_data( 'bp-messages-autocomplete', 'suffix', $min );
48
  }
bp-messages/bp-messages-filters.php CHANGED
@@ -134,14 +134,16 @@ function bp_messages_filter_kses( $content ) {
134
  * Register Messages personal data exporter.
135
  *
136
  * @since 4.0.0
 
137
  *
138
  * @param array $exporters An array of personal data exporters.
139
  * @return array An array of personal data exporters.
140
  */
141
  function bp_messages_register_personal_data_exporter( $exporters ) {
142
  $exporters['buddypress-messages'] = array(
143
- 'exporter_friendly_name' => __( 'BuddyPress Messages', 'buddypress' ),
144
- 'callback' => 'bp_messages_personal_data_exporter',
 
145
  );
146
 
147
  return $exporters;
134
  * Register Messages personal data exporter.
135
  *
136
  * @since 4.0.0
137
+ * @since 5.0.0 adds an `exporter_bp_friendly_name` param to exporters.
138
  *
139
  * @param array $exporters An array of personal data exporters.
140
  * @return array An array of personal data exporters.
141
  */
142
  function bp_messages_register_personal_data_exporter( $exporters ) {
143
  $exporters['buddypress-messages'] = array(
144
+ 'exporter_friendly_name' => __( 'BuddyPress Messages', 'buddypress' ),
145
+ 'callback' => 'bp_messages_personal_data_exporter',
146
+ 'exporter_bp_friendly_name' => _x( 'Private Messages', 'BuddyPress Messages data exporter friendly name', 'buddypress' ),
147
  );
148
 
149
  return $exporters;
bp-messages/bp-messages-functions.php CHANGED
@@ -669,6 +669,13 @@ function bp_messages_personal_data_exporter( $email_address, $page ) {
669
  'page' => $page,
670
  ) );
671
 
 
 
 
 
 
 
 
672
  foreach ( $user_threads['threads'] as $thread ) {
673
  $recipient_links = array();
674
  foreach ( $thread->recipients as $recipient ) {
669
  'page' => $page,
670
  ) );
671
 
672
+ if ( empty( $user_threads ) ) {
673
+ return array(
674
+ 'data' => $data_to_export,
675
+ 'done' => true,
676
+ );
677
+ }
678
+
679
  foreach ( $user_threads['threads'] as $thread ) {
680
  $recipient_links = array();
681
  foreach ( $thread->recipients as $recipient ) {
bp-messages/bp-messages-template.php CHANGED
@@ -1155,18 +1155,29 @@ function bp_message_notice_post_date() {
1155
 
1156
  /**
1157
  * Output the subject of the current notice in the loop.
 
 
 
 
1158
  */
1159
- function bp_message_notice_subject() {
1160
- echo bp_get_message_notice_subject();
1161
  }
1162
  /**
1163
  * Get the subject of the current notice in the loop.
1164
  *
 
 
 
1165
  * @return string
1166
  */
1167
- function bp_get_message_notice_subject() {
1168
  global $messages_template;
1169
 
 
 
 
 
1170
  /**
1171
  * Filters the subject of the current notice in the loop.
1172
  *
@@ -1174,23 +1185,34 @@ function bp_message_notice_subject() {
1174
  *
1175
  * @param string $subject Subject of the current notice in the loop.
1176
  */
1177
- return apply_filters( 'bp_get_message_notice_subject', $messages_template->thread->subject );
1178
  }
1179
 
1180
  /**
1181
  * Output the text of the current notice in the loop.
 
 
 
 
1182
  */
1183
- function bp_message_notice_text() {
1184
- echo bp_get_message_notice_text();
1185
  }
1186
  /**
1187
  * Get the text of the current notice in the loop.
1188
  *
 
 
 
1189
  * @return string
1190
  */
1191
- function bp_get_message_notice_text() {
1192
  global $messages_template;
1193
 
 
 
 
 
1194
  /**
1195
  * Filters the text of the current notice in the loop.
1196
  *
@@ -1198,7 +1220,7 @@ function bp_message_notice_text() {
1198
  *
1199
  * @param string $message Text for the current notice in the loop.
1200
  */
1201
- return apply_filters( 'bp_get_message_notice_text', $messages_template->thread->message );
1202
  }
1203
 
1204
  /**
@@ -1334,12 +1356,10 @@ function bp_message_get_notices() {
1334
  if ( !in_array( $notice->id, $closed_notices ) && $notice->id ) {
1335
  ?>
1336
  <div id="message" class="info notice" rel="n-<?php echo esc_attr( $notice->id ); ?>">
1337
- <p>
1338
- <strong><?php echo stripslashes( wp_filter_kses( $notice->subject ) ) ?></strong><br />
1339
- <?php echo stripslashes( wp_filter_kses( $notice->message) ) ?>
1340
- <button type="button" id="close-notice" class="bp-tooltip" data-bp-tooltip="<?php esc_attr_e( 'Dismiss this notice', 'buddypress' ) ?>"><span class="bp-screen-reader-text"><?php _e( 'Dismiss this notice', 'buddypress' ) ?></span> <span aria-hidden="true">&Chi;</span></button>
1341
- <?php wp_nonce_field( 'bp_messages_close_notice', 'close-notice-nonce' ); ?>
1342
- </p>
1343
  </div>
1344
  <?php
1345
  }
1155
 
1156
  /**
1157
  * Output the subject of the current notice in the loop.
1158
+ *
1159
+ * @since 5.0.0 The $notice parameter has been added.
1160
+ *
1161
+ * @param BP_Messages_Notice $notice The notice object.
1162
  */
1163
+ function bp_message_notice_subject( $notice = null ) {
1164
+ echo bp_get_message_notice_subject( $notice );
1165
  }
1166
  /**
1167
  * Get the subject of the current notice in the loop.
1168
  *
1169
+ * @since 5.0.0 The $notice parameter has been added.
1170
+ *
1171
+ * @param BP_Messages_Notice $notice The notice object.
1172
  * @return string
1173
  */
1174
+ function bp_get_message_notice_subject( $notice = null ) {
1175
  global $messages_template;
1176
 
1177
+ if ( ! isset( $notice->subject ) ) {
1178
+ $notice =& $messages_template->thread;
1179
+ }
1180
+
1181
  /**
1182
  * Filters the subject of the current notice in the loop.
1183
  *
1185
  *
1186
  * @param string $subject Subject of the current notice in the loop.
1187
  */
1188
+ return apply_filters( 'bp_get_message_notice_subject', $notice->subject );
1189
  }
1190
 
1191
  /**
1192
  * Output the text of the current notice in the loop.
1193
+ *
1194
+ * @since 5.0.0 The $notice parameter has been added.
1195
+ *
1196
+ * @param BP_Messages_Notice $notice The notice object.
1197
  */
1198
+ function bp_message_notice_text( $notice = null ) {
1199
+ echo bp_get_message_notice_text( $notice );
1200
  }
1201
  /**
1202
  * Get the text of the current notice in the loop.
1203
  *
1204
+ * @since 5.0.0 The $notice parameter has been added.
1205
+ *
1206
+ * @param BP_Messages_Notice $notice The notice object.
1207
  * @return string
1208
  */
1209
+ function bp_get_message_notice_text( $notice = null ) {
1210
  global $messages_template;
1211
 
1212
+ if ( ! isset( $notice->subject ) ) {
1213
+ $notice =& $messages_template->thread;
1214
+ }
1215
+
1216
  /**
1217
  * Filters the text of the current notice in the loop.
1218
  *
1220
  *
1221
  * @param string $message Text for the current notice in the loop.
1222
  */
1223
+ return apply_filters( 'bp_get_message_notice_text', $notice->message );
1224
  }
1225
 
1226
  /**
1356
  if ( !in_array( $notice->id, $closed_notices ) && $notice->id ) {
1357
  ?>
1358
  <div id="message" class="info notice" rel="n-<?php echo esc_attr( $notice->id ); ?>">
1359
+ <strong><?php bp_message_notice_subject( $notice ); ?></strong>
1360
+ <button type="button" id="close-notice" class="bp-tooltip" data-bp-tooltip="<?php esc_attr_e( 'Dismiss this notice', 'buddypress' ) ?>"><span class="bp-screen-reader-text"><?php _e( 'Dismiss this notice', 'buddypress' ) ?></span> <span aria-hidden="true">&Chi;</span></button>
1361
+ <?php bp_message_notice_text( $notice ); ?>
1362
+ <?php wp_nonce_field( 'bp_messages_close_notice', 'close-notice-nonce' ); ?>
 
 
1363
  </div>
1364
  <?php
1365
  }
bp-messages/classes/class-bp-messages-box-template.php CHANGED
@@ -107,9 +107,10 @@ class BP_Messages_Box_Template {
107
  * }
108
  */
109
  public function __construct( $args = array() ) {
 
110
 
111
  // Backward compatibility with old method of passing arguments.
112
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
113
  _deprecated_argument( __METHOD__, '2.2.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
114
 
115
  $old_args_keys = array(
@@ -122,7 +123,7 @@ class BP_Messages_Box_Template {
122
  6 => 'page_arg'
123
  );
124
 
125
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
126
  }
127
 
128
  $r = wp_parse_args( $args, array(
107
  * }
108
  */
109
  public function __construct( $args = array() ) {
110
+ $function_args = func_get_args();
111
 
112
  // Backward compatibility with old method of passing arguments.
113
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
114
  _deprecated_argument( __METHOD__, '2.2.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
115
 
116
  $old_args_keys = array(
123
  6 => 'page_arg'
124
  );
125
 
126
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
127
  }
128
 
129
  $r = wp_parse_args( $args, array(
bp-messages/classes/class-bp-messages-component.php CHANGED
@@ -433,4 +433,16 @@ class BP_Messages_Component extends BP_Component {
433
 
434
  parent::setup_cache_groups();
435
  }
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
433
 
434
  parent::setup_cache_groups();
435
  }
436
+
437
+ /**
438
+ * Init the BP REST API.
439
+ *
440
+ * @since 5.0.0
441
+ */
442
+ public function rest_api_init() {
443
+ $controller = new BP_REST_Messages_Endpoint();
444
+ $controller->register_routes();
445
+
446
+ parent::rest_api_init();
447
+ }
448
  }
bp-messages/classes/class-bp-messages-thread.php CHANGED
@@ -445,8 +445,10 @@ class BP_Messages_Thread {
445
  public static function get_current_threads_for_user( $args = array() ) {
446
  global $wpdb;
447
 
 
 
448
  // Backward compatibility with old method of passing arguments.
449
- if ( ! is_array( $args ) || func_num_args() > 1 ) {
450
  _deprecated_argument( __METHOD__, '2.2.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
451
 
452
  $old_args_keys = array(
@@ -458,7 +460,7 @@ class BP_Messages_Thread {
458
  5 => 'search_terms',
459
  );
460
 
461
- $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
462
  }
463
 
464
  $r = bp_parse_args( $args, array(
445
  public static function get_current_threads_for_user( $args = array() ) {
446
  global $wpdb;
447
 
448
+ $function_args = func_get_args();
449
+
450
  // Backward compatibility with old method of passing arguments.
451
+ if ( ! is_array( $args ) || count( $function_args ) > 1 ) {
452
  _deprecated_argument( __METHOD__, '2.2.0', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
453
 
454
  $old_args_keys = array(
460
  5 => 'search_terms',
461
  );
462
 
463
+ $args = bp_core_parse_args_array( $old_args_keys, $function_args );
464
  }
465
 
466
  $r = bp_parse_args( $args, array(
bp-messages/classes/class-bp-rest-messages-endpoint.php ADDED
@@ -0,0 +1,1282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Messages_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Messages endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Messages_Endpoint extends WP_REST_Controller {
17
+
18
+ /**
19
+ * Constructor.
20
+ *
21
+ * @since 5.0.0
22
+ */
23
+ public function __construct() {
24
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
25
+ $this->rest_base = buddypress()->messages->id;
26
+ }
27
+
28
+ /**
29
+ * Register the component routes.
30
+ *
31
+ * @since 5.0.0
32
+ */
33
+ public function register_routes() {
34
+ register_rest_route(
35
+ $this->namespace,
36
+ '/' . $this->rest_base,
37
+ array(
38
+ array(
39
+ 'methods' => WP_REST_Server::READABLE,
40
+ 'callback' => array( $this, 'get_items' ),
41
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
42
+ 'args' => $this->get_collection_params(),
43
+ ),
44
+ array(
45
+ 'methods' => WP_REST_Server::CREATABLE,
46
+ 'callback' => array( $this, 'create_item' ),
47
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
48
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
49
+ ),
50
+ 'schema' => array( $this, 'get_item_schema' ),
51
+ )
52
+ );
53
+
54
+ // Attention: (?P<id>[\d]+) is the placeholder for **Thread** ID, not the Message ID one.
55
+ $thread_endpoint = '/' . $this->rest_base . '/(?P<id>[\d]+)';
56
+
57
+ register_rest_route(
58
+ $this->namespace,
59
+ $thread_endpoint,
60
+ array(
61
+ array(
62
+ 'methods' => WP_REST_Server::READABLE,
63
+ 'callback' => array( $this, 'get_item' ),
64
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
65
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::READABLE ),
66
+ ),
67
+ array(
68
+ 'methods' => WP_REST_Server::EDITABLE,
69
+ 'callback' => array( $this, 'update_item' ),
70
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
71
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
72
+ ),
73
+ array(
74
+ 'methods' => WP_REST_Server::DELETABLE,
75
+ 'callback' => array( $this, 'delete_item' ),
76
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
77
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::DELETABLE ),
78
+ ),
79
+ 'schema' => array( $this, 'get_item_schema' ),
80
+ )
81
+ );
82
+
83
+ // Register the starred route.
84
+ if ( bp_is_active( 'messages', 'star' ) ) {
85
+ // Attention: (?P<id>[\d]+) is the placeholder for **Message** ID, not the Thread ID one.
86
+ $starred_endpoint = '/' . $this->rest_base . '/' . bp_get_messages_starred_slug() . '/(?P<id>[\d]+)';
87
+
88
+ register_rest_route(
89
+ $this->namespace,
90
+ $starred_endpoint,
91
+ array(
92
+ 'args' => array(
93
+ 'id' => array(
94
+ 'description' => __( 'ID of one of the message of the Thread.', 'buddypress' ),
95
+ 'type' => 'integer',
96
+ ),
97
+ ),
98
+ array(
99
+ 'methods' => WP_REST_Server::EDITABLE,
100
+ 'callback' => array( $this, 'update_starred' ),
101
+ 'permission_callback' => array( $this, 'update_starred_permissions_check' ),
102
+ ),
103
+ 'schema' => array( $this, 'get_item_schema' ),
104
+ )
105
+ );
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Retrieve threads.
111
+ *
112
+ * @since 5.0.0
113
+ *
114
+ * @param WP_REST_Request $request Full details about the request.
115
+ * @return WP_REST_Response
116
+ */
117
+ public function get_items( $request ) {
118
+ $args = array(
119
+ 'user_id' => $request['user_id'],
120
+ 'box' => $request['box'],
121
+ 'type' => $request['type'],
122
+ 'page' => $request['page'],
123
+ 'per_page' => $request['per_page'],
124
+ 'search_terms' => $request['search'],
125
+ );
126
+
127
+ // Include the meta_query for starred messages.
128
+ if ( 'starred' === $args['box'] ) {
129
+ $args['meta_query'] = array( // phpcs:ignore
130
+ array(
131
+ 'key' => 'starred_by_user',
132
+ 'value' => $args['user_id'],
133
+ ),
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Filter the query arguments for the request.
139
+ *
140
+ * @since 5.0.0
141
+ *
142
+ * @param array $args Key value array of query var to query value.
143
+ * @param WP_REST_Request $request The request sent to the API.
144
+ */
145
+ $args = apply_filters( 'bp_rest_messages_get_items_query_args', $args, $request );
146
+
147
+ // Actually, query it.
148
+ $messages_box = new BP_Messages_Box_Template( $args );
149
+
150
+ $retval = array();
151
+ foreach ( (array) $messages_box->threads as $thread ) {
152
+ $retval[] = $this->prepare_response_for_collection(
153
+ $this->prepare_item_for_response( $thread, $request )
154
+ );
155
+ }
156
+
157
+ $response = rest_ensure_response( $retval );
158
+ $response = bp_rest_response_add_total_headers( $response, $messages_box->total_thread_count, $args['per_page'] );
159
+
160
+ /**
161
+ * Fires after a thread is fetched via the REST API.
162
+ *
163
+ * @since 5.0.0
164
+ *
165
+ * @param BP_Messages_Box_Template $messages_box Fetched thread.
166
+ * @param WP_REST_Response $response The response data.
167
+ * @param WP_REST_Request $request The request sent to the API.
168
+ */
169
+ do_action( 'bp_rest_messages_get_items', $messages_box, $response, $request );
170
+
171
+ return $response;
172
+ }
173
+
174
+ /**
175
+ * Check if a given request has access to thread items.
176
+ *
177
+ * @since 5.0.0
178
+ *
179
+ * @param WP_REST_Request $request Full data about the request.
180
+ * @return WP_Error|bool
181
+ */
182
+ public function get_items_permissions_check( $request ) {
183
+ $retval = true;
184
+
185
+ if ( ! is_user_logged_in() ) {
186
+ $retval = new WP_Error(
187
+ 'bp_rest_authorization_required',
188
+ __( 'Sorry, you are not allowed to see the messages.', 'buddypress' ),
189
+ array(
190
+ 'status' => rest_authorization_required_code(),
191
+ )
192
+ );
193
+ }
194
+
195
+ $user = bp_rest_get_user( $request['user_id'] );
196
+
197
+ if ( true === $retval && ! $user instanceof WP_User ) {
198
+ $retval = new WP_Error(
199
+ 'bp_rest_invalid_id',
200
+ __( 'Invalid member id.', 'buddypress' ),
201
+ array(
202
+ 'status' => 404,
203
+ )
204
+ );
205
+ }
206
+
207
+ if ( true === $retval && (int) bp_loggedin_user_id() !== $user->ID && ! bp_current_user_can( 'bp_moderate' ) ) {
208
+ $retval = new WP_Error(
209
+ 'bp_rest_authorization_required',
210
+ __( 'Sorry, you cannot view the messages.', 'buddypress' ),
211
+ array(
212
+ 'status' => rest_authorization_required_code(),
213
+ )
214
+ );
215
+ }
216
+
217
+ /**
218
+ * Filter the messages `get_items` permissions check.
219
+ *
220
+ * @since 5.0.0
221
+ *
222
+ * @param bool|WP_Error $retval Returned value.
223
+ * @param WP_REST_Request $request The request sent to the API.
224
+ */
225
+ return apply_filters( 'bp_rest_messages_get_items_permissions_check', $retval, $request );
226
+ }
227
+
228
+ /**
229
+ * Get a single thread.
230
+ *
231
+ * @since 5.0.0
232
+ *
233
+ * @param WP_REST_Request $request Full data about the request.
234
+ * @return WP_REST_Response
235
+ */
236
+ public function get_item( $request ) {
237
+ $thread = $this->get_thread_object( $request['id'] );
238
+
239
+ $retval = array(
240
+ $this->prepare_response_for_collection(
241
+ $this->prepare_item_for_response( $thread, $request )
242
+ ),
243
+ );
244
+
245
+ $response = rest_ensure_response( $retval );
246
+
247
+ /**
248
+ * Fires after a thread is fetched via the REST API.
249
+ *
250
+ * @since 5.0.0
251
+ *
252
+ * @param BP_Messages_Thread $thread Thread object.
253
+ * @param WP_REST_Response $retval The response data.
254
+ * @param WP_REST_Request $request The request sent to the API.
255
+ */
256
+ do_action( 'bp_rest_messages_get_item', $thread, $response, $request );
257
+
258
+ return $response;
259
+ }
260
+
261
+ /**
262
+ * Check if a given request has access to a thread item.
263
+ *
264
+ * @since 5.0.0
265
+ *
266
+ * @param WP_REST_Request $request Full data about the request.
267
+ * @return WP_Error|bool
268
+ */
269
+ public function get_item_permissions_check( $request ) {
270
+ $retval = true;
271
+
272
+ if ( ! is_user_logged_in() ) {
273
+ $retval = new WP_Error(
274
+ 'bp_rest_authorization_required',
275
+ __( 'Sorry, you are not allowed to see this thread.', 'buddypress' ),
276
+ array(
277
+ 'status' => rest_authorization_required_code(),
278
+ )
279
+ );
280
+ }
281
+
282
+ $thread = $this->get_thread_object( $request['id'] );
283
+
284
+ if ( true === $retval && empty( $thread->thread_id ) ) {
285
+ $retval = new WP_Error(
286
+ 'bp_rest_invalid_id',
287
+ __( 'Sorry, this thread does not exist.', 'buddypress' ),
288
+ array(
289
+ 'status' => 404,
290
+ )
291
+ );
292
+ }
293
+
294
+ if ( true === $retval && bp_current_user_can( 'bp_moderate' ) ) {
295
+ $retval = true;
296
+ } else {
297
+ $id = messages_check_thread_access( $thread->thread_id );
298
+ if ( true === $retval && is_null( $id ) ) {
299
+ $retval = new WP_Error(
300
+ 'bp_rest_authorization_required',
301
+ __( 'Sorry, you are not allowed to see this thread.', 'buddypress' ),
302
+ array(
303
+ 'status' => rest_authorization_required_code(),
304
+ )
305
+ );
306
+ }
307
+
308
+ if ( true === $retval ) {
309
+ $retval = true;
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Filter the messages `get_item` permissions check.
315
+ *
316
+ * @since 5.0.0
317
+ *
318
+ * @param bool|WP_Error $retval Returned value.
319
+ * @param WP_REST_Request $request The request sent to the API.
320
+ */
321
+ return apply_filters( 'bp_rest_messages_get_item_permissions_check', $retval, $request );
322
+ }
323
+
324
+ /**
325
+ * Init a Messages Thread or add a reply to an existing Thread.
326
+ *
327
+ * @since 5.0.0
328
+ *
329
+ * @param WP_REST_Request $request Full details about the request.
330
+ * @return WP_REST_Response|WP_Error
331
+ */
332
+ public function create_item( $request ) {
333
+ // Setting context.
334
+ $request->set_param( 'context', 'edit' );
335
+
336
+ // Prepare the message or the reply arguments.
337
+ $args = array(
338
+ 'sender_id' => $request['sender_id'],
339
+ 'thread_id' => 0,
340
+ 'subject' => $request['subject'],
341
+ 'content' => $request['message'],
342
+ 'recipients' => $request['recipients'],
343
+ );
344
+
345
+ $error = new WP_Error(
346
+ 'bp_rest_messages_create_failed',
347
+ __( 'There was an error trying to create the message.', 'buddypress' ),
348
+ array(
349
+ 'status' => 500,
350
+ )
351
+ );
352
+
353
+ // Replying to an existing Thread ?
354
+ if ( $request['id'] ) {
355
+ // Try to get the thread.
356
+ $thread = $this->get_thread_object( $request['id'] );
357
+
358
+ // Validate the Thread exists.
359
+ if ( ! $thread->thread_id ) {
360
+ return $error;
361
+ }
362
+
363
+ $args['thread_id'] = (int) $thread->thread_id;
364
+ $args['recipients'] = wp_parse_id_list( wp_list_pluck( $thread->recipients, 'user_id' ) );
365
+ }
366
+
367
+ if ( ! $args['recipients'] ) {
368
+ return new WP_Error(
369
+ 'bp_rest_messages_missing_recipients',
370
+ __( 'Please provide some recipients for your message or reply.', 'buddypress' ),
371
+ array(
372
+ 'status' => 400,
373
+ )
374
+ );
375
+ }
376
+
377
+ // Create the message or the reply.
378
+ $thread_id = messages_new_message( $args );
379
+
380
+ // Validate it created a Thread or was added to it.
381
+ if ( ! $thread_id ) {
382
+ return $error;
383
+ }
384
+
385
+ // Make sure to get the newest message to update REST Additional fields.
386
+ $thread = $this->get_thread_object( $thread_id );
387
+ $last_message = wp_list_filter( $thread->messages, array( 'id' => $thread->last_message_id ) );
388
+ $last_message = reset( $last_message );
389
+ $fields_update = $this->update_additional_fields_for_object( $last_message, $request );
390
+
391
+ if ( is_wp_error( $fields_update ) ) {
392
+ return $fields_update;
393
+ }
394
+
395
+ $retval = array(
396
+ $this->prepare_response_for_collection(
397
+ $this->prepare_item_for_response( $thread, $request )
398
+ ),
399
+ );
400
+
401
+ $response = rest_ensure_response( $retval );
402
+
403
+ /**
404
+ * Fires after a message is created via the REST API.
405
+ *
406
+ * @since 5.0.0
407
+ *
408
+ * @param BP_Messages_Thread $thread Thread object.
409
+ * @param WP_REST_Response $retval The response data.
410
+ * @param WP_REST_Request $request The request sent to the API.
411
+ */
412
+ do_action( 'bp_rest_messages_create_item', $thread, $response, $request );
413
+
414
+ return $response;
415
+ }
416
+
417
+ /**
418
+ * Check if a given request has access to create a message.
419
+ *
420
+ * @since 5.0.0
421
+ *
422
+ * @param WP_REST_Request $request Full details about the request.
423
+ * @return WP_Error|bool
424
+ */
425
+ public function create_item_permissions_check( $request ) {
426
+ $retval = true;
427
+
428
+ if ( ! is_user_logged_in() ) {
429
+ $retval = new WP_Error(
430
+ 'bp_rest_authorization_required',
431
+ __( 'Sorry, you need to be logged in to create a message.', 'buddypress' ),
432
+ array(
433
+ 'status' => rest_authorization_required_code(),
434
+ )
435
+ );
436
+ }
437
+
438
+ /**
439
+ * Filter the messages `create_item` permissions check.
440
+ *
441
+ * @since 5.0.0
442
+ *
443
+ * @param bool|WP_Error $retval Returned value.
444
+ * @param WP_REST_Request $request The request sent to the API.
445
+ */
446
+ return apply_filters( 'bp_rest_messages_create_item_permissions_check', $retval, $request );
447
+ }
448
+
449
+ /**
450
+ * Update metadata for one of the messages of the thread.
451
+ *
452
+ * @since 5.0.0
453
+ *
454
+ * @param WP_REST_Request $request Full details about the request.
455
+ * @return WP_REST_Response|WP_Error
456
+ */
457
+ public function update_item( $request ) {
458
+ // Setting context.
459
+ $request->set_param( 'context', 'edit' );
460
+
461
+ // Get the thread.
462
+ $thread = $this->get_thread_object( $request['id'] );
463
+ $error = new WP_Error(
464
+ 'bp_rest_messages_update_failed',
465
+ __( 'There was an error trying to update the message.', 'buddypress' ),
466
+ array(
467
+ 'status' => 500,
468
+ )
469
+ );
470
+
471
+ if ( ! $thread->thread_id ) {
472
+ return $error;
473
+ }
474
+
475
+ // By default use the last message.
476
+ $message_id = $thread->last_message_id;
477
+ if ( $request['message_id'] ) {
478
+ $message_id = $request['message_id'];
479
+ }
480
+
481
+ $updated_message = wp_list_filter( $thread->messages, array( 'id' => $message_id ) );
482
+ $updated_message = reset( $updated_message );
483
+
484
+ /**
485
+ * Filter here to allow more users to edit the message meta (eg: the recipients).
486
+ *
487
+ * @since 5.0.0
488
+ *
489
+ * @param boolean $value Whether the user can edit the message meta.
490
+ * By default: only the sender and a community moderator can.
491
+ * @param BP_Messages_Message $updated_message The updated message object.
492
+ * @param WP_REST_Request $request The request sent to the API.
493
+ */
494
+ $can_edit_item_meta = apply_filters(
495
+ 'bp_rest_messages_can_edit_item_meta',
496
+ bp_loggedin_user_id() === $updated_message->sender_id || bp_current_user_can( 'bp_moderate' ),
497
+ $updated_message,
498
+ $request
499
+ );
500
+
501
+ // The message must exist in the thread, and the logged in user must be the sender.
502
+ if ( ! isset( $updated_message->id ) || ! $updated_message->id || ! $can_edit_item_meta ) {
503
+ return $error;
504
+ }
505
+
506
+ $fields_update = $this->update_additional_fields_for_object( $updated_message, $request );
507
+ if ( is_wp_error( $fields_update ) ) {
508
+ return $fields_update;
509
+ }
510
+
511
+ $retval = array(
512
+ $this->prepare_response_for_collection(
513
+ $this->prepare_item_for_response( $thread, $request )
514
+ ),
515
+ );
516
+
517
+ $response = rest_ensure_response( $retval );
518
+
519
+ /**
520
+ * Fires after a message is updated via the REST API.
521
+ *
522
+ * @since 5.0.0
523
+ *
524
+ * @param BP_Messages_Message $updated_message The updated message.
525
+ * @param WP_REST_Response $response The response data.
526
+ * @param WP_REST_Request $request The request sent to the API.
527
+ */
528
+ do_action( 'bp_rest_messages_update_item', $updated_message, $response, $request );
529
+
530
+ return $response;
531
+ }
532
+
533
+ /**
534
+ * Check if a given request has access to update a message.
535
+ *
536
+ * @since 5.0.0
537
+ *
538
+ * @param WP_REST_Request $request Full details about the request.
539
+ * @return bool|WP_Error
540
+ */
541
+ public function update_item_permissions_check( $request ) {
542
+ $retval = $this->get_item_permissions_check( $request );
543
+
544
+ /**
545
+ * Filter the message `update_item` permissions check.
546
+ *
547
+ * @since 5.0.0
548
+ *
549
+ * @param bool|WP_Error $retval Returned value.
550
+ * @param WP_REST_Request $request The request sent to the API.
551
+ */
552
+ return apply_filters( 'bp_rest_messages_update_item_permissions_check', $retval, $request );
553
+ }
554
+
555
+ /**
556
+ * Adds or removes the message from the current user's starred box.
557
+ *
558
+ * @since 5.0.0
559
+ *
560
+ * @param WP_REST_Request $request Full details about the request.
561
+ * @return WP_REST_Response|WP_Error
562
+ */
563
+ public function update_starred( $request ) {
564
+ // Setting context.
565
+ $request->set_param( 'context', 'edit' );
566
+
567
+ $message = $this->get_message_object( $request['id'] );
568
+
569
+ if ( empty( $message->id ) ) {
570
+ return new WP_Error(
571
+ 'bp_rest_invalid_id',
572
+ __( 'Sorry, this message does not exist.', 'buddypress' ),
573
+ array(
574
+ 'status' => 404,
575
+ )
576
+ );
577
+ }
578
+
579
+ $user_id = bp_loggedin_user_id();
580
+ $result = false;
581
+ $action = 'star';
582
+ $info = __( 'Sorry, you cannot add the message to your starred box.', 'buddypress' );
583
+
584
+ if ( bp_messages_is_message_starred( $message->id, $user_id ) ) {
585
+ $action = 'unstar';
586
+ $info = __( 'Sorry, you cannot remove the message from your starred box.', 'buddypress' );
587
+ }
588
+
589
+ $result = bp_messages_star_set_action(
590
+ array(
591
+ 'user_id' => $user_id,
592
+ 'message_id' => $message->id,
593
+ 'action' => $action,
594
+ )
595
+ );
596
+
597
+ if ( ! $result ) {
598
+ return new WP_Error(
599
+ 'bp_rest_user_cannot_update_starred_message',
600
+ $info,
601
+ array(
602
+ 'status' => 500,
603
+ )
604
+ );
605
+ }
606
+
607
+ // Prepare the message for the REST response.
608
+ $data = array(
609
+ $this->prepare_response_for_collection(
610
+ $this->prepare_message_for_response( $message, $request )
611
+ ),
612
+ );
613
+
614
+ $response = rest_ensure_response( $data );
615
+
616
+ /**
617
+ * Fires after a message is starred/unstarred via the REST API.
618
+ *
619
+ * @since 5.0.0
620
+ *
621
+ * @param BP_Messages_Message $message Message object.
622
+ * @param string $action Informs about the update performed.
623
+ * Possible values are `star` or `unstar`.
624
+ * @param WP_REST_Response $response The response data.
625
+ * @param WP_REST_Request $request The request sent to the API.
626
+ */
627
+ do_action( 'bp_rest_message_update_starred_item', $message, $action, $response, $request );
628
+
629
+ return $response;
630
+ }
631
+
632
+ /**
633
+ * Check if a given request has access to update user starred messages.
634
+ *
635
+ * @since 5.0.0
636
+ *
637
+ * @param WP_REST_Request $request Full details about the request.
638
+ * @return bool|WP_Error
639
+ */
640
+ public function update_starred_permissions_check( $request ) {
641
+ $retval = true;
642
+ $thread_id = messages_get_message_thread_id( $request['id'] );
643
+
644
+ if ( ! is_user_logged_in() || ! messages_check_thread_access( $thread_id ) ) {
645
+ $retval = new WP_Error(
646
+ 'bp_rest_authorization_required',
647
+ __( 'Sorry, you are not allowed to star/unstar messages.', 'buddypress' ),
648
+ array(
649
+ 'status' => rest_authorization_required_code(),
650
+ )
651
+ );
652
+ }
653
+
654
+ /**
655
+ * Filter the message `update_starred` permissions check.
656
+ *
657
+ * @since 5.0.0
658
+ *
659
+ * @param bool|WP_Error $retval Returned value.
660
+ * @param WP_REST_Request $request The request sent to the API.
661
+ */
662
+ return apply_filters( 'bp_rest_messages_update_starred_permissions_check', $retval, $request );
663
+ }
664
+
665
+ /**
666
+ * Delete a thread.
667
+ *
668
+ * @since 5.0.0
669
+ *
670
+ * @param WP_REST_Request $request Full details about the request.
671
+ * @return WP_REST_Response|WP_Error
672
+ */
673
+ public function delete_item( $request ) {
674
+ // Setting context.
675
+ $request->set_param( 'context', 'edit' );
676
+
677
+ // Get the thread before it's deleted.
678
+ $thread = $this->get_thread_object( $request['id'] );
679
+ $previous = $this->prepare_item_for_response( $thread, $request );
680
+
681
+ $user_id = bp_loggedin_user_id();
682
+ if ( ! empty( $request['user_id'] ) ) {
683
+ $user_id = $request['user_id'];
684
+ }
685
+
686
+ // Check the user is one of the recipients.
687
+ $recipient_ids = wp_parse_id_list( wp_list_pluck( $thread->recipients, 'user_id' ) );
688
+
689
+ // Delete a thread.
690
+ if ( ! in_array( $user_id, $recipient_ids, true ) || ! messages_delete_thread( $thread->thread_id, $user_id ) ) {
691
+ return new WP_Error(
692
+ 'bp_rest_messages_delete_thread_failed',
693
+ __( 'There was an error trying to delete a thread.', 'buddypress' ),
694
+ array(
695
+ 'status' => 500,
696
+ )
697
+ );
698
+ }
699
+
700
+ // Build the response.
701
+ $response = new WP_REST_Response();
702
+ $response->set_data(
703
+ array(
704
+ 'deleted' => true,
705
+ 'previous' => $previous->get_data(),
706
+ )
707
+ );
708
+
709
+ /**
710
+ * Fires after a thread is deleted via the REST API.
711
+ *
712
+ * @since 5.0.0
713
+ *
714
+ * @param BP_Messages_Thread $thread Thread object.
715
+ * @param WP_REST_Response $response The response data.
716
+ * @param WP_REST_Request $request The request sent to the API.
717
+ */
718
+ do_action( 'bp_rest_messages_delete_item', $thread, $response, $request );
719
+
720
+ return $response;
721
+ }
722
+
723
+ /**
724
+ * Check if a given request has access to delete a thread.
725
+ *
726
+ * @since 5.0.0
727
+ *
728
+ * @param WP_REST_Request $request Full details about the request.
729
+ * @return WP_Error|bool
730
+ */
731
+ public function delete_item_permissions_check( $request ) {
732
+ $retval = $this->get_item_permissions_check( $request );
733
+
734
+ /**
735
+ * Filter the thread `delete_item` permissions check.
736
+ *
737
+ * @since 5.0.0
738
+ *
739
+ * @param bool|WP_Error $retval Returned value.
740
+ * @param WP_REST_Request $request The request sent to the API.
741
+ */
742
+ return apply_filters( 'bp_rest_messages_delete_item_permissions_check', $retval, $request );
743
+ }
744
+
745
+ /**
746
+ * Prepares message data for the REST response.
747
+ *
748
+ * @since 5.0.0
749
+ *
750
+ * @param BP_Messages_Message $message The Message object.
751
+ * @param WP_REST_Request $request Full details about the request.
752
+ * @return array The Message data for the REST response.
753
+ */
754
+ public function prepare_message_for_response( $message, $request ) {
755
+ $data = array(
756
+ 'id' => (int) $message->id,
757
+ 'thread_id' => (int) $message->thread_id,
758
+ 'sender_id' => (int) $message->sender_id,
759
+ 'subject' => array(
760
+ 'raw' => $message->subject,
761
+ 'rendered' => apply_filters( 'bp_get_message_thread_subject', wp_staticize_emoji( $message->subject ) ),
762
+ ),
763
+ 'message' => array(
764
+ 'raw' => $message->message,
765
+ 'rendered' => apply_filters( 'bp_get_the_thread_message_content', wp_staticize_emoji( $message->message ) ),
766
+ ),
767
+ 'date_sent' => bp_rest_prepare_date_response( $message->date_sent ),
768
+ );
769
+
770
+ if ( bp_is_active( 'messages', 'star' ) ) {
771
+ $user_id = bp_loggedin_user_id();
772
+
773
+ if ( isset( $request['user_id'] ) && $request['user_id'] ) {
774
+ $user_id = (int) $request['user_id'];
775
+ }
776
+
777
+ $data['is_starred'] = bp_messages_is_message_starred( $data['id'], $user_id );
778
+ }
779
+
780
+ // Add REST Fields (BP Messages meta) data.
781
+ $data = $this->add_additional_fields_to_object( $data, $request );
782
+
783
+ /**
784
+ * Filter a message value returned from the API.
785
+ *
786
+ * @since 5.0.0
787
+ *
788
+ * @param array $data The message value for the REST response.
789
+ * @param BP_Messages_Message $message The Message object.
790
+ * @param WP_REST_Request $request Request used to generate the response.
791
+ */
792
+ return apply_filters( 'bp_rest_message_prepare_value', $data, $message, $request );
793
+ }
794
+
795
+ /**
796
+ * Prepares recipient data for the REST response.
797
+ *
798
+ * @since 5.0.0
799
+ *
800
+ * @param object $recipient The recipient object.
801
+ * @param WP_REST_Request $request Full details about the request.
802
+ * @return array The recipient data for the REST response.
803
+ */
804
+ public function prepare_recipient_for_response( $recipient, $request ) {
805
+ $data = array(
806
+ 'id' => (int) $recipient->id,
807
+ 'user_id' => (int) $recipient->user_id,
808
+ 'user_link' => esc_url( bp_core_get_user_domain( $recipient->user_id ) ),
809
+ );
810
+
811
+ // Fetch the user avatar urls (Full & thumb).
812
+ if ( true === buddypress()->avatar->show_avatars ) {
813
+ foreach ( array( 'full', 'thumb' ) as $type ) {
814
+ $data['user_avatars'][ $type ] = bp_core_fetch_avatar(
815
+ array(
816
+ 'item_id' => $recipient->user_id,
817
+ 'html' => false,
818
+ 'type' => $type,
819
+ )
820
+ );
821
+ }
822
+ }
823
+
824
+ $data = array_merge(
825
+ $data,
826
+ array(
827
+ 'thread_id' => (int) $recipient->thread_id,
828
+ 'unread_count' => (int) $recipient->unread_count,
829
+ 'sender_only' => (int) $recipient->sender_only,
830
+ 'is_deleted' => (int) $recipient->is_deleted,
831
+ )
832
+ );
833
+
834
+ /**
835
+ * Filter a recipient value returned from the API.
836
+ *
837
+ * @since 5.0.0
838
+ *
839
+ * @param array $data The recipient value for the REST response.
840
+ * @param object $recipient The recipient object.
841
+ * @param WP_REST_Request $request Request used to generate the response.
842
+ */
843
+ return apply_filters( 'bp_rest_messages_prepare_recipient_value', $data, $recipient, $request );
844
+ }
845
+
846
+ /**
847
+ * Prepare links for the request.
848
+ *
849
+ * @since 5.0.0
850
+ *
851
+ * @param BP_Messages_Thread $thread Thread object.
852
+ * @return array Links for the given thread.
853
+ */
854
+ protected function prepare_links( $thread ) {
855
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
856
+
857
+ // Entity meta.
858
+ $links = array(
859
+ 'self' => array(
860
+ 'href' => rest_url( $base . $thread->thread_id ),
861
+ ),
862
+ 'collection' => array(
863
+ 'href' => rest_url( $base ),
864
+ ),
865
+ );
866
+
867
+ // Add star links for each message of the thread.
868
+ if ( bp_is_active( 'messages', 'star' ) ) {
869
+ $starred_base = $base . bp_get_messages_starred_slug() . '/';
870
+
871
+ foreach ( $thread->messages as $message ) {
872
+ $links[ $message->id ] = array(
873
+ 'href' => rest_url( $starred_base . $message->id ),
874
+ );
875
+ }
876
+ }
877
+
878
+ /**
879
+ * Filter links prepared for the REST response.
880
+ *
881
+ * @since 5.0.0
882
+ *
883
+ * @param array $links The prepared links of the REST response.
884
+ * @param BP_Messages_Thread $thread Thread object.
885
+ */
886
+ return apply_filters( 'bp_rest_messages_prepare_links', $links, $thread );
887
+ }
888
+
889
+ /**
890
+ * Prepares thread data for return as an object.
891
+ *
892
+ * @since 5.0.0
893
+ *
894
+ * @param BP_Messages_Thread $thread Thread object.
895
+ * @param WP_REST_Request $request Full details about the request.
896
+ * @return WP_REST_Response
897
+ */
898
+ public function prepare_item_for_response( $thread, $request ) {
899
+ $excerpt = '';
900
+ if ( isset( $thread->last_message_content ) ) {
901
+ $excerpt = wp_strip_all_tags( bp_create_excerpt( $thread->last_message_content, 75 ) );
902
+ }
903
+
904
+ $data = array(
905
+ 'id' => $thread->thread_id,
906
+ 'message_id' => $thread->last_message_id,
907
+ 'last_sender_id' => $thread->last_sender_id,
908
+ 'subject' => array(
909
+ 'raw' => $thread->last_message_subject,
910
+ 'rendered' => apply_filters( 'bp_get_message_thread_subject', wp_staticize_emoji( $thread->last_message_subject ) ),
911
+ ),
912
+ 'excerpt' => array(
913
+ 'raw' => $excerpt,
914
+ 'rendered' => apply_filters( 'bp_get_message_thread_excerpt', $excerpt ),
915
+ ),
916
+ 'message' => array(
917
+ 'raw' => $thread->last_message_content,
918
+ 'rendered' => apply_filters( 'bp_get_message_thread_content', wp_staticize_emoji( $thread->last_message_content ) ),
919
+ ),
920
+ 'date' => bp_rest_prepare_date_response( $thread->last_message_date ),
921
+ 'unread_count' => ! empty( $thread->unread_count ) ? $thread->unread_count : 0,
922
+ 'sender_ids' => $thread->sender_ids,
923
+ 'recipients' => array(),
924
+ 'messages' => array(),
925
+ );
926
+
927
+ // Loop through messages to prepare them for the response.
928
+ foreach ( $thread->messages as $message ) {
929
+ $data['messages'][] = $this->prepare_message_for_response( $message, $request );
930
+ }
931
+
932
+ // Loop through recipients to prepare them for the response.
933
+ foreach ( $thread->recipients as $recipient ) {
934
+ $data['recipients'][ $recipient->user_id ] = $this->prepare_recipient_for_response( $recipient, $request );
935
+ }
936
+
937
+ // Pluck starred message ids.
938
+ $data['starred_message_ids'] = array_keys( array_filter( wp_list_pluck( $data['messages'], 'is_starred', 'id' ) ) );
939
+
940
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
941
+ $data = $this->add_additional_fields_to_object( $data, $request );
942
+ $data = $this->filter_response_by_context( $data, $context );
943
+ $response = rest_ensure_response( $data );
944
+
945
+ $response->add_links( $this->prepare_links( $thread ) );
946
+
947
+ /**
948
+ * Filter a thread value returned from the API.
949
+ *
950
+ * @since 5.0.0
951
+ *
952
+ * @param WP_REST_Response $response Response generated by the request.
953
+ * @param WP_REST_Request $request Request used to generate the response.
954
+ * @param BP_Messages_Thread $thread The thread object.
955
+ */
956
+ return apply_filters( 'bp_rest_messages_prepare_value', $response, $request, $thread );
957
+ }
958
+
959
+ /**
960
+ * Get thread object.
961
+ *
962
+ * @since 5.0.0
963
+ *
964
+ * @param int $thread_id Thread ID.
965
+ * @return BP_Messages_Thread
966
+ */
967
+ public function get_thread_object( $thread_id ) {
968
+ return new BP_Messages_Thread( $thread_id );
969
+ }
970
+
971
+ /**
972
+ * Get the message object thanks to its ID.
973
+ *
974
+ * @since 5.0.0
975
+ *
976
+ * @param int $message_id Message ID.
977
+ * @return BP_Messages_Message
978
+ */
979
+ public function get_message_object( $message_id ) {
980
+ return new BP_Messages_Message( $message_id );
981
+ }
982
+
983
+ /**
984
+ * Select the item schema arguments needed for the CREATABLE, EDITABLE and DELETABLE methods.
985
+ *
986
+ * @since 5.0.0
987
+ *
988
+ * @param string $method Optional. HTTP method of the request.
989
+ * @return array Endpoint arguments.
990
+ */
991
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
992
+ $key = 'get_item';
993
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
994
+ $args['id']['description'] = __( 'ID of the Messages Thread.', 'buddypress' );
995
+
996
+ if ( WP_REST_Server::CREATABLE === $method ) {
997
+ $key = 'create_item';
998
+
999
+ // Edit the Thread ID description and default properties.
1000
+ $args['id']['description'] = __( 'ID of the Messages Thread. Required when replying to an existing Thread.', 'buddypress' );
1001
+ $args['id']['default'] = 0;
1002
+
1003
+ // Add the sender_id argument.
1004
+ $args['sender_id'] = array(
1005
+ 'description' => __( 'The user ID of the Message sender.', 'buddypress' ),
1006
+ 'required' => false,
1007
+ 'default' => bp_loggedin_user_id(),
1008
+ 'type' => 'integer',
1009
+ 'sanitize_callback' => 'absint',
1010
+ 'validate_callback' => 'rest_validate_request_arg',
1011
+ );
1012
+
1013
+ // Edit subject's properties.
1014
+ $args['subject']['type'] = 'string';
1015
+ $args['subject']['default'] = false;
1016
+ $args['subject']['description'] = __( 'Subject of the Message initializing the Thread.', 'buddypress' );
1017
+
1018
+ // Edit message's properties.
1019
+ $args['message']['type'] = 'string';
1020
+ $args['message']['description'] = __( 'Content of the Message to add to the Thread.', 'buddypress' );
1021
+
1022
+ // Edit recipients properties.
1023
+ $args['recipients']['items'] = array( 'type' => 'integer' );
1024
+ $args['recipients']['sanitize_callback'] = 'wp_parse_id_list';
1025
+ $args['recipients']['validate_callback'] = 'rest_validate_request_arg';
1026
+ $args['recipients']['description'] = __( 'The list of the recipients user IDs of the Message.', 'buddypress' );
1027
+
1028
+ // Remove unused properties for this transport method.
1029
+ unset( $args['subject']['properties'], $args['message']['properties'] );
1030
+
1031
+ } else {
1032
+ unset( $args['sender_id'], $args['subject'], $args['message'], $args['recipients'] );
1033
+
1034
+ if ( WP_REST_Server::EDITABLE === $method ) {
1035
+ $key = 'update_item';
1036
+
1037
+ $args['message_id'] = array(
1038
+ 'description' => __( 'By default the latest message of the thread will be updated. Specify this message ID to edit another message of the thread.', 'buddypress' ),
1039
+ 'required' => false,
1040
+ 'type' => 'integer',
1041
+ 'sanitize_callback' => 'absint',
1042
+ 'validate_callback' => 'rest_validate_request_arg',
1043
+ );
1044
+ }
1045
+
1046
+ if ( WP_REST_Server::DELETABLE === $method ) {
1047
+ $key = 'delete_item';
1048
+
1049
+ $args['user_id'] = array(
1050
+ 'description' => __( 'The user ID to remove from the thread', 'buddypress' ),
1051
+ 'required' => true,
1052
+ 'type' => 'integer',
1053
+ 'sanitize_callback' => 'absint',
1054
+ 'validate_callback' => 'rest_validate_request_arg',
1055
+ 'default' => bp_loggedin_user_id(),
1056
+ );
1057
+ }
1058
+ }
1059
+
1060
+ /**
1061
+ * Filters the method query arguments.
1062
+ *
1063
+ * @since 5.0.0
1064
+ *
1065
+ * @param array $args Query arguments.
1066
+ * @param string $method HTTP method of the request.
1067
+ */
1068
+ return apply_filters( "bp_rest_messages_{$key}_query_arguments", $args, $method );
1069
+ }
1070
+
1071
+ /**
1072
+ * Get the message schema, conforming to JSON Schema.
1073
+ *
1074
+ * @since 5.0.0
1075
+ *
1076
+ * @return array
1077
+ */
1078
+ public function get_item_schema() {
1079
+ $schema = array(
1080
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
1081
+ 'title' => 'bp_messages',
1082
+ 'type' => 'object',
1083
+ 'properties' => array(
1084
+ 'id' => array(
1085
+ 'context' => array( 'view', 'edit' ),
1086
+ 'description' => __( 'A unique numeric ID for the Thread.', 'buddypress' ),
1087
+ 'type' => 'integer',
1088
+ ),
1089
+ 'message_id' => array(
1090
+ 'context' => array( 'view', 'edit' ),
1091
+ 'description' => __( 'The ID of the latest message of the Thread.', 'buddypress' ),
1092
+ 'readonly' => true,
1093
+ 'type' => 'integer',
1094
+ ),
1095
+ 'last_sender_id' => array(
1096
+ 'context' => array( 'view', 'edit' ),
1097
+ 'description' => __( 'The ID of latest sender of the Thread.', 'buddypress' ),
1098
+ 'readonly' => true,
1099
+ 'type' => 'integer',
1100
+ ),
1101
+ 'subject' => array(
1102
+ 'context' => array( 'view', 'edit' ),
1103
+ 'description' => __( 'Title of the latest message of the Thread.', 'buddypress' ),
1104
+ 'type' => 'object',
1105
+ 'arg_options' => array(
1106
+ 'sanitize_callback' => null,
1107
+ 'validate_callback' => null,
1108
+ ),
1109
+ 'properties' => array(
1110
+ 'raw' => array(
1111
+ 'description' => __( 'Title of the latest message of the Thread, as it exists in the database.', 'buddypress' ),
1112
+ 'type' => 'string',
1113
+ 'context' => array( 'edit' ),
1114
+ 'default' => false,
1115
+ ),
1116
+ 'rendered' => array(
1117
+ 'description' => __( 'Title of the latest message of the Thread, transformed for display.', 'buddypress' ),
1118
+ 'type' => 'string',
1119
+ 'context' => array( 'view', 'edit' ),
1120
+ 'readonly' => true,
1121
+ 'default' => false,
1122
+ ),
1123
+ ),
1124
+ ),
1125
+ 'excerpt' => array(
1126
+ 'context' => array( 'view', 'edit' ),
1127
+ 'description' => __( 'Summary of the latest message of the Thread.', 'buddypress' ),
1128
+ 'type' => 'object',
1129
+ 'readonly' => true,
1130
+ 'arg_options' => array(
1131
+ 'sanitize_callback' => null,
1132
+ 'validate_callback' => null,
1133
+ ),
1134
+ 'properties' => array(
1135
+ 'raw' => array(
1136
+ 'description' => __( 'Summary for the latest message of the Thread, as it exists in the database.', 'buddypress' ),
1137
+ 'type' => 'string',
1138
+ 'context' => array( 'edit' ),
1139
+ ),
1140
+ 'rendered' => array(
1141
+ 'description' => __( 'HTML summary for the latest message of the Thread, transformed for display.', 'buddypress' ),
1142
+ 'type' => 'string',
1143
+ 'context' => array( 'view', 'edit' ),
1144
+ ),
1145
+ ),
1146
+ ),
1147
+ 'message' => array(
1148
+ 'context' => array( 'view', 'edit' ),
1149
+ 'description' => __( 'Content of the latest message of the Thread.', 'buddypress' ),
1150
+ 'type' => 'object',
1151
+ 'required' => true,
1152
+ 'arg_options' => array(
1153
+ 'sanitize_callback' => null,
1154
+ 'validate_callback' => null,
1155
+ ),
1156
+ 'properties' => array(
1157
+ 'raw' => array(
1158
+ 'description' => __( 'Content for the latest message of the Thread, as it exists in the database.', 'buddypress' ),
1159
+ 'type' => 'string',
1160
+ 'context' => array( 'edit' ),
1161
+ ),
1162
+ 'rendered' => array(
1163
+ 'description' => __( 'HTML content for the latest message of the Thread, transformed for display.', 'buddypress' ),
1164
+ 'type' => 'string',
1165
+ 'context' => array( 'view', 'edit' ),
1166
+ 'readonly' => true,
1167
+ ),
1168
+ ),
1169
+ ),
1170
+ 'date' => array(
1171
+ 'context' => array( 'view', 'edit' ),
1172
+ 'description' => __( "The date the latest message of the Thread, in the site's timezone.", 'buddypress' ),
1173
+ 'readonly' => true,
1174
+ 'type' => 'string',
1175
+ 'format' => 'date-time',
1176
+ ),
1177
+ 'unread_count' => array(
1178
+ 'context' => array( 'view', 'edit' ),
1179
+ 'description' => __( 'Total count of unread messages into the Thread for the requested user.', 'buddypress' ),
1180
+ 'readonly' => true,
1181
+ 'type' => 'integer',
1182
+ ),
1183
+ 'sender_ids' => array(
1184
+ 'context' => array( 'view', 'edit' ),
1185
+ 'description' => __( 'The list of user IDs for all messages in the Thread.', 'buddypress' ),
1186
+ 'readonly' => true,
1187
+ 'type' => 'array',
1188
+ 'items' => array(
1189
+ 'type' => 'integer',
1190
+ ),
1191
+ ),
1192
+ 'recipients' => array(
1193
+ 'context' => array( 'view', 'edit' ),
1194
+ 'description' => __( 'The list of recipient User Objects involved into the Thread.', 'buddypress' ),
1195
+ 'type' => 'array',
1196
+ 'items' => array(
1197
+ 'type' => 'object',
1198
+ ),
1199
+ ),
1200
+ 'messages' => array(
1201
+ 'context' => array( 'view', 'edit' ),
1202
+ 'description' => __( 'List of message objects for the thread.', 'buddypress' ),
1203
+ 'readonly' => true,
1204
+ 'type' => 'array',
1205
+ 'items' => array(
1206
+ 'type' => 'object',
1207
+ ),
1208
+ ),
1209
+ 'starred_message_ids' => array(
1210
+ 'context' => array( 'view', 'edit' ),
1211
+ 'description' => __( 'List of starred message ids.', 'buddypress' ),
1212
+ 'readonly' => true,
1213
+ 'type' => 'array',
1214
+ 'items' => array(
1215
+ 'type' => 'integer',
1216
+ ),
1217
+ 'default' => array(),
1218
+ ),
1219
+ ),
1220
+ );
1221
+
1222
+ /**
1223
+ * Filters the message schema.
1224
+ *
1225
+ * @since 5.0.0
1226
+ *
1227
+ * @param array $schema The endpoint schema.
1228
+ */
1229
+ return apply_filters( 'bp_rest_message_schema', $this->add_additional_fields_schema( $schema ) );
1230
+ }
1231
+
1232
+ /**
1233
+ * Get the query params for Messages collections.
1234
+ *
1235
+ * @since 5.0.0
1236
+ *
1237
+ * @return array
1238
+ */
1239
+ public function get_collection_params() {
1240
+ $params = parent::get_collection_params();
1241
+ $params['context']['default'] = 'view';
1242
+ $boxes = array( 'sentbox', 'inbox' );
1243
+
1244
+ if ( bp_is_active( 'messages', 'star' ) ) {
1245
+ $boxes[] = 'starred';
1246
+ }
1247
+
1248
+ $params['box'] = array(
1249
+ 'description' => __( 'Filter the result by box.', 'buddypress' ),
1250
+ 'default' => 'inbox',
1251
+ 'type' => 'string',
1252
+ 'enum' => $boxes,
1253
+ 'sanitize_callback' => 'sanitize_key',
1254
+ 'validate_callback' => 'rest_validate_request_arg',
1255
+ );
1256
+
1257
+ $params['type'] = array(
1258
+ 'description' => __( 'Filter the result by thread status.', 'buddypress' ),
1259
+ 'default' => 'all',
1260
+ 'type' => 'string',
1261
+ 'enum' => array( 'all', 'read', 'unread' ),
1262
+ 'sanitize_callback' => 'sanitize_key',
1263
+ 'validate_callback' => 'rest_validate_request_arg',
1264
+ );
1265
+
1266
+ $params['user_id'] = array(
1267
+ 'description' => __( 'Limit result to messages created by a specific user.', 'buddypress' ),
1268
+ 'default' => bp_loggedin_user_id(),
1269
+ 'type' => 'integer',
1270
+ 'required' => true,
1271
+ 'sanitize_callback' => 'absint',
1272
+ 'validate_callback' => 'rest_validate_request_arg',
1273
+ );
1274
+
1275
+ /**
1276
+ * Filters the collection query params.
1277
+ *
1278
+ * @param array $params Query params.
1279
+ */
1280
+ return apply_filters( 'bp_rest_messages_collection_params', $params );
1281
+ }
1282
+ }
bp-notifications/bp-notifications-filters.php CHANGED
@@ -14,14 +14,16 @@ add_filter( 'wp_privacy_personal_data_exporters', 'bp_register_notifications_per
14
  * Register Notifications personal data exporter.
15
  *
16
  * @since 4.0.0
 
17
  *
18
  * @param array $exporters An array of personal data exporters.
19
  * @return array An array of personal data exporters.
20
  */
21
  function bp_register_notifications_personal_data_exporter( $exporters ) {
22
  $exporters['buddypress-notifications'] = array(
23
- 'exporter_friendly_name' => __( 'BuddyPress Notifications Data', 'buddypress' ),
24
- 'callback' => 'bp_notifications_personal_data_exporter',
 
25
  );
26
 
27
  return $exporters;
14
  * Register Notifications personal data exporter.
15
  *
16
  * @since 4.0.0
17
+ * @since 5.0.0 adds an `exporter_bp_friendly_name` param to exporters.
18
  *
19
  * @param array $exporters An array of personal data exporters.
20
  * @return array An array of personal data exporters.
21
  */
22
  function bp_register_notifications_personal_data_exporter( $exporters ) {
23
  $exporters['buddypress-notifications'] = array(
24
+ 'exporter_friendly_name' => __( 'BuddyPress Notifications Data', 'buddypress' ),
25
+ 'callback' => 'bp_notifications_personal_data_exporter',
26
+ 'exporter_bp_friendly_name' => _x( 'Notifications Data', 'BuddyPress Notifications data exporter friendly name', 'buddypress' ),
27
  );
28
 
29
  return $exporters;
bp-notifications/classes/class-bp-notifications-component.php CHANGED
@@ -315,4 +315,16 @@ class BP_Notifications_Component extends BP_Component {
315
 
316
  parent::setup_cache_groups();
317
  }
 
 
 
 
 
 
 
 
 
 
 
 
318
  }
315
 
316
  parent::setup_cache_groups();
317
  }
318
+
319
+ /**
320
+ * Init the BP REST API.
321
+ *
322
+ * @since 5.0.0
323
+ */
324
+ public function rest_api_init() {
325
+ $controller = new BP_REST_Notifications_Endpoint();
326
+ $controller->register_routes();
327
+
328
+ parent::rest_api_init();
329
+ }
330
  }
bp-notifications/classes/class-bp-rest-notifications-endpoint.php ADDED
@@ -0,0 +1,897 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP REST: BP_REST_Notifications_Endpoint class
4
+ *
5
+ * @package BuddyPress
6
+ * @since 5.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) || exit;
10
+
11
+ /**
12
+ * Notifications endpoints.
13
+ *
14
+ * @since 5.0.0
15
+ */
16
+ class BP_REST_Notifications_Endpoint extends WP_REST_Controller {
17
+
18
+ /**
19
+ * Constructor.
20
+ *
21
+ * @since 5.0.0
22
+ */
23
+ public function __construct() {
24
+ $this->namespace = bp_rest_namespace() . '/' . bp_rest_version();
25
+ $this->rest_base = buddypress()->notifications->id;
26
+ }
27
+
28
+ /**
29
+ * Register the component routes.
30
+ *
31
+ * @since 5.0.0
32
+ */
33
+ public function register_routes() {
34
+ register_rest_route(
35
+ $this->namespace,
36
+ '/' . $this->rest_base,
37
+ array(
38
+ array(
39
+ 'methods' => WP_REST_Server::READABLE,
40
+ 'callback' => array( $this, 'get_items' ),
41
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
42
+ 'args' => $this->get_collection_params(),
43
+ ),
44
+ array(
45
+ 'methods' => WP_REST_Server::CREATABLE,
46
+ 'callback' => array( $this, 'create_item' ),
47
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
48
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
49
+ ),
50
+ 'schema' => array( $this, 'get_item_schema' ),
51
+ )
52
+ );
53
+
54
+ register_rest_route(
55
+ $this->namespace,
56
+ '/' . $this->rest_base . '/(?P<id>[\d]+)',
57
+ array(
58
+ 'args' => array(
59
+ 'id' => array(
60
+ 'description' => __( 'The unique numeric ID for the notification.', 'buddypress' ),
61
+ 'type' => 'integer',
62
+ ),
63
+ ),
64
+ array(
65
+ 'methods' => WP_REST_Server::READABLE,
66
+ 'callback' => array( $this, 'get_item' ),
67
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
68
+ 'args' => array(
69
+ 'context' => $this->get_context_param(
70
+ array(
71
+ 'default' => 'view',
72
+ )
73
+ ),
74
+ ),
75
+ ),
76
+ array(
77
+ 'methods' => WP_REST_Server::EDITABLE,
78
+ 'callback' => array( $this, 'update_item' ),
79
+ 'permission_callback' => array( $this, 'update_item_permissions_check' ),
80
+ 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
81
+ ),
82
+ array(
83
+ 'methods' => WP_REST_Server::DELETABLE,
84
+ 'callback' => array( $this, 'delete_item' ),
85
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
86
+ ),
87
+ 'schema' => array( $this, 'get_item_schema' ),
88
+ )
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Retrieve notifications.
94
+ *
95
+ * @since 5.0.0
96
+ *
97
+ * @param WP_REST_Request $request Full details about the request.
98
+ * @return WP_REST_Response
99
+ */
100
+ public function get_items( $request ) {
101
+ $args = array(
102
+ 'user_id' => $request['user_id'],
103
+ 'item_id' => $request['item_id'],
104
+ 'secondary_item_id' => $request['secondary_item_id'],
105
+ 'component_name' => $request['component_name'],
106
+ 'component_action' => $request['component_action'],
107
+ 'order_by' => $request['order_by'],
108
+ 'sort_order' => strtoupper( $request['sort_order'] ),
109
+ 'is_new' => $request['is_new'],
110
+ 'page' => $request['page'],
111
+ 'per_page' => $request['per_page'],
112
+ );
113
+
114
+ if ( empty( $request['component_action'] ) ) {
115
+ $args['component_action'] = false;
116
+ }
117
+
118
+ if ( empty( $request['component_name'] ) ) {
119
+ $args['component_name'] = false;
120
+ }
121
+
122
+ /**
123
+ * Filter the query arguments for the request.
124
+ *
125
+ * @since 5.0.0
126
+ *
127
+ * @param array $args Key value array of query var to query value.
128
+ * @param WP_REST_Request $request The request sent to the API.
129
+ */
130
+ $args = apply_filters( 'bp_rest_notifications_get_items_query_args', $args, $request );
131
+
132
+ // Actually, query it.
133
+ $notifications = BP_Notifications_Notification::get( $args );
134
+
135
+ $retval = array();
136
+ foreach ( $notifications as $notification ) {
137
+ $retval[] = $this->prepare_response_for_collection(
138
+ $this->prepare_item_for_response( $notification, $request )
139
+ );
140
+ }
141
+
142
+ $response = rest_ensure_response( $retval );
143
+
144
+ /**
145
+ * Fires after notifications are fetched via the REST API.
146
+ *
147
+ * @since 5.0.0
148
+ *
149
+ * @param array $notifications Fetched notifications.
150
+ * @param WP_REST_Response $response The response data.
151
+ * @param WP_REST_Request $request The request sent to the API.
152
+ */
153
+ do_action( 'bp_rest_notifications_get_items', $notifications, $response, $request );
154
+
155
+ return $response;
156
+ }
157
+
158
+ /**
159
+ * Check if a given request has access to notification items.
160
+ *
161
+ * @since 5.0.0
162
+ *
163
+ * @param WP_REST_Request $request Full data about the request.
164
+ * @return WP_Error|bool
165
+ */
166
+ public function get_items_permissions_check( $request ) {
167
+ $retval = true;
168
+
169
+ if ( ! is_user_logged_in() || ( bp_loggedin_user_id() !== $request['user_id'] && ! $this->can_see() ) ) {
170
+ $retval = new WP_Error(
171
+ 'bp_rest_authorization_required',
172
+ __( 'Sorry, you are not allowed to see the notifications.', 'buddypress' ),
173
+ array(
174
+ 'status' => rest_authorization_required_code(),
175
+ )
176
+ );
177
+ }
178
+
179
+ /**
180
+ * Filter the notifications `get_items` permissions check.
181
+ *
182
+ * @since 5.0.0
183
+ *
184
+ * @param bool|WP_Error $retval Returned value.
185
+ * @param WP_REST_Request $request The request sent to the API.
186
+ */
187
+ return apply_filters( 'bp_rest_notifications_get_items_permissions_check', $retval, $request );
188
+ }
189
+
190
+ /**
191
+ * Retrieve a notification.
192
+ *
193
+ * @since 5.0.0
194
+ *
195
+ * @param WP_REST_Request $request Full details about the request.
196
+ * @return WP_REST_Response
197
+ */
198
+ public function get_item( $request ) {
199
+ $notification = $this->get_notification_object( $request );
200
+
201
+ $retval = array(
202
+ $this->prepare_response_for_collection(
203
+ $this->prepare_item_for_response( $notification, $request )
204
+ ),
205
+ );
206
+
207
+ $response = rest_ensure_response( $retval );
208
+
209
+ /**
210
+ * Fires after a notification is fetched via the REST API.
211
+ *
212
+ * @since 5.0.0
213
+ *
214
+ * @param BP_Notifications_Notification $notification Fetched notification.
215
+ * @param WP_REST_Response $response The response data.
216
+ * @param WP_REST_Request $request The request sent to the API.
217
+ */
218
+ do_action( 'bp_rest_notifications_get_item', $notification, $response, $request );
219
+
220
+ return $response;
221
+ }
222
+
223
+ /**
224
+ * Check if a given request has access to get information about a specific notification.
225
+ *
226
+ * @since 5.0.0
227
+ *
228
+ * @param WP_REST_Request $request Full data about the request.
229
+ * @return WP_Error|bool
230
+ */
231
+ public function get_item_permissions_check( $request ) {
232
+ $retval = true;
233
+
234
+ if ( ! is_user_logged_in() ) {
235
+ $retval = new WP_Error(
236
+ 'bp_rest_authorization_required',
237
+ __( 'Sorry, you are not allowed to see the notification.', 'buddypress' ),
238
+ array(
239
+ 'status' => rest_authorization_required_code(),
240
+ )
241
+ );
242
+ }
243
+
244
+ $notification = $this->get_notification_object( $request );
245
+
246
+ if ( true === $retval && is_null( $notification->item_id ) ) {
247
+ $retval = new WP_Error(
248
+ 'bp_rest_notification_invalid_id',
249
+ __( 'Invalid notification id.', 'buddypress' ),
250
+ array(
251
+ 'status' => 404,
252
+ )
253
+ );
254
+ }
255
+
256
+ if ( true === $retval && ! $this->can_see( $notification->id ) ) {
257
+ $retval = new WP_Error(
258
+ 'bp_rest_authorization_required',
259
+ __( 'Sorry, you cannot view this notification.', 'buddypress' ),
260
+ array(
261
+ 'status' => rest_authorization_required_code(),
262
+ )
263
+ );
264
+ }
265
+
266
+ /**
267
+ * Filter the notifications `get_item` permissions check.
268
+ *
269
+ * @since 5.0.0
270
+ *
271
+ * @param bool|WP_Error $retval Returned value.
272
+ * @param WP_REST_Request $request The request sent to the API.
273
+ */
274
+ return apply_filters( 'bp_rest_notifications_get_item_permissions_check', $retval, $request );
275
+ }
276
+
277
+ /**
278
+ * Create a notification.
279
+ *
280
+ * @since 5.0.0
281
+ *
282
+ * @param WP_REST_Request $request Full data about the request.
283
+ * @return WP_REST_Response|WP_Error
284
+ */
285
+ public function create_item( $request ) {
286
+ // Setting context.
287
+ $request->set_param( 'context', 'edit' );
288
+
289
+ $notification_id = bp_notifications_add_notification( $this->prepare_item_for_database( $request ) );
290
+
291
+ if ( ! is_numeric( $notification_id ) ) {
292
+ return new WP_Error(
293
+ 'bp_rest_user_cannot_create_notification',
294
+ __( 'Cannot create new notification.', 'buddypress' ),
295
+ array(
296
+ 'status' => 500,
297
+ )
298
+ );
299
+ }
300
+
301
+ $notification = $this->get_notification_object( $notification_id );
302
+ $fields_update = $this->update_additional_fields_for_object( $notification, $request );
303
+
304
+ if ( is_wp_error( $fields_update ) ) {
305
+ return $fields_update;
306
+ }
307
+
308
+ $retval = array(
309
+ $this->prepare_response_for_collection(
310
+ $this->prepare_item_for_response( $notification, $request )
311
+ ),
312
+ );
313
+
314
+ $response = rest_ensure_response( $retval );
315
+
316
+ /**
317
+ * Fires after a notification is created via the REST API.
318
+ *
319
+ * @since 5.0.0
320
+ *
321
+ * @param BP_Notifications_Notification $notification The created notification.
322
+ * @param WP_REST_Response $response The response data.
323
+ * @param WP_REST_Request $request The request sent to the API.
324
+ */
325
+ do_action( 'bp_rest_notifications_create_item', $notification, $response, $request );
326
+
327
+ return $response;
328
+ }
329
+
330
+ /**
331
+ * Checks if a given request has access to create a notification.
332
+ *
333
+ * @since 5.0.0
334
+ *
335
+ * @param WP_REST_Request $request Full details about the request.
336
+ * @return WP_Error|bool
337
+ */
338
+ public function create_item_permissions_check( $request ) {
339
+ $retval = $this->get_items_permissions_check( $request );
340
+
341
+ /**
342
+ * Filter the notifications `create_item` permissions check.
343
+ *
344
+ * @since 5.0.0
345
+ *
346
+ * @param bool|WP_Error $retval Returned value.
347
+ * @param WP_REST_Request $request The request sent to the API.
348
+ */
349
+ return apply_filters( 'bp_rest_notifications_create_item_permissions_check', $retval, $request );
350
+ }
351
+
352
+ /**
353
+ * Update a notification.
354
+ *
355
+ * @since 5.0.0
356
+ *
357
+ * @param WP_REST_Request $request Full details about the request.
358
+ * @return WP_REST_Response|WP_Error
359
+ */
360
+ public function update_item( $request ) {
361
+ // Setting context.
362
+ $request->set_param( 'context', 'edit' );
363
+
364
+ $notification = $this->get_notification_object( $request );
365
+
366
+ if ( $request['is_new'] === $notification->is_new ) {
367
+ return new WP_Error(
368
+ 'bp_rest_user_cannot_update_notification_status',
369
+ __( 'Notification is already with the status you are trying to update into.', 'buddypress' ),
370
+ array(
371
+ 'status' => 500,
372
+ )
373
+ );
374
+ }
375
+
376
+ $updated = BP_Notifications_Notification::update(
377
+ array( 'is_new' => $request['is_new'] ),
378
+ array( 'id' => $notification->id )
379
+ );
380
+
381
+ if ( ! (bool) $updated ) {
382
+ return new WP_Error(
383
+ 'bp_rest_user_cannot_update_notification',
384
+ __( 'Cannot update the status of this notification.', 'buddypress' ),
385
+ array(
386
+ 'status' => 500,
387
+ )
388
+ );
389
+ }
390
+
391
+ // Make sure to update the status of the notification.
392
+ $notification = $this->prepare_item_for_database( $request );
393
+
394
+ // Update additional fields.
395
+ $fields_update = $this->update_additional_fields_for_object( $notification, $request );
396
+
397
+ if ( is_wp_error( $fields_update ) ) {
398
+ return $fields_update;
399
+ }
400
+
401
+ $retval = array(
402
+ $this->prepare_response_for_collection(
403
+ $this->prepare_item_for_response( $notification, $request )
404
+ ),
405
+ );
406
+
407
+ $response = rest_ensure_response( $retval );
408
+
409
+ /**
410
+ * Fires after a notification is updated via the REST API.
411
+ *
412
+ * @since 5.0.0
413
+ *
414
+ * @param BP_Notifications_Notification $notification The updated notification.
415
+ * @param WP_REST_Response $response The response data.
416
+ * @param WP_REST_Request $request The request sent to the API.
417
+ */
418
+ do_action( 'bp_rest_notifications_update_item', $notification, $response, $request );
419
+
420
+ return $response;
421
+ }
422
+
423
+ /**
424
+ * Check if a given request has access to update a notification.
425
+ *
426
+ * @since 5.0.0
427
+ *
428
+ * @param WP_REST_Request $request Full details about the request.
429
+ * @return WP_Error|bool
430
+ */
431
+ public function update_item_permissions_check( $request ) {
432
+ $retval = $this->get_item_permissions_check( $request );
433
+
434
+ /**
435
+ * Filter the notifications `update_item` permissions check.
436
+ *
437
+ * @since 5.0.0
438
+ *
439
+ * @param bool|WP_Error $retval Returned value.
440
+ * @param WP_REST_Request $request The request sent to the API.
441
+ */
442
+ return apply_filters( 'bp_rest_notifications_update_item_permissions_check', $retval, $request );
443
+ }
444
+
445
+ /**
446
+ * Delete a notification.
447
+ *
448
+ * @since 5.0.0
449
+ *
450
+ * @param WP_REST_Request $request Full details about the request.
451
+ * @return WP_REST_Response|WP_Error
452
+ */
453
+ public function delete_item( $request ) {
454
+ // Setting context.
455
+ $request->set_param( 'context', 'edit' );
456
+
457
+ // Get the notification before it's deleted.
458
+ $notification = $this->get_notification_object( $request );
459
+ $previous = $this->prepare_item_for_response( $notification, $request );
460
+
461
+ if ( ! BP_Notifications_Notification::delete( array( 'id' => $notification->id ) ) ) {
462
+ return new WP_Error(
463
+ 'bp_rest_notification_invalid_id',
464
+ __( 'Invalid notification id.', 'buddypress' ),
465
+ array(
466
+ 'status' => 500,
467
+ )
468
+ );
469
+ }
470
+
471
+ // Build the response.
472
+ $response = new WP_REST_Response();
473
+ $response->set_data(
474
+ array(
475
+ 'deleted' => true,
476
+ 'previous' => $previous->get_data(),
477
+ )
478
+ );
479
+
480
+ /**
481
+ * Fires after a notification is deleted via the REST API.
482
+ *
483
+ * @since 5.0.0
484
+ *
485
+ * @param BP_Notifications_Notification $notification The deleted notification.
486
+ * @param WP_REST_Response $response The response data.
487
+ * @param WP_REST_Request $request The request sent to the API.
488
+ */
489
+ do_action( 'bp_rest_notifications_delete_item', $notification, $response, $request );
490
+
491
+ return $response;
492
+ }
493
+
494
+ /**
495
+ * Check if a given request has access to delete a notification.
496
+ *
497
+ * @since 5.0.0
498
+ *
499
+ * @param WP_REST_Request $request Full details about the request.
500
+ * @return bool|WP_Error
501
+ */
502
+ public function delete_item_permissions_check( $request ) {
503
+ $retval = $this->get_item_permissions_check( $request );
504
+
505
+ /**
506
+ * Filter the notifications `delete_item` permissions check.
507
+ *
508
+ * @since 5.0.0
509
+ *
510
+ * @param bool|WP_Error $retval Returned value.
511
+ * @param WP_REST_Request $request The request sent to the API.
512
+ */
513
+ return apply_filters( 'bp_rest_notifications_delete_item_permissions_check', $retval, $request );
514
+ }
515
+
516
+ /**
517
+ * Prepares notification data for return as an object.
518
+ *
519
+ * @since 5.0.0
520
+ *
521
+ * @param BP_Notifications_Notification $notification Notification data.
522
+ * @param WP_REST_Request $request Full details about the request.
523
+ * @return WP_REST_Response
524
+ */
525
+ public function prepare_item_for_response( $notification, $request ) {
526
+ $data = array(
527
+ 'id' => $notification->id,
528
+ 'user_id' => $notification->user_id,
529
+ 'item_id' => $notification->item_id,
530
+ 'secondary_item_id' => $notification->secondary_item_id,
531
+ 'component' => $notification->component_name,
532
+ 'action' => $notification->component_action,
533
+ 'date' => bp_rest_prepare_date_response( $notification->date_notified ),
534
+ 'is_new' => $notification->is_new,
535
+ );
536
+
537
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
538
+ $data = $this->add_additional_fields_to_object( $data, $request );
539
+ $data = $this->filter_response_by_context( $data, $context );
540
+
541
+ // @todo add prepare_links
542
+ $response = rest_ensure_response( $data );
543
+
544
+ /**
545
+ * Filter a notification value returned from the API.
546
+ *
547
+ * @since 5.0.0
548
+ *
549
+ * @param WP_REST_Response $response The response data.
550
+ * @param WP_REST_Request $request Request used to generate the response.
551
+ * @param BP_Notifications_Notification $notification Notification object.
552
+ */
553
+ return apply_filters( 'bp_rest_notifications_prepare_value', $response, $request, $notification );
554
+ }
555
+
556
+ /**
557
+ * Prepare a notification for create or update.
558
+ *
559
+ * @since 5.0.0
560
+ *
561
+ * @param WP_REST_Request $request Request object.
562
+ * @return stdClass
563
+ */
564
+ protected function prepare_item_for_database( $request ) {
565
+ $prepared_notification = new stdClass();
566
+ $schema = $this->get_item_schema();
567
+ $notification = $this->get_notification_object( $request );
568
+
569
+ if ( ! empty( $schema['properties']['id'] ) && ! empty( $notification->id ) ) {
570
+ $prepared_notification->id = $notification->id;
571
+ }
572
+
573
+ if ( ! empty( $schema['properties']['user_id'] ) && isset( $request['user_id'] ) ) {
574
+ $prepared_notification->user_id = (int) $request['user_id'];
575
+ } elseif ( isset( $notification->user_id ) ) {
576
+ $prepared_notification->user_id = $notification->user_id;
577
+ } else {
578
+ $prepared_notification->user_id = bp_loggedin_user_id();
579
+ }
580
+
581
+ if ( ! empty( $schema['properties']['item_id'] ) && isset( $request['item_id'] ) ) {
582
+ $prepared_notification->item_id = $request['item_id'];
583
+ } elseif ( isset( $notification->item_id ) ) {
584
+ $prepared_notification->item_id = $notification->item_id;
585
+ }
586
+
587
+ if ( ! empty( $schema['properties']['secondary_item_id'] ) && isset( $request['secondary_item_id'] ) ) {
588
+ $prepared_notification->secondary_item_id = $request['secondary_item_id'];
589
+ } elseif ( isset( $notification->secondary_item_id ) ) {
590
+ $prepared_notification->secondary_item_id = $notification->secondary_item_id;
591
+ }
592
+
593
+ if ( ! empty( $schema['properties']['component'] ) && isset( $request['component'] ) ) {
594
+ $prepared_notification->component_name = $request['component'];
595
+ } elseif ( isset( $notification->component_name ) ) {
596
+ $prepared_notification->component_name = $notification->component_name;
597
+ }
598
+
599
+ if ( ! empty( $schema['properties']['action'] ) && isset( $request['action'] ) ) {
600
+ $prepared_notification->component_action = $request['action'];
601
+ } elseif ( isset( $notification->component_action ) ) {
602
+ $prepared_notification->component_action = $notification->component_action;
603
+ }
604
+
605
+ if ( ! empty( $schema['properties']['is_new'] ) && isset( $request['is_new'] ) ) {
606
+ $prepared_notification->is_new = $request['is_new'];
607
+ } elseif ( isset( $notification->is_new ) ) {
608
+ $prepared_notification->is_new = $notification->is_new;
609
+ }
610
+
611
+ if ( ! empty( $schema['properties']['date'] ) && isset( $request['date'] ) ) {
612
+ $prepared_notification->date_notified = $request['date'];
613
+ } elseif ( isset( $notification->date_notified ) ) {
614
+ $prepared_notification->date_notified = $notification->date_notified;
615
+ }
616
+
617
+ /**
618
+ * Filters a notification before it is inserted or updated via the REST API.
619
+ *
620
+ * @since 5.0.0
621
+ *
622
+ * @param stdClass $prepared_notification An object prepared for inserting or updating the database.
623
+ * @param WP_REST_Request $request Request object.
624
+ */
625
+ return apply_filters( 'bp_rest_notifications_pre_insert_value', $prepared_notification, $request );
626
+ }
627
+
628
+ /**
629
+ * Prepare links for the request.
630
+ *
631
+ * @since 5.0.0
632
+ *
633
+ * @param BP_Notifications_Notification $notification Notification item.
634
+ * @return array Links for the given plugin.
635
+ */
636
+ protected function prepare_links( $notification ) {
637
+ $base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );
638
+
639
+ // Entity meta.
640
+ $links = array(
641
+ 'self' => array(
642
+ 'href' => rest_url( $base . $notification->id ),
643
+ ),
644
+ 'collection' => array(
645
+ 'href' => rest_url( $base ),
646
+ ),
647
+ 'user' => array(
648
+ 'href' => rest_url( bp_rest_get_user_url( $notification->user_id ) ),
649
+ 'embeddable' => true,
650
+ ),
651
+ );
652
+
653
+ /**
654
+ * Filter links prepared for the REST response.
655
+ *
656
+ * @since 5.0.0
657
+ *
658
+ * @param array $links The prepared links of the REST response.
659
+ * @param BP_Notifications_Notification $notification Notification object.
660
+ */
661
+ return apply_filters( 'bp_rest_notifications_prepare_links', $links, $notification );
662
+ }
663
+
664
+ /**
665
+ * Can this user see the notification?
666
+ *
667
+ * @since 5.0.0
668
+ *
669
+ * @param int $notification_id Notification ID.
670
+ * @return bool
671
+ */
672
+ protected function can_see( $notification_id = 0 ) {
673
+
674
+ // Check notification access.
675
+ if ( ! empty( $notification_id ) && (bool) BP_Notifications_Notification::check_access( bp_loggedin_user_id(), $notification_id ) ) {
676
+ return true;
677
+ }
678
+
679
+ // Moderators as well.
680
+ if ( bp_current_user_can( 'bp_moderate' ) ) {
681
+ return true;
682
+ }
683
+
684
+ return false;
685
+ }
686
+
687
+ /**
688
+ * Get notification object.
689
+ *
690
+ * @since 5.0.0
691
+ *
692
+ * @param WP_REST_Request $request Full details about the request.
693
+ * @return BP_Notifications_Notification|string A notification object.
694
+ */
695
+ public function get_notification_object( $request ) {
696
+ $notification_id = is_numeric( $request ) ? $request : (int) $request['id'];
697
+
698
+ $notification = bp_notifications_get_notification( $notification_id );
699
+
700
+ if ( empty( $notification->id ) ) {
701
+ return '';
702
+ }
703
+
704
+ return $notification;
705
+ }
706
+
707
+ /**
708
+ * Select the item schema arguments needed for the EDITABLE method.
709
+ *
710
+ * @since 5.0.0
711
+ *
712
+ * @param string $method Optional. HTTP method of the request.
713
+ * @return array Endpoint arguments.
714
+ */
715
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
716
+ $args = WP_REST_Controller::get_endpoint_args_for_item_schema( $method );
717
+ $key = 'get_item';
718
+
719
+ if ( WP_REST_Server::EDITABLE === $method ) {
720
+ $key = 'update_item';
721
+
722
+ // Only switching the is_new property can be achieved.
723
+ $args = array_intersect_key( $args, array( 'is_new' => true ) );
724
+ $args['is_new']['default'] = 0;
725
+ } elseif ( WP_REST_Server::CREATABLE === $method ) {
726
+ $key = 'create_item';
727
+ } elseif ( WP_REST_Server::DELETABLE === $method ) {
728
+ $key = 'delete_item';
729
+ }
730
+
731
+ /**
732
+ * Filters the method query arguments.
733
+ *
734
+ * @since 5.0.0
735
+ *
736
+ * @param array $args Query arguments.
737
+ * @param string $method HTTP method of the request.
738
+ */
739
+ return apply_filters( "bp_rest_notifications_{$key}_query_arguments", $args, $method );
740
+ }
741
+
742
+ /**
743
+ * Get the notification schema, conforming to JSON Schema.
744
+ *
745
+ * @since 5.0.0
746
+ *
747
+ * @return array
748
+ */
749
+ public function get_item_schema() {
750
+ $schema = array(
751
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
752
+ 'title' => 'bp_notifications',
753
+ 'type' => 'object',
754
+ 'properties' => array(
755
+ 'id' => array(
756
+ 'context' => array( 'view', 'edit' ),
757
+ 'description' => __( 'A unique numeric ID for the notification.', 'buddypress' ),
758
+ 'readonly' => true,
759
+ 'type' => 'integer',
760
+ ),
761
+ 'user_id' => array(
762
+ 'context' => array( 'view', 'edit' ),
763
+ 'description' => __( 'The ID of the user the notification is addressed to.', 'buddypress' ),
764
+ 'type' => 'integer',
765
+ 'default' => bp_loggedin_user_id(),
766
+ ),
767
+ 'item_id' => array(
768
+ 'context' => array( 'view', 'edit' ),
769
+ 'description' => __( 'The ID of the item associated with the notification.', 'buddypress' ),
770
+ 'type' => 'integer',
771
+ ),
772
+ 'secondary_item_id' => array(
773
+ 'context' => array( 'view', 'edit' ),
774
+ 'description' => __( 'The ID of the secondary item associated with the notification.', 'buddypress' ),
775
+ 'type' => 'integer',
776
+ ),
777
+ 'component' => array(
778
+ 'context' => array( 'view', 'edit' ),
779
+ 'description' => __( 'The name of the BuddyPress component the notification relates to.', 'buddypress' ),
780
+ 'type' => 'string',
781
+ ),
782
+ 'action' => array(
783
+ 'context' => array( 'view', 'edit' ),
784
+ 'description' => __( 'The name of the component\'s action the notification is about.', 'buddypress' ),
785
+ 'type' => 'string',
786
+ ),
787
+ 'date' => array(
788
+ 'description' => __( 'The date the notification was created, in the site\'s timezone.', 'buddypress' ),
789
+ 'type' => 'string',
790
+ 'format' => 'date-time',
791
+ 'context' => array( 'view', 'edit' ),
792
+ ),
793
+ 'is_new' => array(
794
+ 'context' => array( 'view', 'edit' ),
795
+ 'description' => __( 'Whether it\'s a new notification or not.', 'buddypress' ),
796
+ 'type' => 'integer',
797
+ 'default' => 1,
798
+ ),
799
+ ),
800
+ );
801
+
802
+ /**
803
+ * Filters the notifications schema.
804
+ *
805
+ * @param array $schema The endpoint schema.
806
+ */
807
+ return apply_filters( 'bp_rest_notification_schema', $this->add_additional_fields_schema( $schema ) );
808
+ }
809
+
810
+ /**
811
+ * Get the query params for the notifications collections.
812
+ *
813
+ * @since 5.0.0
814
+ *
815
+ * @return array
816
+ */
817
+ public function get_collection_params() {
818
+ $params = parent::get_collection_params();
819
+ $params['context']['default'] = 'view';
820
+
821
+ // Remove the search argument.
822
+ unset( $params['search'] );
823
+
824
+ $params['order_by'] = array(
825
+ 'description' => __( 'Name of the field to order according to.', 'buddypress' ),
826
+ 'default' => 'id',
827
+ 'type' => 'string',
828
+ 'enum' => array( 'id', 'date_notified', 'item_id', 'secondary_item_id', 'component_name', 'component_action' ),
829
+ 'sanitize_callback' => 'sanitize_key',
830
+ 'validate_callback' => 'rest_validate_request_arg',
831
+ );
832
+
833
+ $params['sort_order'] = array(
834
+ 'description' => __( 'Order sort attribute ascending or descending.', 'buddypress' ),
835
+ 'default' => 'ASC',
836
+ 'type' => 'string',
837
+ 'enum' => array( 'ASC', 'DESC' ),
838
+ 'sanitize_callback' => 'sanitize_key',
839
+ 'validate_callback' => 'rest_validate_request_arg',
840
+ );
841
+
842
+ $params['component_name'] = array(
843
+ 'description' => __( 'Limit result set to notifications associated with a specific component', 'buddypress' ),
844
+ 'default' => '',
845
+ 'type' => 'string',
846
+ 'sanitize_callback' => 'sanitize_text_field',
847
+ 'validate_callback' => 'rest_validate_request_arg',
848
+ );
849
+
850
+ $params['component_action'] = array(
851
+ 'description' => __( 'Limit result set to notifications associated with a specific component\'s action name.', 'buddypress' ),
852
+ 'default' => '',
853
+ 'type' => 'string',
854
+ 'sanitize_callback' => 'sanitize_text_field',
855
+ 'validate_callback' => 'rest_validate_request_arg',
856
+ );
857
+
858
+ $params['user_id'] = array(
859
+ 'description' => __( 'Limit result set to notifications addressed to a specific user.', 'buddypress' ),
860
+ 'default' => bp_loggedin_user_id(),
861
+ 'type' => 'integer',
862
+ 'sanitize_callback' => 'absint',
863
+ 'validate_callback' => 'rest_validate_request_arg',
864
+ );
865
+
866
+ $params['item_id'] = array(
867
+ 'description' => __( 'Limit result set to notifications associated with a specific item ID.', 'buddypress' ),
868
+ 'default' => 0,
869
+ 'type' => 'integer',
870
+ 'sanitize_callback' => 'absint',
871
+ 'validate_callback' => 'rest_validate_request_arg',
872
+ );
873
+
874
+ $params['secondary_item_id'] = array(
875
+ 'description' => __( 'Limit result set to notifications associated with a specific secondary item ID.', 'buddypress' ),
876
+ 'default' => 0,
877
+ 'type' => 'integer',
878
+ 'sanitize_callback' => 'absint',
879
+ 'validate_callback' => 'rest_validate_request_arg',
880
+ );
881
+
882
+ $params['is_new'] = array(
883
+ 'description' => __( 'Limit result set to items from specific states.', 'buddypress' ),
884
+ 'default' => true,
885
+ 'type' => 'boolean',
886
+ 'sanitize_callback' => 'rest_sanitize_boolean',
887
+ 'validate_callback' => 'rest_validate_request_arg',
888
+ );
889
+
890
+ /**
891
+ * Filters the collection query params.
892
+ *
893
+ * @param array $params Query params.
894
+ */
895
+ return apply_filters( 'bp_rest_notifications_collection_params', $params );
896
+ }
897
+ }
bp-settings/bp-settings-filters.php CHANGED
@@ -13,14 +13,16 @@ add_filter( 'wp_privacy_personal_data_exporters', 'bp_settings_register_personal
13
  * Registers Settings personal data exporter.
14
  *
15
  * @since 4.0.0
 
16
  *
17
  * @param array $exporters An array of personal data exporters.
18
  * @return array An array of personal data exporters.
19
  */
20
  function bp_settings_register_personal_data_exporter( $exporters ) {
21
  $exporters['buddypress-settings'] = array(
22
- 'exporter_friendly_name' => __( 'BuddyPress Settings Data', 'buddypress' ),
23
- 'callback' => 'bp_settings_personal_data_exporter',
 
24
  );
25
 
26
  return $exporters;
13
  * Registers Settings personal data exporter.
14
  *
15
  * @since 4.0.0
16
+ * @since 5.0.0 adds an `exporter_bp_friendly_name` param to exporters.
17
  *
18
  * @param array $exporters An array of personal data exporters.
19
  * @return array An array of personal data exporters.
20
  */
21
  function bp_settings_register_personal_data_exporter( $exporters ) {
22
  $exporters['buddypress-settings'] = array(
23
+ 'exporter_friendly_name' => __( 'BuddyPress Settings Data', 'buddypress' ),
24
+ 'callback' => 'bp_settings_personal_data_exporter',
25
+ 'exporter_bp_friendly_name' => _x( 'Personal settings', 'BuddyPress Settings Data data exporter friendly name', 'buddypress' ),
26
  );
27
 
28
  return $exporters;
bp-settings/bp-settings-functions.php CHANGED
@@ -316,26 +316,46 @@ function bp_settings_personal_data_export_exists( WP_User_Request $request ) {
316
  * Piggybacks off of the 'wp_privacy_personal_data_exporters' filter and the
317
  * 'exporter_friendly_name' key, which is meant for the admin area.
318
  *
319
- * @todo We should look for a custom key like 'exporter_frontend_name' if available.
320
- *
321
  * @since 4.0.0
 
322
  */
323
  function bp_settings_data_exporter_items() {
324
  /** This filter is documented in /wp-admin/includes/ajax-actions.php */
325
- $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
 
 
 
 
 
326
 
327
  ?>
328
  <ul>
329
  <?php foreach ( $exporters as $exporter => $data ) :
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  /**
331
- * Filters the data exporter name for display on the "Settings > Data" page.
332
  *
333
  * @since 4.0.0
 
334
  *
335
- * @param string $name Data exporter friendly name.
336
- * @param string $exporter Internal exporter name.
337
  */
338
- $item = apply_filters( 'bp_settings_data_exporter_name', esc_html( $data['exporter_friendly_name'] ), $exporter );
339
  ?>
340
 
341
  <li><?php echo $item; ?></li>
316
  * Piggybacks off of the 'wp_privacy_personal_data_exporters' filter and the
317
  * 'exporter_friendly_name' key, which is meant for the admin area.
318
  *
 
 
319
  * @since 4.0.0
320
+ * @since 5.0.0 Looks for a potential exporter's BP/custom friendly name.
321
  */
322
  function bp_settings_data_exporter_items() {
323
  /** This filter is documented in /wp-admin/includes/ajax-actions.php */
324
+ $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
325
+ $custom_friendly_names = apply_filters( 'bp_settings_data_custom_friendly_names', array(
326
+ 'wordpress-comments' => _x( 'Comments', 'WP Comments data exporter friendly name', 'buddypress' ),
327
+ 'wordpress-media' => _x( 'Media', 'WP Media data exporter friendly name', 'buddypress' ),
328
+ 'wordpress-user' => _x( 'Personal information', 'WP Media data exporter friendly name', 'buddypress' ),
329
+ ) );
330
 
331
  ?>
332
  <ul>
333
  <?php foreach ( $exporters as $exporter => $data ) :
334
+ // Use the exporter friendly name by default.
335
+ $friendly_name = $data['exporter_friendly_name'];
336
+
337
+ /**
338
+ * Use the exporter friendly name if directly available
339
+ * into the exporters array.
340
+ */
341
+ if ( isset( $data['exporter_bp_friendly_name'] ) ) {
342
+ $friendly_name = $data['exporter_bp_friendly_name'];
343
+
344
+ // Look for a potential match into the custom friendly names.
345
+ } elseif ( isset( $custom_friendly_names[ $exporter ] ) ) {
346
+ $friendly_name = $custom_friendly_names[ $exporter ];
347
+ }
348
+
349
  /**
350
+ * Filters the data exporter friendly name for display on the "Settings > Data" page.
351
  *
352
  * @since 4.0.0
353
+ * @since 5.0.0 replaces the `$name` parameter with the `$friendly_name` one.
354
  *
355
+ * @param string $friendly_name Data exporter friendly name.
356
+ * @param string $exporter Internal exporter name.
357
  */
358
+ $item = apply_filters( 'bp_settings_data_exporter_name', esc_html( $friendly_name ), $exporter );
359
  ?>
360
 
361
  <li><?php echo $item; ?></li>
bp-templates/bp-legacy/buddypress-functions.php CHANGED
@@ -988,7 +988,7 @@ function bp_legacy_theme_post_update() {
988
 
989
  } else {
990
 
991
- /** This filter is documented in bp-activity/bp-activity-actions.php */
992
  $activity_id = apply_filters( 'bp_activity_custom_update', false, $object, $item_id, $_POST['content'] );
993
  }
994
 
988
 
989
  } else {
990
 
991
+ /** This filter is documented in bp-activity/actions/post.php */
992
  $activity_id = apply_filters( 'bp_activity_custom_update', false, $object, $item_id, $_POST['content'] );
993
  }
994
 
bp-templates/bp-legacy/css/buddypress-rtl.css CHANGED
@@ -624,7 +624,8 @@ body.activity-permalink #buddypress div.activity-comments div.acomment-content {
624
  }
625
 
626
  #buddypress div#message p,
627
- #sitewide-notice p {
 
628
  font-size: 90%;
629
  display: block;
630
  padding: 10px 15px;
@@ -1392,8 +1393,13 @@ fieldset.create-site label {
1392
  font-weight: 700;
1393
  }
1394
 
 
 
 
 
 
1395
  #buddypress div#message p,
1396
- #sitewide-notice p {
1397
  background-color: #ffd;
1398
  border: 1px solid #cb2;
1399
  color: #440;
@@ -1405,7 +1411,6 @@ fieldset.create-site label {
1405
  .bp-site-wide-message #message p,
1406
  .admin-bar-on #message p {
1407
  padding-left: 25px;
1408
- position: relative;
1409
  }
1410
 
1411
  .bp-site-wide-message #message button,
624
  }
625
 
626
  #buddypress div#message p,
627
+ #sitewide-notice p,
628
+ #sitewide-notice strong:first-child {
629
  font-size: 90%;
630
  display: block;
631
  padding: 10px 15px;
1393
  font-weight: 700;
1394
  }
1395
 
1396
+ #sitewide-notice,
1397
+ .bp-site-wide-message {
1398
+ position: relative;
1399
+ }
1400
+
1401
  #buddypress div#message p,
1402
+ #sitewide-notice #message {
1403
  background-color: #ffd;
1404
  border: 1px solid #cb2;
1405
  color: #440;
1411
  .bp-site-wide-message #message p,
1412
  .admin-bar-on #message p {
1413
  padding-left: 25px;
 
1414
  }
1415
 
1416
  .bp-site-wide-message #message button,
bp-templates/bp-legacy/css/buddypress-rtl.min.css CHANGED
@@ -1 +1 @@
1
- #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 div.pagination .pagination-links a:hover{font-weight:700}#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:.5;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:1.5;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:2.2}#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{margin:0}#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 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}#buddypress ul.button-nav li.current a{font-weight:700}#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 label.xprofile-field-label{display:inline}#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 .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}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 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}fieldset.register-site{margin-top:1em}fieldset.create-site{margin-bottom:2em}fieldset.create-site legend{margin-bottom:1em}fieldset.create-site label{margin-left:3em}.bp-screen-reader-text{clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden;position:absolute!important;width:1px;word-wrap:normal!important}.bp-screen-reader-text:focus{background-color:#f1f1f1;border-radius:3px;box-shadow:0 0 2px 2px rgba(0,0,0,.6);clip:auto!important;color:#21759b;display:block;font-size:14px;font-size:.875rem;font-weight:700;height:auto;right:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}#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}#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=button].disabled,#buddypress input[type=button].pending,#buddypress input[type=reset].disabled,#buddypress input[type=reset].pending,#buddypress input[type=submit].disabled,#buddypress input[type=submit].pending,#buddypress input[type=submit][disabled=disabled]{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=button]:hover.disabled,#buddypress input[type=button]:hover.pending,#buddypress input[type=reset]:hover.disabled,#buddypress input[type=reset]:hover.pending,#buddypress input[type=submit]:hover.disabled,#buddypress input[type=submit]: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.profile-fields:last-child{margin-bottom:0}#buddypress table.profile-fields p{margin: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{margin:0}#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 td:first-child,#buddypress table.notification-settings th.icon,#buddypress table.notifications td:first-child,#buddypress table.notifications th.icon{display:none}#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{background-color:#ffd;border:1px solid #cb2;color:#440;font-weight:400;margin-top:3px;text-decoration:none}.admin-bar-on #message p,.bp-site-wide-message #message p{padding-left:25px;position:relative}.admin-bar-on #message button,.bp-site-wide-message #message button{font-size:.8em;padding:2px 4px;position:absolute;left:0;top:0}.admin-bar-on #message button{left:10px;top:7px}#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:1.2;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:1.7;vertical-align:middle;display:inline-block}#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 div#item-actions a{display:inline-block}#buddypress div#item-header ul{margin-bottom:15px}#buddypress div#item-header ul:after{clear:both;content:"";display:table}#buddypress div#item-header ul h5,#buddypress div#item-header ul hr,#buddypress div#item-header ul span{display:none}#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}body.no-js #buddypress div#item-header .js-self-profile-button{display:none}#buddypress div#item-header div#message.info{line-height:.8}#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 #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-metadata:after{clear:both;content:"";display:table}#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{border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0;background:#f5f5f5;color:#707070}#buddypress .tmce-active button.switch-tmce{border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0;background:#f5f5f5;color:#707070}#buddypress .standard-form .wp-editor-container textarea{width:100%;padding-top:0;padding-bottom:0}.widget.buddypress span.activity{display:inline-block;font-size:small;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 div.avatar-block:after{clear:both;content:"";display:table}.widget.buddypress .item-avatar a{float:right;margin-bottom:15px;margin-left:10px}.widget.buddypress div.item-avatar img{display:inline-block;height:40px;margin:1px;width:40px}.widget.buddypress .item-avatar a,.widget.buddypress .item-avatar a img,.widget.buddypress .item-avatar a:active,.widget.buddypress .item-avatar a:focus,.widget.buddypress .item-avatar a:hover{box-shadow:none}.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}.widget.buddypress .bp-login-widget-user-links>div{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}.buddypress .bp-tooltip{position:relative}.bp-tooltip:after{background:#fff;border:1px solid #aaa;border-collapse:separate;border-radius:1px;box-shadow:-1px 1px 0 1px rgba(132,132,132,.3);color:#000;content:attr(data-bp-tooltip);display:none;font-family:sans-serif;font-size:11px;font-weight:400;letter-spacing:normal;line-height:1.5;margin-top:10px;max-width:240px;opacity:0;padding:3px 6px;position:absolute;left:50%;text-align:center;text-decoration:none;text-shadow:none;text-transform:none;top:100%;transform:translateX(-50%);transition:opacity 2s ease-out;white-space:pre;word-wrap:break-word;z-index:998}.bp-tooltip:active:after,.bp-tooltip:focus:after,.bp-tooltip:hover:after{display:inline-block;opacity:1;overflow:visible;text-decoration:none;z-index:999}#group-admins .bp-tooltip:after,#group-mods .bp-tooltip:after,.message-metadata .bp-tooltip:after{left:0;text-align:left;transform:translateX(0)}.feed .bp-tooltip:after,.item-list .bp-tooltip:after,.messages-notices .bp-tooltip:after{right:0;left:auto;text-align:right;transform:translateX(0)}.admin-bar-on .bp-tooltip:after,.bp-site-wide-message .bp-tooltip:after{left:50px}@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 h3,#buddypress form.standard-form .main-column ul#friend-list h4{width:100%}}@media only screen and (max-width:320px){#buddypress div.dir-search{clear:right;float:right;margin-top:0;text-align:right}#buddypress li#groups-order-select{clear:right;float:right}#buddypress ul.item-list li div.action{clear:right;float:right;margin-top:0;margin-right:70px;position:relative;top:0;left:0;text-align:right}#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{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 div.pagination .pagination-links a:hover{font-weight:700}#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:.5;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:1.5;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:2.2}#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{margin:0}#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 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,#sitewide-notice strong:first-child{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}#buddypress ul.button-nav li.current a{font-weight:700}#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 label.xprofile-field-label{display:inline}#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 .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}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 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}fieldset.register-site{margin-top:1em}fieldset.create-site{margin-bottom:2em}fieldset.create-site legend{margin-bottom:1em}fieldset.create-site label{margin-left:3em}.bp-screen-reader-text{clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden;position:absolute!important;width:1px;word-wrap:normal!important}.bp-screen-reader-text:focus{background-color:#f1f1f1;border-radius:3px;box-shadow:0 0 2px 2px rgba(0,0,0,.6);clip:auto!important;color:#21759b;display:block;font-size:14px;font-size:.875rem;font-weight:700;height:auto;right:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}#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}#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=button].disabled,#buddypress input[type=button].pending,#buddypress input[type=reset].disabled,#buddypress input[type=reset].pending,#buddypress input[type=submit].disabled,#buddypress input[type=submit].pending,#buddypress input[type=submit][disabled=disabled]{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=button]:hover.disabled,#buddypress input[type=button]:hover.pending,#buddypress input[type=reset]:hover.disabled,#buddypress input[type=reset]:hover.pending,#buddypress input[type=submit]:hover.disabled,#buddypress input[type=submit]: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.profile-fields:last-child{margin-bottom:0}#buddypress table.profile-fields p{margin: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{margin:0}#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 td:first-child,#buddypress table.notification-settings th.icon,#buddypress table.notifications td:first-child,#buddypress table.notifications th.icon{display:none}#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}#sitewide-notice,.bp-site-wide-message{position:relative}#buddypress div#message p,#sitewide-notice #message{background-color:#ffd;border:1px solid #cb2;color:#440;font-weight:400;margin-top:3px;text-decoration:none}.admin-bar-on #message p,.bp-site-wide-message #message p{padding-left:25px}.admin-bar-on #message button,.bp-site-wide-message #message button{font-size:.8em;padding:2px 4px;position:absolute;left:0;top:0}.admin-bar-on #message button{left:10px;top:7px}#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:1.2;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:1.7;vertical-align:middle;display:inline-block}#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 div#item-actions a{display:inline-block}#buddypress div#item-header ul{margin-bottom:15px}#buddypress div#item-header ul:after{clear:both;content:"";display:table}#buddypress div#item-header ul h5,#buddypress div#item-header ul hr,#buddypress div#item-header ul span{display:none}#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}body.no-js #buddypress div#item-header .js-self-profile-button{display:none}#buddypress div#item-header div#message.info{line-height:.8}#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 #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-metadata:after{clear:both;content:"";display:table}#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{border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0;background:#f5f5f5;color:#707070}#buddypress .tmce-active button.switch-tmce{border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0;background:#f5f5f5;color:#707070}#buddypress .standard-form .wp-editor-container textarea{width:100%;padding-top:0;padding-bottom:0}.widget.buddypress span.activity{display:inline-block;font-size:small;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 div.avatar-block:after{clear:both;content:"";display:table}.widget.buddypress .item-avatar a{float:right;margin-bottom:15px;margin-left:10px}.widget.buddypress div.item-avatar img{display:inline-block;height:40px;margin:1px;width:40px}.widget.buddypress .item-avatar a,.widget.buddypress .item-avatar a img,.widget.buddypress .item-avatar a:active,.widget.buddypress .item-avatar a:focus,.widget.buddypress .item-avatar a:hover{box-shadow:none}.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}.widget.buddypress .bp-login-widget-user-links>div{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}.buddypress .bp-tooltip{position:relative}.bp-tooltip:after{background:#fff;border:1px solid #aaa;border-collapse:separate;border-radius:1px;box-shadow:-1px 1px 0 1px rgba(132,132,132,.3);color:#000;content:attr(data-bp-tooltip);display:none;font-family:sans-serif;font-size:11px;font-weight:400;letter-spacing:normal;line-height:1.5;margin-top:10px;max-width:240px;opacity:0;padding:3px 6px;position:absolute;left:50%;text-align:center;text-decoration:none;text-shadow:none;text-transform:none;top:100%;transform:translateX(-50%);transition:opacity 2s ease-out;white-space:pre;word-wrap:break-word;z-index:998}.bp-tooltip:active:after,.bp-tooltip:focus:after,.bp-tooltip:hover:after{display:inline-block;opacity:1;overflow:visible;text-decoration:none;z-index:999}#group-admins .bp-tooltip:after,#group-mods .bp-tooltip:after,.message-metadata .bp-tooltip:after{left:0;text-align:left;transform:translateX(0)}.feed .bp-tooltip:after,.item-list .bp-tooltip:after,.messages-notices .bp-tooltip:after{right:0;left:auto;text-align:right;transform:translateX(0)}.admin-bar-on .bp-tooltip:after,.bp-site-wide-message .bp-tooltip:after{left:50px}@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 h3,#buddypress form.standard-form .main-column ul#friend-list h4{width:100%}}@media only screen and (max-width:320px){#buddypress div.dir-search{clear:right;float:right;margin-top:0;text-align:right}#buddypress li#groups-order-select{clear:right;float:right}#buddypress ul.item-list li div.action{clear:right;float:right;margin-top:0;margin-right:70px;position:relative;top:0;left:0;text-align:right}#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}}
bp-templates/bp-legacy/css/buddypress.css CHANGED
@@ -624,7 +624,8 @@ body.activity-permalink #buddypress div.activity-comments div.acomment-content {
624
  }
625
 
626
  #buddypress div#message p,
627
- #sitewide-notice p {
 
628
  font-size: 90%;
629
  display: block;
630
  padding: 10px 15px;
@@ -1392,8 +1393,13 @@ fieldset.create-site label {
1392
  font-weight: 700;
1393
  }
1394
 
 
 
 
 
 
1395
  #buddypress div#message p,
1396
- #sitewide-notice p {
1397
  background-color: #ffd;
1398
  border: 1px solid #cb2;
1399
  color: #440;
@@ -1405,7 +1411,6 @@ fieldset.create-site label {
1405
  .bp-site-wide-message #message p,
1406
  .admin-bar-on #message p {
1407
  padding-right: 25px;
1408
- position: relative;
1409
  }
1410
 
1411
  .bp-site-wide-message #message button,
624
  }
625
 
626
  #buddypress div#message p,
627
+ #sitewide-notice p,
628
+ #sitewide-notice strong:first-child {
629
  font-size: 90%;
630
  display: block;
631
  padding: 10px 15px;
1393
  font-weight: 700;
1394
  }
1395
 
1396
+ #sitewide-notice,
1397
+ .bp-site-wide-message {
1398
+ position: relative;
1399
+ }
1400
+
1401
  #buddypress div#message p,
1402
+ #sitewide-notice #message {
1403
  background-color: #ffd;
1404
  border: 1px solid #cb2;
1405
  color: #440;
1411
  .bp-site-wide-message #message p,
1412
  .admin-bar-on #message p {
1413
  padding-right: 25px;
 
1414
  }
1415
 
1416
  .bp-site-wide-message #message button,
bp-templates/bp-legacy/css/buddypress.min.css CHANGED
@@ -1 +1 @@
1
- #buddypress div.pagination{background:0 0;border:none;color:#767676;font-size:small;margin:0;position:relative;display:block;float:left;width:100%;padding:10px 0}#buddypress div.pagination .pag-count{float:left;margin-left:10px}#buddypress div.pagination .pagination-links{float:right;margin-right:10px}#buddypress div.pagination .pagination-links a,#buddypress div.pagination .pagination-links span{font-size:90%;padding:0 5px}#buddypress div.pagination .pagination-links a:hover{font-weight:700}#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:left}#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:left}#buddypress form#whats-new-form #whats-new-content{margin-left:55px;padding:0 0 20px 20px}#buddypress form#whats-new-form p.activity-greeting{line-height:.5;margin-bottom:15px;margin-left: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:right;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:left}#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-left: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-left: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 0 0 70px}body.activity-permalink #buddypress .activity-list li .activity-content{border:none;font-size:100%;line-height:1.5;margin-left:170px;margin-right: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:2.2}#buddypress .activity-header{margin-right: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 5px -8px 0!important}#buddypress a.bp-secondary-action,#buddypress span.highlight{font-size:80%;padding:0;margin-right:5px;text-decoration:none}#buddypress .activity-list .activity-content .activity-inner,#buddypress .activity-list .activity-content blockquote{margin:10px 10px 5px 0;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-left:2px solid #eaeaea;margin-left:5px;padding-left:10px}body.activity-permalink #buddypress .activity-content .activity-inner,body.activity-permalink #buddypress .activity-content blockquote{margin-left:0;margin-top:5px}#buddypress .activity-inner>p{word-wrap:break-word}#buddypress .activity-inner>.activity-inner{margin:0}#buddypress .activity-inner>blockquote{margin:0}#buddypress .activity-list .activity-content img.thumbnail{border:2px solid #eee;float:left;margin:0 10px 5px 0}#buddypress .activity-read-more{margin-left: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-right:5px;text-decoration:none}#buddypress #reply-title small a span,#buddypress a.bp-primary-action span{background:#767676;color:#fff;font-size:90%;margin-left: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 0 0 70px;overflow:hidden;position:relative;width:auto;clear:both}body.activity-permalink #buddypress div.activity-comments{background:0 0;margin-left:170px;width:auto}#buddypress div.activity-comments>ul{padding:0 0 0 10px}#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-left:30px;margin-top:0;padding-left:10px}body.activity-permalink #buddypress div.activity-comments ul li>ul{margin-top:10px}body.activity-permalink #buddypress div.activity-comments>ul{padding:0 10px 0 15px}#buddypress div.activity-comments div.acomment-avatar img{border-width:1px;float:left;height:25px;margin-right:10px;width:25px}#buddypress div.activity-comments div.acomment-content{font-size:80%;margin:5px 0 0 40px}#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-right:15px;clear:both}#buddypress div.activity-comments form.root{margin-left: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:left}#buddypress div.ac-reply-avatar img{border:1px solid #eee}#buddypress div.activity-comments form div.ac-reply-content{color:#767676;margin-left:50px;padding-left:15px}#buddypress div.activity-comments form div.ac-reply-content a{text-decoration:none}#buddypress .acomment-options{float:left;margin:5px 0 5px 40px}#buddypress .acomment-options a{color:#767676}#buddypress .acomment-options a:hover{color:inherit}#buddypress div.dir-search{float:right;margin:-39px 0 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:left;color:#800}#buddypress div#message.warning p{background-color:#ffe0af;border:1px solid #ffd087;clear:left;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 5px 5px 0;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:left;margin-left:10px}#buddypress ul.button-nav li{float:left;margin:0 10px 10px 0;list-style:none}#buddypress ul.button-nav li.current a{font-weight:700}#sitewide-notice #message{left: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 label.xprofile-field-label{display:inline}#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-right: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:right}#buddypress div#signup-avatar img{margin:0 15px 10px 0}#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-right:15px}#buddypress .standard-form div.radio ul{margin:10px 0 15px 38px;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 .standard-form #basic-details-section,#buddypress .standard-form #blog-details-section,#buddypress .standard-form #profile-details-section{float:left;width:48%}#buddypress .standard-form #profile-details-section{float:right}#buddypress #notifications-bulk-management,#buddypress .standard-form #blog-details-section{clear:left}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 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:left}#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 0 0 1%}#buddypress form.standard-form .main-column{margin-left:190px}#buddypress form.standard-form .main-column ul#friend-list{clear:none;float:left}#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}fieldset.register-site{margin-top:1em}fieldset.create-site{margin-bottom:2em}fieldset.create-site legend{margin-bottom:1em}fieldset.create-site label{margin-right:3em}.bp-screen-reader-text{clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden;position:absolute!important;width:1px;word-wrap:normal!important}.bp-screen-reader-text:focus{background-color:#f1f1f1;border-radius:3px;box-shadow:0 0 2px 2px rgba(0,0,0,.6);clip:auto!important;color:#21759b;display:block;font-size:14px;font-size:.875rem;font-weight:700;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}#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}#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=button].disabled,#buddypress input[type=button].pending,#buddypress input[type=reset].disabled,#buddypress input[type=reset].pending,#buddypress input[type=submit].disabled,#buddypress input[type=submit].pending,#buddypress input[type=submit][disabled=disabled]{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=button]:hover.disabled,#buddypress input[type=button]:hover.pending,#buddypress input[type=reset]:hover.disabled,#buddypress input[type=reset]:hover.pending,#buddypress input[type=submit]:hover.disabled,#buddypress input[type=submit]: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-left:54px}#buddypress div.topic-tags{font-size:80%}#buddypress div.admin-links{color:#767676;font-size:80%;position:absolute;top:15px;right:25px}#buddypress div#topic-meta{margin:0;padding:5px 19px 30px;position:relative}#buddypress div#topic-meta div.admin-links{right: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.profile-fields:last-child{margin-bottom:0}#buddypress table.profile-fields p{margin: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-right:1px solid #eaeaea;font-weight:700;width:25%}#buddypress #message-threads .thread-info{min-width:40%}#buddypress table tr td.thread-info p{margin:0}#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:left}#buddypress #groups-notification-settings{margin-bottom: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{display:none}#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-left: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-left:15px}#buddypress table.forum tr>td:last-child,#buddypress table.forum tr>th:last-child{padding-right: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:left}#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 5px -8px 0}#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{background-color:#ffd;border:1px solid #cb2;color:#440;font-weight:400;margin-top:3px;text-decoration:none}.admin-bar-on #message p,.bp-site-wide-message #message p{padding-right:25px;position:relative}.admin-bar-on #message button,.bp-site-wide-message #message button{font-size:.8em;padding:2px 4px;position:absolute;right:0;top:0}.admin-bar-on #message button{right:10px;top:7px}#buddypress #item-header:after{clear:both;content:"";display:table}#buddypress div#item-header div#item-header-content{float:left;margin-left:0}#buddypress div#item-header h2{line-height:1.2;margin:0 0 15px}#buddypress div#item-header h2 a{color:#767676;text-decoration:none}#buddypress div#item-header img.avatar{float:left;margin:0 15px 19px 0}#buddypress div#item-header h2{margin-bottom:5px}#buddypress div#item-header h2 span.highlight{font-size:60%;font-weight:400;line-height:1.7;vertical-align:middle;display:inline-block}#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;right:-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:right;margin:0 0 15px 15px;text-align:right;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 div#item-actions a{display:inline-block}#buddypress div#item-header ul{margin-bottom:15px}#buddypress div#item-header ul:after{clear:both;content:"";display:table}#buddypress div#item-header ul h5,#buddypress div#item-header ul hr,#buddypress div#item-header ul span{display:none}#buddypress div#item-header ul li{float:right;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:left;margin:10px 10px 0 0}body.no-js #buddypress div#item-header .js-self-profile-button{display:none}#buddypress div#item-header div#message.info{line-height:.8}#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:left;margin:0 10px 0 0}#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 0 0 60px;width:50%}#buddypress ul.item-list li.group-no-avatar div.item-desc{margin-left:0}#buddypress ul.item-list li div.action{position:absolute;top:15px;right:0;text-align:right}#buddypress ul.item-list li div.meta{color:#767676;font-size:80%;margin-top:10px}#buddypress ul.item-list li h5 span.small{float:right;font-size:80%;font-weight:400}#buddypress div.item-list-tabs{background:0 0;clear:left;overflow:hidden}#buddypress div.item-list-tabs ul{margin:0;padding:0}#buddypress div.item-list-tabs ul li{float:left;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:right;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-left: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:88% 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 #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;left: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:left;margin:0 10px 0 0;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-metadata:after{clear:both;content:"";display:table}#buddypress div#message-thread div.message-content{margin-left:45px}#buddypress div#message-thread div.message-options{text-align:right}#buddypress #message-threads img.avatar{max-width:none}#buddypress div.message-search{float:right;margin:0 20px}.message-metadata{position:relative}.message-star-actions{position:absolute;right: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{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0;background:#f5f5f5;color:#707070}#buddypress .tmce-active button.switch-tmce{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0;background:#f5f5f5;color:#707070}#buddypress .standard-form .wp-editor-container textarea{width:100%;padding-top:0;padding-bottom:0}.widget.buddypress span.activity{display:inline-block;font-size:small;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-left:50px}.widget.buddypress div.avatar-block:after{clear:both;content:"";display:table}.widget.buddypress .item-avatar a{float:left;margin-bottom:15px;margin-right:10px}.widget.buddypress div.item-avatar img{display:inline-block;height:40px;margin:1px;width:40px}.widget.buddypress .item-avatar a,.widget.buddypress .item-avatar a img,.widget.buddypress .item-avatar a:active,.widget.buddypress .item-avatar a:focus,.widget.buddypress .item-avatar a:hover{box-shadow:none}.widget.buddypress #bp-login-widget-form label{display:block;margin:1rem 0 .5rem}.widget.buddypress #bp-login-widget-form #bp-login-widget-submit{margin-right:10px}.widget.buddypress .bp-login-widget-user-avatar{float:left}.bp-login-widget-user-avatar img.avatar{height:40px;width:40px}.widget.buddypress .bp-login-widget-user-links>div{padding-left:60px}.widget.buddypress .bp-login-widget-user-links>div{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-left:0;padding-left:0}.widget.buddypress #friends-list li,.widget.buddypress #groups-list li,.widget.buddypress #members-list li{clear:both;list-style-type:none}.buddypress .bp-tooltip{position:relative}.bp-tooltip:after{background:#fff;border:1px solid #aaa;border-collapse:separate;border-radius:1px;box-shadow:1px 1px 0 1px rgba(132,132,132,.3);color:#000;content:attr(data-bp-tooltip);display:none;font-family:sans-serif;font-size:11px;font-weight:400;letter-spacing:normal;line-height:1.5;margin-top:10px;max-width:240px;opacity:0;padding:3px 6px;position:absolute;right:50%;text-align:center;text-decoration:none;text-shadow:none;text-transform:none;top:100%;transform:translateX(50%);transition:opacity 2s ease-out;white-space:pre;word-wrap:break-word;z-index:998}.bp-tooltip:active:after,.bp-tooltip:focus:after,.bp-tooltip:hover:after{display:inline-block;opacity:1;overflow:visible;text-decoration:none;z-index:999}#group-admins .bp-tooltip:after,#group-mods .bp-tooltip:after,.message-metadata .bp-tooltip:after{right:0;text-align:right;transform:translateX(0)}.feed .bp-tooltip:after,.item-list .bp-tooltip:after,.messages-notices .bp-tooltip:after{left:0;right:auto;text-align:left;transform:translateX(0)}.admin-bar-on .bp-tooltip:after,.bp-site-wide-message .bp-tooltip:after{right:50px}@media only screen and (max-width:480px){#buddypress div.dir-search{float:right;margin-top:-50px;text-align:right}#buddypress div.dir-search input[type=text]{margin-bottom:1em;width:50%}a.bp-title-button{margin-left:10px}#buddypress form.standard-form .main-column div.action{position:relative;margin-bottom:1em}#buddypress form.standard-form .main-column ul#friend-list h3,#buddypress form.standard-form .main-column ul#friend-list h4{width:100%}}@media only screen and (max-width:320px){#buddypress div.dir-search{clear:left;float:left;margin-top:0;text-align:left}#buddypress li#groups-order-select{clear:left;float:left}#buddypress ul.item-list li div.action{clear:left;float:left;margin-top:0;margin-left:70px;position:relative;top:0;right:0;text-align:left}#buddypress ul.item-list li div.item-desc{clear:left;float:left;margin:10px 0 0;width:auto}#buddypress li div.item{margin-left: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-left:0}}@media only screen and (max-width:240px){#buddypress div.dir-search{float:left;margin:0}#buddypress div.dir-search input[type=text]{width:50%}#buddypress li#groups-order-select{float:left}#buddypress ul.item-list li img.avatar{width:30px;height:auto}#buddypress li div.item,#buddypress ul.item-list li div.action{margin-left:45px}h1 a.bp-title-button{clear:left;float:left;margin:10px 0 20px}}
1
+ #buddypress div.pagination{background:0 0;border:none;color:#767676;font-size:small;margin:0;position:relative;display:block;float:left;width:100%;padding:10px 0}#buddypress div.pagination .pag-count{float:left;margin-left:10px}#buddypress div.pagination .pagination-links{float:right;margin-right:10px}#buddypress div.pagination .pagination-links a,#buddypress div.pagination .pagination-links span{font-size:90%;padding:0 5px}#buddypress div.pagination .pagination-links a:hover{font-weight:700}#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:left}#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:left}#buddypress form#whats-new-form #whats-new-content{margin-left:55px;padding:0 0 20px 20px}#buddypress form#whats-new-form p.activity-greeting{line-height:.5;margin-bottom:15px;margin-left: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:right;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:left}#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-left: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-left: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 0 0 70px}body.activity-permalink #buddypress .activity-list li .activity-content{border:none;font-size:100%;line-height:1.5;margin-left:170px;margin-right: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:2.2}#buddypress .activity-header{margin-right: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 5px -8px 0!important}#buddypress a.bp-secondary-action,#buddypress span.highlight{font-size:80%;padding:0;margin-right:5px;text-decoration:none}#buddypress .activity-list .activity-content .activity-inner,#buddypress .activity-list .activity-content blockquote{margin:10px 10px 5px 0;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-left:2px solid #eaeaea;margin-left:5px;padding-left:10px}body.activity-permalink #buddypress .activity-content .activity-inner,body.activity-permalink #buddypress .activity-content blockquote{margin-left:0;margin-top:5px}#buddypress .activity-inner>p{word-wrap:break-word}#buddypress .activity-inner>.activity-inner{margin:0}#buddypress .activity-inner>blockquote{margin:0}#buddypress .activity-list .activity-content img.thumbnail{border:2px solid #eee;float:left;margin:0 10px 5px 0}#buddypress .activity-read-more{margin-left: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-right:5px;text-decoration:none}#buddypress #reply-title small a span,#buddypress a.bp-primary-action span{background:#767676;color:#fff;font-size:90%;margin-left: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 0 0 70px;overflow:hidden;position:relative;width:auto;clear:both}body.activity-permalink #buddypress div.activity-comments{background:0 0;margin-left:170px;width:auto}#buddypress div.activity-comments>ul{padding:0 0 0 10px}#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-left:30px;margin-top:0;padding-left:10px}body.activity-permalink #buddypress div.activity-comments ul li>ul{margin-top:10px}body.activity-permalink #buddypress div.activity-comments>ul{padding:0 10px 0 15px}#buddypress div.activity-comments div.acomment-avatar img{border-width:1px;float:left;height:25px;margin-right:10px;width:25px}#buddypress div.activity-comments div.acomment-content{font-size:80%;margin:5px 0 0 40px}#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-right:15px;clear:both}#buddypress div.activity-comments form.root{margin-left: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:left}#buddypress div.ac-reply-avatar img{border:1px solid #eee}#buddypress div.activity-comments form div.ac-reply-content{color:#767676;margin-left:50px;padding-left:15px}#buddypress div.activity-comments form div.ac-reply-content a{text-decoration:none}#buddypress .acomment-options{float:left;margin:5px 0 5px 40px}#buddypress .acomment-options a{color:#767676}#buddypress .acomment-options a:hover{color:inherit}#buddypress div.dir-search{float:right;margin:-39px 0 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,#sitewide-notice strong:first-child{font-size:90%;display:block;padding:10px 15px}#buddypress div#message.error p{background-color:#fdc;border:1px solid #a00;clear:left;color:#800}#buddypress div#message.warning p{background-color:#ffe0af;border:1px solid #ffd087;clear:left;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 5px 5px 0;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:left;margin-left:10px}#buddypress ul.button-nav li{float:left;margin:0 10px 10px 0;list-style:none}#buddypress ul.button-nav li.current a{font-weight:700}#sitewide-notice #message{left: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 label.xprofile-field-label{display:inline}#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-right: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:right}#buddypress div#signup-avatar img{margin:0 15px 10px 0}#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-right:15px}#buddypress .standard-form div.radio ul{margin:10px 0 15px 38px;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 .standard-form #basic-details-section,#buddypress .standard-form #blog-details-section,#buddypress .standard-form #profile-details-section{float:left;width:48%}#buddypress .standard-form #profile-details-section{float:right}#buddypress #notifications-bulk-management,#buddypress .standard-form #blog-details-section{clear:left}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 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:left}#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 0 0 1%}#buddypress form.standard-form .main-column{margin-left:190px}#buddypress form.standard-form .main-column ul#friend-list{clear:none;float:left}#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}fieldset.register-site{margin-top:1em}fieldset.create-site{margin-bottom:2em}fieldset.create-site legend{margin-bottom:1em}fieldset.create-site label{margin-right:3em}.bp-screen-reader-text{clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden;position:absolute!important;width:1px;word-wrap:normal!important}.bp-screen-reader-text:focus{background-color:#f1f1f1;border-radius:3px;box-shadow:0 0 2px 2px rgba(0,0,0,.6);clip:auto!important;color:#21759b;display:block;font-size:14px;font-size:.875rem;font-weight:700;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}#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}#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=button].disabled,#buddypress input[type=button].pending,#buddypress input[type=reset].disabled,#buddypress input[type=reset].pending,#buddypress input[type=submit].disabled,#buddypress input[type=submit].pending,#buddypress input[type=submit][disabled=disabled]{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=button]:hover.disabled,#buddypress input[type=button]:hover.pending,#buddypress input[type=reset]:hover.disabled,#buddypress input[type=reset]:hover.pending,#buddypress input[type=submit]:hover.disabled,#buddypress input[type=submit]: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-left:54px}#buddypress div.topic-tags{font-size:80%}#buddypress div.admin-links{color:#767676;font-size:80%;position:absolute;top:15px;right:25px}#buddypress div#topic-meta{margin:0;padding:5px 19px 30px;position:relative}#buddypress div#topic-meta div.admin-links{right: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.profile-fields:last-child{margin-bottom:0}#buddypress table.profile-fields p{margin: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-right:1px solid #eaeaea;font-weight:700;width:25%}#buddypress #message-threads .thread-info{min-width:40%}#buddypress table tr td.thread-info p{margin:0}#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:left}#buddypress #groups-notification-settings{margin-bottom: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{display:none}#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-left: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-left:15px}#buddypress table.forum tr>td:last-child,#buddypress table.forum tr>th:last-child{padding-right: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:left}#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 5px -8px 0}#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}#sitewide-notice,.bp-site-wide-message{position:relative}#buddypress div#message p,#sitewide-notice #message{background-color:#ffd;border:1px solid #cb2;color:#440;font-weight:400;margin-top:3px;text-decoration:none}.admin-bar-on #message p,.bp-site-wide-message #message p{padding-right:25px}.admin-bar-on #message button,.bp-site-wide-message #message button{font-size:.8em;padding:2px 4px;position:absolute;right:0;top:0}.admin-bar-on #message button{right:10px;top:7px}#buddypress #item-header:after{clear:both;content:"";display:table}#buddypress div#item-header div#item-header-content{float:left;margin-left:0}#buddypress div#item-header h2{line-height:1.2;margin:0 0 15px}#buddypress div#item-header h2 a{color:#767676;text-decoration:none}#buddypress div#item-header img.avatar{float:left;margin:0 15px 19px 0}#buddypress div#item-header h2{margin-bottom:5px}#buddypress div#item-header h2 span.highlight{font-size:60%;font-weight:400;line-height:1.7;vertical-align:middle;display:inline-block}#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;right:-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:right;margin:0 0 15px 15px;text-align:right;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 div#item-actions a{display:inline-block}#buddypress div#item-header ul{margin-bottom:15px}#buddypress div#item-header ul:after{clear:both;content:"";display:table}#buddypress div#item-header ul h5,#buddypress div#item-header ul hr,#buddypress div#item-header ul span{display:none}#buddypress div#item-header ul li{float:right;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:left;margin:10px 10px 0 0}body.no-js #buddypress div#item-header .js-self-profile-button{display:none}#buddypress div#item-header div#message.info{line-height:.8}#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:left;margin:0 10px 0 0}#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 0 0 60px;width:50%}#buddypress ul.item-list li.group-no-avatar div.item-desc{margin-left:0}#buddypress ul.item-list li div.action{position:absolute;top:15px;right:0;text-align:right}#buddypress ul.item-list li div.meta{color:#767676;font-size:80%;margin-top:10px}#buddypress ul.item-list li h5 span.small{float:right;font-size:80%;font-weight:400}#buddypress div.item-list-tabs{background:0 0;clear:left;overflow:hidden}#buddypress div.item-list-tabs ul{margin:0;padding:0}#buddypress div.item-list-tabs ul li{float:left;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:right;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-left: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:88% 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 #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;left: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:left;margin:0 10px 0 0;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-metadata:after{clear:both;content:"";display:table}#buddypress div#message-thread div.message-content{margin-left:45px}#buddypress div#message-thread div.message-options{text-align:right}#buddypress #message-threads img.avatar{max-width:none}#buddypress div.message-search{float:right;margin:0 20px}.message-metadata{position:relative}.message-star-actions{position:absolute;right: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{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0;background:#f5f5f5;color:#707070}#buddypress .tmce-active button.switch-tmce{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0;background:#f5f5f5;color:#707070}#buddypress .standard-form .wp-editor-container textarea{width:100%;padding-top:0;padding-bottom:0}.widget.buddypress span.activity{display:inline-block;font-size:small;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-left:50px}.widget.buddypress div.avatar-block:after{clear:both;content:"";display:table}.widget.buddypress .item-avatar a{float:left;margin-bottom:15px;margin-right:10px}.widget.buddypress div.item-avatar img{display:inline-block;height:40px;margin:1px;width:40px}.widget.buddypress .item-avatar a,.widget.buddypress .item-avatar a img,.widget.buddypress .item-avatar a:active,.widget.buddypress .item-avatar a:focus,.widget.buddypress .item-avatar a:hover{box-shadow:none}.widget.buddypress #bp-login-widget-form label{display:block;margin:1rem 0 .5rem}.widget.buddypress #bp-login-widget-form #bp-login-widget-submit{margin-right:10px}.widget.buddypress .bp-login-widget-user-avatar{float:left}.bp-login-widget-user-avatar img.avatar{height:40px;width:40px}.widget.buddypress .bp-login-widget-user-links>div{padding-left:60px}.widget.buddypress .bp-login-widget-user-links>div{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-left:0;padding-left:0}.widget.buddypress #friends-list li,.widget.buddypress #groups-list li,.widget.buddypress #members-list li{clear:both;list-style-type:none}.buddypress .bp-tooltip{position:relative}.bp-tooltip:after{background:#fff;border:1px solid #aaa;border-collapse:separate;border-radius:1px;box-shadow:1px 1px 0 1px rgba(132,132,132,.3);color:#000;content:attr(data-bp-tooltip);display:none;font-family:sans-serif;font-size:11px;font-weight:400;letter-spacing:normal;line-height:1.5;margin-top:10px;max-width:240px;opacity:0;padding:3px 6px;position:absolute;right:50%;text-align:center;text-decoration:none;text-shadow:none;text-transform:none;top:100%;transform:translateX(50%);transition:opacity 2s ease-out;white-space:pre;word-wrap:break-word;z-index:998}.bp-tooltip:active:after,.bp-tooltip:focus:after,.bp-tooltip:hover:after{display:inline-block;opacity:1;overflow:visible;text-decoration:none;z-index:999}#group-admins .bp-tooltip:after,#group-mods .bp-tooltip:after,.message-metadata .bp-tooltip:after{right:0;text-align:right;transform:translateX(0)}.feed .bp-tooltip:after,.item-list .bp-tooltip:after,.messages-notices .bp-tooltip:after{left:0;right:auto;text-align:left;transform:translateX(0)}.admin-bar-on .bp-tooltip:after,.bp-site-wide-message .bp-tooltip:after{right:50px}@media only screen and (max-width:480px){#buddypress div.dir-search{float:right;margin-top:-50px;text-align:right}#buddypress div.dir-search input[type=text]{margin-bottom:1em;width:50%}a.bp-title-button{margin-left:10px}#buddypress form.standard-form .main-column div.action{position:relative;margin-bottom:1em}#buddypress form.standard-form .main-column ul#friend-list h3,#buddypress form.standard-form .main-column ul#friend-list h4{width:100%}}@media only screen and (max-width:320px){#buddypress div.dir-search{clear:left;float:left;margin-top:0;text-align:left}#buddypress li#groups-order-select{clear:left;float:left}#buddypress ul.item-list li div.action{clear:left;float:left;margin-top:0;margin-left:70px;position:relative;top:0;right:0;text-align:left}#buddypress ul.item-list li div.item-desc{clear:left;float:left;margin:10px 0 0;width:auto}#buddypress li div.item{margin-left: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-left:0}}@media only screen and (max-width:240px){#buddypress div.dir-search{float:left;margin:0}#buddypress div.dir-search input[type=text]{width:50%}#buddypress li#groups-order-select{float:left}#buddypress ul.item-list li img.avatar{width:30px;height:auto}#buddypress li div.item,#buddypress ul.item-list li div.action{margin-left:45px}h1 a.bp-title-button{clear:left;float:left;margin:10px 0 20px}}
bp-templates/bp-legacy/js/buddypress.js CHANGED
@@ -1160,7 +1160,7 @@ jq(document).ready( function() {
1160
 
1161
  settings_div.hide().removeClass( 'field-visibility-settings-open' )
1162
  .siblings( '.field-visibility-settings-toggle' )
1163
- .children( '.current-visibility-level' ).text( vis_setting_text ).end()
1164
  .show().removeClass( 'field-visibility-settings-hide' );
1165
  } );
1166
 
1160
 
1161
  settings_div.hide().removeClass( 'field-visibility-settings-open' )
1162
  .siblings( '.field-visibility-settings-toggle' )
1163
+ .find( '.current-visibility-level' ).text( vis_setting_text ).end()
1164
  .show().removeClass( 'field-visibility-settings-hide' );
1165
  } );
1166
 
bp-templates/bp-legacy/js/buddypress.min.js CHANGED
@@ -1 +1 @@
1
- function bp_get_directory_preference(e,t){var i={filter:"",scope:"",extras:""};if(!directoryPreferences.hasOwnProperty(e)){var a={};for(var s in i)i.hasOwnProperty(s)&&(a[s]=i[s]);directoryPreferences[e]=a}return BP_DTheme.store_filter_settings&&(directoryPreferences[e][t]=jq.cookie("bp-"+e+"-"+t)),directoryPreferences[e][t]}function bp_set_directory_preference(e,t,i){var a={filter:"",scope:"",extras:""};if(!directoryPreferences.hasOwnProperty(e)){var s={};for(var r in a)a.hasOwnProperty(r)&&(s[r]=a[r]);directoryPreferences[e]=s}BP_DTheme.store_filter_settings&&jq.cookie("bp-"+e+"-"+t,i,{path:"/",secure:"https:"===window.location.protocol}),directoryPreferences[e][t]=i}function bp_init_activity(){var e=bp_get_directory_preference("activity","scope"),t=bp_get_directory_preference("activity","filter");void 0!==t&&jq("#activity-filter-select").length&&jq('#activity-filter-select select option[value="'+t+'"]').prop("selected",!0),void 0!==e&&jq(".activity-type-tabs").length&&(jq(".activity-type-tabs li").each(function(){jq(this).removeClass("selected")}),jq("#activity-"+e+", .item-list-tabs li.current").addClass("selected"))}function bp_init_objects(e){jq(e).each(function(t){var i=bp_get_directory_preference(e[t],"scope"),a=bp_get_directory_preference(e[t],"filter");void 0!==a&&jq("#"+e[t]+"-order-select select").length&&jq("#"+e[t]+'-order-select select option[value="'+a+'"]').prop("selected",!0),void 0!==i&&jq("div."+e[t]).length&&(jq(".item-list-tabs li").each(function(){jq(this).removeClass("selected")}),jq("#"+e[t]+"-"+i+", #object-nav li.current").addClass("selected"))})}function bp_filter_request(e,t,i,a,s,r,n,o,c){if("activity"===e)return!1;null===i&&(i="all"),bp_set_directory_preference(e,"scope",i),bp_set_directory_preference(e,"filter",t),bp_set_directory_preference(e,"extras",n),jq(".item-list-tabs li").each(function(){jq(this).removeClass("selected")}),jq("#"+e+"-"+i+", #object-nav li.current").addClass("selected"),jq(".item-list-tabs li.selected").addClass("loading"),jq('.item-list-tabs select option[value="'+t+'"]').prop("selected",!0),"friends"!==e&&"group_members"!==e||(e="members"),bp_ajax_request&&bp_ajax_request.abort();var l={};l["bp-"+e+"-filter"]=bp_get_directory_preference(e,"filter"),l["bp-"+e+"-scope"]=bp_get_directory_preference(e,"scope");var d=encodeURIComponent(jq.param(l));bp_ajax_request=jq.post(ajaxurl,{action:e+"_filter",cookie:d,object:e,filter:t,search_terms:s,scope:i,page:r,extras:n,template:c},function(e){if("pag-bottom"===o&&jq("#subnav").length){var t=jq("#subnav").parent();jq("html,body").animate({scrollTop:t.offset().top},"slow",function(){jq(a).fadeOut(100,function(){jq(this).html(e),jq(this).fadeIn(100)})})}else jq(a).fadeOut(100,function(){jq(this).html(e),jq(this).fadeIn(100)});jq(".item-list-tabs li.selected").removeClass("loading")})}function bp_activity_request(e,t){bp_set_directory_preference("activity","scope",e),bp_set_directory_preference("activity","filter",t),jq(".item-list-tabs li").each(function(){jq(this).removeClass("selected loading")}),jq("#activity-"+e+", .item-list-tabs li.current").addClass("selected"),jq("#object-nav.item-list-tabs li.selected, div.activity-type-tabs li.selected").addClass("loading"),jq('#activity-filter-select select option[value="'+t+'"]').prop("selected",!0),jq(".widget_bp_activity_widget h2 span.ajax-loader").show(),bp_ajax_request&&bp_ajax_request.abort();var i={"bp-activity-filter":bp_get_directory_preference("activity","filter"),"bp-activity-scope":bp_get_directory_preference("activity","scope")},a=encodeURIComponent(jq.param(i));bp_ajax_request=jq.post(ajaxurl,{action:"activity_widget_filter",cookie:a,_wpnonce_activity_filter:jq("#_wpnonce_activity_filter").val(),scope:e,filter:t},function(e){jq(".widget_bp_activity_widget h2 span.ajax-loader").hide(),jq("div.activity").fadeOut(100,function(){jq(this).html(e.contents),jq(this).fadeIn(100),bp_legacy_theme_hide_comments()}),void 0!==e.feed_url&&jq(".directory #subnav li.feed a, .home-page #subnav li.feed a").attr("href",e.feed_url),jq(".item-list-tabs li.selected").removeClass("loading")},"json")}function bp_legacy_theme_hide_comments(){var e,t,i,a=jq("div.activity-comments");if(!a.length)return!1;a.each(function(){jq(this).children("ul").children("li").length<5||(comments_div=jq(this),e=comments_div.parents("#activity-stream > li"),t=jq(this).children("ul").children("li"),i=" ",jq("#"+e.attr("id")+" li").length&&(i=jq("#"+e.attr("id")+" li").length),t.each(function(a){a<t.length-5&&(jq(this).hide(),a||jq(this).before('<li class="show-all"><a href="#'+e.attr("id")+'/show-all/">'+BP_DTheme.show_x_comments.replace("%d",i)+"</a></li>"))}))})}function checkAll(){var e,t=document.getElementsByTagName("input");for(e=0;e<t.length;e++)"checkbox"===t[e].type&&(""===$("check_all").checked?t[e].checked="":t[e].checked="checked")}function clear(e){if(e=document.getElementById(e)){var t=e.getElementsByTagName("INPUT"),i=e.getElementsByTagName("OPTION"),a=0;if(t)for(a=0;a<t.length;a++)t[a].checked="";if(i)for(a=0;a<i.length;a++)i[a].selected=!1}}function bp_get_cookies(){var e,t,i,a,s,r=document.cookie.split(";"),n={};for(e=0;e<r.length;e++)i=(t=r[e]).indexOf("="),a=jq.trim(unescape(t.slice(0,i))),s=unescape(t.slice(i+1)),0===a.indexOf("bp-")&&(n[a]=s);return encodeURIComponent(jq.param(n))}function bp_get_query_var(e,t){var i={};return(t=void 0===t?location.search.substr(1).split("&"):t.split("?")[1].split("&")).forEach(function(e){i[e.split("=")[0]]=e.split("=")[1]&&decodeURIComponent(e.split("=")[1])}),!(!i.hasOwnProperty(e)||null==i[e])&&i[e]}var jq=jQuery,bp_ajax_request=null,newest_activities="",activity_last_recorded=0,directoryPreferences={};jq(document).ready(function(){var e=1;bp_init_activity();var t=["members","groups","blogs","group_members"],i=jq("#whats-new");if(bp_init_objects(t),i.length&&bp_get_querystring("r")){var a=i.val();jq("#whats-new-options").slideDown(),i.animate({height:"3.8em"}),jq.scrollTo(i,500,{offset:-125,easing:"swing"}),i.val("").focus().val(a)}else jq("#whats-new-options").hide();if(i.focus(function(){jq("#whats-new-options").slideDown(),jq(this).animate({height:"3.8em"}),jq("#aw-whats-new-submit").prop("disabled",!1),jq(this).parent().addClass("active"),jq("#whats-new-content").addClass("active");var e=jq("form#whats-new-form"),t=jq("#activity-all");e.hasClass("submitted")&&e.removeClass("submitted"),t.length&&(t.hasClass("selected")?"-1"!==jq("#activity-filter-select select").val()&&(jq("#activity-filter-select select").val("-1"),jq("#activity-filter-select select").trigger("change")):(jq("#activity-filter-select select").val("-1"),t.children("a").trigger("click")))}),jq("#whats-new-form").on("focusout",function(e){var t=jq(this);setTimeout(function(){if(!t.find(":hover").length){if(""!==i.val())return;i.animate({height:"2.2em"}),jq("#whats-new-options").slideUp(),jq("#aw-whats-new-submit").prop("disabled",!0),jq("#whats-new-content").removeClass("active"),i.parent().removeClass("active")}},0)}),jq("#aw-whats-new-submit").on("click",function(){var e,t=0,i=jq(this),a=i.closest("form#whats-new-form"),s={};return jq.each(a.serializeArray(),function(e,t){"_"!==t.name.substr(0,1)&&"whats-new"!==t.name.substr(0,9)&&(s[t.name]?jq.isArray(s[t.name])?s[t.name].push(t.value):s[t.name]=new Array(s[t.name],t.value):s[t.name]=t.value)}),a.find("*").each(function(){(jq.nodeName(this,"textarea")||jq.nodeName(this,"input"))&&jq(this).prop("disabled",!0)}),jq("div.error").remove(),i.addClass("loading"),i.prop("disabled",!0),a.addClass("submitted"),object="",item_id=jq("#whats-new-post-in").val(),content=jq("#whats-new").val(),firstrow=jq("#buddypress ul.activity-list li").first(),activity_row=firstrow,timestamp=null,firstrow.length&&(activity_row.hasClass("load-newest")&&(activity_row=firstrow.next()),timestamp=activity_row.prop("class").match(/date-recorded-([0-9]+)/)),timestamp&&(t=timestamp[1]),item_id>0&&(object=jq("#whats-new-post-object").val()),e=jq.extend({action:"post_update",cookie:bp_get_cookies(),_wpnonce_post_update:jq("#_wpnonce_post_update").val(),content:content,object:object,item_id:item_id,since:t,_bp_as_nonce:jq("#_bp_as_nonce").val()||""},s),jq.post(ajaxurl,e,function(e){if(a.find("*").each(function(){(jq.nodeName(this,"textarea")||jq.nodeName(this,"input"))&&jq(this).prop("disabled",!1)}),e[0]+e[1]==="-1")a.prepend(e.substr(2,e.length)),jq("#"+a.attr("id")+" div.error").hide().fadeIn(200);else{if(0===jq("ul.activity-list").length&&(jq("div.error").slideUp(100).remove(),jq("#message").slideUp(100).remove(),jq("div.activity").append('<ul id="activity-stream" class="activity-list item-list">')),firstrow.hasClass("load-newest")&&firstrow.remove(),jq("#activity-stream").prepend(e),t||jq("#activity-stream li:first").addClass("new-update just-posted"),0!==jq("#latest-update").length){var i=jq("#activity-stream li.new-update .activity-content .activity-inner p").html(),s=jq("#activity-stream li.new-update .activity-content .activity-header p a.view").attr("href"),r="";""!==jq("#activity-stream li.new-update .activity-content .activity-inner p").text()&&(r=i+" "),r+='<a href="'+s+'" rel="nofollow">'+BP_DTheme.view+"</a>",jq("#latest-update").slideUp(300,function(){jq("#latest-update").html(r),jq("#latest-update").slideDown(300)})}jq("li.new-update").hide().slideDown(300),jq("li.new-update").removeClass("new-update"),jq("#whats-new").val(""),a.get(0).reset(),newest_activities="",activity_last_recorded=0}jq("#whats-new-options").slideUp(),jq("#whats-new-form textarea").animate({height:"2.2em"}),jq("#aw-whats-new-submit").prop("disabled",!0).removeClass("loading"),jq("#whats-new-content").removeClass("active")}),!1}),jq("div.activity-type-tabs").on("click",function(e){var t,i,a=jq(e.target).parent();if("STRONG"===e.target.nodeName||"SPAN"===e.target.nodeName)a=a.parent();else if("A"!==e.target.nodeName)return!1;return t=a.attr("id").substr(9,a.attr("id").length),i=jq("#activity-filter-select select").val(),"mentions"===t&&jq("#"+a.attr("id")+" a strong").remove(),bp_activity_request(t,i),!1}),jq("#activity-filter-select select").change(function(){var e,t=jq("div.activity-type-tabs li.selected"),i=jq(this).val();return e=t.length?t.attr("id").substr(9,t.attr("id").length):null,bp_activity_request(e,i),!1}),jq("div.activity").on("click",function(t){var i,a,s,r,n,o,c,l,d,p,u=jq(t.target);return u.hasClass("fav")||u.hasClass("unfav")?!u.hasClass("loading")&&(i=u.hasClass("fav")?"fav":"unfav",a=u.closest(".activity-item"),s=a.attr("id").substr(9,a.attr("id").length),c=bp_get_query_var("_wpnonce",u.attr("href")),u.addClass("loading"),jq.post(ajaxurl,{action:"activity_mark_"+i,cookie:bp_get_cookies(),id:s,nonce:c},function(e){u.removeClass("loading"),u.fadeOut(200,function(){jq(this).html(e),jq(this).attr("title","fav"===i?BP_DTheme.remove_fav:BP_DTheme.mark_as_fav),jq(this).fadeIn(200)}),"fav"===i?(jq(".item-list-tabs #activity-favs-personal-li").length||(jq(".item-list-tabs #activity-favorites").length||jq(".item-list-tabs ul #activity-mentions").before('<li id="activity-favorites"><a href="#">'+BP_DTheme.my_favs+" <span>0</span></a></li>"),jq(".item-list-tabs ul #activity-favorites span").html(Number(jq(".item-list-tabs ul #activity-favorites span").html())+1)),u.removeClass("fav"),u.addClass("unfav")):(u.removeClass("unfav"),u.addClass("fav"),jq(".item-list-tabs ul #activity-favorites span").html(Number(jq(".item-list-tabs ul #activity-favorites span").html())-1),Number(jq(".item-list-tabs ul #activity-favorites span").html())||(jq(".item-list-tabs ul #activity-favorites").hasClass("selected")&&bp_activity_request(null,null),jq(".item-list-tabs ul #activity-favorites").remove())),"activity-favorites"===jq(".item-list-tabs li.selected").attr("id")&&u.closest(".activity-item").slideUp(100)}),!1):u.hasClass("delete-activity")?(r=u.parents("div.activity ul li"),n=r.attr("id").substr(9,r.attr("id").length),o=u.attr("href"),c=o.split("_wpnonce="),l=r.prop("class").match(/date-recorded-([0-9]+)/),c=c[1],u.addClass("loading"),jq.post(ajaxurl,{action:"delete_activity",cookie:bp_get_cookies(),id:n,_wpnonce:c},function(e){e[0]+e[1]==="-1"?(r.prepend(e.substr(2,e.length)),r.children("#message").hide().fadeIn(300)):(r.slideUp(300),l&&activity_last_recorded===l[1]&&(newest_activities="",activity_last_recorded=0))}),!1):u.hasClass("spam-activity")?(r=u.parents("div.activity ul li"),l=r.prop("class").match(/date-recorded-([0-9]+)/),u.addClass("loading"),jq.post(ajaxurl,{action:"bp_spam_activity",cookie:encodeURIComponent(document.cookie),id:r.attr("id").substr(9,r.attr("id").length),_wpnonce:u.attr("href").split("_wpnonce=")[1]},function(e){e[0]+e[1]==="-1"?(r.prepend(e.substr(2,e.length)),r.children("#message").hide().fadeIn(300)):(r.slideUp(300),l&&activity_last_recorded===l[1]&&(newest_activities="",activity_last_recorded=0))}),!1):u.parent().hasClass("load-more")?(bp_ajax_request&&bp_ajax_request.abort(),jq("#buddypress li.load-more").addClass("loading"),d=e+1,p=[],jq(".activity-list li.just-posted").each(function(){p.push(jq(this).attr("id").replace("activity-",""))}),load_more_args={action:"activity_get_older_updates",cookie:bp_get_cookies(),page:d,exclude_just_posted:p.join(",")},load_more_search=bp_get_querystring("s"),load_more_search&&(load_more_args.search_terms=load_more_search),bp_ajax_request=jq.post(ajaxurl,load_more_args,function(t){jq("#buddypress li.load-more").removeClass("loading"),e=d,jq("#buddypress ul.activity-list").append(t.contents),u.parent().hide()},"json"),!1):void(u.parent().hasClass("load-newest")&&(t.preventDefault(),u.parent().hide(),activity_html=jq.parseHTML(newest_activities),jq.each(activity_html,function(e,t){"LI"===t.nodeName&&jq(t).hasClass("just-posted")&&jq("#"+jq(t).attr("id")).length&&jq("#"+jq(t).attr("id")).remove()}),jq("#buddypress ul.activity-list").prepend(newest_activities),newest_activities=""))}),jq("div.activity").on("click",".activity-read-more a",function(e){var t,i,a=jq(e.target),s=a.parent().attr("id").split("-"),r=s[3],n=s[0];return t="acomment"===n?"acomment-content":"activity-inner",i=jq("#"+n+"-"+r+" ."+t+":first"),jq(a).addClass("loading"),jq.post(ajaxurl,{action:"get_single_activity_content",activity_id:r},function(e){jq(i).slideUp(300).html(e).slideDown(300)}),!1}),jq("form.ac-form").hide(),jq(".activity-comments").length&&bp_legacy_theme_hide_comments(),jq("div.activity").on("click",function(e){var t,i,a,s,r,n,o,c,l,d,p,u,m,h,_,v=jq(e.target);return v.hasClass("acomment-reply")||v.parent().hasClass("acomment-reply")?(v.parent().hasClass("acomment-reply")&&(v=v.parent()),t=v.attr("id"),i=t.split("-"),a=i[2],s=v.attr("href").substr(10,v.attr("href").length),(r=jq("#ac-form-"+a)).css("display","none"),r.removeClass("root"),jq(".ac-form").hide(),r.children("div").each(function(){jq(this).hasClass("error")&&jq(this).hide()}),"comment"!==i[1]?jq("#acomment-"+s).append(r):jq("#activity-"+a+" .activity-comments").append(r),r.parent().hasClass("activity-comments")&&r.addClass("root"),r.slideDown(200),jq.scrollTo(r,500,{offset:-100,easing:"swing"}),jq("#ac-form-"+i[2]+" textarea").focus(),!1):"ac_form_submit"===v.attr("name")?(r=v.parents("form"),n=r.parent(),o=r.attr("id").split("-"),c=n.hasClass("activity-comments")?o[2]:n.attr("id").split("-")[1],content=jq("#"+r.attr("id")+" textarea"),jq("#"+r.attr("id")+" div.error").hide(),v.addClass("loading").prop("disabled",!0),content.addClass("loading").prop("disabled",!0),l={action:"new_activity_comment",cookie:bp_get_cookies(),_wpnonce_new_activity_comment:jq("#_wpnonce_new_activity_comment").val(),comment_id:c,form_id:o[2],content:content.val()},(d=jq("#_bp_as_nonce_"+c).val())&&(l["_bp_as_nonce_"+c]=d),jq.post(ajaxurl,l,function(e){if(v.removeClass("loading"),content.removeClass("loading"),e[0]+e[1]==="-1")r.append(jq(e.substr(2,e.length)).hide().fadeIn(200));else{var t=r.parent();r.fadeOut(200,function(){0===t.children("ul").length&&(t.hasClass("activity-comments")?t.prepend("<ul></ul>"):t.append("<ul></ul>"));var i=jq.trim(e);t.children("ul").append(jq(i).hide().fadeIn(200)),r.children("textarea").val(""),t.parent().addClass("has-comments")}),jq("#"+r.attr("id")+" textarea").val(""),u=Number(jq("#activity-"+o[2]+" a.acomment-reply span").html())+1,jq("#activity-"+o[2]+" a.acomment-reply span").html(u),(p=t.parents(".activity-comments").find(".show-all a"))&&p.html(BP_DTheme.show_x_comments.replace("%d",u))}jq(v).prop("disabled",!1),jq(content).prop("disabled",!1)}),!1):v.hasClass("acomment-delete")?(m=v.attr("href"),h=v.parent().parent(),r=h.parents("div.activity-comments").children("form"),_=m.split("_wpnonce="),_=_[1],c=m.split("cid="),c=c[1].split("&"),c=c[0],v.addClass("loading"),jq(".activity-comments ul .error").remove(),h.parents(".activity-comments").append(r),jq.post(ajaxurl,{action:"delete_activity_comment",cookie:bp_get_cookies(),_wpnonce:_,id:c},function(e){if(e[0]+e[1]==="-1")h.prepend(jq(e.substr(2,e.length)).hide().fadeIn(200));else{var t,i,a,s=jq("#"+h.attr("id")+" ul").children("li"),r=0;jq(s).each(function(){jq(this).is(":hidden")||r++}),h.fadeOut(200,function(){h.remove()}),i=(t=jq("#"+h.parents("#activity-stream > li").attr("id")+" a.acomment-reply span")).html()-(1+r),t.html(i),(a=h.parents(".activity-comments").find(".show-all a"))&&a.html(BP_DTheme.show_x_comments.replace("%d",i)),0===i&&jq(h.parents("#activity-stream > li")).removeClass("has-comments")}}),!1):v.hasClass("spam-activity-comment")?(m=v.attr("href"),h=v.parent().parent(),v.addClass("loading"),jq(".activity-comments ul div.error").remove(),h.parents(".activity-comments").append(h.parents(".activity-comments").children("form")),jq.post(ajaxurl,{action:"bp_spam_activity_comment",cookie:encodeURIComponent(document.cookie),_wpnonce:m.split("_wpnonce=")[1],id:m.split("cid=")[1].split("&")[0]},function(e){if(e[0]+e[1]==="-1")h.prepend(jq(e.substr(2,e.length)).hide().fadeIn(200));else{var t,i=jq("#"+h.attr("id")+" ul").children("li"),a=0;jq(i).each(function(){jq(this).is(":hidden")||a++}),h.fadeOut(200),t=h.parents("#activity-stream > li"),jq("#"+t.attr("id")+" a.acomment-reply span").html(jq("#"+t.attr("id")+" a.acomment-reply span").html()-(1+a))}}),!1):v.parent().hasClass("show-all")?(v.parent().addClass("loading"),setTimeout(function(){v.parent().parent().children("li").fadeIn(200,function(){v.parent().remove()})},600),!1):v.hasClass("ac-reply-cancel")?(jq(v).closest(".ac-form").slideUp(200),!1):void 0}),jq(document).keydown(function(e){(e=e||window.event).target?element=e.target:e.srcElement&&(element=e.srcElement),3===element.nodeType&&(element=element.parentNode),!0!==e.ctrlKey&&!0!==e.altKey&&!0!==e.metaKey&&27===(e.keyCode?e.keyCode:e.which)&&"TEXTAREA"===element.tagName&&jq(element).hasClass("ac-input")&&jq(element).parent().parent().parent().slideUp(200)}),jq(".dir-search, .groups-members-search").on("click",function(e){if(!jq(this).hasClass("no-ajax")){var t,i,a,s=jq(e.target);if("submit"===s.attr("type")){t=jq(".item-list-tabs li.selected").attr("id").split("-")[0],i=null,a=s.parent().find("#"+t+"_search").val(),"groups-members-search"===e.currentTarget.className&&(t="group_members",i="groups/single/members");var r=bp_get_directory_preference(t,"scope");return bp_filter_request(t,bp_get_directory_preference(t,"filter"),r,"div."+t,a,1,bp_get_directory_preference(t,"extras"),null,i),!1}}}),jq("div.item-list-tabs").on("click",function(e){if(jq("body").hasClass("type")&&jq("body").hasClass("directory")&&jq(this).addClass("no-ajax"),!jq(this).hasClass("no-ajax")&&!jq(e.target).hasClass("no-ajax")){var t,i,a,s="SPAN"===e.target.nodeName?e.target.parentNode:e.target,r=jq(s).parent();return"LI"!==r[0].nodeName||r.hasClass("last")?void 0:(t=r.attr("id").split("-"),"activity"!==(i=t[0])&&(a=t[1],bp_filter_request(i,jq("#"+i+"-order-select select").val(),a,"div."+i,jq("#"+i+"_search").val(),1,bp_get_directory_preference(i,"extras")),!1))}}),jq("li.filter select").change(function(){var e,t,i,a,s,r,n;return t=(e=jq(jq(".item-list-tabs li.selected").length?".item-list-tabs li.selected":this).attr("id").split("-"))[0],i=e[1],a=jq(this).val(),s=!1,r=null,jq(".dir-search input").length&&(s=jq(".dir-search input").val()),(n=jq(".groups-members-search input")).length&&(s=n.val(),t="members",i="groups"),"members"===t&&"groups"===i&&(t="group_members",r="groups/single/members"),"friends"===t&&(t="members"),bp_filter_request(t,a,i,"div."+t,s,1,bp_get_directory_preference(t,"extras"),null,r),!1}),jq("#buddypress").on("click",function(e){var t,i,a,s,r,n,o,c,l=jq(e.target);if(l.hasClass("button"))return!0;if(l.parent().parent().hasClass("pagination")&&!l.parent().parent().hasClass("no-ajax")){if(l.hasClass("dots")||l.hasClass("current"))return!1;i=(t=jq(jq(".item-list-tabs li.selected").length?".item-list-tabs li.selected":"li.filter select").attr("id").split("-"))[0],a=!1,s=jq(l).closest(".pagination-links").attr("id"),r=null,jq("div.dir-search input").length&&(a=!(a=jq(".dir-search input")).val()&&bp_get_querystring(a.attr("name"))?jq(".dir-search input").prop("placeholder"):a.val()),n=jq(l).hasClass("next")||jq(l).hasClass("prev")?jq(".pagination span.current").html():jq(l).html(),n=Number(n.replace(/\D/g,"")),jq(l).hasClass("next")?n++:jq(l).hasClass("prev")&&n--,(o=jq(".groups-members-search input")).length&&(a=o.val(),i="members"),"members"===i&&"groups"===t[1]&&(i="group_members",r="groups/single/members"),"admin"===i&&jq("body").hasClass("membership-requests")&&(i="requests"),c=-1!==s.indexOf("pag-bottom")?"pag-bottom":null;var d=bp_get_directory_preference(i,"scope");return bp_filter_request(i,bp_get_directory_preference(i,"filter"),d,"div."+i,a,n,bp_get_directory_preference(i,"extras"),c,r),!1}}),jq("#send-invite-form").on("click","#invite-list input",function(){var e,t,i=jq("#send-invite-form > .invite").length;jq(".ajax-loader").toggle(),i&&jq(this).parents("ul").find("input").prop("disabled",!0),e=jq(this).val(),t=!0===jq(this).prop("checked")?"invite":"uninvite",i||jq(".item-list-tabs li.selected").addClass("loading"),jq.post(ajaxurl,{action:"groups_invite_user",friend_action:t,cookie:bp_get_cookies(),_wpnonce:jq("#_wpnonce_invite_uninvite_user").val(),friend_id:e,group_id:jq("#group_id").val()},function(a){jq("#message")&&jq("#message").hide(),i?bp_filter_request("invite","bp-invite-filter","bp-invite-scope","div.invite",!1,1,"","",""):(jq(".ajax-loader").toggle(),"invite"===t?jq("#friend-list").append(a):"uninvite"===t&&jq("#friend-list li#uid-"+e).remove(),jq(".item-list-tabs li.selected").removeClass("loading"))})}),jq("#send-invite-form").on("click","a.remove",function(){var e=jq("#send-invite-form > .invite").length,t=jq(this).attr("id");return jq(".ajax-loader").toggle(),t=t.split("-"),t=t[1],jq.post(ajaxurl,{action:"groups_invite_user",friend_action:"uninvite",cookie:bp_get_cookies(),_wpnonce:jq("#_wpnonce_invite_uninvite_user").val(),friend_id:t,group_id:jq("#group_id").val()},function(i){e?bp_filter_request("invite","bp-invite-filter","bp-invite-scope","div.invite",!1,1,"","",""):(jq(".ajax-loader").toggle(),jq("#friend-list #uid-"+t).remove(),jq("#invite-list #f-"+t).prop("checked",!1))}),!1}),jq(".visibility-toggle-link").on("click",function(e){e.preventDefault(),jq(this).attr("aria-expanded","true").parent().hide().addClass("field-visibility-settings-hide").siblings(".field-visibility-settings").show().addClass("field-visibility-settings-open")}),jq(".field-visibility-settings-close").on("click",function(e){e.preventDefault(),jq(".visibility-toggle-link").attr("aria-expanded","false");var t=jq(this).parent(),i=t.find("input:checked").parent().text();t.hide().removeClass("field-visibility-settings-open").siblings(".field-visibility-settings-toggle").children(".current-visibility-level").text(i).end().show().removeClass("field-visibility-settings-hide")}),jq("#profile-edit-form input:not(:submit), #profile-edit-form textarea, #profile-edit-form select, #signup_form input:not(:submit), #signup_form textarea, #signup_form select").change(function(){var e=!0;jq("#profile-edit-form input:submit, #signup_form input:submit").on("click",function(){e=!1}),window.onbeforeunload=function(t){if(e)return BP_DTheme.unsaved_changes}}),jq("#friend-list a.accept, #friend-list a.reject").on("click",function(){var e,t=jq(this),i=jq(this).parents("#friend-list li"),a=jq(this).parents("li div.action"),s=i.attr("id").substr(11,i.attr("id").length),r=t.attr("href").split("_wpnonce=")[1];return!jq(this).hasClass("accepted")&&!jq(this).hasClass("rejected")&&(jq(this).hasClass("accept")?(e="accept_friendship",a.children("a.reject").css("visibility","hidden")):(e="reject_friendship",a.children("a.accept").css("visibility","hidden")),t.addClass("loading"),jq.post(ajaxurl,{action:e,cookie:bp_get_cookies(),id:s,_wpnonce:r},function(e){t.removeClass("loading"),e[0]+e[1]==="-1"?(i.prepend(e.substr(2,e.length)),i.children("#message").hide().fadeIn(200)):t.fadeOut(100,function(){jq(this).hasClass("accept")?(a.children("a.reject").hide(),jq(this).html(BP_DTheme.accepted).contents().unwrap()):(a.children("a.accept").hide(),jq(this).html(BP_DTheme.rejected).contents().unwrap())})}),!1)}),jq("#members-dir-list, #members-group-list, #item-header").on("click",".friendship-button a",function(){jq(this).parent().addClass("loading");var e=jq(this).attr("id"),t=jq(this).attr("href"),i=jq(this);return e=e.split("-"),e=e[1],t=t.split("?_wpnonce="),t=t[1].split("&"),t=t[0],jq.post(ajaxurl,{action:"addremove_friend",cookie:bp_get_cookies(),fid:e,_wpnonce:t},function(e){var t=i.attr("rel");parentdiv=i.parent(),"add"===t?jq(parentdiv).fadeOut(200,function(){parentdiv.removeClass("add_friend"),parentdiv.removeClass("loading"),parentdiv.addClass("pending_friend"),parentdiv.fadeIn(200).html(e)}):"remove"===t&&jq(parentdiv).fadeOut(200,function(){parentdiv.removeClass("remove_friend"),parentdiv.removeClass("loading"),parentdiv.addClass("add"),parentdiv.fadeIn(200).html(e)})}),!1}),jq("#buddypress").on("click",".group-button .leave-group",function(){if(!1===confirm(BP_DTheme.leave_group_confirm))return!1}),jq("#groups-dir-list").on("click",".group-button a",function(){var e=jq(this).parent().attr("id"),t=jq(this).attr("href"),i=jq(this);return e=e.split("-"),e=e[1],t=t.split("?_wpnonce="),t=t[1].split("&"),t=t[0],(!i.hasClass("leave-group")||!1!==confirm(BP_DTheme.leave_group_confirm))&&(jq.post(ajaxurl,{action:"joinleave_group",cookie:bp_get_cookies(),gid:e,_wpnonce:t},function(e){var t=i.parent();jq("body.directory").length?jq(t).fadeOut(200,function(){t.fadeIn(200).html(e);var a=jq("#groups-personal span"),s=1;i.hasClass("leave-group")?(t.hasClass("hidden")&&t.closest("li").slideUp(200),s=0):i.hasClass("request-membership")&&(s=!1),a.length&&!1!==s&&(s?a.text(1+(a.text()>>0)):a.text((a.text()>>0)-1))}):window.location.reload()}),!1)}),jq("#groups-list li.hidden").each(function(){"none"===jq(this).css("display")&&jq(this).css("cssText","display: list-item !important")}),jq("#buddypress").on("click",".pending",function(){return!1}),jq("body").hasClass("register")){var s=jq("#signup_with_blog");s.prop("checked")||jq("#blog-details").toggle(),s.change(function(){jq("#blog-details").toggle()})}jq(".message-search").on("click",function(e){if(!jq(this).hasClass("no-ajax")){var t,i=jq(e.target);if("submit"===i.attr("type")||"button"===i.attr("type")){var a=bp_get_directory_preference(t="messages","scope"),s=bp_get_directory_preference(t,"filter"),r=bp_get_directory_preference(t,"extras");return bp_filter_request(t,s,a,"div."+t,jq("#messages_search").val(),1,r),!1}}}),jq("#send_reply_button").click(function(){var e=jq("#messages_order").val()||"ASC",t=jq("#message-recipients").offset(),i=jq("#send_reply_button");return jq(i).addClass("loading").prop("disabled",!0),jq.post(ajaxurl,{action:"messages_send_reply",cookie:bp_get_cookies(),_wpnonce:jq("#send_message_nonce").val(),content:jq("#message_content").val(),send_to:jq("#send_to").val(),subject:jq("#subject").val(),thread_id:jq("#thread_id").val()},function(a){a[0]+a[1]==="-1"?jq("#send-reply").prepend(a.substr(2,a.length)):(jq("#send-reply #message").remove(),jq("#message_content").val(""),"ASC"===e?jq("#send-reply").before(a):(jq("#message-recipients").after(a),jq(window).scrollTop(t.top)),jq(".new-message").hide().slideDown(200,function(){jq(".new-message").removeClass("new-message")})),jq(i).removeClass("loading").prop("disabled",!1)}),!1}),jq("body.messages #item-body div.messages").on("change","#message-type-select",function(){var e=this.value,t=jq('td input[type="checkbox"]'),i="checked";switch(t.each(function(e){t[e].checked=""}),e){case"unread":t=jq('tr.unread td input[type="checkbox"]');break;case"read":t=jq('tr.read td input[type="checkbox"]');break;case"":i=""}t.each(function(e){t[e].checked=i})}),jq("#select-all-messages").click(function(e){this.checked?jq(".message-check").each(function(){this.checked=!0}):jq(".message-check").each(function(){this.checked=!1})}),jq("#messages-bulk-manage").attr("disabled","disabled"),jq("#messages-select").on("change",function(){jq("#messages-bulk-manage").attr("disabled",jq(this).val().length<=0)}),starAction=function(){var e=jq(this);return jq.post(ajaxurl,{action:"messages_star",message_id:e.data("message-id"),star_status:e.data("star-status"),nonce:e.data("star-nonce"),bulk:e.data("star-bulk")},function(t){1===parseInt(t,10)&&("unstar"===e.data("star-status")?(e.data("star-status","star"),e.removeClass("message-action-unstar").addClass("message-action-star"),e.find(".bp-screen-reader-text").text(BP_PM_Star.strings.text_star),1===BP_PM_Star.is_single_thread?e.attr("data-bp-tooltip",BP_PM_Star.strings.title_star):e.attr("data-bp-tooltip",BP_PM_Star.strings.title_star_thread)):(e.data("star-status","unstar"),e.removeClass("message-action-star").addClass("message-action-unstar"),e.find(".bp-screen-reader-text").text(BP_PM_Star.strings.text_unstar),1===BP_PM_Star.is_single_thread?e.attr("data-bp-tooltip",BP_PM_Star.strings.title_unstar):e.attr("data-bp-tooltip",BP_PM_Star.strings.title_unstar_thread)))}),!1},jq("#message-threads").on("click","td.thread-star a",starAction),jq("#message-thread").on("click",".message-star-actions a",starAction),jq("#message-threads td.bulk-select-check :checkbox").on("change",function(){var e=jq(this),t=e.closest("tr").find(".thread-star a");e.prop("checked")?"unstar"===t.data("star-status")?BP_PM_Star.star_counter++:BP_PM_Star.unstar_counter++:"unstar"===t.data("star-status")?BP_PM_Star.star_counter--:BP_PM_Star.unstar_counter--,BP_PM_Star.star_counter>0&&0===parseInt(BP_PM_Star.unstar_counter,10)?jq('option[value="star"]').hide():jq('option[value="star"]').show(),BP_PM_Star.unstar_counter>0&&0===parseInt(BP_PM_Star.star_counter,10)?jq('option[value="unstar"]').hide():jq('option[value="unstar"]').show()}),jq("#select-all-notifications").click(function(e){this.checked?jq(".notification-check").each(function(){this.checked=!0}):jq(".notification-check").each(function(){this.checked=!1})}),jq("#notification-bulk-manage").attr("disabled","disabled"),jq("#notification-select").on("change",function(){jq("#notification-bulk-manage").attr("disabled",jq(this).val().length<=0)}),jq("#close-notice").on("click",function(){return jq(this).addClass("loading"),jq("#sidebar div.error").remove(),jq.post(ajaxurl,{action:"messages_close_notice",notice_id:jq(".notice").attr("rel").substr(2,jq(".notice").attr("rel").length),nonce:jq("#close-notice-nonce").val()},function(e){jq("#close-notice").removeClass("loading"),e[0]+e[1]==="-1"?(jq(".notice").prepend(e.substr(2,e.length)),jq("#sidebar div.error").hide().fadeIn(200)):jq(".notice").slideUp(100)}),!1}),jq("#wp-admin-bar ul.main-nav li, #nav li").mouseover(function(){jq(this).addClass("sfhover")}),jq("#wp-admin-bar ul.main-nav li, #nav li").mouseout(function(){jq(this).removeClass("sfhover")}),jq("#wp-admin-bar-logout, a.logout").on("click",function(){jq.removeCookie("bp-activity-scope",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-activity-filter",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-activity-oldestpage",{path:"/",secure:"https:"===window.location.protocol});var e=["members","groups","blogs","forums"];jq(e).each(function(t){jq.removeCookie("bp-"+e[t]+"-scope",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-"+e[t]+"-filter",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-"+e[t]+"-extras",{path:"/",secure:"https:"===window.location.protocol})})}),jq("body").hasClass("no-js")&&jq("body").attr("class",jq("body").attr("class").replace(/no-js/,"js")),"undefined"!=typeof wp&&void 0!==wp.heartbeat&&void 0!==BP_DTheme.pulse&&(wp.heartbeat.interval(Number(BP_DTheme.pulse)),jq.fn.extend({"heartbeat-send":function(){return this.bind("heartbeat-send.buddypress")}}));var r=0;jq(document).on("heartbeat-send.buddypress",function(e,t){r=0,jq("#buddypress ul.activity-list li").first().prop("id")&&(timestamp=jq("#buddypress ul.activity-list li").first().prop("class").match(/date-recorded-([0-9]+)/),timestamp&&(r=timestamp[1])),(0===activity_last_recorded||Number(r)>activity_last_recorded)&&(activity_last_recorded=Number(r)),t.bp_activity_last_recorded=activity_last_recorded,last_recorded_search=bp_get_querystring("s"),last_recorded_search&&(t.bp_activity_last_recorded_search_terms=last_recorded_search)}),jq(document).on("heartbeat-tick",function(e,t){t.bp_activity_newest_activities&&(newest_activities=t.bp_activity_newest_activities.activities+newest_activities,activity_last_recorded=Number(t.bp_activity_newest_activities.last_recorded),jq("#buddypress ul.activity-list li").first().hasClass("load-newest")||jq("#buddypress ul.activity-list").prepend('<li class="load-newest"><a href="#newest">'+BP_DTheme.newest+"</a></li>"))})});
1
+ function bp_get_directory_preference(e,t){var i={filter:"",scope:"",extras:""};if(!directoryPreferences.hasOwnProperty(e)){var a={};for(var s in i)i.hasOwnProperty(s)&&(a[s]=i[s]);directoryPreferences[e]=a}return BP_DTheme.store_filter_settings&&(directoryPreferences[e][t]=jq.cookie("bp-"+e+"-"+t)),directoryPreferences[e][t]}function bp_set_directory_preference(e,t,i){var a={filter:"",scope:"",extras:""};if(!directoryPreferences.hasOwnProperty(e)){var s={};for(var r in a)a.hasOwnProperty(r)&&(s[r]=a[r]);directoryPreferences[e]=s}BP_DTheme.store_filter_settings&&jq.cookie("bp-"+e+"-"+t,i,{path:"/",secure:"https:"===window.location.protocol}),directoryPreferences[e][t]=i}function bp_init_activity(){var e=bp_get_directory_preference("activity","scope"),t=bp_get_directory_preference("activity","filter");void 0!==t&&jq("#activity-filter-select").length&&jq('#activity-filter-select select option[value="'+t+'"]').prop("selected",!0),void 0!==e&&jq(".activity-type-tabs").length&&(jq(".activity-type-tabs li").each(function(){jq(this).removeClass("selected")}),jq("#activity-"+e+", .item-list-tabs li.current").addClass("selected"))}function bp_init_objects(e){jq(e).each(function(t){var i=bp_get_directory_preference(e[t],"scope"),a=bp_get_directory_preference(e[t],"filter");void 0!==a&&jq("#"+e[t]+"-order-select select").length&&jq("#"+e[t]+'-order-select select option[value="'+a+'"]').prop("selected",!0),void 0!==i&&jq("div."+e[t]).length&&(jq(".item-list-tabs li").each(function(){jq(this).removeClass("selected")}),jq("#"+e[t]+"-"+i+", #object-nav li.current").addClass("selected"))})}function bp_filter_request(e,t,i,a,s,r,n,o,c){if("activity"===e)return!1;null===i&&(i="all"),bp_set_directory_preference(e,"scope",i),bp_set_directory_preference(e,"filter",t),bp_set_directory_preference(e,"extras",n),jq(".item-list-tabs li").each(function(){jq(this).removeClass("selected")}),jq("#"+e+"-"+i+", #object-nav li.current").addClass("selected"),jq(".item-list-tabs li.selected").addClass("loading"),jq('.item-list-tabs select option[value="'+t+'"]').prop("selected",!0),"friends"!==e&&"group_members"!==e||(e="members"),bp_ajax_request&&bp_ajax_request.abort();var l={};l["bp-"+e+"-filter"]=bp_get_directory_preference(e,"filter"),l["bp-"+e+"-scope"]=bp_get_directory_preference(e,"scope");var d=encodeURIComponent(jq.param(l));bp_ajax_request=jq.post(ajaxurl,{action:e+"_filter",cookie:d,object:e,filter:t,search_terms:s,scope:i,page:r,extras:n,template:c},function(e){if("pag-bottom"===o&&jq("#subnav").length){var t=jq("#subnav").parent();jq("html,body").animate({scrollTop:t.offset().top},"slow",function(){jq(a).fadeOut(100,function(){jq(this).html(e),jq(this).fadeIn(100)})})}else jq(a).fadeOut(100,function(){jq(this).html(e),jq(this).fadeIn(100)});jq(".item-list-tabs li.selected").removeClass("loading")})}function bp_activity_request(e,t){bp_set_directory_preference("activity","scope",e),bp_set_directory_preference("activity","filter",t),jq(".item-list-tabs li").each(function(){jq(this).removeClass("selected loading")}),jq("#activity-"+e+", .item-list-tabs li.current").addClass("selected"),jq("#object-nav.item-list-tabs li.selected, div.activity-type-tabs li.selected").addClass("loading"),jq('#activity-filter-select select option[value="'+t+'"]').prop("selected",!0),jq(".widget_bp_activity_widget h2 span.ajax-loader").show(),bp_ajax_request&&bp_ajax_request.abort();var i={"bp-activity-filter":bp_get_directory_preference("activity","filter"),"bp-activity-scope":bp_get_directory_preference("activity","scope")},a=encodeURIComponent(jq.param(i));bp_ajax_request=jq.post(ajaxurl,{action:"activity_widget_filter",cookie:a,_wpnonce_activity_filter:jq("#_wpnonce_activity_filter").val(),scope:e,filter:t},function(e){jq(".widget_bp_activity_widget h2 span.ajax-loader").hide(),jq("div.activity").fadeOut(100,function(){jq(this).html(e.contents),jq(this).fadeIn(100),bp_legacy_theme_hide_comments()}),void 0!==e.feed_url&&jq(".directory #subnav li.feed a, .home-page #subnav li.feed a").attr("href",e.feed_url),jq(".item-list-tabs li.selected").removeClass("loading")},"json")}function bp_legacy_theme_hide_comments(){var e,t,i,a=jq("div.activity-comments");if(!a.length)return!1;a.each(function(){jq(this).children("ul").children("li").length<5||(comments_div=jq(this),e=comments_div.parents("#activity-stream > li"),t=jq(this).children("ul").children("li"),i=" ",jq("#"+e.attr("id")+" li").length&&(i=jq("#"+e.attr("id")+" li").length),t.each(function(a){a<t.length-5&&(jq(this).hide(),a||jq(this).before('<li class="show-all"><a href="#'+e.attr("id")+'/show-all/">'+BP_DTheme.show_x_comments.replace("%d",i)+"</a></li>"))}))})}function checkAll(){var e,t=document.getElementsByTagName("input");for(e=0;e<t.length;e++)"checkbox"===t[e].type&&(""===$("check_all").checked?t[e].checked="":t[e].checked="checked")}function clear(e){if(e=document.getElementById(e)){var t=e.getElementsByTagName("INPUT"),i=e.getElementsByTagName("OPTION"),a=0;if(t)for(a=0;a<t.length;a++)t[a].checked="";if(i)for(a=0;a<i.length;a++)i[a].selected=!1}}function bp_get_cookies(){var e,t,i,a,s,r=document.cookie.split(";"),n={};for(e=0;e<r.length;e++)i=(t=r[e]).indexOf("="),a=jq.trim(unescape(t.slice(0,i))),s=unescape(t.slice(i+1)),0===a.indexOf("bp-")&&(n[a]=s);return encodeURIComponent(jq.param(n))}function bp_get_query_var(e,t){var i={};return(t=void 0===t?location.search.substr(1).split("&"):t.split("?")[1].split("&")).forEach(function(e){i[e.split("=")[0]]=e.split("=")[1]&&decodeURIComponent(e.split("=")[1])}),!(!i.hasOwnProperty(e)||null==i[e])&&i[e]}var jq=jQuery,bp_ajax_request=null,newest_activities="",activity_last_recorded=0,directoryPreferences={};jq(document).ready(function(){var e=1;bp_init_activity();var t=["members","groups","blogs","group_members"],i=jq("#whats-new");if(bp_init_objects(t),i.length&&bp_get_querystring("r")){var a=i.val();jq("#whats-new-options").slideDown(),i.animate({height:"3.8em"}),jq.scrollTo(i,500,{offset:-125,easing:"swing"}),i.val("").focus().val(a)}else jq("#whats-new-options").hide();if(i.focus(function(){jq("#whats-new-options").slideDown(),jq(this).animate({height:"3.8em"}),jq("#aw-whats-new-submit").prop("disabled",!1),jq(this).parent().addClass("active"),jq("#whats-new-content").addClass("active");var e=jq("form#whats-new-form"),t=jq("#activity-all");e.hasClass("submitted")&&e.removeClass("submitted"),t.length&&(t.hasClass("selected")?"-1"!==jq("#activity-filter-select select").val()&&(jq("#activity-filter-select select").val("-1"),jq("#activity-filter-select select").trigger("change")):(jq("#activity-filter-select select").val("-1"),t.children("a").trigger("click")))}),jq("#whats-new-form").on("focusout",function(e){var t=jq(this);setTimeout(function(){if(!t.find(":hover").length){if(""!==i.val())return;i.animate({height:"2.2em"}),jq("#whats-new-options").slideUp(),jq("#aw-whats-new-submit").prop("disabled",!0),jq("#whats-new-content").removeClass("active"),i.parent().removeClass("active")}},0)}),jq("#aw-whats-new-submit").on("click",function(){var e,t=0,i=jq(this),a=i.closest("form#whats-new-form"),s={};return jq.each(a.serializeArray(),function(e,t){"_"!==t.name.substr(0,1)&&"whats-new"!==t.name.substr(0,9)&&(s[t.name]?jq.isArray(s[t.name])?s[t.name].push(t.value):s[t.name]=new Array(s[t.name],t.value):s[t.name]=t.value)}),a.find("*").each(function(){(jq.nodeName(this,"textarea")||jq.nodeName(this,"input"))&&jq(this).prop("disabled",!0)}),jq("div.error").remove(),i.addClass("loading"),i.prop("disabled",!0),a.addClass("submitted"),object="",item_id=jq("#whats-new-post-in").val(),content=jq("#whats-new").val(),firstrow=jq("#buddypress ul.activity-list li").first(),activity_row=firstrow,timestamp=null,firstrow.length&&(activity_row.hasClass("load-newest")&&(activity_row=firstrow.next()),timestamp=activity_row.prop("class").match(/date-recorded-([0-9]+)/)),timestamp&&(t=timestamp[1]),item_id>0&&(object=jq("#whats-new-post-object").val()),e=jq.extend({action:"post_update",cookie:bp_get_cookies(),_wpnonce_post_update:jq("#_wpnonce_post_update").val(),content:content,object:object,item_id:item_id,since:t,_bp_as_nonce:jq("#_bp_as_nonce").val()||""},s),jq.post(ajaxurl,e,function(e){if(a.find("*").each(function(){(jq.nodeName(this,"textarea")||jq.nodeName(this,"input"))&&jq(this).prop("disabled",!1)}),e[0]+e[1]==="-1")a.prepend(e.substr(2,e.length)),jq("#"+a.attr("id")+" div.error").hide().fadeIn(200);else{if(0===jq("ul.activity-list").length&&(jq("div.error").slideUp(100).remove(),jq("#message").slideUp(100).remove(),jq("div.activity").append('<ul id="activity-stream" class="activity-list item-list">')),firstrow.hasClass("load-newest")&&firstrow.remove(),jq("#activity-stream").prepend(e),t||jq("#activity-stream li:first").addClass("new-update just-posted"),0!==jq("#latest-update").length){var i=jq("#activity-stream li.new-update .activity-content .activity-inner p").html(),s=jq("#activity-stream li.new-update .activity-content .activity-header p a.view").attr("href"),r="";""!==jq("#activity-stream li.new-update .activity-content .activity-inner p").text()&&(r=i+" "),r+='<a href="'+s+'" rel="nofollow">'+BP_DTheme.view+"</a>",jq("#latest-update").slideUp(300,function(){jq("#latest-update").html(r),jq("#latest-update").slideDown(300)})}jq("li.new-update").hide().slideDown(300),jq("li.new-update").removeClass("new-update"),jq("#whats-new").val(""),a.get(0).reset(),newest_activities="",activity_last_recorded=0}jq("#whats-new-options").slideUp(),jq("#whats-new-form textarea").animate({height:"2.2em"}),jq("#aw-whats-new-submit").prop("disabled",!0).removeClass("loading"),jq("#whats-new-content").removeClass("active")}),!1}),jq("div.activity-type-tabs").on("click",function(e){var t,i,a=jq(e.target).parent();if("STRONG"===e.target.nodeName||"SPAN"===e.target.nodeName)a=a.parent();else if("A"!==e.target.nodeName)return!1;return t=a.attr("id").substr(9,a.attr("id").length),i=jq("#activity-filter-select select").val(),"mentions"===t&&jq("#"+a.attr("id")+" a strong").remove(),bp_activity_request(t,i),!1}),jq("#activity-filter-select select").change(function(){var e,t=jq("div.activity-type-tabs li.selected"),i=jq(this).val();return e=t.length?t.attr("id").substr(9,t.attr("id").length):null,bp_activity_request(e,i),!1}),jq("div.activity").on("click",function(t){var i,a,s,r,n,o,c,l,d,p,u=jq(t.target);return u.hasClass("fav")||u.hasClass("unfav")?!u.hasClass("loading")&&(i=u.hasClass("fav")?"fav":"unfav",a=u.closest(".activity-item"),s=a.attr("id").substr(9,a.attr("id").length),c=bp_get_query_var("_wpnonce",u.attr("href")),u.addClass("loading"),jq.post(ajaxurl,{action:"activity_mark_"+i,cookie:bp_get_cookies(),id:s,nonce:c},function(e){u.removeClass("loading"),u.fadeOut(200,function(){jq(this).html(e),jq(this).attr("title","fav"===i?BP_DTheme.remove_fav:BP_DTheme.mark_as_fav),jq(this).fadeIn(200)}),"fav"===i?(jq(".item-list-tabs #activity-favs-personal-li").length||(jq(".item-list-tabs #activity-favorites").length||jq(".item-list-tabs ul #activity-mentions").before('<li id="activity-favorites"><a href="#">'+BP_DTheme.my_favs+" <span>0</span></a></li>"),jq(".item-list-tabs ul #activity-favorites span").html(Number(jq(".item-list-tabs ul #activity-favorites span").html())+1)),u.removeClass("fav"),u.addClass("unfav")):(u.removeClass("unfav"),u.addClass("fav"),jq(".item-list-tabs ul #activity-favorites span").html(Number(jq(".item-list-tabs ul #activity-favorites span").html())-1),Number(jq(".item-list-tabs ul #activity-favorites span").html())||(jq(".item-list-tabs ul #activity-favorites").hasClass("selected")&&bp_activity_request(null,null),jq(".item-list-tabs ul #activity-favorites").remove())),"activity-favorites"===jq(".item-list-tabs li.selected").attr("id")&&u.closest(".activity-item").slideUp(100)}),!1):u.hasClass("delete-activity")?(r=u.parents("div.activity ul li"),n=r.attr("id").substr(9,r.attr("id").length),o=u.attr("href"),c=o.split("_wpnonce="),l=r.prop("class").match(/date-recorded-([0-9]+)/),c=c[1],u.addClass("loading"),jq.post(ajaxurl,{action:"delete_activity",cookie:bp_get_cookies(),id:n,_wpnonce:c},function(e){e[0]+e[1]==="-1"?(r.prepend(e.substr(2,e.length)),r.children("#message").hide().fadeIn(300)):(r.slideUp(300),l&&activity_last_recorded===l[1]&&(newest_activities="",activity_last_recorded=0))}),!1):u.hasClass("spam-activity")?(r=u.parents("div.activity ul li"),l=r.prop("class").match(/date-recorded-([0-9]+)/),u.addClass("loading"),jq.post(ajaxurl,{action:"bp_spam_activity",cookie:encodeURIComponent(document.cookie),id:r.attr("id").substr(9,r.attr("id").length),_wpnonce:u.attr("href").split("_wpnonce=")[1]},function(e){e[0]+e[1]==="-1"?(r.prepend(e.substr(2,e.length)),r.children("#message").hide().fadeIn(300)):(r.slideUp(300),l&&activity_last_recorded===l[1]&&(newest_activities="",activity_last_recorded=0))}),!1):u.parent().hasClass("load-more")?(bp_ajax_request&&bp_ajax_request.abort(),jq("#buddypress li.load-more").addClass("loading"),d=e+1,p=[],jq(".activity-list li.just-posted").each(function(){p.push(jq(this).attr("id").replace("activity-",""))}),load_more_args={action:"activity_get_older_updates",cookie:bp_get_cookies(),page:d,exclude_just_posted:p.join(",")},load_more_search=bp_get_querystring("s"),load_more_search&&(load_more_args.search_terms=load_more_search),bp_ajax_request=jq.post(ajaxurl,load_more_args,function(t){jq("#buddypress li.load-more").removeClass("loading"),e=d,jq("#buddypress ul.activity-list").append(t.contents),u.parent().hide()},"json"),!1):void(u.parent().hasClass("load-newest")&&(t.preventDefault(),u.parent().hide(),activity_html=jq.parseHTML(newest_activities),jq.each(activity_html,function(e,t){"LI"===t.nodeName&&jq(t).hasClass("just-posted")&&jq("#"+jq(t).attr("id")).length&&jq("#"+jq(t).attr("id")).remove()}),jq("#buddypress ul.activity-list").prepend(newest_activities),newest_activities=""))}),jq("div.activity").on("click",".activity-read-more a",function(e){var t,i,a=jq(e.target),s=a.parent().attr("id").split("-"),r=s[3],n=s[0];return t="acomment"===n?"acomment-content":"activity-inner",i=jq("#"+n+"-"+r+" ."+t+":first"),jq(a).addClass("loading"),jq.post(ajaxurl,{action:"get_single_activity_content",activity_id:r},function(e){jq(i).slideUp(300).html(e).slideDown(300)}),!1}),jq("form.ac-form").hide(),jq(".activity-comments").length&&bp_legacy_theme_hide_comments(),jq("div.activity").on("click",function(e){var t,i,a,s,r,n,o,c,l,d,p,u,m,h,_,v=jq(e.target);return v.hasClass("acomment-reply")||v.parent().hasClass("acomment-reply")?(v.parent().hasClass("acomment-reply")&&(v=v.parent()),t=v.attr("id"),i=t.split("-"),a=i[2],s=v.attr("href").substr(10,v.attr("href").length),(r=jq("#ac-form-"+a)).css("display","none"),r.removeClass("root"),jq(".ac-form").hide(),r.children("div").each(function(){jq(this).hasClass("error")&&jq(this).hide()}),"comment"!==i[1]?jq("#acomment-"+s).append(r):jq("#activity-"+a+" .activity-comments").append(r),r.parent().hasClass("activity-comments")&&r.addClass("root"),r.slideDown(200),jq.scrollTo(r,500,{offset:-100,easing:"swing"}),jq("#ac-form-"+i[2]+" textarea").focus(),!1):"ac_form_submit"===v.attr("name")?(r=v.parents("form"),n=r.parent(),o=r.attr("id").split("-"),c=n.hasClass("activity-comments")?o[2]:n.attr("id").split("-")[1],content=jq("#"+r.attr("id")+" textarea"),jq("#"+r.attr("id")+" div.error").hide(),v.addClass("loading").prop("disabled",!0),content.addClass("loading").prop("disabled",!0),l={action:"new_activity_comment",cookie:bp_get_cookies(),_wpnonce_new_activity_comment:jq("#_wpnonce_new_activity_comment").val(),comment_id:c,form_id:o[2],content:content.val()},(d=jq("#_bp_as_nonce_"+c).val())&&(l["_bp_as_nonce_"+c]=d),jq.post(ajaxurl,l,function(e){if(v.removeClass("loading"),content.removeClass("loading"),e[0]+e[1]==="-1")r.append(jq(e.substr(2,e.length)).hide().fadeIn(200));else{var t=r.parent();r.fadeOut(200,function(){0===t.children("ul").length&&(t.hasClass("activity-comments")?t.prepend("<ul></ul>"):t.append("<ul></ul>"));var i=jq.trim(e);t.children("ul").append(jq(i).hide().fadeIn(200)),r.children("textarea").val(""),t.parent().addClass("has-comments")}),jq("#"+r.attr("id")+" textarea").val(""),u=Number(jq("#activity-"+o[2]+" a.acomment-reply span").html())+1,jq("#activity-"+o[2]+" a.acomment-reply span").html(u),(p=t.parents(".activity-comments").find(".show-all a"))&&p.html(BP_DTheme.show_x_comments.replace("%d",u))}jq(v).prop("disabled",!1),jq(content).prop("disabled",!1)}),!1):v.hasClass("acomment-delete")?(m=v.attr("href"),h=v.parent().parent(),r=h.parents("div.activity-comments").children("form"),_=m.split("_wpnonce="),_=_[1],c=m.split("cid="),c=c[1].split("&"),c=c[0],v.addClass("loading"),jq(".activity-comments ul .error").remove(),h.parents(".activity-comments").append(r),jq.post(ajaxurl,{action:"delete_activity_comment",cookie:bp_get_cookies(),_wpnonce:_,id:c},function(e){if(e[0]+e[1]==="-1")h.prepend(jq(e.substr(2,e.length)).hide().fadeIn(200));else{var t,i,a,s=jq("#"+h.attr("id")+" ul").children("li"),r=0;jq(s).each(function(){jq(this).is(":hidden")||r++}),h.fadeOut(200,function(){h.remove()}),i=(t=jq("#"+h.parents("#activity-stream > li").attr("id")+" a.acomment-reply span")).html()-(1+r),t.html(i),(a=h.parents(".activity-comments").find(".show-all a"))&&a.html(BP_DTheme.show_x_comments.replace("%d",i)),0===i&&jq(h.parents("#activity-stream > li")).removeClass("has-comments")}}),!1):v.hasClass("spam-activity-comment")?(m=v.attr("href"),h=v.parent().parent(),v.addClass("loading"),jq(".activity-comments ul div.error").remove(),h.parents(".activity-comments").append(h.parents(".activity-comments").children("form")),jq.post(ajaxurl,{action:"bp_spam_activity_comment",cookie:encodeURIComponent(document.cookie),_wpnonce:m.split("_wpnonce=")[1],id:m.split("cid=")[1].split("&")[0]},function(e){if(e[0]+e[1]==="-1")h.prepend(jq(e.substr(2,e.length)).hide().fadeIn(200));else{var t,i=jq("#"+h.attr("id")+" ul").children("li"),a=0;jq(i).each(function(){jq(this).is(":hidden")||a++}),h.fadeOut(200),t=h.parents("#activity-stream > li"),jq("#"+t.attr("id")+" a.acomment-reply span").html(jq("#"+t.attr("id")+" a.acomment-reply span").html()-(1+a))}}),!1):v.parent().hasClass("show-all")?(v.parent().addClass("loading"),setTimeout(function(){v.parent().parent().children("li").fadeIn(200,function(){v.parent().remove()})},600),!1):v.hasClass("ac-reply-cancel")?(jq(v).closest(".ac-form").slideUp(200),!1):void 0}),jq(document).keydown(function(e){(e=e||window.event).target?element=e.target:e.srcElement&&(element=e.srcElement),3===element.nodeType&&(element=element.parentNode),!0!==e.ctrlKey&&!0!==e.altKey&&!0!==e.metaKey&&27===(e.keyCode?e.keyCode:e.which)&&"TEXTAREA"===element.tagName&&jq(element).hasClass("ac-input")&&jq(element).parent().parent().parent().slideUp(200)}),jq(".dir-search, .groups-members-search").on("click",function(e){if(!jq(this).hasClass("no-ajax")){var t,i,a,s=jq(e.target);if("submit"===s.attr("type")){t=jq(".item-list-tabs li.selected").attr("id").split("-")[0],i=null,a=s.parent().find("#"+t+"_search").val(),"groups-members-search"===e.currentTarget.className&&(t="group_members",i="groups/single/members");var r=bp_get_directory_preference(t,"scope");return bp_filter_request(t,bp_get_directory_preference(t,"filter"),r,"div."+t,a,1,bp_get_directory_preference(t,"extras"),null,i),!1}}}),jq("div.item-list-tabs").on("click",function(e){if(jq("body").hasClass("type")&&jq("body").hasClass("directory")&&jq(this).addClass("no-ajax"),!jq(this).hasClass("no-ajax")&&!jq(e.target).hasClass("no-ajax")){var t,i,a,s="SPAN"===e.target.nodeName?e.target.parentNode:e.target,r=jq(s).parent();return"LI"!==r[0].nodeName||r.hasClass("last")?void 0:(t=r.attr("id").split("-"),"activity"!==(i=t[0])&&(a=t[1],bp_filter_request(i,jq("#"+i+"-order-select select").val(),a,"div."+i,jq("#"+i+"_search").val(),1,bp_get_directory_preference(i,"extras")),!1))}}),jq("li.filter select").change(function(){var e,t,i,a,s,r,n;return t=(e=jq(jq(".item-list-tabs li.selected").length?".item-list-tabs li.selected":this).attr("id").split("-"))[0],i=e[1],a=jq(this).val(),s=!1,r=null,jq(".dir-search input").length&&(s=jq(".dir-search input").val()),(n=jq(".groups-members-search input")).length&&(s=n.val(),t="members",i="groups"),"members"===t&&"groups"===i&&(t="group_members",r="groups/single/members"),"friends"===t&&(t="members"),bp_filter_request(t,a,i,"div."+t,s,1,bp_get_directory_preference(t,"extras"),null,r),!1}),jq("#buddypress").on("click",function(e){var t,i,a,s,r,n,o,c,l=jq(e.target);if(l.hasClass("button"))return!0;if(l.parent().parent().hasClass("pagination")&&!l.parent().parent().hasClass("no-ajax")){if(l.hasClass("dots")||l.hasClass("current"))return!1;i=(t=jq(jq(".item-list-tabs li.selected").length?".item-list-tabs li.selected":"li.filter select").attr("id").split("-"))[0],a=!1,s=jq(l).closest(".pagination-links").attr("id"),r=null,jq("div.dir-search input").length&&(a=!(a=jq(".dir-search input")).val()&&bp_get_querystring(a.attr("name"))?jq(".dir-search input").prop("placeholder"):a.val()),n=jq(l).hasClass("next")||jq(l).hasClass("prev")?jq(".pagination span.current").html():jq(l).html(),n=Number(n.replace(/\D/g,"")),jq(l).hasClass("next")?n++:jq(l).hasClass("prev")&&n--,(o=jq(".groups-members-search input")).length&&(a=o.val(),i="members"),"members"===i&&"groups"===t[1]&&(i="group_members",r="groups/single/members"),"admin"===i&&jq("body").hasClass("membership-requests")&&(i="requests"),c=-1!==s.indexOf("pag-bottom")?"pag-bottom":null;var d=bp_get_directory_preference(i,"scope");return bp_filter_request(i,bp_get_directory_preference(i,"filter"),d,"div."+i,a,n,bp_get_directory_preference(i,"extras"),c,r),!1}}),jq("#send-invite-form").on("click","#invite-list input",function(){var e,t,i=jq("#send-invite-form > .invite").length;jq(".ajax-loader").toggle(),i&&jq(this).parents("ul").find("input").prop("disabled",!0),e=jq(this).val(),t=!0===jq(this).prop("checked")?"invite":"uninvite",i||jq(".item-list-tabs li.selected").addClass("loading"),jq.post(ajaxurl,{action:"groups_invite_user",friend_action:t,cookie:bp_get_cookies(),_wpnonce:jq("#_wpnonce_invite_uninvite_user").val(),friend_id:e,group_id:jq("#group_id").val()},function(a){jq("#message")&&jq("#message").hide(),i?bp_filter_request("invite","bp-invite-filter","bp-invite-scope","div.invite",!1,1,"","",""):(jq(".ajax-loader").toggle(),"invite"===t?jq("#friend-list").append(a):"uninvite"===t&&jq("#friend-list li#uid-"+e).remove(),jq(".item-list-tabs li.selected").removeClass("loading"))})}),jq("#send-invite-form").on("click","a.remove",function(){var e=jq("#send-invite-form > .invite").length,t=jq(this).attr("id");return jq(".ajax-loader").toggle(),t=t.split("-"),t=t[1],jq.post(ajaxurl,{action:"groups_invite_user",friend_action:"uninvite",cookie:bp_get_cookies(),_wpnonce:jq("#_wpnonce_invite_uninvite_user").val(),friend_id:t,group_id:jq("#group_id").val()},function(i){e?bp_filter_request("invite","bp-invite-filter","bp-invite-scope","div.invite",!1,1,"","",""):(jq(".ajax-loader").toggle(),jq("#friend-list #uid-"+t).remove(),jq("#invite-list #f-"+t).prop("checked",!1))}),!1}),jq(".visibility-toggle-link").on("click",function(e){e.preventDefault(),jq(this).attr("aria-expanded","true").parent().hide().addClass("field-visibility-settings-hide").siblings(".field-visibility-settings").show().addClass("field-visibility-settings-open")}),jq(".field-visibility-settings-close").on("click",function(e){e.preventDefault(),jq(".visibility-toggle-link").attr("aria-expanded","false");var t=jq(this).parent(),i=t.find("input:checked").parent().text();t.hide().removeClass("field-visibility-settings-open").siblings(".field-visibility-settings-toggle").find(".current-visibility-level").text(i).end().show().removeClass("field-visibility-settings-hide")}),jq("#profile-edit-form input:not(:submit), #profile-edit-form textarea, #profile-edit-form select, #signup_form input:not(:submit), #signup_form textarea, #signup_form select").change(function(){var e=!0;jq("#profile-edit-form input:submit, #signup_form input:submit").on("click",function(){e=!1}),window.onbeforeunload=function(t){if(e)return BP_DTheme.unsaved_changes}}),jq("#friend-list a.accept, #friend-list a.reject").on("click",function(){var e,t=jq(this),i=jq(this).parents("#friend-list li"),a=jq(this).parents("li div.action"),s=i.attr("id").substr(11,i.attr("id").length),r=t.attr("href").split("_wpnonce=")[1];return!jq(this).hasClass("accepted")&&!jq(this).hasClass("rejected")&&(jq(this).hasClass("accept")?(e="accept_friendship",a.children("a.reject").css("visibility","hidden")):(e="reject_friendship",a.children("a.accept").css("visibility","hidden")),t.addClass("loading"),jq.post(ajaxurl,{action:e,cookie:bp_get_cookies(),id:s,_wpnonce:r},function(e){t.removeClass("loading"),e[0]+e[1]==="-1"?(i.prepend(e.substr(2,e.length)),i.children("#message").hide().fadeIn(200)):t.fadeOut(100,function(){jq(this).hasClass("accept")?(a.children("a.reject").hide(),jq(this).html(BP_DTheme.accepted).contents().unwrap()):(a.children("a.accept").hide(),jq(this).html(BP_DTheme.rejected).contents().unwrap())})}),!1)}),jq("#members-dir-list, #members-group-list, #item-header").on("click",".friendship-button a",function(){jq(this).parent().addClass("loading");var e=jq(this).attr("id"),t=jq(this).attr("href"),i=jq(this);return e=e.split("-"),e=e[1],t=t.split("?_wpnonce="),t=t[1].split("&"),t=t[0],jq.post(ajaxurl,{action:"addremove_friend",cookie:bp_get_cookies(),fid:e,_wpnonce:t},function(e){var t=i.attr("rel");parentdiv=i.parent(),"add"===t?jq(parentdiv).fadeOut(200,function(){parentdiv.removeClass("add_friend"),parentdiv.removeClass("loading"),parentdiv.addClass("pending_friend"),parentdiv.fadeIn(200).html(e)}):"remove"===t&&jq(parentdiv).fadeOut(200,function(){parentdiv.removeClass("remove_friend"),parentdiv.removeClass("loading"),parentdiv.addClass("add"),parentdiv.fadeIn(200).html(e)})}),!1}),jq("#buddypress").on("click",".group-button .leave-group",function(){if(!1===confirm(BP_DTheme.leave_group_confirm))return!1}),jq("#groups-dir-list").on("click",".group-button a",function(){var e=jq(this).parent().attr("id"),t=jq(this).attr("href"),i=jq(this);return e=e.split("-"),e=e[1],t=t.split("?_wpnonce="),t=t[1].split("&"),t=t[0],(!i.hasClass("leave-group")||!1!==confirm(BP_DTheme.leave_group_confirm))&&(jq.post(ajaxurl,{action:"joinleave_group",cookie:bp_get_cookies(),gid:e,_wpnonce:t},function(e){var t=i.parent();jq("body.directory").length?jq(t).fadeOut(200,function(){t.fadeIn(200).html(e);var a=jq("#groups-personal span"),s=1;i.hasClass("leave-group")?(t.hasClass("hidden")&&t.closest("li").slideUp(200),s=0):i.hasClass("request-membership")&&(s=!1),a.length&&!1!==s&&(s?a.text(1+(a.text()>>0)):a.text((a.text()>>0)-1))}):window.location.reload()}),!1)}),jq("#groups-list li.hidden").each(function(){"none"===jq(this).css("display")&&jq(this).css("cssText","display: list-item !important")}),jq("#buddypress").on("click",".pending",function(){return!1}),jq("body").hasClass("register")){var s=jq("#signup_with_blog");s.prop("checked")||jq("#blog-details").toggle(),s.change(function(){jq("#blog-details").toggle()})}jq(".message-search").on("click",function(e){if(!jq(this).hasClass("no-ajax")){var t,i=jq(e.target);if("submit"===i.attr("type")||"button"===i.attr("type")){var a=bp_get_directory_preference(t="messages","scope"),s=bp_get_directory_preference(t,"filter"),r=bp_get_directory_preference(t,"extras");return bp_filter_request(t,s,a,"div."+t,jq("#messages_search").val(),1,r),!1}}}),jq("#send_reply_button").click(function(){var e=jq("#messages_order").val()||"ASC",t=jq("#message-recipients").offset(),i=jq("#send_reply_button");return jq(i).addClass("loading").prop("disabled",!0),jq.post(ajaxurl,{action:"messages_send_reply",cookie:bp_get_cookies(),_wpnonce:jq("#send_message_nonce").val(),content:jq("#message_content").val(),send_to:jq("#send_to").val(),subject:jq("#subject").val(),thread_id:jq("#thread_id").val()},function(a){a[0]+a[1]==="-1"?jq("#send-reply").prepend(a.substr(2,a.length)):(jq("#send-reply #message").remove(),jq("#message_content").val(""),"ASC"===e?jq("#send-reply").before(a):(jq("#message-recipients").after(a),jq(window).scrollTop(t.top)),jq(".new-message").hide().slideDown(200,function(){jq(".new-message").removeClass("new-message")})),jq(i).removeClass("loading").prop("disabled",!1)}),!1}),jq("body.messages #item-body div.messages").on("change","#message-type-select",function(){var e=this.value,t=jq('td input[type="checkbox"]'),i="checked";switch(t.each(function(e){t[e].checked=""}),e){case"unread":t=jq('tr.unread td input[type="checkbox"]');break;case"read":t=jq('tr.read td input[type="checkbox"]');break;case"":i=""}t.each(function(e){t[e].checked=i})}),jq("#select-all-messages").click(function(e){this.checked?jq(".message-check").each(function(){this.checked=!0}):jq(".message-check").each(function(){this.checked=!1})}),jq("#messages-bulk-manage").attr("disabled","disabled"),jq("#messages-select").on("change",function(){jq("#messages-bulk-manage").attr("disabled",jq(this).val().length<=0)}),starAction=function(){var e=jq(this);return jq.post(ajaxurl,{action:"messages_star",message_id:e.data("message-id"),star_status:e.data("star-status"),nonce:e.data("star-nonce"),bulk:e.data("star-bulk")},function(t){1===parseInt(t,10)&&("unstar"===e.data("star-status")?(e.data("star-status","star"),e.removeClass("message-action-unstar").addClass("message-action-star"),e.find(".bp-screen-reader-text").text(BP_PM_Star.strings.text_star),1===BP_PM_Star.is_single_thread?e.attr("data-bp-tooltip",BP_PM_Star.strings.title_star):e.attr("data-bp-tooltip",BP_PM_Star.strings.title_star_thread)):(e.data("star-status","unstar"),e.removeClass("message-action-star").addClass("message-action-unstar"),e.find(".bp-screen-reader-text").text(BP_PM_Star.strings.text_unstar),1===BP_PM_Star.is_single_thread?e.attr("data-bp-tooltip",BP_PM_Star.strings.title_unstar):e.attr("data-bp-tooltip",BP_PM_Star.strings.title_unstar_thread)))}),!1},jq("#message-threads").on("click","td.thread-star a",starAction),jq("#message-thread").on("click",".message-star-actions a",starAction),jq("#message-threads td.bulk-select-check :checkbox").on("change",function(){var e=jq(this),t=e.closest("tr").find(".thread-star a");e.prop("checked")?"unstar"===t.data("star-status")?BP_PM_Star.star_counter++:BP_PM_Star.unstar_counter++:"unstar"===t.data("star-status")?BP_PM_Star.star_counter--:BP_PM_Star.unstar_counter--,BP_PM_Star.star_counter>0&&0===parseInt(BP_PM_Star.unstar_counter,10)?jq('option[value="star"]').hide():jq('option[value="star"]').show(),BP_PM_Star.unstar_counter>0&&0===parseInt(BP_PM_Star.star_counter,10)?jq('option[value="unstar"]').hide():jq('option[value="unstar"]').show()}),jq("#select-all-notifications").click(function(e){this.checked?jq(".notification-check").each(function(){this.checked=!0}):jq(".notification-check").each(function(){this.checked=!1})}),jq("#notification-bulk-manage").attr("disabled","disabled"),jq("#notification-select").on("change",function(){jq("#notification-bulk-manage").attr("disabled",jq(this).val().length<=0)}),jq("#close-notice").on("click",function(){return jq(this).addClass("loading"),jq("#sidebar div.error").remove(),jq.post(ajaxurl,{action:"messages_close_notice",notice_id:jq(".notice").attr("rel").substr(2,jq(".notice").attr("rel").length),nonce:jq("#close-notice-nonce").val()},function(e){jq("#close-notice").removeClass("loading"),e[0]+e[1]==="-1"?(jq(".notice").prepend(e.substr(2,e.length)),jq("#sidebar div.error").hide().fadeIn(200)):jq(".notice").slideUp(100)}),!1}),jq("#wp-admin-bar ul.main-nav li, #nav li").mouseover(function(){jq(this).addClass("sfhover")}),jq("#wp-admin-bar ul.main-nav li, #nav li").mouseout(function(){jq(this).removeClass("sfhover")}),jq("#wp-admin-bar-logout, a.logout").on("click",function(){jq.removeCookie("bp-activity-scope",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-activity-filter",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-activity-oldestpage",{path:"/",secure:"https:"===window.location.protocol});var e=["members","groups","blogs","forums"];jq(e).each(function(t){jq.removeCookie("bp-"+e[t]+"-scope",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-"+e[t]+"-filter",{path:"/",secure:"https:"===window.location.protocol}),jq.removeCookie("bp-"+e[t]+"-extras",{path:"/",secure:"https:"===window.location.protocol})})}),jq("body").hasClass("no-js")&&jq("body").attr("class",jq("body").attr("class").replace(/no-js/,"js")),"undefined"!=typeof wp&&void 0!==wp.heartbeat&&void 0!==BP_DTheme.pulse&&(wp.heartbeat.interval(Number(BP_DTheme.pulse)),jq.fn.extend({"heartbeat-send":function(){return this.bind("heartbeat-send.buddypress")}}));var r=0;jq(document).on("heartbeat-send.buddypress",function(e,t){r=0,jq("#buddypress ul.activity-list li").first().prop("id")&&(timestamp=jq("#buddypress ul.activity-list li").first().prop("class").match(/date-recorded-([0-9]+)/),timestamp&&(r=timestamp[1])),(0===activity_last_recorded||Number(r)>activity_last_recorded)&&(activity_last_recorded=Number(r)),t.bp_activity_last_recorded=activity_last_recorded,last_recorded_search=bp_get_querystring("s"),last_recorded_search&&(t.bp_activity_last_recorded_search_terms=last_recorded_search)}),jq(document).on("heartbeat-tick",function(e,t){t.bp_activity_newest_activities&&(newest_activities=t.bp_activity_newest_activities.activities+newest_activities,activity_last_recorded=Number(t.bp_activity_newest_activities.last_recorded),jq("#buddypress ul.activity-list li").first().hasClass("load-newest")||jq("#buddypress ul.activity-list").prepend('<li class="load-newest"><a href="#newest">'+BP_DTheme.newest+"</a></li>"))})});
bp-templates/bp-nouveau/buddypress-functions.php CHANGED
@@ -324,6 +324,13 @@ class BP_Nouveau extends BP_Theme_Compat {
324
 
325
  // Add The password verify if needed.
326
  if ( bp_is_active( 'settings' ) || bp_get_signup_allowed() ) {
 
 
 
 
 
 
 
327
  $scripts['bp-nouveau-password-verify'] = array(
328
  'file' => 'js/password-verify%s.js',
329
  'dependencies' => array( 'bp-nouveau', 'password-strength-meter' ),
@@ -372,7 +379,7 @@ class BP_Nouveau extends BP_Theme_Compat {
372
  wp_enqueue_script( 'bp-nouveau' );
373
 
374
  if ( bp_is_register_page() || bp_is_user_settings_general() ) {
375
- wp_enqueue_script( 'bp-nouveau-password-verify' );
376
  }
377
 
378
  if ( is_singular() && bp_is_blog_page() && get_option( 'thread_comments' ) ) {
324
 
325
  // Add The password verify if needed.
326
  if ( bp_is_active( 'settings' ) || bp_get_signup_allowed() ) {
327
+ /**
328
+ * BP Nouveau is now directly using the `wp-admin/js/user-profile.js` script.
329
+ *
330
+ * Setting the user password is now more consistent with how WordPress handles it.
331
+ *
332
+ * @deprecated 5.0.0
333
+ */
334
  $scripts['bp-nouveau-password-verify'] = array(
335
  'file' => 'js/password-verify%s.js',
336
  'dependencies' => array( 'bp-nouveau', 'password-strength-meter' ),
379
  wp_enqueue_script( 'bp-nouveau' );
380
 
381
  if ( bp_is_register_page() || bp_is_user_settings_general() ) {
382
+ wp_enqueue_script( 'user-profile' );
383
  }
384
 
385
  if ( is_singular() && bp_is_blog_page() && get_option( 'thread_comments' ) ) {
bp-templates/bp-nouveau/buddypress/common/js-templates/activity/form.php CHANGED
@@ -2,10 +2,15 @@
2
  /**
3
  * Activity Post form JS Templates
4
  *
5
- * @version 3.1.0
 
6
  */
7
  ?>
8
 
 
 
 
 
9
  <script type="text/html" id="tmpl-activity-post-form-feedback">
10
  <span class="bp-icon" aria-hidden="true"></span><p>{{{data.message}}}</p>
11
  </script>
2
  /**
3
  * Activity Post form JS Templates
4
  *
5
+ * @since 3.0.0
6
+ * @version 5.0.0
7
  */
8
  ?>
9
 
10
+ <script type="text/html" id="tmpl-activity-before-post-form-inputs">
11
+ <?php bp_nouveau_activity_hook( 'before', 'post_form' ); ?>
12
+ </script>
13
+
14
  <script type="text/html" id="tmpl-activity-post-form-feedback">
15
  <span class="bp-icon" aria-hidden="true"></span><p>{{{data.message}}}</p>
16
  </script>
bp-templates/bp-nouveau/buddypress/common/js-templates/group-members/index.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BP Nouveau single group's membership management main template.
4
+ *
5
+ * This template is used to inject the BuddyPress Backbone views
6
+ * dealing with a group's membership management.
7
+ *
8
+ * @since 5.0.0
9
+ * @version 5.0.0
10
+ */
11
+ ?>
12
+
13
+ <?php
14
+ /**
15
+ * Placeholder to inject elements of the UI
16
+ * to manage Group members.
17
+ *
18
+ * @since 5.0.0
19
+ * @version 5.0.0
20
+ */
21
+ ?>
22
+ <div id="group-manage-members-ui" class="standard-form">
23
+ <ul class="subnav-filters">
24
+ <li id="group-roles-filter" class="last filter"><?php // Placeholder for the Group Role Tabs ?></li>
25
+ <li id="group-members-pagination" class="left-menu"><?php // Placeholder for paginate links ?></li>
26
+ <li id="group-members-search-form" class="bp-search"><?php // Placeholder for search form ?></li>
27
+ </ul>
28
+ <table id="group-members-list-table" class="<?php echo is_admin() ? 'widefat bp-group-members' : 'bp-list'; ?>"><?php // Placeholder to list members ?></table>
29
+ </div>
30
+
31
+ <script type="text/html" id="tmpl-bp-manage-members-updating">
32
+ <# if ( ! data.type ) { #>
33
+ <small><?php echo esc_html_x( 'Updating role... Please wait.', 'group manage members update feedback', 'buddypress' ); ?></small>
34
+ <# } else if ( 'ban' === data.type ) { #>
35
+ <small><?php echo esc_html_x( 'Banning member... Please wait.', 'group manage members ban feedback', 'buddypress' ); ?></small>
36
+ <# } else if ( 'unban' === data.type ) { #>
37
+ <small><?php echo esc_html_x( 'Unbanning member... Please wait.', 'group manage members unban feedback', 'buddypress' ); ?></small>
38
+ <# } else if ( 'remove' === data.type ) { #>
39
+ <small><?php echo esc_html_x( 'Removing member... Please wait.', 'group manage members remove feedback', 'buddypress' ); ?></small>
40
+ <# } #>
41
+ </script>
42
+
43
+ <script type="text/html" id="tmpl-bp-manage-members-error">
44
+ <small>{{data.message}}</small>
45
+ </script>
46
+
47
+ <script type="text/html" id="tmpl-bp-manage-members-header">
48
+ <tr>
49
+ <th><?php echo esc_html_x( 'Group Members', 'group manage members table header', 'buddypress' ); ?></th>
50
+ <th><?php echo esc_html_x( 'Roles', 'group manage members table header', 'buddypress' ); ?></th>
51
+ </tr>
52
+ </script>
53
+
54
+ <script type="text/html" id="tmpl-bp-manage-members-empty-row">
55
+ <td colspan="2">
56
+ <div class="bp-feedback info">
57
+ <span class="bp-icon" aria-hidden="true"></span>
58
+ <p><?php esc_html_e( 'No Group members were found for this request.', 'buddypress' ); ?></p>
59
+ </div>
60
+ </td>
61
+ </script>
62
+
63
+ <script type="text/html" id="tmpl-bp-manage-members-label">
64
+ <# if ( data.type && 'filter' !== data.type ) { #>
65
+ <?php echo esc_html_x( 'Change role for:', 'group manage members row edit', 'buddypress' ); ?>
66
+ <# } else { #>
67
+ <?php echo esc_html_x( 'Filter:', 'group manage members roles filter', 'buddypress' ); ?></small>
68
+ <# } #>
69
+ </script>
70
+
71
+ <script type="text/html" id="tmpl-bp-manage-members-row">
72
+ <td class="uname-column">
73
+ <div class="group-member">
74
+ <a href="{{{data.link}}}">
75
+ <img src="{{{data.avatar_urls.thumb}}}" alt="{{data.name}}" class="avatar profile-photo alignleft"/>
76
+ {{data.name}}
77
+ </a>
78
+ </div>
79
+ <div class="group-member-actions row-actions">
80
+ <# if ( ! data.editing && ! data.is_banned ) { #>
81
+ <span class="edit"><a href="#edit-role" data-action="edit"><?php echo esc_html_x( 'Edit', 'group member edit role link', 'buddypress' ); ?></a> | </span>
82
+ <# } #>
83
+ <# if ( data.editing ) { #>
84
+ <span><a href="#edit-role-abort" data-action="abort"><?php echo esc_html_x( 'Stop editing', 'group member edit role abort link', 'buddypress' ); ?></a> | </span>
85
+ <# } #>
86
+ <# if ( ! data.is_banned ) { #>
87
+ <span class="spam"><a href="#ban" class="submitdelete" data-action="ban"><?php echo esc_html_x( 'Ban', 'group member ban link', 'buddypress' ); ?></a> | </span>
88
+ <# } else { #>
89
+ <span class="ham"><a href="#unban" data-action="unban"><?php echo esc_html_x( 'Unban', 'group member unban link', 'buddypress' ); ?></a> | </span>
90
+ <# } #>
91
+ <span class="delete"><a href="#remove" class="submitdelete" data-action="remove"><?php echo esc_html_x( 'Remove', 'group member ban link', 'buddypress' ); ?></a></span>
92
+ </div>
93
+ </td>
94
+ <td class="urole-column">
95
+ <# if ( ! data.editing && ! data.managingBan && ! data.removing ) { #>
96
+ {{data.role.name}}
97
+ <# } else { #>
98
+ <div id="edit-group-member-{{data.id}}" class="group-member-edit"><?php // Placeholder for the Edit Role Dropdown. ;?></div>
99
+ <# } #>
100
+ </td>
101
+ </script>
102
+
103
+ <script type="text/html" id="tmpl-bp-manage-members-search">
104
+ <?php
105
+ $button_classes = array( 'bp-button', 'bp-search' );
106
+ $screen_reader_class = 'bp-screen-reader-text';
107
+
108
+ if ( is_admin() ) {
109
+ $button_classes[] = 'button-secondary';
110
+ $screen_reader_class = 'screen-reader-text';
111
+ }
112
+ ?>
113
+ <label for="manage-members-search" class="<?php echo sanitize_html_class( $screen_reader_class ); ?>">
114
+ <?php esc_html_e( 'Search Members', 'buddypress' ); ?>
115
+ </label>
116
+ <input type="search" id="manage-members-search" class="small" placeholder="<?php echo esc_attr_x( 'Search', 'search placeholder text', 'buddypress' ); ?>"/>
117
+ <button type="submit" id="manage-members-search-submit" class="<?php echo join( ' ', array_map( 'sanitize_html_class', $button_classes ) ); ?>">
118
+ <span class="dashicons dashicons-search" aria-hidden="true"></span>
119
+ <span class="<?php echo sanitize_html_class( $screen_reader_class ); ?>"><?php echo esc_html_x( 'Search', 'button', 'buddypress' ); ?></span>
120
+ </button>
121
+ </script>
122
+
123
+ <script type="text/html" id="tmpl-bp-manage-members-paginate">
124
+ <?php
125
+ $button_classes = array( 'group-members-paginate-button' );
126
+ $screen_reader_class = 'bp-screen-reader-text';
127
+
128
+ if ( is_admin() ) {
129
+ $button_classes[] = 'button-secondary';
130
+ $screen_reader_class = 'screen-reader-text';
131
+ }
132
+ ?>
133
+ <# if ( ! isNaN( data.currentPage ) && ! isNaN( data.totalPages ) ) { #>
134
+ <# if ( 1 !== data.currentPage && data.totalPages ) { #>
135
+ <button class="<?php echo join( ' ', array_map( 'sanitize_html_class', $button_classes ) ); ?>" data-page="{{data.prevPage}}">
136
+ <span class="dashicons dashicons-arrow-left"></span>
137
+ <span class="<?php echo sanitize_html_class( $screen_reader_class ); ?>"><?php echo esc_html_x( 'Prev.', 'link', 'buddypress' ); ?></span>
138
+ </button>
139
+ <# } #>
140
+ <# if ( data.totalPages !== data.currentPage ) { #>
141
+ <button class="<?php echo join( ' ', array_map( 'sanitize_html_class', $button_classes ) ); ?>" data-page="{{data.nextPage}}">
142
+ <span class="<?php echo sanitize_html_class( $screen_reader_class ); ?>"><?php echo esc_html_x( 'Next', 'link', 'buddypress' ); ?></span>
143
+ <span class="dashicons dashicons-arrow-right"></span>
144
+ </button>
145
+ <# } #>
146
+ <# } #>
147
+ </script>
bp-templates/bp-nouveau/buddypress/groups/single/admin/manage-members.php CHANGED
@@ -3,7 +3,7 @@
3
  * BP Nouveau Group's manage members template.
4
  *
5
  * @since 3.0.0
6
- * @version 3.1.0
7
  */
8
  ?>
9
 
@@ -11,7 +11,17 @@
11
  <?php esc_html_e( 'Manage Group Members', 'buddypress' ); ?>
12
  </h2>
13
 
14
- <p class="bp-help-text"><?php esc_html_e( 'Manage your group members; promote to moderators, admins or demote or ban.', 'buddypress' ); ?></p>
 
 
 
 
 
 
 
 
 
 
15
 
16
  <dl class="groups-manage-members-list">
17
 
@@ -119,5 +129,6 @@
119
 
120
  bp_nouveau_user_feedback( 'group-manage-members-none' );
121
 
122
- endif; ?>
123
 
 
3
  * BP Nouveau Group's manage members template.
4
  *
5
  * @since 3.0.0
6
+ * @version 5.0.0
7
  */
8
  ?>
9
 
11
  <?php esc_html_e( 'Manage Group Members', 'buddypress' ); ?>
12
  </h2>
13
 
14
+ <p class="bp-help-text"><?php esc_html_e( 'Manage your group members; promote to moderators, admins or demote or ban.', 'buddypress' ); ?></p>
15
+
16
+ <?php if ( bp_rest_api_is_available() ) :
17
+ /**
18
+ * Get the templates to manage Group Members using the BP REST API.
19
+ *
20
+ * @since 5.0.0
21
+ */
22
+ bp_get_template_part( 'common/js-templates/group-members/index' );
23
+
24
+ else : ?>
25
 
26
  <dl class="groups-manage-members-list">
27
 
129
 
130
  bp_nouveau_user_feedback( 'group-manage-members-none' );
131
 
132
+ endif;
133
 
134
+ endif;
bp-templates/bp-nouveau/buddypress/members/single/friends/requests-loop.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress - Members Friends Requests Loop
4
+ *
5
+ * @since 5.0.0
6
+ * @version 5.0.0
7
+ */
8
+ ?>
9
+
10
+ <?php if ( bp_has_members( bp_ajax_querystring( 'friendship_requests' ) . '&include=' . bp_get_friendship_requests() ) ) : ?>
11
+
12
+ <?php bp_nouveau_pagination( 'top' ); ?>
13
+
14
+ <ul id="friend-list" class="<?php bp_nouveau_loop_classes(); ?>">
15
+ <?php
16
+ while ( bp_members() ) :
17
+ bp_the_member();
18
+ ?>
19
+
20
+ <li id="friendship-<?php bp_friend_friendship_id(); ?>" <?php bp_member_class( array( 'item-entry' ) ); ?> data-bp-item-id="<?php bp_friend_friendship_id(); ?>" data-bp-item-component="members">
21
+ <div class="item-avatar">
22
+ <a href="<?php bp_member_link(); ?>"><?php bp_member_avatar( array( 'type' => 'full' ) ); ?></a>
23
+ </div>
24
+
25
+ <div class="item">
26
+ <div class="item-title"><a href="<?php bp_member_link(); ?>"><?php bp_member_name(); ?></a></div>
27
+ <div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
28
+
29
+ <?php bp_nouveau_friend_hook( 'requests_item' ); ?>
30
+ </div>
31
+
32
+ <?php bp_nouveau_members_loop_buttons(); ?>
33
+ </li>
34
+
35
+ <?php endwhile; ?>
36
+ </ul>
37
+
38
+ <?php bp_nouveau_friend_hook( 'requests_content' ); ?>
39
+
40
+ <?php bp_nouveau_pagination( 'bottom' ); ?>
41
+
42
+ <?php else : ?>
43
+
44
+ <?php bp_nouveau_user_feedback( 'member-requests-none' ); ?>
45
+
46
+ <?php endif; ?>
bp-templates/bp-nouveau/buddypress/members/single/friends/requests.php CHANGED
@@ -3,7 +3,7 @@
3
  * BuddyPress - Members Friends Requests
4
  *
5
  * @since 3.0.0
6
- * @version 3.0.0
7
  */
8
  ?>
9
 
@@ -11,43 +11,8 @@
11
 
12
  <?php bp_nouveau_member_hook( 'before', 'friend_requests_content' ); ?>
13
 
14
- <?php if ( bp_has_members( 'type=alphabetical&include=' . bp_get_friendship_requests() ) ) : ?>
 
 
15
 
16
- <?php bp_nouveau_pagination( 'top' ); ?>
17
-
18
- <ul id="friend-list" class="<?php bp_nouveau_loop_classes(); ?>" data-bp-list="friendship_requests">
19
- <?php
20
- while ( bp_members() ) :
21
- bp_the_member();
22
- ?>
23
-
24
- <li id="friendship-<?php bp_friend_friendship_id(); ?>" <?php bp_member_class( array( 'item-entry' ) ); ?> data-bp-item-id="<?php bp_friend_friendship_id(); ?>" data-bp-item-component="members">
25
- <div class="item-avatar">
26
- <a href="<?php bp_member_link(); ?>"><?php bp_member_avatar( array( 'type' => 'full' ) ); ?></a>
27
- </div>
28
-
29
- <div class="item">
30
- <div class="item-title"><a href="<?php bp_member_link(); ?>"><?php bp_member_name(); ?></a></div>
31
- <div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
32
-
33
- <?php bp_nouveau_friend_hook( 'requests_item' ); ?>
34
- </div>
35
-
36
- <?php bp_nouveau_members_loop_buttons(); ?>
37
- </li>
38
-
39
- <?php endwhile; ?>
40
- </ul>
41
-
42
- <?php bp_nouveau_friend_hook( 'requests_content' ); ?>
43
-
44
- <?php bp_nouveau_pagination( 'bottom' ); ?>
45
-
46
- <?php else : ?>
47
-
48
- <?php bp_nouveau_user_feedback( 'member-requests-none' ); ?>
49
-
50
- <?php endif; ?>
51
-
52
- <?php
53
- bp_nouveau_member_hook( 'after', 'friend_requests_content' );
3
  * BuddyPress - Members Friends Requests
4
  *
5
  * @since 3.0.0
6
+ * @version 5.0.0
7
  */
8
  ?>
9
 
11
 
12
  <?php bp_nouveau_member_hook( 'before', 'friend_requests_content' ); ?>
13
 
14
+ <div data-bp-list="friendship_requests">
15
+ <?php bp_get_template_part( 'members/single/friends/requests-loop' ); ?>
16
+ </div>
17
 
18
+ <?php bp_nouveau_member_hook( 'after', 'friend_requests_content' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bp-templates/bp-nouveau/buddypress/members/single/settings/general.php CHANGED
@@ -3,43 +3,68 @@
3
  * BuddyPress - Members Settings ( General )
4
  *
5
  * @since 3.0.0
6
- * @version 3.1.0
7
  */
8
 
9
  bp_nouveau_member_hook( 'before', 'settings_template' ); ?>
10
 
11
  <h2 class="screen-heading general-settings-screen">
12
- <?php _e( 'Email & Password', 'buddypress' ); ?>
13
  </h2>
14
 
15
  <p class="info email-pwd-info">
16
- <?php _e( 'Update your email and or password.', 'buddypress' ); ?>
17
  </p>
18
 
19
- <form action="<?php echo esc_url( bp_displayed_user_domain() . bp_get_settings_slug() . '/general' ); ?>" method="post" class="standard-form" id="settings-form">
20
 
21
  <?php if ( ! is_super_admin() ) : ?>
22
 
23
- <label for="pwd"><?php _e( 'Current Password <span>(required to update email or change current password)</span>', 'buddypress' ); ?></label>
24
- <input type="password" name="pwd" id="pwd" size="16" value="" class="settings-input small" <?php bp_form_field_attributes( 'password' ); ?>/> &nbsp;<a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php esc_html_e( 'Lost your password?', 'buddypress' ); ?></a>
25
 
26
  <?php endif; ?>
27
 
28
- <label for="email"><?php _e( 'Account Email', 'buddypress' ); ?></label>
29
  <input type="email" name="email" id="email" value="<?php echo esc_attr( bp_get_displayed_user_email() ); ?>" class="settings-input" <?php bp_form_field_attributes( 'email' ); ?>/>
30
 
31
  <div class="info bp-feedback">
32
  <span class="bp-icon" aria-hidden="true"></span>
33
- <p class="text"><?php esc_html_e( 'Leave password fields blank for no change', 'buddypress' ); ?></p>
34
  </div>
35
 
36
- <label for="pass1"><?php esc_html_e( 'Add Your New Password', 'buddypress' ); ?></label>
37
- <input type="password" name="pass1" id="pass1" size="16" value="" class="settings-input small password-entry" <?php bp_form_field_attributes( 'password' ); ?>/>
 
 
38
 
39
- <label for="pass2" class="repeated-pwd"><?php esc_html_e( 'Repeat Your New Password', 'buddypress' ); ?></label>
40
- <input type="password" name="pass2" id="pass2" size="16" value="" class="settings-input small password-entry-confirm" <?php bp_form_field_attributes( 'password' ); ?>/>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- <div id="pass-strength-result"></div>
 
 
 
 
 
43
 
44
  <?php bp_nouveau_submit_button( 'members-general-settings' ); ?>
45
 
3
  * BuddyPress - Members Settings ( General )
4
  *
5
  * @since 3.0.0
6
+ * @version 5.0.0
7
  */
8
 
9
  bp_nouveau_member_hook( 'before', 'settings_template' ); ?>
10
 
11
  <h2 class="screen-heading general-settings-screen">
12
+ <?php esc_html_e( 'Email & Password', 'buddypress' ); ?>
13
  </h2>
14
 
15
  <p class="info email-pwd-info">
16
+ <?php esc_html_e( 'Update your email and or password.', 'buddypress' ); ?>
17
  </p>
18
 
19
+ <form action="<?php echo esc_url( bp_displayed_user_domain() . bp_get_settings_slug() . '/general' ); ?>" method="post" class="standard-form" id="your-profile">
20
 
21
  <?php if ( ! is_super_admin() ) : ?>
22
 
23
+ <label for="pwd"><?php printf( esc_html__( 'Current Password %s', 'buddypress' ), '<span>' . esc_html__( '(required to update email or change current password)', 'buddypress' ) . '</span>' ); ?></label>
24
+ <input type="password" name="pwd" id="pwd" value="" size="24" class="settings-input small" <?php bp_form_field_attributes( 'password' ); ?>/> &nbsp;<a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php esc_html_e( 'Lost your password?', 'buddypress' ); ?></a>
25
 
26
  <?php endif; ?>
27
 
28
+ <label for="email"><?php esc_html_e( 'Account Email', 'buddypress' ); ?></label>
29
  <input type="email" name="email" id="email" value="<?php echo esc_attr( bp_get_displayed_user_email() ); ?>" class="settings-input" <?php bp_form_field_attributes( 'email' ); ?>/>
30
 
31
  <div class="info bp-feedback">
32
  <span class="bp-icon" aria-hidden="true"></span>
33
+ <p class="text"><?php esc_html_e( 'Click on the "Generate Password" button to change your password.', 'buddypress' ); ?></p>
34
  </div>
35
 
36
+ <div class="user-pass1-wrap">
37
+ <button type="button" class="button wp-generate-pw">
38
+ <?php esc_html_e( 'Generate Password', 'buddypress' ); ?>
39
+ </button>
40
 
41
+ <div class="wp-pwd">
42
+ <label for="pass1"><?php esc_html_e( 'Add Your New Password', 'buddypress' ); ?></label>
43
+ <span class="password-input-wrapper">
44
+ <input type="password" name="pass1" id="pass1" size="24" class="settings-input small password-entry" value="" <?php bp_form_field_attributes( 'password', array( 'data-pw' => wp_generate_password( 24 ), 'aria-describedby' => 'pass-strength-result' ) ); ?> />
45
+ </span>
46
+ <button type="button" class="button wp-hide-pw" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password', 'buddypress' ); ?>">
47
+ <span class="dashicons dashicons-hidden" aria-hidden="true"></span>
48
+ <span class="text bp-screen-reader-text"><?php esc_html_e( 'Hide', 'buddypress' ); ?></span>
49
+ </button>
50
+ <button type="button" class="button wp-cancel-pw" data-toggle="0" aria-label="<?php esc_attr_e( 'Cancel password change', 'buddypress' ); ?>">
51
+ <span class="text"><?php esc_html_e( 'Cancel', 'buddypress' ); ?></span>
52
+ </button>
53
+ <div id="pass-strength-result" aria-live="polite"></div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="user-pass2-wrap">
58
+ <label class="label" for="pass2"><?php esc_html_e( 'Repeat Your New Password', 'buddypress' ); ?></label>
59
+ <input name="pass2" type="password" id="pass2" size="24" class="settings-input small password-entry-confirm" value="" <?php bp_form_field_attributes( 'password' ); ?> />
60
+ </div>
61
 
62
+ <div class="pw-weak">
63
+ <label>
64
+ <input type="checkbox" name="pw_weak" class="pw-checkbox" />
65
+ <span id="pw-weak-text-label"><?php esc_html_e( 'Confirm use of potentially weak password', 'buddypress' ); ?></span>
66
+ </label>
67
+ </div>
68
 
69
  <?php bp_nouveau_submit_button( 'members-general-settings' ); ?>
70
 
bp-templates/bp-nouveau/common-styles/_bp-mixins.scss CHANGED
@@ -532,6 +532,27 @@
532
  color: $color;
533
  }
534
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
  // BP Tooltips
536
 
537
  // Bottom center tooltip - Default
532
  color: $color;
533
  }
534
 
535
+ @mixin pwd-strong-colors($color: inherit, $background: null, $border: null) {
536
+
537
+ @if $background {
538
+ $background: $background;
539
+ } @else {
540
+ $background: $background-strong;
541
+ }
542
+
543
+ background-color: $background;
544
+
545
+ @if $border {
546
+ $border: $border;
547
+ } @else {
548
+ $border: $border-strong;
549
+ }
550
+
551
+ border-color: $border;
552
+
553
+ color: $color;
554
+ }
555
+
556
  // BP Tooltips
557
 
558
  // Bottom center tooltip - Default
bp-templates/bp-nouveau/common-styles/_bp-variables.scss CHANGED
@@ -69,8 +69,10 @@ $update-success: #8a2 !default;
69
  $pwd-background: #eee !default;
70
  $background-short: #ffa0a0 !default;
71
  $border-short: #f04040 !default;
72
- $background-good: #66d66e !default;
73
- $border-good: #438c48 !default;
 
 
74
  $background-bad: #ffb78c !default;
75
  $border-bad: #ff853c !default;
76
 
69
  $pwd-background: #eee !default;
70
  $background-short: #ffa0a0 !default;
71
  $border-short: #f04040 !default;
72
+ $background-good: #ffec8b !default;
73
+ $border-good: #fc0 !default;
74
+ $background-strong: #66d66e !default;
75
+ $border-strong: #438c48 !default;
76
  $background-bad: #ffb78c !default;
77
  $border-bad: #ff853c !default;
78
 
bp-templates/bp-nouveau/common-styles/_bp_activity_entries.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Activity Entries - activity loop
2
- // @version 3.0.0
 
3
 
4
  .activity-list {
5
 
@@ -133,7 +134,9 @@
133
  .avatar {
134
  display: inline-block;
135
  margin: 0 $marg-xsml;
136
- vertical-align: bottom;
 
 
137
  }
138
 
139
  .time-since {
@@ -215,6 +218,7 @@
215
 
216
  .button {
217
  background: transparent;
 
218
  }
219
 
220
  a {
@@ -326,7 +330,7 @@
326
  padding: $pad-sml 0;
327
 
328
  &:focus,
329
- &:hover, {
330
  background: $white;
331
  color: $black;
332
  }
@@ -371,6 +375,7 @@ body.activity-permalink {
371
 
372
  img {
373
  max-width: 100%;
 
374
  }
375
  }
376
 
@@ -409,6 +414,11 @@ body.activity-permalink {
409
  margin-right: 0;
410
  position: relative;
411
  top: -20px;
 
 
 
 
 
412
  }
413
 
414
  .activity-content {
1
  // BP Activity Entries - activity loop
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  .activity-list {
6
 
134
  .avatar {
135
  display: inline-block;
136
  margin: 0 $marg-xsml;
137
+ vertical-align: text-top;
138
+ width: 20px;
139
+ height: 20px;
140
  }
141
 
142
  .time-since {
218
 
219
  .button {
220
  background: transparent;
221
+ color: $dark-grey;
222
  }
223
 
224
  a {
330
  padding: $pad-sml 0;
331
 
332
  &:focus,
333
+ &:hover {
334
  background: $white;
335
  color: $black;
336
  }
375
 
376
  img {
377
  max-width: 100%;
378
+ background-color: $light-grey;
379
  }
380
  }
381
 
414
  margin-right: 0;
415
  position: relative;
416
  top: -20px;
417
+
418
+ img {
419
+ -webkit-box-shadow: 0 0 0 8px #fff;
420
+ box-shadow: 0 0 0 8px #fff;
421
+ }
422
  }
423
 
424
  .activity-content {
bp-templates/bp-nouveau/common-styles/_bp_buttons.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Buttons, Submits, Icons and general clicky things styling.
2
- // @version 3.0.0
 
3
 
4
  // Buttons by default are styled as simple boxes but we may
5
  // change that by adding a parent class ( on any close parent to
@@ -25,8 +26,10 @@
25
  border-color: $bp-border-dark;
26
  border-style: solid;
27
  border-width: 1px;
 
28
  color: $dark-grey;
29
  cursor: pointer;
 
30
  font-size: inherit;
31
  font-weight: 400;
32
  outline: none;
@@ -34,6 +37,12 @@
34
  text-align: center;
35
  text-decoration: none;
36
  width: auto;
 
 
 
 
 
 
37
  }
38
 
39
  // Re-instate the quick-tag padding to avoid the above ruleset
1
  // BP Buttons, Submits, Icons and general clicky things styling.
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  // Buttons by default are styled as simple boxes but we may
6
  // change that by adding a parent class ( on any close parent to
26
  border-color: $bp-border-dark;
27
  border-style: solid;
28
  border-width: 1px;
29
+ border-radius: 0;
30
  color: $dark-grey;
31
  cursor: pointer;
32
+ font-family: inherit;
33
  font-size: inherit;
34
  font-weight: 400;
35
  outline: none;
37
  text-align: center;
38
  text-decoration: none;
39
  width: auto;
40
+ line-height: 1;
41
+ }
42
+
43
+ button.dashicons,
44
+ a.button.dashicons {
45
+ font-family: dashicons;
46
  }
47
 
48
  // Re-instate the quick-tag padding to avoid the above ruleset
bp-templates/bp-nouveau/common-styles/_bp_forms.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Forms Elements Global Styles
2
- // @version 3.0.0
 
3
 
4
  // Some essential classes used for forms elements:
5
  // labels - sizing especially for standalone controls
@@ -132,7 +133,7 @@
132
  }
133
  }
134
 
135
- input:not(.button-small),
136
  textarea {
137
  width: 100%;
138
  }
@@ -353,7 +354,7 @@ body.no-js {
353
  position: relative;
354
  text-indent: -2px;
355
  z-index: 1;
356
- width: 100%;
357
  }
358
 
359
  select,
1
  // BP Forms Elements Global Styles
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  // Some essential classes used for forms elements:
6
  // labels - sizing especially for standalone controls
133
  }
134
  }
135
 
136
+ input:not(.small),
137
  textarea {
138
  width: 100%;
139
  }
354
  position: relative;
355
  text-indent: -2px;
356
  z-index: 1;
357
+ width: auto;
358
  }
359
 
360
  select,
bp-templates/bp-nouveau/common-styles/_bp_generic_and_typography.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Generic elements, Typography and Images.
2
- // @version 4.0.0
 
3
 
4
  // ========= Generic Sitewide elements ========
5
  body {
@@ -66,10 +67,10 @@ body.buddypress {
66
  max-width: none;
67
  }
68
 
69
- .entry-content {
 
70
  float: none;
71
  max-width: none;
72
- //padding: 0 $pad-xlrg;
73
  }
74
 
75
  // 2017 has a very large top padding we'll reduce that for bp screens
@@ -125,6 +126,11 @@ body.buddypress { // add weight
125
  // some themes add padding top lets manage that generically sitewide
126
  padding: 0;
127
  }
 
 
 
 
 
128
  }
129
  }
130
 
1
  // BP Generic elements, Typography and Images.
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  // ========= Generic Sitewide elements ========
6
  body {
67
  max-width: none;
68
  }
69
 
70
+ .entry-content,
71
+ .entry .entry-content > * {
72
  float: none;
73
  max-width: none;
 
74
  }
75
 
76
  // 2017 has a very large top padding we'll reduce that for bp screens
126
  // some themes add padding top lets manage that generically sitewide
127
  padding: 0;
128
  }
129
+
130
+ // Specific to Twenty Nineteen
131
+ h2:before {
132
+ display: none;
133
+ }
134
  }
135
  }
136
 
bp-templates/bp-nouveau/common-styles/_bp_groups_create.scss CHANGED
@@ -8,6 +8,11 @@
8
  text-align: center;
9
  }
10
 
 
 
 
 
 
11
  .avatar-nav-items {
12
  margin-top: $marg-med;
13
  }
8
  text-align: center;
9
  }
10
 
11
+ img.avatar {
12
+ width: auto;
13
+ height: auto;
14
+ }
15
+
16
  .avatar-nav-items {
17
  margin-top: $marg-med;
18
  }
bp-templates/bp-nouveau/common-styles/_bp_groups_management.scss CHANGED
@@ -139,3 +139,36 @@
139
  }
140
 
141
  } //close .groups-manage-members-list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  }
140
 
141
  } //close .groups-manage-members-list
142
+
143
+ #group-manage-members-ui {
144
+
145
+ #group-members-search-form {
146
+
147
+ button[type="submit"] {
148
+ float: right;
149
+ font-size: inherit;
150
+ font-weight: 400;
151
+ line-height: 1.5;
152
+ text-align: center;
153
+ text-transform: none;
154
+
155
+ span {
156
+ font-family: dashicons;
157
+
158
+ @include font-size(18);
159
+ line-height: 1.6;
160
+ }
161
+ }
162
+ }
163
+
164
+ #group-members-pagination {
165
+
166
+ button:last-child {
167
+ margin-right: 2em;
168
+ }
169
+ }
170
+
171
+ #bp-no-group-members td {
172
+ border: none;
173
+ }
174
+ }
bp-templates/bp-nouveau/common-styles/_bp_info_messages.scss CHANGED
@@ -259,17 +259,22 @@
259
  &.error,
260
  &.bad {
261
 
262
- @include pwd-bad-colors($color: $white);
263
  }
264
 
265
  &.short {
266
 
267
- @include pwd-short-colors($color: $white);
 
 
 
 
 
268
  }
269
 
270
  &.strong {
271
 
272
- @include pwd-good-colors($color: $white);
273
  }
274
 
275
  } // close #pass-strength-result
259
  &.error,
260
  &.bad {
261
 
262
+ @include pwd-bad-colors($color: $black);
263
  }
264
 
265
  &.short {
266
 
267
+ @include pwd-short-colors($color: $black);
268
+ }
269
+
270
+ &.good {
271
+
272
+ @include pwd-good-colors($color: $black);
273
  }
274
 
275
  &.strong {
276
 
277
+ @include pwd-strong-colors($color: $black);
278
  }
279
 
280
  } // close #pass-strength-result
bp-templates/bp-nouveau/common-styles/_bp_item_body_general.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Single Screens Item Body General Styles.
2
- // @version 3.0.0
 
3
 
4
  .buddypress-wrap {
5
 
@@ -15,6 +16,7 @@
15
 
16
  .button-tabs {
17
  margin: $marg-xlrg 0 $marg-med;
 
18
  }
19
 
20
  }
1
  // BP Single Screens Item Body General Styles.
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  .buddypress-wrap {
6
 
16
 
17
  .button-tabs {
18
  margin: $marg-xlrg 0 $marg-med;
19
+ list-style: none;
20
  }
21
 
22
  }
bp-templates/bp-nouveau/common-styles/_bp_item_header_general.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Single Screens Item Header General Styles.
2
- // @version 3.0.0
 
3
 
4
  @include clearfix-element(".single-headers");
5
 
@@ -16,6 +17,8 @@
16
 
17
  img {
18
  float: none;
 
 
19
  }
20
  }
21
  }
1
  // BP Single Screens Item Header General Styles.
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  @include clearfix-element(".single-headers");
6
 
17
 
18
  img {
19
  float: none;
20
+ width: auto;
21
+ height: auto;
22
  }
23
  }
24
  }
bp-templates/bp-nouveau/common-styles/_bp_lists.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Lists Global Styles.
2
- // @version 3.0.0
 
3
 
4
  // @todo decide whether using .buddypress quasi namespace parent
5
  // is useful, causing issue with specificity on other
@@ -42,7 +43,9 @@
42
  text-align: center;
43
 
44
  img.avatar {
45
- display: inline;
 
 
46
  }
47
  }
48
 
1
  // BP Lists Global Styles.
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  // @todo decide whether using .buddypress quasi namespace parent
6
  // is useful, causing issue with specificity on other
43
  text-align: center;
44
 
45
  img.avatar {
46
+ display: inline-block;
47
+ width: auto;
48
+ height: auto;
49
  }
50
  }
51
 
bp-templates/bp-nouveau/common-styles/_bp_registration.scss CHANGED
@@ -51,6 +51,48 @@
51
  margin: 0 $marg-med $marg-sml 0;
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  .password-entry,
55
  .password-entry-confirm {
56
  border: 1px solid $bp-border-color;
@@ -59,6 +101,20 @@
59
 
60
  } // close .register-page
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  // Flex layout containers for registration sections
63
 
64
  @include medium-up() {
@@ -101,6 +157,7 @@
101
  .register-page {
102
 
103
  .default-profile {
 
104
  flex: 1;
105
  padding-right: $pad-med;
106
  }
51
  margin: 0 $marg-med $marg-sml 0;
52
  }
53
 
54
+ .wp-pwd button {
55
+ vertical-align: middle;
56
+ }
57
+
58
+ #pass1,
59
+ #pass1-text,
60
+ #pass-strength-result {
61
+ width: 10em;
62
+ }
63
+
64
+ #pass1 {
65
+ display: inline-block;
66
+ margin-bottom: inherit;
67
+ }
68
+
69
+ #pass1-text,
70
+ .pw-weak {
71
+ display: none;
72
+ }
73
+
74
+ .show-password {
75
+
76
+ #pass1-text {
77
+ display: inline-block;
78
+ margin-bottom: inherit;
79
+ }
80
+
81
+ #pass1 {
82
+ display: none;
83
+ }
84
+ }
85
+
86
+ .description.indicator-hint {
87
+
88
+ @include font-size(14);
89
+ }
90
+
91
+ #submit:disabled {
92
+ color: $light-text;
93
+ opacity: 0.4;
94
+ }
95
+
96
  .password-entry,
97
  .password-entry-confirm {
98
  border: 1px solid $bp-border-color;
101
 
102
  } // close .register-page
103
 
104
+ body.buddypress.register.js {
105
+
106
+ .user-pass2-wrap {
107
+ display: none;
108
+ }
109
+ }
110
+
111
+ body.buddypress.register.no-js {
112
+
113
+ .wp-hide-pw {
114
+ display: none;
115
+ }
116
+ }
117
+
118
  // Flex layout containers for registration sections
119
 
120
  @include medium-up() {
157
  .register-page {
158
 
159
  .default-profile {
160
+ min-width: 14em;
161
  flex: 1;
162
  padding-right: $pad-med;
163
  }
bp-templates/bp-nouveau/common-styles/_bp_search.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Directory Search elements
2
- // @version 3.0.0
 
3
 
4
  .buddypress-wrap { // the ID is required to add weight to rules
5
 
@@ -7,15 +8,12 @@
7
 
8
  form.bp-dir-search-form,
9
  form.bp-messages-search-form,
10
- form.bp-invites-search-form {
 
11
  border: 1px solid $bp-border-color;
12
 
13
  width: 100%;
14
 
15
- @include medium-lrg-up() {
16
- width: 15em;
17
- }
18
-
19
  label {
20
  margin: 0;
21
  }
@@ -71,6 +69,14 @@
71
 
72
  } // close form
73
 
 
 
 
 
 
 
 
 
74
  // this block needs to be moved really.
75
  ul.filters {
76
 
1
  // BP Directory Search elements
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  .buddypress-wrap { // the ID is required to add weight to rules
6
 
8
 
9
  form.bp-dir-search-form,
10
  form.bp-messages-search-form,
11
+ form[data-bp-search].bp-invites-search-form,
12
+ form#group-members-search {
13
  border: 1px solid $bp-border-color;
14
 
15
  width: 100%;
16
 
 
 
 
 
17
  label {
18
  margin: 0;
19
  }
69
 
70
  } // close form
71
 
72
+ form#group-members-search {
73
+
74
+ &:hover {
75
+ border: 1px solid darken($bp-border-color, 10%);
76
+ box-shadow: inset 0 0 3px #eee;
77
+ }
78
+ }
79
+
80
  // this block needs to be moved really.
81
  ul.filters {
82
 
bp-templates/bp-nouveau/common-styles/_bp_update_form.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP Whats new form handles user updates to groups or profiles
2
- // @version 3.0.0
 
3
 
4
  .activity-update-form {
5
  padding: 10px 10px 0;
@@ -30,6 +31,8 @@
30
  img {
31
  box-shadow: none;
32
  display: inline-block;
 
 
33
  }
34
  }
35
 
@@ -70,13 +73,20 @@
70
  #whats-new-post-in-box-items {
71
  list-style: none;
72
  margin: $marg-sml 0;
 
73
 
74
  li {
75
  margin-bottom: $marg-sml;
76
  }
77
 
 
 
 
 
 
78
  #activity-autocomplete {
79
  padding: 0.3em;
 
80
  }
81
 
82
  .bp-activity-object {
@@ -86,6 +96,7 @@
86
 
87
  .avatar {
88
  width: 30px;
 
89
  }
90
 
91
  span {
@@ -133,8 +144,7 @@
133
  #whats-new-content,
134
  #whats-new-post-in-box,
135
  #whats-new-submit {
136
- margin-left: 8.5%;
137
-
138
  }
139
 
140
  #whats-new-submit {
1
  // BP Whats new form handles user updates to groups or profiles
2
+ // @since 3.0.0
3
+ // @version 5.0.0
4
 
5
  .activity-update-form {
6
  padding: 10px 10px 0;
31
  img {
32
  box-shadow: none;
33
  display: inline-block;
34
+ height: auto;
35
+ width: auto;
36
  }
37
  }
38
 
73
  #whats-new-post-in-box-items {
74
  list-style: none;
75
  margin: $marg-sml 0;
76
+ padding-left: 0;
77
 
78
  li {
79
  margin-bottom: $marg-sml;
80
  }
81
 
82
+ button.bp-remove-item {
83
+ margin-left: $marg-sml;
84
+ height: auto;
85
+ }
86
+
87
  #activity-autocomplete {
88
  padding: 0.3em;
89
+ width: 100%;
90
  }
91
 
92
  .bp-activity-object {
96
 
97
  .avatar {
98
  width: 30px;
99
+ height: 30px;
100
  }
101
 
102
  span {
144
  #whats-new-content,
145
  #whats-new-post-in-box,
146
  #whats-new-submit {
147
+ margin-left: 55px;
 
148
  }
149
 
150
  #whats-new-submit {
bp-templates/bp-nouveau/common-styles/_bp_user_profile.scss CHANGED
@@ -33,17 +33,17 @@
33
  .profile.edit {
34
 
35
  // The groups tabs
36
- .button-nav {
37
  list-style: none;
38
  margin: $marg-xlrg 0 $marg-sml;
 
39
 
40
  li {
41
  display: inline-block;
42
  margin-right: $marg-sml;
43
 
44
  a {
45
-
46
- @include font-size(18);
47
  }
48
  }
49
  }
33
  .profile.edit {
34
 
35
  // The groups tabs
36
+ ul.button-nav {
37
  list-style: none;
38
  margin: $marg-xlrg 0 $marg-sml;
39
+ padding-left: 0;
40
 
41
  li {
42
  display: inline-block;
43
  margin-right: $marg-sml;
44
 
45
  a {
46
+ padding: $pad-sml;
 
47
  }
48
  }
49
  }
bp-templates/bp-nouveau/common-styles/_bp_user_settings.scss CHANGED
@@ -1,5 +1,6 @@
1
  // BP User settings screens
2
- // @version 3.0.0
 
3
 
4
  // 1. Settings Global
5
  // 1. General (email/password change)
@@ -27,7 +28,66 @@
27
  // General
28
 
29
  /*__ General __*/
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  // Email notifications
33
 
@@ -41,3 +101,22 @@
41
  // Group Invites
42
 
43
  /*__ Group Invites __*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  // BP User settings screens
2
+ // @since 3.0.0
3
+ // @version 5.0.0 Add data export settings screen rules.
4
 
5
  // 1. Settings Global
6
  // 1. General (email/password change)
28
  // General
29
 
30
  /*__ General __*/
31
+ body.buddypress.settings {
32
 
33
+ .wp-pwd button {
34
+ vertical-align: middle;
35
+ }
36
+
37
+ #pass1,
38
+ #pass1-text,
39
+ #pass-strength-result {
40
+ width: 16em;
41
+ }
42
+
43
+ #pass1 {
44
+ display: inline-block;
45
+ margin-bottom: inherit;
46
+ }
47
+
48
+ #pass1-text,
49
+ .pw-weak,
50
+ #pass-strength-result {
51
+ display: none;
52
+ }
53
+
54
+ .show-password {
55
+
56
+ #pass1-text {
57
+ display: inline-block;
58
+ margin-bottom: inherit;
59
+ }
60
+
61
+ #pass1 {
62
+ display: none;
63
+ }
64
+ }
65
+
66
+ #your-profile {
67
+
68
+ #submit:disabled {
69
+ color: $light-text;
70
+ opacity: 0.4;
71
+ }
72
+ }
73
+ }
74
+
75
+ body.buddypress.settings.js {
76
+
77
+ .wp-pwd,
78
+ .user-pass2-wrap {
79
+ display: none;
80
+ }
81
+ }
82
+
83
+ body.buddypress.settings.no-js {
84
+
85
+ .wp-generate-pw,
86
+ .wp-cancel-pw,
87
+ .wp-hide-pw {
88
+ display: none;
89
+ }
90
+ }
91
 
92
  // Email notifications
93
 
101
  // Group Invites
102
 
103
  /*__ Group Invites __*/
104
+
105
+ // Data Export
106
+
107
+ /*__ Data Export __*/
108
+ body.buddypress.settings.data {
109
+
110
+ #buddypress.buddypress-wrap {
111
+
112
+ .item-body {
113
+
114
+ p {
115
+
116
+ a {
117
+ text-decoration: underline;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
bp-templates/bp-nouveau/css/buddypress-rtl.css CHANGED
@@ -91,7 +91,8 @@ body #buddypress .bp-list .action {
91
  float: none;
92
  max-width: none;
93
  }
94
- body.buddypress .entry-content {
 
95
  float: none;
96
  max-width: none;
97
  }
@@ -119,6 +120,10 @@ body.buddypress .buddypress-wrap h6 {
119
  padding: 0;
120
  }
121
 
 
 
 
 
122
  /* Ensure .bp-wrap encloses it's children */
123
  .bp-wrap:before,
124
  .bp-wrap:after {
@@ -897,7 +902,9 @@ body.buddypress article.page > .entry-header .entry-title {
897
  }
898
 
899
  .bp-list li .item-avatar img.avatar {
900
- display: inline;
 
 
901
  }
902
 
903
  .bp-list li .item .item-avatar,
@@ -1107,6 +1114,8 @@ body.buddypress article.page > .entry-header .entry-title {
1107
  .activity-update-form #whats-new-avatar img {
1108
  box-shadow: none;
1109
  display: inline-block;
 
 
1110
  }
1111
 
1112
  .activity-update-form #whats-new-content {
@@ -1136,14 +1145,21 @@ body.buddypress article.page > .entry-header .entry-title {
1136
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items {
1137
  list-style: none;
1138
  margin: 10px 0;
 
1139
  }
1140
 
1141
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items li {
1142
  margin-bottom: 10px;
1143
  }
1144
 
 
 
 
 
 
1145
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items #activity-autocomplete {
1146
  padding: 0.3em;
 
1147
  }
1148
 
1149
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object {
@@ -1154,6 +1170,7 @@ body.buddypress article.page > .entry-header .entry-title {
1154
 
1155
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object .avatar {
1156
  width: 30px;
 
1157
  }
1158
 
1159
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object span {
@@ -1193,7 +1210,7 @@ body.buddypress article.page > .entry-header .entry-title {
1193
  .activity-update-form #whats-new-content,
1194
  .activity-update-form #whats-new-post-in-box,
1195
  .activity-update-form #whats-new-submit {
1196
- margin-right: 8.5%;
1197
  }
1198
  .activity-update-form #whats-new-submit input {
1199
  margin-bottom: 0;
@@ -1325,7 +1342,9 @@ body.buddypress article.page > .entry-header .entry-title {
1325
  .activity-list .activity-item .activity-header .avatar {
1326
  display: inline-block;
1327
  margin: 0 5px;
1328
- vertical-align: bottom;
 
 
1329
  }
1330
 
1331
  .activity-list .activity-item .activity-header .time-since {
@@ -1391,6 +1410,7 @@ body.buddypress article.page > .entry-header .entry-title {
1391
 
1392
  .activity-list .activity-item .activity-meta.action .button {
1393
  background: transparent;
 
1394
  }
1395
 
1396
  .activity-list .activity-item .activity-meta.action a {
@@ -1517,6 +1537,7 @@ body.activity-permalink .activity-list .activity-avatar a {
1517
 
1518
  body.activity-permalink .activity-list .activity-avatar img {
1519
  max-width: 100%;
 
1520
  }
1521
 
1522
  body.activity-permalink .activity-list .activity-content {
@@ -1554,6 +1575,9 @@ body.activity-permalink .activity-list .activity-comments {
1554
  position: relative;
1555
  top: -20px;
1556
  }
 
 
 
1557
  body.activity-permalink .activity-list .activity-content {
1558
  margin-left: 10px;
1559
  }
@@ -1946,11 +1970,57 @@ form.ac-form .ac-reply-content input {
1946
  margin: 0 0 10px 15px;
1947
  }
1948
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1949
  .register-page .signup-form .password-entry,
1950
  .register-page .signup-form .password-entry-confirm {
1951
  border: 1px solid #eee;
1952
  }
1953
 
 
 
 
 
 
 
 
 
1954
  @media screen and (min-width: 46.8em) {
1955
  .buddypress-wrap .register-page .layout-wrap {
1956
  display: flex;
@@ -1972,6 +2042,7 @@ form.ac-form .ac-reply-content input {
1972
 
1973
  @media screen and (min-width: 46.8em) {
1974
  .buddypress-wrap.extended-default-reg .register-page .default-profile {
 
1975
  flex: 1;
1976
  padding-left: 1em;
1977
  }
@@ -1997,6 +2068,11 @@ form.ac-form .ac-reply-content input {
1997
  text-align: center;
1998
  }
1999
 
 
 
 
 
 
2000
  #group-create-body .avatar-nav-items {
2001
  margin-top: 15px;
2002
  }
@@ -2032,6 +2108,8 @@ form.ac-form .ac-reply-content input {
2032
 
2033
  .single-headers #item-header-avatar a img {
2034
  float: none;
 
 
2035
  }
2036
 
2037
  .single-headers div#item-header-content {
@@ -2333,6 +2411,7 @@ body.no-js .single-item-header .js-self-profile-button {
2333
 
2334
  .buddypress-wrap .item-body .button-tabs {
2335
  margin: 30px 0 15px;
 
2336
  }
2337
 
2338
  .buddypress-wrap.bp-single-vert-nav .bp-list:not(.grid) .item-entry {
@@ -2480,6 +2559,29 @@ body.no-js .single-item-header .js-self-profile-button {
2480
  }
2481
  }
2482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2483
  /**
2484
  *-----------------------------------------
2485
  * @subsection 5.2.1.2 - Group Members List
@@ -2538,7 +2640,6 @@ body.no-js .single-item-header .js-self-profile-button {
2538
  .buddypress .bp-invites-content li ul.group-inviters {
2539
  clear: both;
2540
  margin: 0;
2541
- overflow: hidden;
2542
  }
2543
 
2544
  .buddypress .bp-invites-content li ul.group-inviters li {
@@ -2676,18 +2777,19 @@ body.no-js .single-item-header .js-self-profile-button {
2676
  width: 30%;
2677
  }
2678
 
2679
- .buddypress-wrap .profile.edit .button-nav {
2680
  list-style: none;
2681
  margin: 30px 0 10px;
 
2682
  }
2683
 
2684
- .buddypress-wrap .profile.edit .button-nav li {
2685
  display: inline-block;
2686
  margin-left: 10px;
2687
  }
2688
 
2689
- .buddypress-wrap .profile.edit .button-nav li a {
2690
- font-size: 18px;
2691
  }
2692
 
2693
  .buddypress-wrap .profile.edit .editfield {
@@ -3016,6 +3118,7 @@ body.register .buddypress-wrap .page ul {
3016
  .bp-messages-content .actions {
3017
  float: left;
3018
  max-width: 30%;
 
3019
  }
3020
 
3021
  .bp-messages-content .actions .bp-icons:not(.bp-hide) {
@@ -3169,6 +3272,7 @@ body.register .buddypress-wrap .page ul {
3169
 
3170
  .bp-messages-content .thread-participants img {
3171
  width: 30px;
 
3172
  }
3173
 
3174
  .bp-messages-content #thread-preview .preview-message ul,
@@ -3221,9 +3325,60 @@ div.bp-navs#subsubnav.bp-messages-filters .user-messages-bulk-actions {
3221
  }
3222
 
3223
  /*__ General __*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3224
  /*__ Email notifications __*/
3225
  /*__ Profile visibility __*/
3226
  /*__ Group Invites __*/
 
 
 
 
 
3227
  /**
3228
  *-------------------------------------------------------------------------------
3229
  * @section 6.0 - Forms - General
@@ -3331,7 +3486,7 @@ div.bp-navs#subsubnav.bp-messages-filters .user-messages-bulk-actions {
3331
  border-color: #b71717;
3332
  }
3333
 
3334
- .buddypress-wrap .standard-form input:not(.button-small),
3335
  .buddypress-wrap .standard-form textarea {
3336
  width: 100%;
3337
  }
@@ -3504,7 +3659,7 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3504
  position: relative;
3505
  text-indent: -2px;
3506
  z-index: 1;
3507
- width: 100%;
3508
  }
3509
 
3510
  .buddypress-wrap .select-wrap select,
@@ -3560,22 +3715,16 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3560
 
3561
  .buddypress-wrap form.bp-dir-search-form,
3562
  .buddypress-wrap form.bp-messages-search-form,
3563
- .buddypress-wrap form.bp-invites-search-form {
 
3564
  border: 1px solid #eee;
3565
  width: 100%;
3566
  }
3567
 
3568
- @media screen and (min-width: 55em) {
3569
- .buddypress-wrap form.bp-dir-search-form,
3570
- .buddypress-wrap form.bp-messages-search-form,
3571
- .buddypress-wrap form.bp-invites-search-form {
3572
- width: 15em;
3573
- }
3574
- }
3575
-
3576
  .buddypress-wrap form.bp-dir-search-form label,
3577
  .buddypress-wrap form.bp-messages-search-form label,
3578
- .buddypress-wrap form.bp-invites-search-form label {
 
3579
  margin: 0;
3580
  }
3581
 
@@ -3585,9 +3734,12 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3585
  .buddypress-wrap form.bp-messages-search-form input[type="search"],
3586
  .buddypress-wrap form.bp-messages-search-form input[type="text"],
3587
  .buddypress-wrap form.bp-messages-search-form button[type="submit"],
3588
- .buddypress-wrap form.bp-invites-search-form input[type="search"],
3589
- .buddypress-wrap form.bp-invites-search-form input[type="text"],
3590
- .buddypress-wrap form.bp-invites-search-form button[type="submit"] {
 
 
 
3591
  background: none;
3592
  border: 0;
3593
  border-radius: 0;
@@ -3598,8 +3750,10 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3598
  .buddypress-wrap form.bp-dir-search-form input[type="text"],
3599
  .buddypress-wrap form.bp-messages-search-form input[type="search"],
3600
  .buddypress-wrap form.bp-messages-search-form input[type="text"],
3601
- .buddypress-wrap form.bp-invites-search-form input[type="search"],
3602
- .buddypress-wrap form.bp-invites-search-form input[type="text"] {
 
 
3603
  float: right;
3604
  line-height: 1.5;
3605
  padding: 3px 10px;
@@ -3608,7 +3762,8 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3608
 
3609
  .buddypress-wrap form.bp-dir-search-form button[type="submit"],
3610
  .buddypress-wrap form.bp-messages-search-form button[type="submit"],
3611
- .buddypress-wrap form.bp-invites-search-form button[type="submit"] {
 
3612
  float: left;
3613
  font-size: inherit;
3614
  font-weight: 400;
@@ -3621,7 +3776,8 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3621
 
3622
  .buddypress-wrap form.bp-dir-search-form button[type="submit"] span,
3623
  .buddypress-wrap form.bp-messages-search-form button[type="submit"] span,
3624
- .buddypress-wrap form.bp-invites-search-form button[type="submit"] span {
 
3625
  font-family: dashicons;
3626
  font-size: 18px;
3627
  line-height: 1.6;
@@ -3629,7 +3785,8 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3629
 
3630
  .buddypress-wrap form.bp-dir-search-form button[type="submit"].bp-show,
3631
  .buddypress-wrap form.bp-messages-search-form button[type="submit"].bp-show,
3632
- .buddypress-wrap form.bp-invites-search-form button[type="submit"].bp-show {
 
3633
  height: auto;
3634
  right: 0;
3635
  overflow: visible;
@@ -3639,7 +3796,8 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3639
 
3640
  .buddypress-wrap form.bp-dir-search-form input[type="search"]::-webkit-search-cancel-button,
3641
  .buddypress-wrap form.bp-messages-search-form input[type="search"]::-webkit-search-cancel-button,
3642
- .buddypress-wrap form.bp-invites-search-form input[type="search"]::-webkit-search-cancel-button {
 
3643
  -webkit-appearance: searchfield-cancel-button;
3644
  }
3645
 
@@ -3647,11 +3805,18 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3647
  .buddypress-wrap form.bp-dir-search-form input[type="search"]::-webkit-search-results-decoration,
3648
  .buddypress-wrap form.bp-messages-search-form input[type="search"]::-webkit-search-results-button,
3649
  .buddypress-wrap form.bp-messages-search-form input[type="search"]::-webkit-search-results-decoration,
3650
- .buddypress-wrap form.bp-invites-search-form input[type="search"]::-webkit-search-results-button,
3651
- .buddypress-wrap form.bp-invites-search-form input[type="search"]::-webkit-search-results-decoration {
 
 
3652
  display: none;
3653
  }
3654
 
 
 
 
 
 
3655
  .buddypress-wrap ul.filters li form label input {
3656
  line-height: 1.4;
3657
  padding: 0.1em 0.7em;
@@ -3883,8 +4048,10 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3883
  border-color: #ccc;
3884
  border-style: solid;
3885
  border-width: 1px;
 
3886
  color: #555;
3887
  cursor: pointer;
 
3888
  font-size: inherit;
3889
  font-weight: 400;
3890
  outline: none;
@@ -3892,6 +4059,12 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
3892
  text-align: center;
3893
  text-decoration: none;
3894
  width: auto;
 
 
 
 
 
 
3895
  }
3896
 
3897
  .buddypress .buddypress-wrap .button-small[type="button"] {
@@ -4350,19 +4523,25 @@ body.no-js .buddypress #messages-bulk-management #select-all-messages {
4350
  .buddypress-wrap #pass-strength-result.error, .buddypress-wrap #pass-strength-result.bad {
4351
  background-color: #ffb78c;
4352
  border-color: #ff853c;
4353
- color: #fff;
4354
  }
4355
 
4356
  .buddypress-wrap #pass-strength-result.short {
4357
  background-color: #ffa0a0;
4358
  border-color: #f04040;
4359
- color: #fff;
 
 
 
 
 
 
4360
  }
4361
 
4362
  .buddypress-wrap #pass-strength-result.strong {
4363
  background-color: #66d66e;
4364
  border-color: #438c48;
4365
- color: #fff;
4366
  }
4367
 
4368
  .buddypress-wrap .standard-form#signup_form div div.error {
91
  float: none;
92
  max-width: none;
93
  }
94
+ body.buddypress .entry-content,
95
+ body.buddypress .entry .entry-content > * {
96
  float: none;
97
  max-width: none;
98
  }
120
  padding: 0;
121
  }
122
 
123
+ body.buddypress .buddypress-wrap h2:before {
124
+ display: none;
125
+ }
126
+
127
  /* Ensure .bp-wrap encloses it's children */
128
  .bp-wrap:before,
129
  .bp-wrap:after {
902
  }
903
 
904
  .bp-list li .item-avatar img.avatar {
905
+ display: inline-block;
906
+ width: auto;
907
+ height: auto;
908
  }
909
 
910
  .bp-list li .item .item-avatar,
1114
  .activity-update-form #whats-new-avatar img {
1115
  box-shadow: none;
1116
  display: inline-block;
1117
+ height: auto;
1118
+ width: auto;
1119
  }
1120
 
1121
  .activity-update-form #whats-new-content {
1145
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items {
1146
  list-style: none;
1147
  margin: 10px 0;
1148
+ padding-right: 0;
1149
  }
1150
 
1151
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items li {
1152
  margin-bottom: 10px;
1153
  }
1154
 
1155
+ .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items button.bp-remove-item {
1156
+ margin-right: 10px;
1157
+ height: auto;
1158
+ }
1159
+
1160
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items #activity-autocomplete {
1161
  padding: 0.3em;
1162
+ width: 100%;
1163
  }
1164
 
1165
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object {
1170
 
1171
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object .avatar {
1172
  width: 30px;
1173
+ height: 30px;
1174
  }
1175
 
1176
  .activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object span {
1210
  .activity-update-form #whats-new-content,
1211
  .activity-update-form #whats-new-post-in-box,
1212
  .activity-update-form #whats-new-submit {
1213
+ margin-right: 55px;
1214
  }
1215
  .activity-update-form #whats-new-submit input {
1216
  margin-bottom: 0;
1342
  .activity-list .activity-item .activity-header .avatar {
1343
  display: inline-block;
1344
  margin: 0 5px;
1345
+ vertical-align: text-top;
1346
+ width: 20px;
1347
+ height: 20px;
1348
  }
1349
 
1350
  .activity-list .activity-item .activity-header .time-since {
1410
 
1411
  .activity-list .activity-item .activity-meta.action .button {
1412
  background: transparent;
1413
+ color: #555;
1414
  }
1415
 
1416
  .activity-list .activity-item .activity-meta.action a {
1537
 
1538
  body.activity-permalink .activity-list .activity-avatar img {
1539
  max-width: 100%;
1540
+ background-color: #eaeaea;
1541
  }
1542
 
1543
  body.activity-permalink .activity-list .activity-content {
1575
  position: relative;
1576
  top: -20px;
1577
  }
1578
+ body.activity-permalink .activity-list .activity-avatar img {
1579
+ box-shadow: 0 0 0 8px #fff;
1580
+ }
1581
  body.activity-permalink .activity-list .activity-content {
1582
  margin-left: 10px;
1583
  }
1970
  margin: 0 0 10px 15px;
1971
  }
1972
 
1973
+ .register-page .signup-form .wp-pwd button {
1974
+ vertical-align: middle;
1975
+ }
1976
+
1977
+ .register-page .signup-form #pass1,
1978
+ .register-page .signup-form #pass1-text,
1979
+ .register-page .signup-form #pass-strength-result {
1980
+ width: 10em;
1981
+ }
1982
+
1983
+ .register-page .signup-form #pass1 {
1984
+ display: inline-block;
1985
+ margin-bottom: inherit;
1986
+ }
1987
+
1988
+ .register-page .signup-form #pass1-text,
1989
+ .register-page .signup-form .pw-weak {
1990
+ display: none;
1991
+ }
1992
+
1993
+ .register-page .signup-form .show-password #pass1-text {
1994
+ display: inline-block;
1995
+ margin-bottom: inherit;
1996
+ }
1997
+
1998
+ .register-page .signup-form .show-password #pass1 {
1999
+ display: none;
2000
+ }
2001
+
2002
+ .register-page .signup-form .description.indicator-hint {
2003
+ font-size: 14px;
2004
+ }
2005
+
2006
+ .register-page .signup-form #submit:disabled {
2007
+ color: #767676;
2008
+ opacity: 0.4;
2009
+ }
2010
+
2011
  .register-page .signup-form .password-entry,
2012
  .register-page .signup-form .password-entry-confirm {
2013
  border: 1px solid #eee;
2014
  }
2015
 
2016
+ body.buddypress.register.js .user-pass2-wrap {
2017
+ display: none;
2018
+ }
2019
+
2020
+ body.buddypress.register.no-js .wp-hide-pw {
2021
+ display: none;
2022
+ }
2023
+
2024
  @media screen and (min-width: 46.8em) {
2025
  .buddypress-wrap .register-page .layout-wrap {
2026
  display: flex;
2042
 
2043
  @media screen and (min-width: 46.8em) {
2044
  .buddypress-wrap.extended-default-reg .register-page .default-profile {
2045
+ min-width: 14em;
2046
  flex: 1;
2047
  padding-left: 1em;
2048
  }
2068
  text-align: center;
2069
  }
2070
 
2071
+ #group-create-body img.avatar {
2072
+ width: auto;
2073
+ height: auto;
2074
+ }
2075
+
2076
  #group-create-body .avatar-nav-items {
2077
  margin-top: 15px;
2078
  }
2108
 
2109
  .single-headers #item-header-avatar a img {
2110
  float: none;
2111
+ width: auto;
2112
+ height: auto;
2113
  }
2114
 
2115
  .single-headers div#item-header-content {
2411
 
2412
  .buddypress-wrap .item-body .button-tabs {
2413
  margin: 30px 0 15px;
2414
+ list-style: none;
2415
  }
2416
 
2417
  .buddypress-wrap.bp-single-vert-nav .bp-list:not(.grid) .item-entry {
2559
  }
2560
  }
2561
 
2562
+ #group-manage-members-ui #group-members-search-form button[type="submit"] {
2563
+ float: left;
2564
+ font-size: inherit;
2565
+ font-weight: 400;
2566
+ line-height: 1.5;
2567
+ text-align: center;
2568
+ text-transform: none;
2569
+ }
2570
+
2571
+ #group-manage-members-ui #group-members-search-form button[type="submit"] span {
2572
+ font-family: dashicons;
2573
+ font-size: 18px;
2574
+ line-height: 1.6;
2575
+ }
2576
+
2577
+ #group-manage-members-ui #group-members-pagination button:last-child {
2578
+ margin-left: 2em;
2579
+ }
2580
+
2581
+ #group-manage-members-ui #bp-no-group-members td {
2582
+ border: none;
2583
+ }
2584
+
2585
  /**
2586
  *-----------------------------------------
2587
  * @subsection 5.2.1.2 - Group Members List
2640
  .buddypress .bp-invites-content li ul.group-inviters {
2641
  clear: both;
2642
  margin: 0;
 
2643
  }
2644
 
2645
  .buddypress .bp-invites-content li ul.group-inviters li {
2777
  width: 30%;
2778
  }
2779
 
2780
+ .buddypress-wrap .profile.edit ul.button-nav {
2781
  list-style: none;
2782
  margin: 30px 0 10px;
2783
+ padding-right: 0;
2784
  }
2785
 
2786
+ .buddypress-wrap .profile.edit ul.button-nav li {
2787
  display: inline-block;
2788
  margin-left: 10px;
2789
  }
2790
 
2791
+ .buddypress-wrap .profile.edit ul.button-nav li a {
2792
+ padding: 0.5em;
2793
  }
2794
 
2795
  .buddypress-wrap .profile.edit .editfield {
3118
  .bp-messages-content .actions {
3119
  float: left;
3120
  max-width: 30%;
3121
+ line-height: 1;
3122
  }
3123
 
3124
  .bp-messages-content .actions .bp-icons:not(.bp-hide) {
3272
 
3273
  .bp-messages-content .thread-participants img {
3274
  width: 30px;
3275
+ height: 30px;
3276
  }
3277
 
3278
  .bp-messages-content #thread-preview .preview-message ul,
3325
  }
3326
 
3327
  /*__ General __*/
3328
+ body.buddypress.settings .wp-pwd button {
3329
+ vertical-align: middle;
3330
+ }
3331
+
3332
+ body.buddypress.settings #pass1,
3333
+ body.buddypress.settings #pass1-text,
3334
+ body.buddypress.settings #pass-strength-result {
3335
+ width: 16em;
3336
+ }
3337
+
3338
+ body.buddypress.settings #pass1 {
3339
+ display: inline-block;
3340
+ margin-bottom: inherit;
3341
+ }
3342
+
3343
+ body.buddypress.settings #pass1-text,
3344
+ body.buddypress.settings .pw-weak,
3345
+ body.buddypress.settings #pass-strength-result {
3346
+ display: none;
3347
+ }
3348
+
3349
+ body.buddypress.settings .show-password #pass1-text {
3350
+ display: inline-block;
3351
+ margin-bottom: inherit;
3352
+ }
3353
+
3354
+ body.buddypress.settings .show-password #pass1 {
3355
+ display: none;
3356
+ }
3357
+
3358
+ body.buddypress.settings #your-profile #submit:disabled {
3359
+ color: #767676;
3360
+ opacity: 0.4;
3361
+ }
3362
+
3363
+ body.buddypress.settings.js .wp-pwd,
3364
+ body.buddypress.settings.js .user-pass2-wrap {
3365
+ display: none;
3366
+ }
3367
+
3368
+ body.buddypress.settings.no-js .wp-generate-pw,
3369
+ body.buddypress.settings.no-js .wp-cancel-pw,
3370
+ body.buddypress.settings.no-js .wp-hide-pw {
3371
+ display: none;
3372
+ }
3373
+
3374
  /*__ Email notifications __*/
3375
  /*__ Profile visibility __*/
3376
  /*__ Group Invites __*/
3377
+ /*__ Data Export __*/
3378
+ body.buddypress.settings.data #buddypress.buddypress-wrap .item-body p a {
3379
+ text-decoration: underline;
3380
+ }
3381
+
3382
  /**
3383
  *-------------------------------------------------------------------------------
3384
  * @section 6.0 - Forms - General
3486
  border-color: #b71717;
3487
  }
3488
 
3489
+ .buddypress-wrap .standard-form input:not(.small),
3490
  .buddypress-wrap .standard-form textarea {
3491
  width: 100%;
3492
  }
3659
  position: relative;
3660
  text-indent: -2px;
3661
  z-index: 1;
3662
+ width: auto;
3663
  }
3664
 
3665
  .buddypress-wrap .select-wrap select,
3715
 
3716
  .buddypress-wrap form.bp-dir-search-form,
3717
  .buddypress-wrap form.bp-messages-search-form,
3718
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form,
3719
+ .buddypress-wrap form#group-members-search {
3720
  border: 1px solid #eee;
3721
  width: 100%;
3722
  }
3723
 
 
 
 
 
 
 
 
 
3724
  .buddypress-wrap form.bp-dir-search-form label,
3725
  .buddypress-wrap form.bp-messages-search-form label,
3726
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form label,
3727
+ .buddypress-wrap form#group-members-search label {
3728
  margin: 0;
3729
  }
3730
 
3734
  .buddypress-wrap form.bp-messages-search-form input[type="search"],
3735
  .buddypress-wrap form.bp-messages-search-form input[type="text"],
3736
  .buddypress-wrap form.bp-messages-search-form button[type="submit"],
3737
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="search"],
3738
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="text"],
3739
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form button[type="submit"],
3740
+ .buddypress-wrap form#group-members-search input[type="search"],
3741
+ .buddypress-wrap form#group-members-search input[type="text"],
3742
+ .buddypress-wrap form#group-members-search button[type="submit"] {
3743
  background: none;
3744
  border: 0;
3745
  border-radius: 0;
3750
  .buddypress-wrap form.bp-dir-search-form input[type="text"],
3751
  .buddypress-wrap form.bp-messages-search-form input[type="search"],
3752
  .buddypress-wrap form.bp-messages-search-form input[type="text"],
3753
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="search"],
3754
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="text"],
3755
+ .buddypress-wrap form#group-members-search input[type="search"],
3756
+ .buddypress-wrap form#group-members-search input[type="text"] {
3757
  float: right;
3758
  line-height: 1.5;
3759
  padding: 3px 10px;
3762
 
3763
  .buddypress-wrap form.bp-dir-search-form button[type="submit"],
3764
  .buddypress-wrap form.bp-messages-search-form button[type="submit"],
3765
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form button[type="submit"],
3766
+ .buddypress-wrap form#group-members-search button[type="submit"] {
3767
  float: left;
3768
  font-size: inherit;
3769
  font-weight: 400;
3776
 
3777
  .buddypress-wrap form.bp-dir-search-form button[type="submit"] span,
3778
  .buddypress-wrap form.bp-messages-search-form button[type="submit"] span,
3779
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form button[type="submit"] span,
3780
+ .buddypress-wrap form#group-members-search button[type="submit"] span {
3781
  font-family: dashicons;
3782
  font-size: 18px;
3783
  line-height: 1.6;
3785
 
3786
  .buddypress-wrap form.bp-dir-search-form button[type="submit"].bp-show,
3787
  .buddypress-wrap form.bp-messages-search-form button[type="submit"].bp-show,
3788
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form button[type="submit"].bp-show,
3789
+ .buddypress-wrap form#group-members-search button[type="submit"].bp-show {
3790
  height: auto;
3791
  right: 0;
3792
  overflow: visible;
3796
 
3797
  .buddypress-wrap form.bp-dir-search-form input[type="search"]::-webkit-search-cancel-button,
3798
  .buddypress-wrap form.bp-messages-search-form input[type="search"]::-webkit-search-cancel-button,
3799
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="search"]::-webkit-search-cancel-button,
3800
+ .buddypress-wrap form#group-members-search input[type="search"]::-webkit-search-cancel-button {
3801
  -webkit-appearance: searchfield-cancel-button;
3802
  }
3803
 
3805
  .buddypress-wrap form.bp-dir-search-form input[type="search"]::-webkit-search-results-decoration,
3806
  .buddypress-wrap form.bp-messages-search-form input[type="search"]::-webkit-search-results-button,
3807
  .buddypress-wrap form.bp-messages-search-form input[type="search"]::-webkit-search-results-decoration,
3808
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="search"]::-webkit-search-results-button,
3809
+ .buddypress-wrap form[data-bp-search].bp-invites-search-form input[type="search"]::-webkit-search-results-decoration,
3810
+ .buddypress-wrap form#group-members-search input[type="search"]::-webkit-search-results-button,
3811
+ .buddypress-wrap form#group-members-search input[type="search"]::-webkit-search-results-decoration {
3812
  display: none;
3813
  }
3814
 
3815
+ .buddypress-wrap form#group-members-search:hover {
3816
+ border: 1px solid #d5d4d4;
3817
+ box-shadow: inset 0 0 3px #eee;
3818
+ }
3819
+
3820
  .buddypress-wrap ul.filters li form label input {
3821
  line-height: 1.4;
3822
  padding: 0.1em 0.7em;
4048
  border-color: #ccc;
4049
  border-style: solid;
4050
  border-width: 1px;
4051
+ border-radius: 0;
4052
  color: #555;
4053
  cursor: pointer;
4054
+ font-family: inherit;
4055
  font-size: inherit;
4056
  font-weight: 400;
4057
  outline: none;
4059
  text-align: center;
4060
  text-decoration: none;
4061
  width: auto;
4062
+ line-height: 1;
4063
+ }
4064
+
4065
+ .buddypress .buddypress-wrap button.dashicons,
4066
+ .buddypress .buddypress-wrap a.button.dashicons {
4067
+ font-family: dashicons;
4068
  }
4069
 
4070
  .buddypress .buddypress-wrap .button-small[type="button"] {
4523
  .buddypress-wrap #pass-strength-result.error, .buddypress-wrap #pass-strength-result.bad {
4524
  background-color: #ffb78c;
4525
  border-color: #ff853c;
4526
+ color: #333;
4527
  }
4528
 
4529
  .buddypress-wrap #pass-strength-result.short {
4530
  background-color: #ffa0a0;
4531
  border-color: #f04040;
4532
+ color: #333;
4533
+ }
4534
+
4535
+ .buddypress-wrap #pass-strength-result.good {
4536
+ background-color: #ffec8b;
4537
+ border-color: #fc0;
4538
+ color: #333;
4539
  }
4540
 
4541
  .buddypress-wrap #pass-strength-result.strong {
4542
  background-color: #66d66e;
4543
  border-color: #438c48;
4544
+ color: #333;
4545
  }
4546
 
4547
  .buddypress-wrap .standard-form#signup_form div div.error {
bp-templates/bp-nouveau/css/buddypress-rtl.min.css CHANGED
@@ -1 +1 @@
1
- body #buddypress * a{box-shadow:none;text-decoration:none}body #buddypress div,body #buddypress dl,body #buddypress input[type=reset],body #buddypress input[type=search],body #buddypress input[type=submit],body #buddypress li,body #buddypress select,body #buddypress textarea{border-radius:2px;background-clip:padding-box}body #buddypress #item-body blockquote,body #buddypress .bp-lists blockquote{margin-right:0}body #buddypress .bp-list .action{box-sizing:border-box}@media screen and (min-width:46.8em){body.buddypress .entry-content,body.buddypress .entry-header,body.buddypress .site-content .entry-header{max-width:none}body.buddypress .entry-header{float:none;max-width:none}body.buddypress .entry-content{float:none;max-width:none}body.buddypress .site-content{padding-top:2.5em}body.buddypress #page #primary{max-width:none}body.buddypress #page #primary .entry-content,body.buddypress #page #primary .entry-header{float:none;width:auto}}body.buddypress .buddypress-wrap h1,body.buddypress .buddypress-wrap h2,body.buddypress .buddypress-wrap h3,body.buddypress .buddypress-wrap h4,body.buddypress .buddypress-wrap h5,body.buddypress .buddypress-wrap h6{clear:none;margin:1em 0;padding:0}.bp-wrap:after,.bp-wrap:before{content:" ";display:table}.bp-wrap:after{clear:both}.buddypress-wrap.round-avatars .avatar{border-radius:50%}body.buddypress article.page>.entry-header{margin-bottom:2em;padding:0}body.buddypress article.page>.entry-header .entry-title{font-size:28px;font-weight:inherit;color:#767676}@media screen and (min-width:46.8em){body.buddypress article.page>.entry-header .entry-title{font-size:34px}}.buddypress-wrap dt.section-title{font-size:18px}@media screen and (min-width:46.8em){.buddypress-wrap dt.section-title{font-size:22px}}.buddypress-wrap .bp-label-text,.buddypress-wrap .message-threads{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-label-text,.buddypress-wrap .message-threads{font-size:16px}}.buddypress-wrap .activity-header{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .activity-header{font-size:16px}}.buddypress-wrap .activity-inner{font-size:15px}@media screen and (min-width:46.8em){.buddypress-wrap .activity-inner{font-size:18px}}.buddypress-wrap #whats-new-post-in{font-size:16px}.buddypress-wrap .acomment-meta,.buddypress-wrap .mini .activity-header{font-size:16px}.buddypress-wrap .dir-component-filters #activity-filter-by{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .dir-component-filters #activity-filter-by{font-size:16px}}.buddypress-wrap .bp-tables-user th{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-tables-user th{font-size:16px}}.buddypress-wrap .bp-tables-user td{font-size:12px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-tables-user td{font-size:14px}}.buddypress-wrap .profile-fields th{font-size:15px}@media screen and (min-width:46.8em){.buddypress-wrap .profile-fields th{font-size:18px}}.buddypress-wrap .profile-fields td{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .profile-fields td{font-size:16px}}.buddypress-wrap #notification-select{font-size:12px}@media screen and (min-width:46.8em){.buddypress-wrap #notification-select{font-size:14px}}.bp-navs{background:0 0;clear:both;overflow:hidden}.bp-navs ul{margin:0;padding:0}.bp-navs ul li{list-style:none;margin:0}.bp-navs ul li.last select{max-width:185px}.bp-navs ul li a,.bp-navs ul li span{border:0;display:block;padding:5px 10px;text-decoration:none}.bp-navs ul li .count{background:#eaeaea;border:1px solid #ccc;border-radius:50%;color:#555;display:inline;font-size:12px;margin-right:2px;padding:3px 6px;text-align:center;vertical-align:middle}.bp-navs ul li.current a,.bp-navs ul li.selected a{color:#333;opacity:1}.bp-navs.bp-invites-filters ul li a,.bp-navs.bp-messages-filters ul li a{border:1px solid #ccc;display:inline-block}.main-navs.dir-navs{margin-bottom:20px}.buddypress-wrap .bp-navs li a:hover a .count,.buddypress-wrap .bp-navs li.current a .count,.buddypress-wrap .bp-navs li.selected a .count{background-color:#ccc}.buddypress-wrap .bp-navs li:not(.current) a:focus,.buddypress-wrap .bp-navs li:not(.current) a:hover,.buddypress-wrap .bp-navs li:not(.selected) a:focus,.buddypress-wrap .bp-navs li:not(.selected) a:hover{background:#ccc;color:#333}.buddypress-wrap .bp-navs li.current a,.buddypress-wrap .bp-navs li.current a:focus,.buddypress-wrap .bp-navs li.current a:hover,.buddypress-wrap .bp-navs li.selected a,.buddypress-wrap .bp-navs li.selected a:focus,.buddypress-wrap .bp-navs li.selected a:hover{background:#555;color:#fafafa}@media screen and (min-width:46.8em){.buddypress-wrap .main-navs:not(.dir-navs) li.current a,.buddypress-wrap .main-navs:not(.dir-navs) li.selected a{background:#fff;color:#333;font-weight:600}.buddypress-wrap .main-navs.vertical li.current a,.buddypress-wrap .main-navs.vertical li.selected a{background:#555;color:#fafafa;text-decoration:none}.buddypress-wrap.bp-dir-hori-nav:not(.bp-vertical-navs) nav:not(.tabbed-links){border-bottom:1px solid #eee;border-top:1px solid #eee;box-shadow:0 2px 12px 0 #fafafa}}.buddypress-wrap .bp-subnavs li.current a,.buddypress-wrap .bp-subnavs li.selected a{background:#fff;color:#333;font-weight:600}@media screen and (max-width:46.8em){.buddypress-wrap:not(.bp-single-vert-nav) .bp-navs li{background:#eaeaea}}.buddypress-wrap:not(.bp-single-vert-nav) .main-navs>ul>li>a{padding:.5em calc(.5em + 2px)}.buddypress-wrap:not(.bp-single-vert-nav) .group-subnav#subsubnav,.buddypress-wrap:not(.bp-single-vert-nav) .user-subnav#subsubnav{background:0 0}.buddypress-wrap .bp-subnavs,.buddypress-wrap ul.subnav{width:100%}.buddypress-wrap .bp-subnavs{margin:10px 0;overflow:hidden}.buddypress-wrap .bp-subnavs ul li{margin-top:0}.buddypress-wrap .bp-subnavs ul li.current :focus,.buddypress-wrap .bp-subnavs ul li.current :hover,.buddypress-wrap .bp-subnavs ul li.selected :focus,.buddypress-wrap .bp-subnavs ul li.selected :hover{background:0 0;color:#333}.buddypress-wrap ul.subnav{width:auto}.buddypress-wrap .bp-navs.bp-invites-filters#subsubnav ul li.last,.buddypress-wrap .bp-navs.bp-invites-nav#subnav ul li.last,.buddypress-wrap .bp-navs.bp-messages-filters#subsubnav ul li.last{margin-top:0}@media screen and (max-width:46.8em){.buddypress-wrap .single-screen-navs{border:1px solid #eee}.buddypress-wrap .single-screen-navs li{border-bottom:1px solid #eee}.buddypress-wrap .single-screen-navs li:last-child{border-bottom:none}.buddypress-wrap .bp-subnavs li a{font-size:14px}.buddypress-wrap .bp-subnavs li.current a,.buddypress-wrap .bp-subnavs li.current a:focus,.buddypress-wrap .bp-subnavs li.current a:hover,.buddypress-wrap .bp-subnavs li.selected a,.buddypress-wrap .bp-subnavs li.selected a:focus,.buddypress-wrap .bp-subnavs li.selected a:hover{background:#555;color:#fff}}.buddypress-wrap .bp-navs li.current a .count,.buddypress-wrap .bp-navs li.selected a .count,.buddypress_object_nav .bp-navs li.current a .count,.buddypress_object_nav .bp-navs li.selected a .count{background-color:#fff}.buddypress-wrap .bp-navs li.dynamic a .count,.buddypress-wrap .bp-navs li.dynamic.current a .count,.buddypress-wrap .bp-navs li.dynamic.selected a .count,.buddypress_object_nav .bp-navs li.dynamic a .count,.buddypress_object_nav .bp-navs li.dynamic.current a .count,.buddypress_object_nav .bp-navs li.dynamic.selected a .count{background-color:#5087e5;border:0;color:#fafafa}.buddypress-wrap .bp-navs li.dynamic a:hover .count,.buddypress_object_nav .bp-navs li.dynamic a:hover .count{background-color:#5087e5;border:0;color:#fff}.buddypress-wrap .bp-navs li a .count:empty,.buddypress_object_nav .bp-navs li a .count:empty{display:none}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current),.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current){color:#767676}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a{color:#767676}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a:focus,.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a:hover,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a:focus,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a:hover{background:0 0;color:#333}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a[disabled]:focus,.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a[disabled]:hover,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a[disabled]:focus,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a[disabled]:hover{color:#767676}.buddypress-wrap .bp-navs.group-create-links ul li.current a,.buddypress_object_nav .bp-navs.group-create-links ul li.current a{text-align:center}@media screen and (min-width:46.8em){.buddypress-wrap .bp-navs li{float:right}.buddypress-wrap .subnav{float:right}.buddypress-wrap ul.subnav{width:auto}.buddypress-wrap #subsubnav .activity-search{float:right}.buddypress-wrap #subsubnav .filter{float:left}}.buddypress_object_nav .bp-navs li a .count{display:inline-block;float:left}@media screen and (min-width:46.8em){.bp-dir-vert-nav .bp-navs.dir-navs{background:0 0}.bp-dir-vert-nav .bp-navs.dir-navs a .count{float:left}}@media screen and (min-width:46.8em){.buddypress-wrap .tabbed-links ol,.buddypress-wrap .tabbed-links ul{border-bottom:1px solid #ccc;float:none;margin:20px 0 10px}.buddypress-wrap .tabbed-links ol:after,.buddypress-wrap .tabbed-links ol:before,.buddypress-wrap .tabbed-links ul:after,.buddypress-wrap .tabbed-links ul:before{content:" ";display:block}.buddypress-wrap .tabbed-links ol:after,.buddypress-wrap .tabbed-links ul:after{clear:both}.buddypress-wrap .tabbed-links ol li,.buddypress-wrap .tabbed-links ul li{float:right;list-style:none;margin:0 0 0 10px}.buddypress-wrap .tabbed-links ol li a,.buddypress-wrap .tabbed-links ol li span:not(.count),.buddypress-wrap .tabbed-links ul li a,.buddypress-wrap .tabbed-links ul li span:not(.count){background:0 0;border:none;display:block;padding:4px 10px}.buddypress-wrap .tabbed-links ol li a:focus,.buddypress-wrap .tabbed-links ol li a:hover,.buddypress-wrap .tabbed-links ul li a:focus,.buddypress-wrap .tabbed-links ul li a:hover{background:0 0}.buddypress-wrap .tabbed-links ol li:not(.current),.buddypress-wrap .tabbed-links ul li:not(.current){margin-bottom:2px}.buddypress-wrap .tabbed-links ol li.current,.buddypress-wrap .tabbed-links ul li.current{border-color:#ccc #ccc #fff;border-style:solid;border-top-right-radius:4px;border-top-left-radius:4px;border-width:1px;margin-bottom:-1px;padding:0 .5em 1px}.buddypress-wrap .tabbed-links ol li.current a,.buddypress-wrap .tabbed-links ul li.current a{background:0 0;color:#333}.buddypress-wrap .bp-subnavs.tabbed-links>ul{margin-top:0}.buddypress-wrap .bp-navs.tabbed-links{background:0 0;margin-top:2px}.buddypress-wrap .bp-navs.tabbed-links ul li a{border-left:0;font-size:inherit}.buddypress-wrap .bp-navs.tabbed-links ul li.last{float:left;margin:0}.buddypress-wrap .bp-navs.tabbed-links ul li.last a{margin-top:-.5em}.buddypress-wrap .bp-navs.tabbed-links ul li a,.buddypress-wrap .bp-navs.tabbed-links ul li a:focus,.buddypress-wrap .bp-navs.tabbed-links ul li a:hover,.buddypress-wrap .bp-navs.tabbed-links ul li.current a,.buddypress-wrap .bp-navs.tabbed-links ul li.current a:focus,.buddypress-wrap .bp-navs.tabbed-links ul li.current a:hover{background:0 0;border:0}.buddypress-wrap .bp-navs.tabbed-links ul li a:active,.buddypress-wrap .bp-navs.tabbed-links ul li.current a:active{outline:0}}.buddypress-wrap .dir-component-filters .filter label{display:inline}.buddypress-wrap .subnav-filters:after,.buddypress-wrap .subnav-filters:before{content:" ";display:table}.buddypress-wrap .subnav-filters:after{clear:both}.buddypress-wrap .subnav-filters{background:0 0;list-style:none;margin:15px 0 0;padding:0}.buddypress-wrap .subnav-filters div{margin:0}.buddypress-wrap .subnav-filters>ul{float:right;list-style:none}.buddypress-wrap .subnav-filters.bp-messages-filters ul{width:100%}.buddypress-wrap .subnav-filters.bp-messages-filters .messages-search{margin-bottom:1em}@media screen and (min-width:46.8em){.buddypress-wrap .subnav-filters.bp-messages-filters .messages-search{margin-bottom:0}}.buddypress-wrap .subnav-filters div{float:none}.buddypress-wrap .subnav-filters div input[type=search],.buddypress-wrap .subnav-filters div select{font-size:16px}.buddypress-wrap .subnav-filters div button.nouveau-search-submit{padding:5px .8em 6px}.buddypress-wrap .subnav-filters div button#user_messages_search_submit{padding:7px .8em}.buddypress-wrap .subnav-filters .component-filters{margin-top:10px}.buddypress-wrap .subnav-filters .feed{margin-left:15px}.buddypress-wrap .subnav-filters .last.filter label{display:inline}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap:after,.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap:before{content:" ";display:table}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap:after{clear:both}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap.bp-show{display:inline-block}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap.bp-hide{display:none}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .select-wrap{border:0}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .select-wrap:focus,.buddypress-wrap .subnav-filters .user-messages-bulk-actions .select-wrap:hover{outline:1px solid #d6d6d6}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions{float:right}.buddypress-wrap .subnav-filters .user-messages-bulk-actions label{display:inline-block;font-weight:300;margin-left:25px;padding:5px 0}.buddypress-wrap .subnav-filters .user-messages-bulk-actions div select{-webkit-appearance:textfield}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-apply{border:0;border-radius:none;font-weight:400;line-height:1.8;margin:0 10px 0 0;padding:3px 5px;text-align:center;text-transform:none;width:auto}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-apply span{vertical-align:middle}@media screen and (min-width:32em){.buddypress-wrap .subnav-filters li{margin-bottom:0}.buddypress-wrap .subnav-filters .bp-search,.buddypress-wrap .subnav-filters .dir-search,.buddypress-wrap .subnav-filters .feed,.buddypress-wrap .subnav-filters .group-act-search,.buddypress-wrap .subnav-filters .group-invites-search,.buddypress-wrap .subnav-filters .subnav-search,.buddypress-wrap .subnav-filters .subnav-search form,.buddypress-wrap .subnav-filters .user-messages-bulk-actions,.buddypress-wrap .subnav-filters .user-messages-search{float:right}.buddypress-wrap .subnav-filters .component-filters,.buddypress-wrap .subnav-filters .last{float:left;margin-top:0;width:auto}.buddypress-wrap .subnav-filters .component-filters select,.buddypress-wrap .subnav-filters .last select{max-width:250px}.buddypress-wrap .subnav-filters .user-messages-search{float:left}}.buddypress-wrap .notifications-options-nav input#notification-bulk-manage{border:0;border-radius:0;line-height:1.6}.buddypress-wrap .group-subnav-filters .group-invites-search{margin-bottom:1em}.buddypress-wrap .group-subnav-filters .last{text-align:center}.buddypress-wrap .bp-pagination{background:0 0;border:0;color:#767676;float:right;font-size:small;margin:0;padding:.5em 0;position:relative;width:100%}.buddypress-wrap .bp-pagination .pag-count{float:right}.buddypress-wrap .bp-pagination .bp-pagination-links{float:left;margin-left:10px}.buddypress-wrap .bp-pagination .bp-pagination-links a,.buddypress-wrap .bp-pagination .bp-pagination-links span{font-size:small;padding:0 5px}.buddypress-wrap .bp-pagination .bp-pagination-links a:focus,.buddypress-wrap .bp-pagination .bp-pagination-links a:hover{opacity:1}.buddypress-wrap .bp-pagination p{margin:0}.bp-list:after,.bp-list:before{content:" ";display:table}.bp-list:after{clear:both}.bp-list{box-sizing:border-box;border-top:1px solid #eaeaea;clear:both;list-style:none;margin:20px 0;padding:.5em 0;width:100%}.bp-list li:after,.bp-list li:before{content:" ";display:table}.bp-list li:after{clear:both}.bp-list>li{border-bottom:1px solid #eaeaea}.bp-list li{list-style:none;margin:10px 0;padding:.5em 0;position:relative}.bp-list li .item-avatar{text-align:center}.bp-list li .item-avatar img.avatar{display:inline}.bp-list li .item .group-details,.bp-list li .item .item-avatar,.bp-list li .item .item-meta,.bp-list li .item .list-title{text-align:center}.bp-list li .item .list-title{clear:none;font-size:22px;font-weight:400;line-height:1.1;margin:0 auto}@media screen and (min-width:46.8em){.bp-list li .item .list-title{font-size:26px}}.bp-list li .item-meta,.bp-list li .meta{color:#737373;font-size:12px;margin-bottom:10px;margin-top:10px}.bp-list li .last-post{text-align:center}.bp-list li .action{margin:0;text-align:center}.bp-list li .action .generic-button{display:inline-block;font-size:12px;margin:0 0 0 10px}.bp-list li .action div.generic-button{margin:10px 0}@media screen and (min-width:46.8em){.bp-list li .item-avatar{float:right;margin-left:5%}.bp-list li .item{margin:0;overflow:hidden}.bp-list li .item .item-block{float:right;margin-left:2%;width:50%}.bp-list li .item .item-meta,.bp-list li .item .list-title{float:right;text-align:right}.bp-list li .item .group-details,.bp-list li .item .last-post{text-align:right}.bp-list li .group-desc,.bp-list li .last-post,.bp-list li .user-update{clear:none;overflow:hidden;width:auto}.bp-list li .action{clear:right;padding:0;text-align:right}.bp-list li .action li.generic-button{margin-left:0}.bp-list li .action div.generic-button{margin:0 0 10px}.bp-list li .generic-button{display:block;margin:0 0 5px 0}}@media screen and (min-width:32em){#activity-stream{clear:both;padding-top:1em}}.activity-list.bp-list{background:#fafafa;border:1px solid #eee}.activity-list.bp-list .activity-item{background:#fff;border:1px solid #b7b7b7;box-shadow:0 0 6px #d2d2d2;margin:20px 0}.activity-list.bp-list li:first-child{margin-top:0}.friends-list{list-style-type:none}.friends-request-list .item-title,.membership-requests-list .item-title{text-align:center}@media screen and (min-width:46.8em){.friends-request-list li,.membership-requests-list li{display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row nowrap;flex-flow:row nowrap}.friends-request-list li .item,.membership-requests-list li .item{-moz-flex:1 1 auto;-o-flex:1 1 auto;flex:1 1 auto}.friends-request-list li .action,.membership-requests-list li .action{text-align:left}.friends-request-list li .item-title,.membership-requests-list li .item-title{font-size:22px;text-align:right}.friends-request-list li .item-title h3,.membership-requests-list li .item-title h3{margin:0}}#notifications-user-list{clear:both;padding-top:1em}@media screen and (min-width:46.8em){body:not(.logged-in) .bp-list .item{margin-left:0}}.activity-permalink .item-list,.activity-permalink .item-list li.activity-item{border:0}.activity-update-form{padding:10px 10px 0}.item-body .activity-update-form .activity-form{margin:0;padding:0}.activity-update-form{border:1px solid #ccc;box-shadow:inset 0 0 6px #eee;margin:15px 0}.activity-update-form #whats-new-avatar{margin:10px 0;text-align:center}.activity-update-form #whats-new-avatar img{box-shadow:none;display:inline-block}.activity-update-form #whats-new-content{padding:0 0 20px 0}.activity-update-form #whats-new-textarea textarea{background:#fff;box-sizing:border-box;color:#333;font-family:inherit;font-size:medium;height:2.2em;line-height:1.4;padding:6px;width:100%}.activity-update-form #whats-new-textarea textarea:focus{box-shadow:0 0 6px 0 #d6d6d6}.activity-update-form #whats-new-post-in-box{margin:10px 0}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items{list-style:none;margin:10px 0}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items li{margin-bottom:10px}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items #activity-autocomplete{padding:.3em}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object{display:flex;align-items:center;padding:.2em}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object .avatar{width:30px}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object span{padding-right:10px;vertical-align:middle}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object:focus,.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object:hover{background:#eaeaea;cursor:pointer}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object.selected{border:1px solid #d6d6d6}.activity-update-form #whats-new-submit{margin:15px 0 10px}.activity-update-form #whats-new-submit input{font-size:14px;line-height:inherit;margin-bottom:10px;margin-left:10px;padding:.2em 0;text-align:center;width:100%}@media screen and (min-width:46.8em){.activity-update-form #whats-new-avatar{display:block;float:right;margin:0}.activity-update-form #whats-new-content,.activity-update-form #whats-new-post-in-box,.activity-update-form #whats-new-submit{margin-right:8.5%}.activity-update-form #whats-new-submit input{margin-bottom:0;margin-left:10px;width:8em}}.activity-list{padding:.5em}.activity-list .activity-item:after,.activity-list .activity-item:before{content:" ";display:table}.activity-list .activity-item:after{clear:both}.activity-list .activity-item{list-style:none;padding:1em}.activity-list .activity-item.has-comments{padding-bottom:1em}.activity-list .activity-item div.item-avatar{margin:0 auto;text-align:center;width:auto}.activity-list .activity-item div.item-avatar img{height:auto;max-width:40%}@media screen and (min-width:46.8em){.activity-list .activity-item div.item-avatar{margin:0 0 0 2%;text-align:right;width:15%}.activity-list .activity-item div.item-avatar img{max-width:80%}}.activity-list .activity-item.mini{font-size:13px;position:relative}.activity-list .activity-item.mini .activity-avatar{margin-right:0 auto;text-align:center;width:auto}.activity-list .activity-item.mini .activity-avatar img.FB_profile_pic,.activity-list .activity-item.mini .activity-avatar img.avatar{max-width:15%}@media screen and (min-width:46.8em){.activity-list .activity-item.mini .activity-avatar{margin-right:15px;text-align:right;width:15%}.activity-list .activity-item.mini .activity-avatar img.FB_profile_pic,.activity-list .activity-item.mini .activity-avatar img.avatar{max-width:60%}}.activity-list .activity-item.new_forum_post .activity-inner,.activity-list .activity-item.new_forum_topic .activity-inner{border-right:2px solid #eaeaea;margin-right:10px;padding-right:1em}.activity-list .activity-item.newest_blogs_activity,.activity-list .activity-item.newest_friends_activity,.activity-list .activity-item.newest_groups_activity,.activity-list .activity-item.newest_mentions_activity{background:rgba(31,179,221,.1)}.activity-list .activity-item .activity-inreplyto{color:#767676;font-size:13px}.activity-list .activity-item .activity-inreplyto>p{display:inline;margin:0}.activity-list .activity-item .activity-inreplyto .activity-inner,.activity-list .activity-item .activity-inreplyto blockquote{background:0 0;border:0;display:inline;margin:0;overflow:hidden;padding:0}.activity-list .activity-item .activity-header{margin:0 auto;width:80%}.activity-list .activity-item .activity-header a,.activity-list .activity-item .activity-header img{display:inline}.activity-list .activity-item .activity-header .avatar{display:inline-block;margin:0 5px;vertical-align:bottom}.activity-list .activity-item .activity-header .time-since{font-size:14px;color:#767676;text-decoration:none}.activity-list .activity-item .activity-header .time-since:hover{color:#767676;cursor:pointer;text-decoration:underline}.activity-list .activity-item .activity-content .activity-header,.activity-list .activity-item .activity-content .comment-header{color:#767676;margin-bottom:10px}.activity-list .activity-item .activity-content .activity-inner,.activity-list .activity-item .activity-content blockquote{background:#fafafa;margin:15px 0 10px;overflow:hidden;padding:1em}.activity-list .activity-item .activity-content p{margin:0}.activity-list .activity-item .activity-inner p{word-wrap:break-word}.activity-list .activity-item .activity-read-more{margin-right:1em;white-space:nowrap}.activity-list .activity-item ul.activity-meta{margin:0;padding-right:0}.activity-list .activity-item ul.activity-meta li{border:0;display:inline-block}.activity-list .activity-item .activity-meta.action{border:1px solid transparent;background:#fafafa;padding:2px;position:relative;text-align:right}.activity-list .activity-item .activity-meta.action div.generic-button{margin:0}.activity-list .activity-item .activity-meta.action .button{background:0 0}.activity-list .activity-item .activity-meta.action a{padding:4px 8px}.activity-list .activity-item .activity-meta.action .button:focus,.activity-list .activity-item .activity-meta.action .button:hover{background:0 0}.activity-list .activity-item .activity-meta.action .button:before,.activity-list .activity-item .activity-meta.action .icons:before{font-family:dashicons;font-size:18px;vertical-align:middle}.activity-list .activity-item .activity-meta.action .acomment-reply.button:before{content:"\f101"}.activity-list .activity-item .activity-meta.action .view:before{content:"\f125"}.activity-list .activity-item .activity-meta.action .fav:before{content:"\f154"}.activity-list .activity-item .activity-meta.action .unfav:before{content:"\f155"}.activity-list .activity-item .activity-meta.action .delete-activity:before{content:"\f153"}.activity-list .activity-item .activity-meta.action .delete-activity:hover{color:#800}.activity-list .activity-item .activity-meta.action .button{border:0;box-shadow:none}.activity-list .activity-item .activity-meta.action .button span{background:0 0;color:#555;font-weight:700}@media screen and (min-width:46.8em){.activity-list.bp-list{padding:30px}.activity-list .activity-item .activity-content{margin:0;position:relative}.activity-list .activity-item .activity-content:after{clear:both;content:"";display:table}.activity-list .activity-item .activity-header{margin:0 0 0 15px;width:auto}}.buddypress-wrap .activity-list .load-more,.buddypress-wrap .activity-list .load-newest{background:#fafafa;border:1px solid #eee;font-size:110%;margin:15px 0;padding:0;text-align:center}.buddypress-wrap .activity-list .load-more a,.buddypress-wrap .activity-list .load-newest a{color:#555;display:block;padding:.5em 0}.buddypress-wrap .activity-list .load-more a:focus,.buddypress-wrap .activity-list .load-more a:hover,.buddypress-wrap .activity-list .load-newest a:focus,.buddypress-wrap .activity-list .load-newest a:hover{background:#fff;color:#333}.buddypress-wrap .activity-list .load-more:focus,.buddypress-wrap .activity-list .load-more:hover,.buddypress-wrap .activity-list .load-newest:focus,.buddypress-wrap .activity-list .load-newest:hover{border-color:#e1e1e1;box-shadow:0 0 6px 0 #eaeaea}body.activity-permalink .activity-list li{border-width:1px;padding:1em 0 0 0}body.activity-permalink .activity-list li:first-child{padding-top:0}body.activity-permalink .activity-list li.has-comments{padding-bottom:0}body.activity-permalink .activity-list .activity-avatar{width:auto}body.activity-permalink .activity-list .activity-avatar a{display:block}body.activity-permalink .activity-list .activity-avatar img{max-width:100%}body.activity-permalink .activity-list .activity-content{border:0;font-size:100%;line-height:1.5;padding:0}body.activity-permalink .activity-list .activity-content .activity-header{margin:0;padding:.5em 0 0 0;text-align:center;width:100%}body.activity-permalink .activity-list .activity-content .activity-inner,body.activity-permalink .activity-list .activity-content blockquote{margin-right:0;margin-top:10px}body.activity-permalink .activity-list .activity-meta{margin:10px 0 10px}body.activity-permalink .activity-list .activity-comments{margin-bottom:10px}@media screen and (min-width:46.8em){body.activity-permalink .activity-list .activity-avatar{right:-20px;margin-left:0;position:relative;top:-20px}body.activity-permalink .activity-list .activity-content{margin-left:10px}body.activity-permalink .activity-list .activity-content .activity-header p{text-align:right}}.buddypress-wrap .activity-comments{clear:both;margin:0 5%;overflow:hidden;position:relative;width:auto}.buddypress-wrap .activity-comments ul{clear:both;list-style:none;margin:15px 0 0;padding:0}.buddypress-wrap .activity-comments ul li{border-top:1px solid #eee;border-bottom:0;padding:1em 0 0}.buddypress-wrap .activity-comments ul li ul{margin-right:5%}.buddypress-wrap .activity-comments ul li:first-child{border-top:0}.buddypress-wrap .activity-comments ul li:last-child{margin-bottom:0}.buddypress-wrap .activity-comments div.acomment-avatar{width:auto}.buddypress-wrap .activity-comments div.acomment-avatar img{border-width:1px;float:right;height:25px;max-width:none;width:25px}.buddypress-wrap .activity-comments .acomment-content p,.buddypress-wrap .activity-comments .acomment-meta{font-size:14px}.buddypress-wrap .activity-comments .acomment-meta{color:#555;overflow:hidden;padding-right:2%}.buddypress-wrap .activity-comments .acomment-content{border-right:1px solid #ccc;margin:15px 10% 0 0;padding:.5em 1em}.buddypress-wrap .activity-comments .acomment-content p{margin-bottom:.5em}.buddypress-wrap .activity-comments .acomment-options{float:right;margin:10px 20px 10px 0}.buddypress-wrap .activity-comments .acomment-options a{color:#767676;font-size:14px}.buddypress-wrap .activity-comments .acomment-options a:focus,.buddypress-wrap .activity-comments .acomment-options a:hover{color:inherit}.buddypress-wrap .activity-comments .activity-meta.action{background:0 0;margin-top:10px}.buddypress-wrap .activity-comments .activity-meta.action button{font-size:14px;font-weight:400;text-transform:none}.buddypress-wrap .activity-comments .show-all button{font-size:14px;text-decoration:underline;padding-right:.5em}.buddypress-wrap .activity-comments .show-all button span{text-decoration:none}.buddypress-wrap .activity-comments .show-all button:focus span,.buddypress-wrap .activity-comments .show-all button:hover span{color:#5087e5}.buddypress-wrap .mini .activity-comments{clear:both;margin-top:0}body.activity-permalink .activity-comments{background:0 0;width:auto}body.activity-permalink .activity-comments>ul{padding:0 1em 0 .5em}body.activity-permalink .activity-comments ul li>ul{margin-top:10px}form.ac-form{display:none;padding:1em}form.ac-form .ac-reply-avatar{float:right}form.ac-form .ac-reply-avatar img{border:1px solid #eee}form.ac-form .ac-reply-content{color:#767676;padding-right:1em}form.ac-form .ac-reply-content a{text-decoration:none}form.ac-form .ac-reply-content .ac-textarea{margin-bottom:15px;padding:0 .5em;overflow:hidden}form.ac-form .ac-reply-content .ac-textarea textarea{background:0 0;box-shadow:none;color:#555;font-family:inherit;font-size:100%;height:60px;margin:0;outline:0;padding:.5em;width:100%}form.ac-form .ac-reply-content .ac-textarea textarea:focus{box-shadow:0 0 6px #d6d6d6}form.ac-form .ac-reply-content input{margin-top:10px}.activity-comments li form.ac-form{clear:both;margin-left:15px}.activity-comments form.root{margin-right:0}@media screen and (min-width:46.8em){.buddypress-wrap .blogs-list li .item-block{float:none;width:auto}.buddypress-wrap .blogs-list li .item-meta{clear:right;float:none}}@media screen and (min-width:46.8em){.buddypress-wrap .bp-dir-vert-nav .blogs-list .list-title{width:auto}}.buddypress-wrap .groups-list li .list-title{text-align:center}.buddypress-wrap .groups-list li .group-details{clear:right}.buddypress-wrap .groups-list li .group-desc{border:1px solid #eaeaea;border-radius:10px;background-clip:padding-box;font-size:13px;color:#737373;font-style:italic;margin:10px auto 0;padding:1em}@media screen and (min-width:46.8em){.buddypress-wrap .groups-list li .group-desc{font-size:16px}}.buddypress-wrap .groups-list li p{margin:0 0 .5em}@media screen and (min-width:46.8em){.buddypress-wrap .groups-list li .item{margin-left:0}.buddypress-wrap .groups-list li .item-meta,.buddypress-wrap .groups-list li .list-title{text-align:right;width:auto}.buddypress-wrap .groups-list li .item-meta{margin-bottom:20px}.buddypress-wrap .groups-list li .last-activity{clear:right;margin-top:-20px}}.buddypress-wrap .groups-list li.group-no-avatar div.group-desc{margin-right:0}.buddypress-wrap .mygroups .groups-list.grid .wrap{min-height:450px;padding-bottom:0}@media screen and (min-width:46.8em){.buddypress-wrap .groups-list.grid.four .group-desc,.buddypress-wrap .groups-list.grid.three .group-desc{font-size:14px}}@media screen and (min-width:46.8em){.buddypress .bp-vertical-navs .groups-list .item-avatar{margin-left:3%;width:15%}}.buddypress-wrap .members-list li .member-name{margin-bottom:10px}.buddypress-wrap .members-list li .user-update{border:1px solid #eaeaea;border-radius:10px;background-clip:padding-box;color:#737373;font-style:italic;font-size:13px;margin:15px auto;padding:1em}@media screen and (min-width:46.8em){.buddypress-wrap .members-list li .user-update{font-size:16px}}.buddypress-wrap .members-list li .user-update .activity-read-more{display:block;font-size:12px;font-style:normal;margin-top:10px;padding-right:2px}@media screen and (min-width:46.8em){.buddypress-wrap .members-list li .last-activity{clear:right;margin-top:-10px}}@media screen and (min-width:46.8em){.buddypress-wrap .members-group-list li .joined{clear:right;float:none}}@media screen and (min-width:32em){body:not(.logged-in) .members-list .user-update{width:96%}}.register-page .register-section{box-sizing:border-box}.register-page .signup-form{margin-top:20px}.register-page .signup-form .default-profile input{margin-bottom:20px}.register-page .signup-form label,.register-page .signup-form legend{margin:10px 0 0}.register-page .signup-form .editfield{margin:15px 0}.register-page .signup-form .editfield fieldset{border:0;padding:0}.register-page .signup-form .editfield fieldset legend{margin:0 0 5px;text-indent:0}.register-page .signup-form .editfield .field-visibility-settings{padding:.5em}.register-page .signup-form .editfield .field-visibility-settings fieldset{margin:0 0 10px}.register-page .signup-form #signup-avatar img{margin:0 0 10px 15px}.register-page .signup-form .password-entry,.register-page .signup-form .password-entry-confirm{border:1px solid #eee}@media screen and (min-width:46.8em){.buddypress-wrap .register-page .layout-wrap{display:flex;flex-flow:row wrap;justify-content:space-around}.buddypress-wrap .register-page .layout-wrap .default-profile{flex:1;padding-left:2em}.buddypress-wrap .register-page .layout-wrap .blog-details{flex:1;padding-right:2em}.buddypress-wrap .register-page .submit{clear:both}}@media screen and (min-width:46.8em){.buddypress-wrap.extended-default-reg .register-page .default-profile{flex:1;padding-left:1em}.buddypress-wrap.extended-default-reg .register-page .extended-profile{flex:2;padding-right:1em}.buddypress-wrap.extended-default-reg .register-page .blog-details{flex:1 100%}}#group-create-body{padding:.5em}#group-create-body .creation-step-name{text-align:center}#group-create-body .avatar-nav-items{margin-top:15px}.single-headers:after,.single-headers:before{content:" ";display:table}.single-headers:after{clear:both}.single-headers{margin-bottom:15px}.single-headers #item-header-avatar a{display:block;text-align:center}.single-headers #item-header-avatar a img{float:none}.single-headers div#item-header-content{float:none}@media screen and (min-width:46.8em){.single-headers #item-header-avatar a{text-align:right}.single-headers #item-header-avatar a img{float:right}.single-headers #item-header-content{padding-right:2em}}.single-headers .activity,.single-headers .group-status{display:inline}.single-headers .group-status{font-size:18px;color:#333;padding-left:1em}.single-headers .activity{display:inline-block;font-size:12px;padding:0}.single-headers #sitewide-notice p,.single-headers div#message p{background-color:#ffd;border:1px solid #cb2;color:#440;font-weight:400;margin-top:3px;text-decoration:none}.single-headers h2{line-height:1.2;margin:0 0 5px}.single-headers h2 a{color:#767676;text-decoration:none}.single-headers h2 span.highlight{display:inline-block;font-size:60%;font-weight:400;line-height:1.7;vertical-align:middle}.single-headers h2 span.highlight span{background:#a1dcfa;color:#fff;cursor:pointer;font-size:80%;font-weight:700;margin-bottom:2px;padding:1px 4px;position:relative;left:-2px;top:-2px;vertical-align:middle}.single-headers img.avatar{float:right;margin:0 0 19px 15px}.single-headers .item-meta{color:#767676;font-size:14px;margin:15px 0 5px;padding-bottom:.5em}.single-headers ul{margin-bottom:15px}.single-headers ul li{float:left;list-style:none}.single-headers div.generic-button{text-align:center}.single-headers li.generic-button{display:inline-block;text-align:center}@media screen and (min-width:46.8em){.single-headers a.button,.single-headers div.generic-button,.single-headers li.generic-button{float:right}}.single-headers a.button,.single-headers div.generic-button{margin:10px 0 0 10px}.single-headers li.generic-button{margin:2px 10px}.single-headers li.generic-button:first-child{margin-right:0}.single-headers div#message.info{line-height:.8}body.no-js .single-item-header .js-self-profile-button{display:none}#cover-image-container{position:relative}#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}#item-header-cover-image{position:relative;z-index:2}#item-header-cover-image #item-header-avatar{padding:0 1em}.groups-header .bp-group-type-list{margin:0}.groups-header .bp-feedback{clear:both}.groups-header .group-item-actions{float:right;margin:0 15px 15px 0;padding-top:0;width:100%}.groups-header .moderators-lists{margin-top:0}.groups-header .moderators-lists .moderators-title{font-size:14px}.groups-header .moderators-lists .user-list{margin:0 0 5px}.groups-header .moderators-lists .user-list ul:after{clear:both;content:"";display:table}.groups-header .moderators-lists .user-list li{display:inline-block;float:none;margin-right:4px;padding:4px}.groups-header .moderators-lists img.avatar{box-shadow:none;float:none;height:30px;margin:0;max-width:100%;width:30px}@media screen and (min-width:46.8em){.groups-header div#item-header-content{float:right;margin-right:10%;text-align:right;padding-top:15px;width:42%}.groups-header .group-item-actions{float:left;margin:0 15px 15px 0;text-align:left;width:20%}.groups-header .groups-meta{clear:both}}.groups-header .desc-wrap{background:#eaeaea;border:1px solid #d6d6d6;margin:0 0 15px;padding:1em;text-align:center}.groups-header .desc-wrap .group-description{background:#fafafa;box-shadow:inset 0 0 9px #ccc;padding:1em;text-align:right}.groups-header .desc-wrap .group-description p{margin:0;padding:0}.bp-user .users-header .user-nicename{margin-bottom:5px}.bp-user .member-header-actions{overflow:hidden}.bp-user .member-header-actions *>*{display:block}.buddypress-wrap .item-body{margin:20px 0}.buddypress-wrap .item-body .screen-heading{font-size:20px;font-weight:400}.buddypress-wrap .item-body .button-tabs{margin:30px 0 15px}.buddypress-wrap.bp-single-vert-nav .bp-list:not(.grid) .item-entry{padding-right:.5em}.single-item.group-members .item-body .filters:not(.no-subnav){border-top:5px solid #eaeaea;padding-top:1em}.single-item.group-members .item-body .filters{margin-top:0}.buddypress-wrap .group-status-type ul{margin:0 20px 20px 0}.groups-manage-members-list{padding:.5em 0}.groups-manage-members-list dd{margin:0;padding:1em 0}.groups-manage-members-list .section-title{background:#eaeaea;padding-right:.3em}.groups-manage-members-list ul{list-style:none;margin-bottom:0}.groups-manage-members-list ul li{border-bottom:1px solid #eee;margin-bottom:10px;padding:.5em .3em .3em}.groups-manage-members-list ul li:last-child,.groups-manage-members-list ul li:only-child{border-bottom:0}.groups-manage-members-list ul li:nth-child(even){background:#fafafa}.groups-manage-members-list ul li.banned-user{background:#fad3d3}.groups-manage-members-list ul .member-name{margin-bottom:0;text-align:center}.groups-manage-members-list ul img{display:block;margin:0 auto;width:20%}@media screen and (min-width:32em){.groups-manage-members-list ul .member-name{text-align:right}.groups-manage-members-list ul img{display:inline;width:50px}}.groups-manage-members-list ul .members-manage-buttons:after,.groups-manage-members-list ul .members-manage-buttons:before{content:" ";display:table}.groups-manage-members-list ul .members-manage-buttons:after{clear:both}.groups-manage-members-list ul .members-manage-buttons{margin:15px 0 5px}.groups-manage-members-list ul .members-manage-buttons a.button{color:#767676;display:block;font-size:13px}@media screen and (min-width:32em){.groups-manage-members-list ul .members-manage-buttons a.button{display:inline-block}}.groups-manage-members-list ul .members-manage-buttons.text-links-list{margin-bottom:0}@media screen and (max-width:32em){.groups-manage-members-list ul .members-manage-buttons.text-links-list a.button{background:#fafafa;border:1px solid #eee;display:block;margin-bottom:10px}}.groups-manage-members-list ul .action:not(.text-links-list) a.button{font-size:12px}@media screen and (min-width:46.8em){.groups-manage-members-list ul li .avatar,.groups-manage-members-list ul li .member-name{float:right}.groups-manage-members-list ul li .avatar{margin-left:15px}.groups-manage-members-list ul li .action{clear:both;float:right}}.buddypress .bp-invites-content ul.item-list{border-top:0}.buddypress .bp-invites-content ul.item-list li{border:1px solid #eaeaea;margin:0 0 1%;padding-right:5px;padding-left:5px;position:relative;width:auto}.buddypress .bp-invites-content ul.item-list li .list-title{margin:0 auto;width:80%}.buddypress .bp-invites-content ul.item-list li .action{position:absolute;top:10px;left:10px}.buddypress .bp-invites-content ul.item-list li .action a.button.invite-button{border:0}.buddypress .bp-invites-content ul.item-list li .action a.button.invite-button:focus,.buddypress .bp-invites-content ul.item-list li .action a.button.invite-button:hover{color:#1fb3dd}.buddypress .bp-invites-content ul.item-list li.selected{box-shadow:inset 0 0 12px 0 rgba(237,187,52,.2)}.buddypress .bp-invites-content .group-inviters li,.buddypress .bp-invites-content .item-list .item-meta span{color:#767676}.buddypress .bp-invites-content li ul.group-inviters{clear:both;margin:0;overflow:hidden}.buddypress .bp-invites-content li ul.group-inviters li{border:0;float:right;font-size:20px;width:inherit}.buddypress .bp-invites-content li .status{font-size:20px;font-style:italic;clear:both;color:#555;margin:10px 0}.buddypress .bp-invites-content #send-invites-editor ul:after,.buddypress .bp-invites-content #send-invites-editor ul:before{content:" ";display:table}.buddypress .bp-invites-content #send-invites-editor ul:after{clear:both}.buddypress .bp-invites-content #send-invites-editor textarea{width:100%}.buddypress .bp-invites-content #send-invites-editor ul{clear:both;list-style:none;margin:10px 0}.buddypress .bp-invites-content #send-invites-editor ul li{float:right;margin:.5%;max-height:50px;max-width:50px}.buddypress .bp-invites-content #send-invites-editor #bp-send-invites-form{clear:both;margin-top:10px}.buddypress .bp-invites-content #send-invites-editor .action{margin-top:10px;padding-top:10px}.buddypress .bp-invites-content #send-invites-editor.bp-hide{display:none}@media screen and (min-width:46.8em){.buddypress .bp-invites-content ul.item-list>li{box-sizing:border-box;border:1px solid #eaeaea;float:right;padding-right:.5em;padding-left:.5em;width:49.5%}.buddypress .bp-invites-content ul.item-list>li:nth-child(odd){margin-left:.5%}.buddypress .bp-invites-content ul.item-list>li:nth-child(even){margin-right:.5%}.buddypress .bp-invites-content ul.item-list ul.group-inviters{float:right;width:auto}}@media screen and (min-width:46.8em){:not(.vertical)+.item-body #group-invites-container{display:-ms-grid;display:grid;-ms-grid-columns:25% auto;grid-template-columns:25% auto;grid-template-areas:"group-invites-nav group-invites-column"}:not(.vertical)+.item-body #group-invites-container .bp-invites-nav{-ms-grid-row:1;-ms-grid-column:1;grid-area:group-invites-nav}:not(.vertical)+.item-body #group-invites-container .bp-invites-nav li{display:block;float:none}:not(.vertical)+.item-body #group-invites-container .group-invites-column{-ms-grid-row:1;-ms-grid-column:2;grid-area:group-invites-column}}.buddypress.groups .activity-update-form{margin-top:0}.buddypress-wrap .profile{margin-top:30px}.buddypress-wrap .public .profile-fields td.label{width:30%}.buddypress-wrap .profile.edit .button-nav{list-style:none;margin:30px 0 10px}.buddypress-wrap .profile.edit .button-nav li{display:inline-block;margin-left:10px}.buddypress-wrap .profile.edit .button-nav li a{font-size:18px}.buddypress-wrap .profile.edit .editfield{background:#fafafa;border:1px solid #eee;margin:15px 0;padding:1em}.buddypress-wrap .profile.edit .editfield fieldset{border:0}.buddypress-wrap .profile.edit .editfield fieldset label{font-weight:400}.buddypress-wrap .profile.edit .editfield fieldset label.xprofile-field-label{display:inline}.buddypress-wrap .profile.edit .editfield{display:flex;flex-direction:column}.buddypress-wrap .profile.edit .editfield .description{margin-top:10px;order:2}.buddypress-wrap .profile.edit .editfield>fieldset{order:1}.buddypress-wrap .profile.edit .editfield .field-visibility-settings,.buddypress-wrap .profile.edit .editfield .field-visibility-settings-toggle{order:3}body.no-js .buddypress-wrap .field-visibility-settings-close,body.no-js .buddypress-wrap .field-visibility-settings-toggle{display:none}body.no-js .buddypress-wrap .field-visibility-settings{display:block}.buddypress-wrap .field-visibility-settings{margin:10px 0}.buddypress-wrap .current-visibility-level{font-style:normal;font-weight:700}.buddypress-wrap .field-visibility-settings,.buddypress-wrap .field-visibility-settings-header{color:#737373}.buddypress-wrap .field-visibility-settings fieldset{margin:5px 0}.buddypress-wrap .standard-form .editfield fieldset{margin:0}.buddypress-wrap .standard-form .field-visibility-settings label{font-weight:400;margin:0}.buddypress-wrap .standard-form .field-visibility-settings .radio{list-style:none;margin-bottom:0}.buddypress-wrap .standard-form .field-visibility-settings .field-visibility-settings-close{font-size:12px}.buddypress-wrap .standard-form .wp-editor-container{border:1px solid #dedede}.buddypress-wrap .standard-form .wp-editor-container textarea{background:#fff;width:100%}.buddypress-wrap .standard-form .description{background:#fafafa;font-size:inherit}.buddypress-wrap .standard-form .field-visibility-settings legend,.buddypress-wrap .standard-form .field-visibility-settings-header{font-style:italic}.buddypress-wrap .standard-form .field-visibility-settings-header{font-size:14px}.buddypress-wrap .standard-form .field-visibility-settings label,.buddypress-wrap .standard-form .field-visibility-settings legend{font-size:14px}.buddypress-wrap .standard-form .field-visibility select{margin:0}.buddypress-wrap .html-active button.switch-html{background:#f5f5f5;border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0}.buddypress-wrap .tmce-active button.switch-tmce{background:#f5f5f5;border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0}.buddypress-wrap .profile.public .profile-group-title{border-bottom:1px solid #ccc}body.register .buddypress-wrap .page ul{list-style:none}.buddypress-wrap .profile .bp-avatar-nav{margin-top:20px}.message-action-delete:before,.message-action-star:before,.message-action-unstar:before,.message-action-view:before{font-family:dashicons;font-size:18px}.message-action-star:before{color:#aaa;content:"\f154"}.message-action-unstar:before{color:#fcdd77;content:"\f155"}.message-action-view:before{content:"\f473"}.message-action-delete:before{content:"\f153"}.message-action-delete:hover:before{color:#a00}.preview-content .actions a{text-decoration:none}.bp-messages-content{margin:15px 0}.bp-messages-content .avatar{box-shadow:none}.bp-messages-content .thread-participants{list-style:none}.bp-messages-content .thread-participants dd{margin-right:0}.bp-messages-content time{color:#737373;font-size:12px}#message-threads{border-top:1px solid #eaeaea;clear:both;list-style:none;margin:0;max-height:220px;overflow-x:hidden;overflow-y:auto;padding:0;width:100%}#message-threads li{border-bottom:1px solid #eaeaea;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row nowrap;flex-flow:row nowrap;margin:0;overflow:hidden;padding:.5em 0}#message-threads li .thread-cb{display:flex;align-items:center;-moz-flex:1 2 5%;-o-flex:1 2 5%;flex:1 2 5%}#message-threads li .thread-from,#message-threads li .thread-to{-moz-flex:1 2 20%;-o-flex:1 2 20%;flex:1 2 20%}#message-threads li .thread-from img.avatar,#message-threads li .thread-to img.avatar{float:right;margin:0 0 0 10px}#message-threads li .thread-from .user-name,#message-threads li .thread-to .user-name{display:inline-block;line-height:1.1}#message-threads li .thread-from .num-recipients,#message-threads li .thread-to .num-recipients{color:#737373;font-weight:400;font-size:12px;margin:0}#message-threads li .thread-content{-moz-flex:1 2 60%;-o-flex:1 2 60%;flex:1 2 60%}#message-threads li .thread-date{-moz-flex:1 2 15%;-o-flex:1 2 15%;flex:1 2 15%}#message-threads li.selected{background-color:#fafafa}#message-threads li.selected .thread-subject .subject{color:#5087e5}#message-threads li.unread{font-weight:700}#message-threads li .thread-content .excerpt{color:#737373;font-size:12px;margin:0}#message-threads li .thread-content .thread-from,#message-threads li .thread-content .thread-subject,#message-threads li .thread-content .thread-to{font-size:13px}@media screen and (min-width:46.8em){#message-threads li .thread-content .thread-from,#message-threads li .thread-content .thread-subject,#message-threads li .thread-content .thread-to{font-size:16px}}#message-threads li .thread-content .thread-subject{vertical-align:top}#message-threads li .thread-content .thread-subject .excerpt{font-weight:400}#message-threads li .thread-date{padding-left:5px;text-align:left}.bp-messages-content .actions{float:left;max-width:30%}.bp-messages-content .actions .bp-icons:not(.bp-hide){display:inline-block;margin:0;padding:.3em .5em}.bp-messages-content .actions .bp-icons:not(.bp-hide):before{font-size:26px}.bp-messages-content #thread-preview{border:1px solid #eaeaea;margin-top:20px}.bp-messages-content #thread-preview .preview-message{overflow:hidden}.bp-messages-content #thread-preview .preview-content{margin:.5em}.bp-messages-content #thread-preview .preview-content .preview-message{background:#fafafa;margin:10px 0;padding:1em .3em .3em}.bp-messages-content #bp-message-thread-list{border-top:1px solid #eaeaea;clear:both;list-style:none;padding:1em 0 .3em}.bp-messages-content #bp-message-thread-list li{padding:.5em}.bp-messages-content #bp-message-thread-list li:nth-child(2n) .message-content{background:#fafafa}.bp-messages-content #bp-message-thread-list .message-metadata{border-bottom:1px solid #ccc;box-shadow:2px 1px 9px 0 #eee;display:table;padding:.2em;width:100%}.bp-messages-content #bp-message-thread-list .message-metadata .avatar{width:30px}.bp-messages-content #bp-message-thread-list .message-metadata .user-link{display:block;font-size:13px;float:right}@media screen and (min-width:46.8em){.bp-messages-content #bp-message-thread-list .message-metadata .user-link{font-size:16px}}.bp-messages-content #bp-message-thread-list .message-metadata time{color:#737373;font-size:12px;padding:0 .5em}.bp-messages-content #bp-message-thread-list .message-metadata button{padding:0 .3em}.bp-messages-content #bp-message-thread-list .message-metadata button:before{font-size:20px}.bp-messages-content #bp-message-thread-list .message-content{overflow:hidden;margin:1em auto 0;width:90%}.bp-messages-content #bp-message-thread-list img.avatar{float:right;margin:0 0 0 10px}.bp-messages-content #bp-message-thread-list .actions a:before{font-size:18px}.bp-messages-content form.send-reply .avatar-box{padding:.5em 0}.bp-messages-content .preview-pane-header,.bp-messages-content .single-message-thread-header{border-bottom:1px solid #eaeaea}.bp-messages-content .preview-pane-header:after,.bp-messages-content .single-message-thread-header:after{clear:both;content:"";display:table}.bp-messages-content .preview-thread-title,.bp-messages-content .single-thread-title{font-size:16px}.bp-messages-content .preview-thread-title .messages-title,.bp-messages-content .single-thread-title .messages-title{padding-right:2em}.bp-messages-content .thread-participants{float:right;margin:5px 0;width:70%}.bp-messages-content .thread-participants dd,.bp-messages-content .thread-participants ul{margin-bottom:10px}.bp-messages-content .thread-participants ul{list-style:none}.bp-messages-content .thread-participants ul:after{clear:both;content:"";display:table}.bp-messages-content .thread-participants li{float:right;margin-right:5px}.bp-messages-content .thread-participants img{width:30px}.bp-messages-content #bp-message-thread-list li .message-content blockquote,.bp-messages-content #bp-message-thread-list li .message-content ol,.bp-messages-content #bp-message-thread-list li .message-content ul,.bp-messages-content #thread-preview .preview-message blockquote,.bp-messages-content #thread-preview .preview-message ol,.bp-messages-content #thread-preview .preview-message ul{list-style-position:inside;margin-right:0}.bp-messages-content #thread-preview:empty,.bp-messages-content ul#message-threads:empty{display:none}.bp-messages-content #bp-message-thread-header h2:first-child,.bp-messages-content #thread-preview h2:first-child{background-color:#eaeaea;color:#555;font-weight:700;margin:0;padding:.5em}.bp-messages-content #bp-message-thread-list li a.user-link,.bp-messages-content #message-threads .thread-content a{border:0;text-decoration:none}.bp-messages-content .standard-form #subject{margin-bottom:20px}div.bp-navs#subsubnav.bp-messages-filters .user-messages-bulk-actions{margin-left:15px;max-width:42.5%}.buddypress.settings .profile-settings.bp-tables-user select{width:100%}.buddypress-wrap #whats-new-post-in-box select,.buddypress-wrap .filter select{border:1px solid #d6d6d6}.buddypress-wrap input.action[disabled]{cursor:pointer;opacity:.4}.buddypress-wrap #notification-bulk-manage[disabled]{display:none}.buddypress-wrap fieldset legend{font-size:inherit;font-weight:600}.buddypress-wrap input[type=email]:focus,.buddypress-wrap input[type=password]:focus,.buddypress-wrap input[type=tel]:focus,.buddypress-wrap input[type=text]:focus,.buddypress-wrap input[type=url]:focus,.buddypress-wrap textarea:focus{box-shadow:0 0 8px #eaeaea}.buddypress-wrap select{height:auto}.buddypress-wrap textarea{resize:vertical}.buddypress-wrap .standard-form .bp-controls-wrap{margin:1em 0}.buddypress-wrap .standard-form .groups-members-search input[type=search],.buddypress-wrap .standard-form .groups-members-search input[type=text],.buddypress-wrap .standard-form [data-bp-search] input[type=search],.buddypress-wrap .standard-form [data-bp-search] input[type=text],.buddypress-wrap .standard-form input[type=color],.buddypress-wrap .standard-form input[type=date],.buddypress-wrap .standard-form input[type=datetime-local],.buddypress-wrap .standard-form input[type=datetime],.buddypress-wrap .standard-form input[type=email],.buddypress-wrap .standard-form input[type=month],.buddypress-wrap .standard-form input[type=number],.buddypress-wrap .standard-form input[type=password],.buddypress-wrap .standard-form input[type=range],.buddypress-wrap .standard-form input[type=search],.buddypress-wrap .standard-form input[type=tel],.buddypress-wrap .standard-form input[type=text],.buddypress-wrap .standard-form input[type=time],.buddypress-wrap .standard-form input[type=url],.buddypress-wrap .standard-form input[type=week],.buddypress-wrap .standard-form select,.buddypress-wrap .standard-form textarea{background:#fafafa;border:1px solid #d6d6d6;border-radius:0;font:inherit;font-size:100%;padding:.5em}.buddypress-wrap .standard-form input[required],.buddypress-wrap .standard-form select[required],.buddypress-wrap .standard-form textarea[required]{box-shadow:none;border-width:2px;outline:0}.buddypress-wrap .standard-form input[required]:invalid,.buddypress-wrap .standard-form select[required]:invalid,.buddypress-wrap .standard-form textarea[required]:invalid{border-color:#b71717}.buddypress-wrap .standard-form input[required]:valid,.buddypress-wrap .standard-form select[required]:valid,.buddypress-wrap .standard-form textarea[required]:valid{border-color:#91cc2c}.buddypress-wrap .standard-form input[required]:focus,.buddypress-wrap .standard-form select[required]:focus,.buddypress-wrap .standard-form textarea[required]:focus{border-color:#d6d6d6;border-width:1px}.buddypress-wrap .standard-form input.invalid[required],.buddypress-wrap .standard-form select.invalid[required],.buddypress-wrap .standard-form textarea.invalid[required]{border-color:#b71717}.buddypress-wrap .standard-form input:not(.button-small),.buddypress-wrap .standard-form textarea{width:100%}.buddypress-wrap .standard-form input[type=checkbox],.buddypress-wrap .standard-form input[type=radio]{margin-left:5px;width:auto}.buddypress-wrap .standard-form select{padding:3px}.buddypress-wrap .standard-form textarea{height:120px}.buddypress-wrap .standard-form textarea#message_content{height:200px}.buddypress-wrap .standard-form input[type=password]{margin-bottom:5px}.buddypress-wrap .standard-form input:focus,.buddypress-wrap .standard-form select:focus,.buddypress-wrap .standard-form textarea:focus{background:#fafafa;color:#555;outline:0}.buddypress-wrap .standard-form label,.buddypress-wrap .standard-form span.label{display:block;font-weight:600;margin:15px 0 5px;width:auto}.buddypress-wrap .standard-form a.clear-value{display:block;margin-top:5px;outline:0}.buddypress-wrap .standard-form .submit{clear:both;padding:15px 0 0}.buddypress-wrap .standard-form p.submit{margin-bottom:0}.buddypress-wrap .standard-form div.submit input{margin-left:15px}.buddypress-wrap .standard-form #invite-list label,.buddypress-wrap .standard-form p label{font-weight:400;margin:auto}.buddypress-wrap .standard-form p.description{color:#737373;margin:5px 0}.buddypress-wrap .standard-form div.checkbox label:nth-child(n+2),.buddypress-wrap .standard-form div.radio div label{color:#737373;font-size:100%;font-weight:400;margin:5px 0 0}.buddypress-wrap .standard-form#send-reply textarea{width:97.5%}.buddypress-wrap .standard-form#sidebar-login-form label{margin-top:5px}.buddypress-wrap .standard-form#sidebar-login-form input[type=password],.buddypress-wrap .standard-form#sidebar-login-form input[type=text]{padding:4px;width:95%}.buddypress-wrap .standard-form.profile-edit input:focus{background:#fff}@media screen and (min-width:46.8em){.buddypress-wrap .standard-form .left-menu{float:right}.buddypress-wrap .standard-form #invite-list ul{list-style:none;margin:1%}.buddypress-wrap .standard-form #invite-list ul li{margin:0 1% 0 0}.buddypress-wrap .standard-form .main-column{margin-right:190px}.buddypress-wrap .standard-form .main-column ul#friend-list{clear:none;float:right}.buddypress-wrap .standard-form .main-column ul#friend-list h4{clear:none}}.buddypress-wrap .standard-form .bp-tables-user label{margin:0}.buddypress-wrap .signup-form label,.buddypress-wrap .signup-form legend{font-weight:400}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-wrap .wp-editor-wrap .wp-editor-wrap button,.buddypress-wrap .wp-editor-wrap .wp-editor-wrap input[type=button],.buddypress-wrap .wp-editor-wrap .wp-editor-wrap input[type=submit],.buddypress-wrap .wp-editor-wrap a.button,.buddypress-wrap .wp-editor-wrap input[type=reset]{padding:0 8px 1px}.buddypress-wrap .select-wrap{border:1px solid #eee}.buddypress-wrap .select-wrap label{display:inline}.buddypress-wrap .select-wrap select::-ms-expand{display:none}.buddypress-wrap .select-wrap select{-moz-appearance:none;-webkit-appearance:none;-o-appearance:none;appearance:none;border:0;cursor:pointer;margin-left:-25px;padding:6px 10px 6px 25px;position:relative;text-indent:-2px;z-index:1;width:100%}.buddypress-wrap .select-wrap select,.buddypress-wrap .select-wrap select:active,.buddypress-wrap .select-wrap select:focus{background:0 0}.buddypress-wrap .select-wrap span.select-arrow{display:inline-block;position:relative;z-index:0}.buddypress-wrap .select-wrap span.select-arrow:before{color:#ccc;content:"\25BC"}.buddypress-wrap .select-wrap:focus .select-arrow:before,.buddypress-wrap .select-wrap:hover .select-arrow:before{color:#a6a6a6}.buddypress-wrap .bp-search form:focus,.buddypress-wrap .bp-search form:hover,.buddypress-wrap .select-wrap:focus,.buddypress-wrap .select-wrap:hover{border:1px solid #d5d4d4;box-shadow:inset 0 0 3px #eee}@media screen and (min-width:32em){.buddypress-wrap .notifications-options-nav .select-wrap{float:right}}.buddypress-wrap .bp-dir-search-form,.buddypress-wrap .bp-messages-search-form:after,.buddypress-wrap .bp-messages-search-form:before{content:" ";display:table}.buddypress-wrap .bp-dir-search-form,.buddypress-wrap .bp-messages-search-form:after{clear:both}.buddypress-wrap form.bp-dir-search-form,.buddypress-wrap form.bp-invites-search-form,.buddypress-wrap form.bp-messages-search-form{border:1px solid #eee;width:100%}@media screen and (min-width:55em){.buddypress-wrap form.bp-dir-search-form,.buddypress-wrap form.bp-invites-search-form,.buddypress-wrap form.bp-messages-search-form{width:15em}}.buddypress-wrap form.bp-dir-search-form label,.buddypress-wrap form.bp-invites-search-form label,.buddypress-wrap form.bp-messages-search-form label{margin:0}.buddypress-wrap form.bp-dir-search-form button[type=submit],.buddypress-wrap form.bp-dir-search-form input[type=search],.buddypress-wrap form.bp-dir-search-form input[type=text],.buddypress-wrap form.bp-invites-search-form button[type=submit],.buddypress-wrap form.bp-invites-search-form input[type=search],.buddypress-wrap form.bp-invites-search-form input[type=text],.buddypress-wrap form.bp-messages-search-form button[type=submit],.buddypress-wrap form.bp-messages-search-form input[type=search],.buddypress-wrap form.bp-messages-search-form input[type=text]{background:0 0;border:0;border-radius:0;background-clip:padding-box}.buddypress-wrap form.bp-dir-search-form input[type=search],.buddypress-wrap form.bp-dir-search-form input[type=text],.buddypress-wrap form.bp-invites-search-form input[type=search],.buddypress-wrap form.bp-invites-search-form input[type=text],.buddypress-wrap form.bp-messages-search-form input[type=search],.buddypress-wrap form.bp-messages-search-form input[type=text]{float:right;line-height:1.5;padding:3px 10px;width:80%}.buddypress-wrap form.bp-dir-search-form button[type=submit],.buddypress-wrap form.bp-invites-search-form button[type=submit],.buddypress-wrap form.bp-messages-search-form button[type=submit]{float:left;font-size:inherit;font-weight:400;line-height:1.5;padding:3px .7em;text-align:center;text-transform:none;width:20%}.buddypress-wrap form.bp-dir-search-form button[type=submit] span,.buddypress-wrap form.bp-invites-search-form button[type=submit] span,.buddypress-wrap form.bp-messages-search-form button[type=submit] span{font-family:dashicons;font-size:18px;line-height:1.6}.buddypress-wrap form.bp-dir-search-form button[type=submit].bp-show,.buddypress-wrap form.bp-invites-search-form button[type=submit].bp-show,.buddypress-wrap form.bp-messages-search-form button[type=submit].bp-show{height:auto;right:0;overflow:visible;position:static;top:0}.buddypress-wrap form.bp-dir-search-form input[type=search]::-webkit-search-cancel-button,.buddypress-wrap form.bp-invites-search-form input[type=search]::-webkit-search-cancel-button,.buddypress-wrap form.bp-messages-search-form input[type=search]::-webkit-search-cancel-button{-webkit-appearance:searchfield-cancel-button}.buddypress-wrap form.bp-dir-search-form input[type=search]::-webkit-search-results-button,.buddypress-wrap form.bp-dir-search-form input[type=search]::-webkit-search-results-decoration,.buddypress-wrap form.bp-invites-search-form input[type=search]::-webkit-search-results-button,.buddypress-wrap form.bp-invites-search-form input[type=search]::-webkit-search-results-decoration,.buddypress-wrap form.bp-messages-search-form input[type=search]::-webkit-search-results-button,.buddypress-wrap form.bp-messages-search-form input[type=search]::-webkit-search-results-decoration{display:none}.buddypress-wrap ul.filters li form label input{line-height:1.4;padding:.1em .7em}.buddypress-wrap .current-member-type{font-style:italic}.buddypress-wrap .dir-form{clear:both}.budypress.no-js form.bp-dir-search-form button[type=submit]{height:auto;right:0;overflow:visible;position:static;top:0}.bp-user [data-bp-search] form input[type=search],.bp-user [data-bp-search] form input[type=text]{padding:6px 10px 7px}.buddypress-wrap .bp-tables-user,.buddypress-wrap table.forum,.buddypress-wrap table.wp-profile-fields{width:100%}.buddypress-wrap .bp-tables-user thead tr,.buddypress-wrap table.forum thead tr,.buddypress-wrap table.wp-profile-fields thead tr{background:0 0;border-bottom:2px solid #ccc}.buddypress-wrap .bp-tables-user tbody tr,.buddypress-wrap table.forum tbody tr,.buddypress-wrap table.wp-profile-fields tbody tr{background:#fafafa}.buddypress-wrap .bp-tables-user tr td,.buddypress-wrap .bp-tables-user tr th,.buddypress-wrap table.forum tr td,.buddypress-wrap table.forum tr th,.buddypress-wrap table.wp-profile-fields tr td,.buddypress-wrap table.wp-profile-fields tr th{padding:.5em;vertical-align:middle}.buddypress-wrap .bp-tables-user tr td.label,.buddypress-wrap table.forum tr td.label,.buddypress-wrap table.wp-profile-fields tr td.label{border-left:1px solid #eaeaea;font-weight:600;width:25%}.buddypress-wrap .bp-tables-user tr.alt td,.buddypress-wrap table.wp-profile-fields tr.alt td{background:#fafafa}.buddypress-wrap table.profile-fields .data{padding:.5em 1em}.buddypress-wrap table.profile-fields tr:last-child{border-bottom:none}.buddypress-wrap table.notifications td{padding:1em .5em}.buddypress-wrap table.notifications .bulk-select-all,.buddypress-wrap table.notifications .bulk-select-check{width:7%}.buddypress-wrap table.notifications .bulk-select-check{vertical-align:middle}.buddypress-wrap table.notifications .date,.buddypress-wrap table.notifications .notification-description,.buddypress-wrap table.notifications .notification-since,.buddypress-wrap table.notifications .title{width:39%}.buddypress-wrap table.notifications .actions,.buddypress-wrap table.notifications .notification-actions{width:15%}.buddypress-wrap table.notification-settings th.title,.buddypress-wrap table.profile-settings th.title{width:80%}.buddypress-wrap table.notifications .notification-actions a.delete,.buddypress-wrap table.notifications .notification-actions a.mark-read{display:inline-block}.buddypress-wrap table.notification-settings{margin-bottom:15px;text-align:right}.buddypress-wrap #groups-notification-settings{margin-bottom:0}.buddypress-wrap table.notification-settings td:first-child,.buddypress-wrap table.notification-settings th.icon,.buddypress-wrap table.notifications td:first-child,.buddypress-wrap table.notifications th.icon{display:none}.buddypress-wrap table.notification-settings .no,.buddypress-wrap table.notification-settings .yes{text-align:center;width:40px;vertical-align:middle}.buddypress-wrap table#message-threads{clear:both}.buddypress-wrap table#message-threads .thread-info{min-width:40%}.buddypress-wrap table#message-threads .thread-info p{margin:0}.buddypress-wrap table#message-threads .thread-info p.thread-excerpt{color:#737373;font-size:12px;margin-top:3px}.buddypress-wrap table.profile-fields{margin-bottom:20px}.buddypress-wrap table.profile-fields:last-child{margin-bottom:0}.buddypress-wrap table.profile-fields p{margin:0}.buddypress-wrap table.profile-fields p:last-child{margin-top:0}.bp-screen-reader-text{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.center-vert{display:flex;align-items:center}.bp-hide{display:none}.bp-show{height:auto;right:0;overflow:visible;position:static;top:0}.buddypress .buddypress-wrap .activity-read-more a,.buddypress .buddypress-wrap .comment-reply-link,.buddypress .buddypress-wrap .generic-button a,.buddypress .buddypress-wrap a.bp-title-button,.buddypress .buddypress-wrap a.button,.buddypress .buddypress-wrap button,.buddypress .buddypress-wrap input[type=button],.buddypress .buddypress-wrap input[type=reset],.buddypress .buddypress-wrap input[type=submit],.buddypress .buddypress-wrap ul.button-nav:not(.button-tabs) li a{background:#fff;border-color:#ccc;border-style:solid;border-width:1px;color:#555;cursor:pointer;font-size:inherit;font-weight:400;outline:0;padding:.3em .5em;text-align:center;text-decoration:none;width:auto}.buddypress .buddypress-wrap .button-small[type=button]{padding:0 8px 1px}.buddypress .buddypress-wrap .activity-read-more a:focus,.buddypress .buddypress-wrap .activity-read-more a:hover,.buddypress .buddypress-wrap .button-nav li a:focus,.buddypress .buddypress-wrap .button-nav li a:hover,.buddypress .buddypress-wrap .button-nav li.current a,.buddypress .buddypress-wrap .comment-reply-link:focus,.buddypress .buddypress-wrap .comment-reply-link:hover,.buddypress .buddypress-wrap .generic-button a:focus,.buddypress .buddypress-wrap .generic-button a:hover,.buddypress .buddypress-wrap a.button:focus,.buddypress .buddypress-wrap a.button:hover,.buddypress .buddypress-wrap button:focus,.buddypress .buddypress-wrap button:hover,.buddypress .buddypress-wrap input[type=button]:focus,.buddypress .buddypress-wrap input[type=button]:hover,.buddypress .buddypress-wrap input[type=reset]:focus,.buddypress .buddypress-wrap input[type=reset]:hover,.buddypress .buddypress-wrap input[type=submit]:focus,.buddypress .buddypress-wrap input[type=submit]:hover{background:#ededed;border-color:#999;color:#333;outline:0;text-decoration:none}.buddypress .buddypress-wrap a.disabled,.buddypress .buddypress-wrap button.disabled,.buddypress .buddypress-wrap button.pending,.buddypress .buddypress-wrap div.pending a,.buddypress .buddypress-wrap input[type=button].disabled,.buddypress .buddypress-wrap input[type=button].pending,.buddypress .buddypress-wrap input[type=reset].disabled,.buddypress .buddypress-wrap input[type=reset].pending,.buddypress .buddypress-wrap input[type=submit].pending,.buddypress .buddypress-wrap input[type=submit][disabled=disabled]{border-color:#eee;color:#767676;cursor:default}.buddypress .buddypress-wrap a.disabled:hover,.buddypress .buddypress-wrap button.disabled:hover,.buddypress .buddypress-wrap button.pending:hover,.buddypress .buddypress-wrap div.pending a:hover,.buddypress .buddypress-wrap input[type=button]:hover.disabled,.buddypress .buddypress-wrap input[type=button]:hover.pending,.buddypress .buddypress-wrap input[type=reset]:hover.disabled,.buddypress .buddypress-wrap input[type=reset]:hover.pending,.buddypress .buddypress-wrap input[type=submit]:hover.disabled,.buddypress .buddypress-wrap input[type=submit]:hover.pending{border-color:#eee;color:#767676}.buddypress .buddypress-wrap button.text-button,.buddypress .buddypress-wrap input.text-button{background:0 0;border:0;box-shadow:none;color:#767676}.buddypress .buddypress-wrap button.text-button.small,.buddypress .buddypress-wrap input.text-button.small{font-size:13px}.buddypress .buddypress-wrap button.text-button:focus,.buddypress .buddypress-wrap button.text-button:hover,.buddypress .buddypress-wrap input.text-button:focus,.buddypress .buddypress-wrap input.text-button:hover{background:0 0;text-decoration:underline}.buddypress .buddypress-wrap .activity-list a.button{border:none}.buddypress .buddypress-wrap .bp-invites-content ul.bp-list li a.invite-button:hover{color:#1fb3dd}.buddypress .buddypress-wrap .bp-invites-content ul.bp-list li a.group-remove-invite-button:hover,.buddypress .buddypress-wrap .bp-invites-content ul.bp-list li a.invite-button:hover,.buddypress .buddypress-wrap .bp-invites-content ul.bp-list li.selected a.group-remove-invite-button:hover,.buddypress .buddypress-wrap .bp-invites-content ul.bp-list li.selected a.invite-button:hover{color:#a00}.buddypress .buddypress-wrap #item-buttons:empty{display:none}.buddypress .buddypress-wrap input:disabled:focus,.buddypress .buddypress-wrap input:disabled:hover{background:0 0}.buddypress .buddypress-wrap .text-links-list a.button{background:0 0;border:none;border-left:1px solid #eee;color:#737373;display:inline-block;padding:.3em 1em}.buddypress .buddypress-wrap .text-links-list a.button:visited{color:#d6d6d6}.buddypress .buddypress-wrap .text-links-list a.button:focus,.buddypress .buddypress-wrap .text-links-list a.button:hover{color:#5087e5}.buddypress .buddypress-wrap .text-links-list a:first-child{padding-right:0}.buddypress .buddypress-wrap .text-links-list a:last-child{border-left:none}.buddypress .buddypress-wrap .bp-list.grid .action a,.buddypress .buddypress-wrap .bp-list.grid .action button{border:1px solid #ccc;display:block;margin:0}.buddypress .buddypress-wrap .bp-list.grid .action a:focus,.buddypress .buddypress-wrap .bp-list.grid .action a:hover,.buddypress .buddypress-wrap .bp-list.grid .action button:focus,.buddypress .buddypress-wrap .bp-list.grid .action button:hover{background:#ededed}.buddypress #buddypress .create-button{background:0 0;text-align:center}.buddypress #buddypress .create-button a:focus,.buddypress #buddypress .create-button a:hover{text-decoration:underline}@media screen and (min-width:46.8em){.buddypress #buddypress .create-button{float:left}}.buddypress #buddypress .create-button a{border:1px solid #ccc;border-radius:5px;background-clip:padding-box;box-shadow:inset 0 0 6px 0 #eaeaea;margin:.2em 0;width:auto}.buddypress #buddypress .create-button a:focus,.buddypress #buddypress .create-button a:hover{background:0 0;border-color:#ccc;box-shadow:inset 0 0 12px 0 #eaeaea}@media screen and (min-width:46.8em){.buddypress #buddypress.bp-dir-vert-nav .create-button{float:none;padding-top:2em}.buddypress #buddypress.bp-dir-vert-nav .create-button a{margin-left:.5em}}.buddypress #buddypress.bp-dir-hori-nav .create-button{float:right}.buddypress #buddypress.bp-dir-hori-nav .create-button a,.buddypress #buddypress.bp-dir-hori-nav .create-button a:hover{background:0 0;border:0;box-shadow:none;margin:0}.buddypress-wrap button.ac-reply-cancel,.buddypress-wrap button.bp-icons{background:0 0;border:0}.buddypress-wrap button.bp-icons:focus,.buddypress-wrap button.bp-icons:hover{background:0 0}.buddypress-wrap button.ac-reply-cancel:focus,.buddypress-wrap button.ac-reply-cancel:hover{background:0 0;text-decoration:underline}.buddypress-wrap .bp-invites-content li .invite-button span.icons:before,.buddypress-wrap .bp-invites-filters .invite-button span.icons:before,.buddypress-wrap .bp-messages-filters li a.messages-button:before,.buddypress-wrap .feed a:before,.buddypress-wrap .filter label:before{font-family:dashicons;font-size:18px}.buddypress-wrap .bp-invites-content .item-list li .invite-button span.icons:before{font-size:27px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-invites-content .item-list li .invite-button span.icons:before{font-size:32px}}.buddypress-wrap .bp-list a.button.invite-button:focus,.buddypress-wrap .bp-list a.button.invite-button:hover{background:0 0}.buddypress-wrap .filter label:before{content:"\f536"}.buddypress-wrap div.feed a:before,.buddypress-wrap li.feed a:before{content:"\f303"}.buddypress-wrap ul.item-list li .invite-button:not(.group-remove-invite-button) span.icons:before{content:"\f502"}.buddypress-wrap ul.item-list li .group-remove-invite-button span.icons:before,.buddypress-wrap ul.item-list li.selected .invite-button span.icons:before{content:"\f153"}.buddypress-wrap .bp-invites-filters ul li #bp-invites-next-page:before,.buddypress-wrap .bp-messages-filters ul li #bp-messages-next-page:before{content:"\f345"}.buddypress-wrap .bp-invites-filters ul li #bp-invites-prev-page:before,.buddypress-wrap .bp-messages-filters ul li #bp-messages-prev-page:before{content:"\f341"}.buddypress-wrap .warn{color:#b71717}.buddypress-wrap .bp-messages{border:1px solid #ccc;margin:0 0 15px}.buddypress-wrap .bp-messages .sitewide-notices{display:block;margin:5px;padding:.5em}.buddypress-wrap .bp-messages.info{margin-bottom:0}.buddypress-wrap .bp-messages.updated{clear:both;display:block}.buddypress-wrap .bp-messages.bp-user-messages-feedback{border:0}.buddypress-wrap #group-create-body .bp-cover-image-status p.warning{background:#0b80a4;border:0;box-shadow:0 0 3px 0 rgba(0,0,0,.2);color:#fff}.buddypress-wrap .bp-feedback:not(.custom-homepage-info){display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row nowrap;flex-flow:row nowrap;align-items:stretch}.buddypress-wrap .bp-feedback{background:#fff;color:#807f7f;box-shadow:0 1px 1px 1px rgba(0,0,0,.1);color:#737373;margin:10px 0;position:relative}.buddypress-wrap .bp-feedback p{margin:0}.buddypress-wrap .bp-feedback span.bp-icon{color:#fff;display:block;font-family:dashicons;right:0;margin-left:10px;position:relative;padding:0 .5em}.buddypress-wrap .bp-feedback .bp-help-text{font-style:italic}.buddypress-wrap .bp-feedback .text{font-size:14px;margin:0;padding:.5em 0}.buddypress-wrap .bp-feedback.no-icon{padding:.5em}.buddypress-wrap .bp-feedback.small:before{line-height:inherit}.buddypress-wrap a[data-bp-close] span:before,.buddypress-wrap button[data-bp-close] span:before{font-size:32px}.buddypress-wrap a[data-bp-close],.buddypress-wrap button[data-bp-close]{border:0;position:absolute;top:10px;left:10px;width:32px}.buddypress-wrap .bp-feedback.no-icon a[data-bp-close],.buddypress-wrap .bp-feedback.no-icon button[data-bp-close]{top:-6px;left:6px}.buddypress-wrap button[data-bp-close]:hover{background-color:transparent}.buddypress-wrap .bp-feedback p{margin:0}.buddypress-wrap .bp-feedback .bp-icon{font-size:20px;padding:0 2px}.buddypress-wrap .bp-feedback.error .bp-icon,.buddypress-wrap .bp-feedback.help .bp-icon,.buddypress-wrap .bp-feedback.info .bp-icon,.buddypress-wrap .bp-feedback.loading .bp-icon,.buddypress-wrap .bp-feedback.success .bp-icon,.buddypress-wrap .bp-feedback.updated .bp-icon,.buddypress-wrap .bp-feedback.warning .bp-icon{display:flex;align-items:center}.buddypress-wrap .bp-feedback.help .bp-icon,.buddypress-wrap .bp-feedback.info .bp-icon{background-color:#0b80a4}.buddypress-wrap .bp-feedback.help .bp-icon:before,.buddypress-wrap .bp-feedback.info .bp-icon:before{content:"\f348"}.buddypress-wrap .bp-feedback.error .bp-icon,.buddypress-wrap .bp-feedback.warning .bp-icon{background-color:#d33}.buddypress-wrap .bp-feedback.error .bp-icon:before,.buddypress-wrap .bp-feedback.warning .bp-icon:before{content:"\f534"}.buddypress-wrap .bp-feedback.loading .bp-icon{background-color:#ffd087}.buddypress-wrap .bp-feedback.loading .bp-icon:before{content:"\f469"}.buddypress-wrap .bp-feedback.success .bp-icon,.buddypress-wrap .bp-feedback.updated .bp-icon{background-color:#8a2}.buddypress-wrap .bp-feedback.success .bp-icon:before,.buddypress-wrap .bp-feedback.updated .bp-icon:before{content:"\f147"}.buddypress-wrap .bp-feedback.help .bp-icon:before{content:"\f468"}.buddypress-wrap #pass-strength-result{background-color:#eee;border-color:#ddd;border-style:solid;border-width:1px;display:none;font-weight:700;margin:10px 0 10px 0;padding:.5em;text-align:center;width:auto}.buddypress-wrap #pass-strength-result.show{display:block}.buddypress-wrap #pass-strength-result.mismatch{background-color:#333;border-color:transparent;color:#fff}.buddypress-wrap #pass-strength-result.bad,.buddypress-wrap #pass-strength-result.error{background-color:#ffb78c;border-color:#ff853c;color:#fff}.buddypress-wrap #pass-strength-result.short{background-color:#ffa0a0;border-color:#f04040;color:#fff}.buddypress-wrap #pass-strength-result.strong{background-color:#66d66e;border-color:#438c48;color:#fff}.buddypress-wrap .standard-form#signup_form div div.error{background:#faa;color:#a00;margin:0 0 10px 0;padding:.5em;width:90%}.buddypress-wrap .accept,.buddypress-wrap .reject{float:right;margin-right:10px}.buddypress-wrap .members-list.grid .bp-ajax-message{background:rgba(255,255,255,.9);border:1px solid #eee;font-size:14px;right:2%;position:absolute;padding:.5em 1em;left:2%;top:30px}.buddypress.widget .item-options{font-size:12px;margin:0 0 1em;padding:1em 0}.buddypress.widget .bp-login-widget-user-avatar{float:right}.buddypress.widget .bp-login-widget-user-links{margin-right:70px}.buddypress.widget ul.item-list{list-style:none;margin:10px 0}.buddypress.widget ul.activity-list{padding:0}.buddypress.widget ul.activity-list blockquote{margin:0 0 1.5em;overflow:visible;padding:0 .75em .75em 0}.buddypress.widget ul.activity-list img{margin-bottom:.5em}.buddypress.widget ul.activity-list li{border-bottom:1px solid #ccc;margin-bottom:1em}.buddypress.widget ul.activity-list li .activity-header p{margin-bottom:.5em}.buddypress.widget ul.activity-list li:last-child{border-bottom:0}.buddypress.widget .avatar-block{display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row wrap;flex-flow:row wrap}.buddypress.widget .avatar-block img{margin:.5em}.buddypress.widget ul#friends-list li:after,.buddypress.widget ul#friends-list li:before,.buddypress.widget ul#groups-list li:after,.buddypress.widget ul#groups-list li:before,.buddypress.widget ul#members-list li:after,.buddypress.widget ul#members-list li:before{content:" ";display:table}.buddypress.widget ul#friends-list li:after,.buddypress.widget ul#groups-list li:after,.buddypress.widget ul#members-list li:after{clear:both}.buddypress.widget ul#friends-list li,.buddypress.widget ul#groups-list li,.buddypress.widget ul#members-list li{margin-bottom:1em}.buddypress.widget ul#friends-list li .item-avatar,.buddypress.widget ul#groups-list li .item-avatar,.buddypress.widget ul#members-list li .item-avatar{float:right;width:60px}.buddypress.widget ul#friends-list li .item,.buddypress.widget ul#groups-list li .item,.buddypress.widget ul#members-list li .item{margin-right:70px}.buddypress-wrap .buddypress.widget ul#friends-list,.buddypress-wrap .buddypress.widget ul#groups-list,.buddypress-wrap .buddypress.widget ul#members-list{display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:column nowrap;flex-flow:column nowrap}@media screen and (min-width:32em){.buddypress-wrap .buddypress.widget ul#friends-list,.buddypress-wrap .buddypress.widget ul#groups-list,.buddypress-wrap .buddypress.widget ul#members-list{display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row wrap;flex-flow:row wrap}}.buddypress-wrap .buddypress.widget ul#friends-list li,.buddypress-wrap .buddypress.widget ul#groups-list li,.buddypress-wrap .buddypress.widget ul#members-list li{border:1px solid #eee;align-items:stretch;-moz-flex:1 1 46%;-o-flex:1 1 46%;flex:1 1 46%;margin:2%}@media screen and (min-width:75em){.buddypress-wrap .buddypress.widget ul#friends-list li,.buddypress-wrap .buddypress.widget ul#groups-list li,.buddypress-wrap .buddypress.widget ul#members-list li{-moz-flex:0 1 20%;-o-flex:0 1 20%;flex:0 1 20%}}.buddypress-wrap .buddypress.widget ul#friends-list li .item-avatar,.buddypress-wrap .buddypress.widget ul#groups-list li .item-avatar,.buddypress-wrap .buddypress.widget ul#members-list li .item-avatar{padding:.5em;text-align:center}.buddypress-wrap .buddypress.widget ul#friends-list li .item,.buddypress-wrap .buddypress.widget ul#groups-list li .item,.buddypress-wrap .buddypress.widget ul#members-list li .item{padding:.5em}.buddypress-wrap .buddypress.widget ul#friends-list li .item .item-meta,.buddypress-wrap .buddypress.widget ul#groups-list li .item .item-meta,.buddypress-wrap .buddypress.widget ul#members-list li .item .item-meta{font-size:12px;overflow-wrap:break-word}@media screen and (min-width:75em){.buddypress-wrap .buddypress.widget ul#friends-list,.buddypress-wrap .buddypress.widget ul#groups-list,.buddypress-wrap .buddypress.widget ul#members-list{margin:10px -2%;width:100%}.buddypress-wrap .buddypress.widget ul#friends-list li,.buddypress-wrap .buddypress.widget ul#groups-list li,.buddypress-wrap .buddypress.widget ul#members-list li{-moz-flex:0 1 auto;-o-flex:0 1 auto;flex:0 1 auto;margin:10px 2% 1%;width:46%}}.buddypress-wrap .buddypress.widget blockquote{margin:0 0 1.5em;overflow:visible;padding:0 .75em .75em 0}#buddypress-wrap *{transition:opacity .1s ease-in-out .1s}#buddypress-wrap a.button,#buddypress-wrap a.generic-button,#buddypress-wrap button,#buddypress-wrap input[type=reset],#buddypress-wrap input[type=submit]{transition:background .1s ease-in-out .1s,color .1s ease-in-out .1s,border-color .1s ease-in-out .1s}.buddypress-wrap a.loading,.buddypress-wrap input.loading{animation:loader-pulsate .5s infinite ease-in-out alternate;border-color:#aaa}@keyframes loader-pulsate{from{border-color:#aaa;box-shadow:0 0 6px #ccc}to{border-color:#ccc;box-shadow:0 0 6px #f8f8f8}}.buddypress-wrap a.loading:hover,.buddypress-wrap input.loading:hover{color:#777}[data-bp-tooltip]{position:relative}[data-bp-tooltip]:after{background-color:#fff;display:none;opacity:0;position:absolute;transform:translate3d(0,0,0);visibility:hidden}[data-bp-tooltip]:after{border:1px solid #737373;border-radius:1px;box-shadow:-4px 4px 8px rgba(0,0,0,.2);color:#333;content:attr(data-bp-tooltip);font-family:"Helvetica Neue",helvetica,arial,san-serif;font-size:12px;font-weight:400;letter-spacing:normal;line-height:1.25;max-width:200px;padding:5px 8px;pointer-events:none;text-shadow:none;text-transform:none;transition:all 1.5s ease;white-space:nowrap;word-wrap:break-word;z-index:100000}[data-bp-tooltip]:active:after,[data-bp-tooltip]:focus:after,[data-bp-tooltip]:hover:after{display:block;opacity:1;overflow:visible;visibility:visible}[data-bp-tooltip=""]{display:none;opacity:0;visibility:hidden}.bp-tooltip:after{right:50%;margin-top:7px;top:110%;transform:translate(50%,0)}.user-list .bp-tooltip:after{right:0;transform:translate(0,0)}@media screen and (min-width:46.8em){.user-list .bp-tooltip:after{right:auto;left:0;transform:translate(0,0)}}.activity-list .bp-tooltip:after,.activity-meta-action .bp-tooltip:after,.avatar-block .item-avatar .bp-tooltip:after,.notification-actions .bp-tooltip:after,.participants-list .bp-tooltip:after{right:0;transform:translate(0,0)}.bp-invites-content .bp-tooltip:after,.message-metadata .actions .bp-tooltip:after,.single-message-thread-header .actions .bp-tooltip:after{right:auto;left:0;transform:translate(0,0)}.bp-invites-content #send-invites-editor .bp-tooltip:after{right:0;left:auto}#item-body,.single-screen-navs{box-sizing:border-box}.grid>li,.grid>li .generic-button a{box-sizing:border-box}.grid>li{border-bottom:0;padding-bottom:10px;padding-top:0}.grid>li .list-wrap{background:#fafafa;border:1px solid #eee;padding-bottom:15px;position:relative;overflow:hidden;padding-top:14px}.grid>li .list-wrap .list-title{padding:.5em}.grid>li .list-wrap .update{color:#737373;padding:.5em 2em}.grid>li .item-avatar{text-align:center}.grid>li .item-avatar .avatar{border-radius:50%;display:inline-block;width:50%}@media screen and (min-width:24em){.grid.members-list .list-wrap{min-height:340px}.grid.members-list .list-wrap .item-block{margin:0 auto;min-height:7rem}.grid.members-group-list .list-wrap .item-block{margin:0 auto;min-height:7rem}.grid.groups-list .list-wrap{min-height:470px}.grid.groups-list .list-wrap .item-block{min-height:6rem}.grid.groups-list .list-wrap .group-desc{margin:15px auto 0;min-height:5em;overflow:hidden}.grid.groups-list .list-wrap .group-details,.grid.groups-list .list-wrap .item-desc,.grid.groups-list .list-wrap .last-activity{margin-bottom:0}.grid.groups-list .list-wrap .group-details p,.grid.groups-list .list-wrap .item-desc p,.grid.groups-list .list-wrap .last-activity p{margin-bottom:0}.grid.blogs-list .list-wrap{min-height:350px}.grid.blogs-list .list-wrap .item-block{margin:0 auto;min-height:7rem}}@media screen and (min-width:24em){.grid>li.item-entry{float:right;margin:0}.grid.two>li{padding-bottom:20px}}@media screen and (min-width:24em) and (min-width:75em){.grid.two>li .list-wrap{max-width:500px;margin:0 auto}}@media screen and (min-width:24em){.grid.three>li,.grid.two>li{width:50%}.grid.three>li:nth-child(odd),.grid.two>li:nth-child(odd){padding-left:10px}.grid.three>li:nth-child(even),.grid.two>li:nth-child(even){padding-right:10px}.grid.three>li .item,.grid.two>li .item{margin:1rem auto 0;width:80%}.grid.three>li .item .item-title,.grid.two>li .item .item-title{width:auto}}@media screen and (min-width:46.8em){.grid.three>li{padding-top:0;width:33.333333%;width:calc(100% / 3)}.grid.three>li:nth-child(1n+1){padding-right:5px;padding-left:5px}.grid.three>li:nth-child(3n+3){padding-right:5px;padding-left:0}.grid.three>li:nth-child(3n+1){padding-right:0;padding-left:5px}}@media screen and (min-width:46.8em){.grid.four>li{width:25%}.grid.four>li:nth-child(1n+1){padding-right:5px;padding-left:5px}.grid.four>li:nth-child(4n+4){padding-right:5px;padding-left:0}.grid.four>li:nth-child(4n+1){padding-right:0;padding-left:5px}}.buddypress-wrap .grid.bp-list{padding-top:1em}.buddypress-wrap .grid.bp-list>li{border-bottom:none}.buddypress-wrap .grid.bp-list>li .list-wrap{padding-bottom:3em}.buddypress-wrap .grid.bp-list>li .item-avatar{margin:0;text-align:center;width:auto}.buddypress-wrap .grid.bp-list>li .item-avatar img.avatar{display:inline-block;height:auto;width:50%}.buddypress-wrap .grid.bp-list>li .item-meta,.buddypress-wrap .grid.bp-list>li .list-title{float:none;text-align:center}.buddypress-wrap .grid.bp-list>li .list-title{font-size:inherit;line-height:1.1}.buddypress-wrap .grid.bp-list>li .item{font-size:18px;right:0;margin:0 auto;text-align:center;width:96%}@media screen and (min-width:46.8em){.buddypress-wrap .grid.bp-list>li .item{font-size:22px}}.buddypress-wrap .grid.bp-list>li .item .group-desc,.buddypress-wrap .grid.bp-list>li .item .item-block{float:none;width:96%}.buddypress-wrap .grid.bp-list>li .item .item-block{margin-bottom:10px}.buddypress-wrap .grid.bp-list>li .item .last-activity{margin-top:5px}.buddypress-wrap .grid.bp-list>li .item .group-desc{clear:none}.buddypress-wrap .grid.bp-list>li .item .user-update{clear:both;text-align:right}.buddypress-wrap .grid.bp-list>li .item .activity-read-more a{display:inline}.buddypress-wrap .grid.bp-list>li .action{bottom:5px;float:none;height:auto;right:0;margin:0;padding:0 5px;position:absolute;text-align:center;top:auto;width:100%}.buddypress-wrap .grid.bp-list>li .action .generic-button{float:none;margin:5px 0 0;text-align:center;width:100%}.buddypress-wrap .grid.bp-list>li .action .generic-button a,.buddypress-wrap .grid.bp-list>li .action .generic-button button{width:100%}.buddypress-wrap .grid.bp-list>li .avatar,.buddypress-wrap .grid.bp-list>li .item,.buddypress-wrap .grid.bp-list>li .item-avatar{float:none}.buddypress-wrap .blogs-list.grid.two>li .blogs-title{min-height:5em}.buddypress-wrap .grid.four>li .group-desc,.buddypress-wrap .grid.three>li .group-desc{min-height:8em}.buddypress-wrap .blogs-list.grid.four>li,.buddypress-wrap .blogs-list.grid.three>li{min-height:350px}.buddypress-wrap .blogs-list.grid.four>li .last-activity,.buddypress-wrap .blogs-list.grid.three>li .last-activity{margin-bottom:0}.buddypress-wrap .blogs-list.grid.four>li .last-post,.buddypress-wrap .blogs-list.grid.three>li .last-post{margin-top:0}.buddypress:not(.logged-in) .grid.bp-list .list-wrap{padding-bottom:5px}.buddypress:not(.logged-in) .grid.groups-list .list-wrap{min-height:430px}.buddypress:not(.logged-in) .grid.members-list .list-wrap{min-height:300px}.buddypress:not(.logged-in) .grid.blogs-list .list-wrap{min-height:320px}@media screen and (min-width:46.8em){.bp-single-vert-nav .bp-navs.vertical{overflow:visible}.bp-single-vert-nav .bp-navs.vertical ul{border-left:1px solid #d6d6d6;border-bottom:0;float:right;margin-left:-1px;width:25%}.bp-single-vert-nav .bp-navs.vertical li{float:none;margin-left:0}.bp-single-vert-nav .bp-navs.vertical li.selected a{background:#ccc;color:#333}.bp-single-vert-nav .bp-navs.vertical li:focus,.bp-single-vert-nav .bp-navs.vertical li:hover{background:#ccc}.bp-single-vert-nav .bp-navs.vertical li span{background:#d6d6d6;border-radius:10%;float:left;margin-left:2px}.bp-single-vert-nav .bp-navs.vertical li:hover span{border-color:#eaeaea}.bp-single-vert-nav .bp-navs.vertical.tabbed-links li.selected a{padding-right:0}.bp-single-vert-nav .bp-wrap{margin-bottom:15px}.bp-single-vert-nav .bp-wrap .group-nav-tabs.groups-nav ul li,.bp-single-vert-nav .bp-wrap .user-nav-tabs.users-nav ul li{right:1px;position:relative}.bp-single-vert-nav .item-body:not(#group-create-body){background:#fff;border-right:1px solid #d6d6d6;float:left;margin:0;min-height:400px;padding:0 1em 0 0;width:calc(75% + 1px)}.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links){background:#eaeaea;margin:0 -5px 0 0;width:auto}.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links) li{font-size:16px;margin:10px 0}.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links) li a{border-left:1px solid #ccc;padding:0 .5em}.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links) li a:focus,.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links) li a:hover{background:0 0}.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links) li.current a{background:0 0;color:#333;text-decoration:underline}.bp-single-vert-nav .item-body:not(#group-create-body) #subnav:not(.tabbed-links) li:last-child a{border:none}.bp-dir-vert-nav .dir-navs{float:right;right:1px;position:relative;width:20%}.bp-dir-vert-nav .dir-navs ul li{float:none;overflow:hidden;width:auto}.bp-dir-vert-nav .dir-navs ul li.selected{border:1px solid #eee}.bp-dir-vert-nav .dir-navs ul li.selected a{background:#555;color:#fff}.bp-dir-vert-nav .dir-navs ul li.selected a span{background:#eaeaea;border-color:#ccc;color:#5087e5}.bp-dir-vert-nav .dir-navs ul li a:focus,.bp-dir-vert-nav .dir-navs ul li a:hover{background:#ccc;color:#333}.bp-dir-vert-nav .dir-navs ul li a:focus span,.bp-dir-vert-nav .dir-navs ul li a:hover span{border:1px solid #555}.bp-dir-vert-nav .screen-content{border-right:1px solid #d6d6d6;margin-right:20%;overflow:hidden;padding:0 1em 2em 0}.bp-dir-vert-nav .screen-content .subnav-filters{margin-top:0}.buddypress-wrap.bp-vertical-navs .dir-navs.activity-nav-tabs ul li:not(.selected) a:focus,.buddypress-wrap.bp-vertical-navs .dir-navs.activity-nav-tabs ul li:not(.selected) a:hover,.buddypress-wrap.bp-vertical-navs .dir-navs.groups-nav-tabs ul li:not(.selected) a:focus,.buddypress-wrap.bp-vertical-navs .dir-navs.groups-nav-tabs ul li:not(.selected) a:hover,.buddypress-wrap.bp-vertical-navs .dir-navs.members-nav-tabs ul li:not(.selected) a:focus,.buddypress-wrap.bp-vertical-navs .dir-navs.members-nav-tabs ul li:not(.selected) a:hover,.buddypress-wrap.bp-vertical-navs .dir-navs.sites-nav-tabs ul li:not(.selected) a:focus,.buddypress-wrap.bp-vertical-navs .dir-navs.sites-nav-tabs ul li:not(.selected) a:hover,.buddypress-wrap.bp-vertical-navs .main-navs.group-nav-tabs ul li:not(.selected) a:focus,.buddypress-wrap.bp-vertical-navs .main-navs.group-nav-tabs ul li:not(.selected) a:hover,.buddypress-wrap.bp-vertical-navs .main-navs.user-nav-tabs ul li:not(.selected) a:focus,.buddypress-wrap.bp-vertical-navs .main-navs.user-nav-tabs ul li:not(.selected) a:hover{background:0 0}.buddypress-wrap.bp-vertical-navs .dir-navs.activity-nav-tabs ul li.selected,.buddypress-wrap.bp-vertical-navs .dir-navs.groups-nav-tabs ul li.selected,.buddypress-wrap.bp-vertical-navs .dir-navs.members-nav-tabs ul li.selected,.buddypress-wrap.bp-vertical-navs .dir-navs.sites-nav-tabs ul li.selected,.buddypress-wrap.bp-vertical-navs .main-navs.group-nav-tabs ul li.selected,.buddypress-wrap.bp-vertical-navs .main-navs.user-nav-tabs ul li.selected{background:0 0;border:1px solid #d6d6d6;border-left-color:#fff}.buddypress-wrap.bp-vertical-navs .dir-navs.activity-nav-tabs ul li.selected a,.buddypress-wrap.bp-vertical-navs .dir-navs.groups-nav-tabs ul li.selected a,.buddypress-wrap.bp-vertical-navs .dir-navs.members-nav-tabs ul li.selected a,.buddypress-wrap.bp-vertical-navs .dir-navs.sites-nav-tabs ul li.selected a,.buddypress-wrap.bp-vertical-navs .main-navs.group-nav-tabs ul li.selected a,.buddypress-wrap.bp-vertical-navs .main-navs.user-nav-tabs ul li.selected a{background:0 0;color:#333;font-weight:600}.buddypress-wrap.bp-vertical-navs .dir-navs.activity-nav-tabs ul li.selected a span,.buddypress-wrap.bp-vertical-navs .dir-navs.groups-nav-tabs ul li.selected a span,.buddypress-wrap.bp-vertical-navs .dir-navs.members-nav-tabs ul li.selected a span,.buddypress-wrap.bp-vertical-navs .dir-navs.sites-nav-tabs ul li.selected a span,.buddypress-wrap.bp-vertical-navs .main-navs.group-nav-tabs ul li.selected a span,.buddypress-wrap.bp-vertical-navs .main-navs.user-nav-tabs ul li.selected a span{background:#555;border:1px solid #d6d6d6;color:#fff}}
1
+ body #buddypress * a{box-shadow:none;text-decoration:none}body #buddypress div,body #buddypress dl,body #buddypress input[type=reset],body #buddypress input[type=search],body #buddypress input[type=submit],body #buddypress li,body #buddypress select,body #buddypress textarea{border-radius:2px;background-clip:padding-box}body #buddypress #item-body blockquote,body #buddypress .bp-lists blockquote{margin-right:0}body #buddypress .bp-list .action{box-sizing:border-box}@media screen and (min-width:46.8em){body.buddypress .entry-content,body.buddypress .entry-header,body.buddypress .site-content .entry-header{max-width:none}body.buddypress .entry-header{float:none;max-width:none}body.buddypress .entry .entry-content>*,body.buddypress .entry-content{float:none;max-width:none}body.buddypress .site-content{padding-top:2.5em}body.buddypress #page #primary{max-width:none}body.buddypress #page #primary .entry-content,body.buddypress #page #primary .entry-header{float:none;width:auto}}body.buddypress .buddypress-wrap h1,body.buddypress .buddypress-wrap h2,body.buddypress .buddypress-wrap h3,body.buddypress .buddypress-wrap h4,body.buddypress .buddypress-wrap h5,body.buddypress .buddypress-wrap h6{clear:none;margin:1em 0;padding:0}body.buddypress .buddypress-wrap h2:before{display:none}.bp-wrap:after,.bp-wrap:before{content:" ";display:table}.bp-wrap:after{clear:both}.buddypress-wrap.round-avatars .avatar{border-radius:50%}body.buddypress article.page>.entry-header{margin-bottom:2em;padding:0}body.buddypress article.page>.entry-header .entry-title{font-size:28px;font-weight:inherit;color:#767676}@media screen and (min-width:46.8em){body.buddypress article.page>.entry-header .entry-title{font-size:34px}}.buddypress-wrap dt.section-title{font-size:18px}@media screen and (min-width:46.8em){.buddypress-wrap dt.section-title{font-size:22px}}.buddypress-wrap .bp-label-text,.buddypress-wrap .message-threads{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-label-text,.buddypress-wrap .message-threads{font-size:16px}}.buddypress-wrap .activity-header{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .activity-header{font-size:16px}}.buddypress-wrap .activity-inner{font-size:15px}@media screen and (min-width:46.8em){.buddypress-wrap .activity-inner{font-size:18px}}.buddypress-wrap #whats-new-post-in{font-size:16px}.buddypress-wrap .acomment-meta,.buddypress-wrap .mini .activity-header{font-size:16px}.buddypress-wrap .dir-component-filters #activity-filter-by{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .dir-component-filters #activity-filter-by{font-size:16px}}.buddypress-wrap .bp-tables-user th{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-tables-user th{font-size:16px}}.buddypress-wrap .bp-tables-user td{font-size:12px}@media screen and (min-width:46.8em){.buddypress-wrap .bp-tables-user td{font-size:14px}}.buddypress-wrap .profile-fields th{font-size:15px}@media screen and (min-width:46.8em){.buddypress-wrap .profile-fields th{font-size:18px}}.buddypress-wrap .profile-fields td{font-size:13px}@media screen and (min-width:46.8em){.buddypress-wrap .profile-fields td{font-size:16px}}.buddypress-wrap #notification-select{font-size:12px}@media screen and (min-width:46.8em){.buddypress-wrap #notification-select{font-size:14px}}.bp-navs{background:0 0;clear:both;overflow:hidden}.bp-navs ul{margin:0;padding:0}.bp-navs ul li{list-style:none;margin:0}.bp-navs ul li.last select{max-width:185px}.bp-navs ul li a,.bp-navs ul li span{border:0;display:block;padding:5px 10px;text-decoration:none}.bp-navs ul li .count{background:#eaeaea;border:1px solid #ccc;border-radius:50%;color:#555;display:inline;font-size:12px;margin-right:2px;padding:3px 6px;text-align:center;vertical-align:middle}.bp-navs ul li.current a,.bp-navs ul li.selected a{color:#333;opacity:1}.bp-navs.bp-invites-filters ul li a,.bp-navs.bp-messages-filters ul li a{border:1px solid #ccc;display:inline-block}.main-navs.dir-navs{margin-bottom:20px}.buddypress-wrap .bp-navs li a:hover a .count,.buddypress-wrap .bp-navs li.current a .count,.buddypress-wrap .bp-navs li.selected a .count{background-color:#ccc}.buddypress-wrap .bp-navs li:not(.current) a:focus,.buddypress-wrap .bp-navs li:not(.current) a:hover,.buddypress-wrap .bp-navs li:not(.selected) a:focus,.buddypress-wrap .bp-navs li:not(.selected) a:hover{background:#ccc;color:#333}.buddypress-wrap .bp-navs li.current a,.buddypress-wrap .bp-navs li.current a:focus,.buddypress-wrap .bp-navs li.current a:hover,.buddypress-wrap .bp-navs li.selected a,.buddypress-wrap .bp-navs li.selected a:focus,.buddypress-wrap .bp-navs li.selected a:hover{background:#555;color:#fafafa}@media screen and (min-width:46.8em){.buddypress-wrap .main-navs:not(.dir-navs) li.current a,.buddypress-wrap .main-navs:not(.dir-navs) li.selected a{background:#fff;color:#333;font-weight:600}.buddypress-wrap .main-navs.vertical li.current a,.buddypress-wrap .main-navs.vertical li.selected a{background:#555;color:#fafafa;text-decoration:none}.buddypress-wrap.bp-dir-hori-nav:not(.bp-vertical-navs) nav:not(.tabbed-links){border-bottom:1px solid #eee;border-top:1px solid #eee;box-shadow:0 2px 12px 0 #fafafa}}.buddypress-wrap .bp-subnavs li.current a,.buddypress-wrap .bp-subnavs li.selected a{background:#fff;color:#333;font-weight:600}@media screen and (max-width:46.8em){.buddypress-wrap:not(.bp-single-vert-nav) .bp-navs li{background:#eaeaea}}.buddypress-wrap:not(.bp-single-vert-nav) .main-navs>ul>li>a{padding:.5em calc(.5em + 2px)}.buddypress-wrap:not(.bp-single-vert-nav) .group-subnav#subsubnav,.buddypress-wrap:not(.bp-single-vert-nav) .user-subnav#subsubnav{background:0 0}.buddypress-wrap .bp-subnavs,.buddypress-wrap ul.subnav{width:100%}.buddypress-wrap .bp-subnavs{margin:10px 0;overflow:hidden}.buddypress-wrap .bp-subnavs ul li{margin-top:0}.buddypress-wrap .bp-subnavs ul li.current :focus,.buddypress-wrap .bp-subnavs ul li.current :hover,.buddypress-wrap .bp-subnavs ul li.selected :focus,.buddypress-wrap .bp-subnavs ul li.selected :hover{background:0 0;color:#333}.buddypress-wrap ul.subnav{width:auto}.buddypress-wrap .bp-navs.bp-invites-filters#subsubnav ul li.last,.buddypress-wrap .bp-navs.bp-invites-nav#subnav ul li.last,.buddypress-wrap .bp-navs.bp-messages-filters#subsubnav ul li.last{margin-top:0}@media screen and (max-width:46.8em){.buddypress-wrap .single-screen-navs{border:1px solid #eee}.buddypress-wrap .single-screen-navs li{border-bottom:1px solid #eee}.buddypress-wrap .single-screen-navs li:last-child{border-bottom:none}.buddypress-wrap .bp-subnavs li a{font-size:14px}.buddypress-wrap .bp-subnavs li.current a,.buddypress-wrap .bp-subnavs li.current a:focus,.buddypress-wrap .bp-subnavs li.current a:hover,.buddypress-wrap .bp-subnavs li.selected a,.buddypress-wrap .bp-subnavs li.selected a:focus,.buddypress-wrap .bp-subnavs li.selected a:hover{background:#555;color:#fff}}.buddypress-wrap .bp-navs li.current a .count,.buddypress-wrap .bp-navs li.selected a .count,.buddypress_object_nav .bp-navs li.current a .count,.buddypress_object_nav .bp-navs li.selected a .count{background-color:#fff}.buddypress-wrap .bp-navs li.dynamic a .count,.buddypress-wrap .bp-navs li.dynamic.current a .count,.buddypress-wrap .bp-navs li.dynamic.selected a .count,.buddypress_object_nav .bp-navs li.dynamic a .count,.buddypress_object_nav .bp-navs li.dynamic.current a .count,.buddypress_object_nav .bp-navs li.dynamic.selected a .count{background-color:#5087e5;border:0;color:#fafafa}.buddypress-wrap .bp-navs li.dynamic a:hover .count,.buddypress_object_nav .bp-navs li.dynamic a:hover .count{background-color:#5087e5;border:0;color:#fff}.buddypress-wrap .bp-navs li a .count:empty,.buddypress_object_nav .bp-navs li a .count:empty{display:none}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current),.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current){color:#767676}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a{color:#767676}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a:focus,.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a:hover,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a:focus,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a:hover{background:0 0;color:#333}.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a[disabled]:focus,.buddypress-wrap .bp-navs.group-create-links ul li:not(.current) a[disabled]:hover,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a[disabled]:focus,.buddypress_object_nav .bp-navs.group-create-links ul li:not(.current) a[disabled]:hover{color:#767676}.buddypress-wrap .bp-navs.group-create-links ul li.current a,.buddypress_object_nav .bp-navs.group-create-links ul li.current a{text-align:center}@media screen and (min-width:46.8em){.buddypress-wrap .bp-navs li{float:right}.buddypress-wrap .subnav{float:right}.buddypress-wrap ul.subnav{width:auto}.buddypress-wrap #subsubnav .activity-search{float:right}.buddypress-wrap #subsubnav .filter{float:left}}.buddypress_object_nav .bp-navs li a .count{display:inline-block;float:left}@media screen and (min-width:46.8em){.bp-dir-vert-nav .bp-navs.dir-navs{background:0 0}.bp-dir-vert-nav .bp-navs.dir-navs a .count{float:left}}@media screen and (min-width:46.8em){.buddypress-wrap .tabbed-links ol,.buddypress-wrap .tabbed-links ul{border-bottom:1px solid #ccc;float:none;margin:20px 0 10px}.buddypress-wrap .tabbed-links ol:after,.buddypress-wrap .tabbed-links ol:before,.buddypress-wrap .tabbed-links ul:after,.buddypress-wrap .tabbed-links ul:before{content:" ";display:block}.buddypress-wrap .tabbed-links ol:after,.buddypress-wrap .tabbed-links ul:after{clear:both}.buddypress-wrap .tabbed-links ol li,.buddypress-wrap .tabbed-links ul li{float:right;list-style:none;margin:0 0 0 10px}.buddypress-wrap .tabbed-links ol li a,.buddypress-wrap .tabbed-links ol li span:not(.count),.buddypress-wrap .tabbed-links ul li a,.buddypress-wrap .tabbed-links ul li span:not(.count){background:0 0;border:none;display:block;padding:4px 10px}.buddypress-wrap .tabbed-links ol li a:focus,.buddypress-wrap .tabbed-links ol li a:hover,.buddypress-wrap .tabbed-links ul li a:focus,.buddypress-wrap .tabbed-links ul li a:hover{background:0 0}.buddypress-wrap .tabbed-links ol li:not(.current),.buddypress-wrap .tabbed-links ul li:not(.current){margin-bottom:2px}.buddypress-wrap .tabbed-links ol li.current,.buddypress-wrap .tabbed-links ul li.current{border-color:#ccc #ccc #fff;border-style:solid;border-top-right-radius:4px;border-top-left-radius:4px;border-width:1px;margin-bottom:-1px;padding:0 .5em 1px}.buddypress-wrap .tabbed-links ol li.current a,.buddypress-wrap .tabbed-links ul li.current a{background:0 0;color:#333}.buddypress-wrap .bp-subnavs.tabbed-links>ul{margin-top:0}.buddypress-wrap .bp-navs.tabbed-links{background:0 0;margin-top:2px}.buddypress-wrap .bp-navs.tabbed-links ul li a{border-left:0;font-size:inherit}.buddypress-wrap .bp-navs.tabbed-links ul li.last{float:left;margin:0}.buddypress-wrap .bp-navs.tabbed-links ul li.last a{margin-top:-.5em}.buddypress-wrap .bp-navs.tabbed-links ul li a,.buddypress-wrap .bp-navs.tabbed-links ul li a:focus,.buddypress-wrap .bp-navs.tabbed-links ul li a:hover,.buddypress-wrap .bp-navs.tabbed-links ul li.current a,.buddypress-wrap .bp-navs.tabbed-links ul li.current a:focus,.buddypress-wrap .bp-navs.tabbed-links ul li.current a:hover{background:0 0;border:0}.buddypress-wrap .bp-navs.tabbed-links ul li a:active,.buddypress-wrap .bp-navs.tabbed-links ul li.current a:active{outline:0}}.buddypress-wrap .dir-component-filters .filter label{display:inline}.buddypress-wrap .subnav-filters:after,.buddypress-wrap .subnav-filters:before{content:" ";display:table}.buddypress-wrap .subnav-filters:after{clear:both}.buddypress-wrap .subnav-filters{background:0 0;list-style:none;margin:15px 0 0;padding:0}.buddypress-wrap .subnav-filters div{margin:0}.buddypress-wrap .subnav-filters>ul{float:right;list-style:none}.buddypress-wrap .subnav-filters.bp-messages-filters ul{width:100%}.buddypress-wrap .subnav-filters.bp-messages-filters .messages-search{margin-bottom:1em}@media screen and (min-width:46.8em){.buddypress-wrap .subnav-filters.bp-messages-filters .messages-search{margin-bottom:0}}.buddypress-wrap .subnav-filters div{float:none}.buddypress-wrap .subnav-filters div input[type=search],.buddypress-wrap .subnav-filters div select{font-size:16px}.buddypress-wrap .subnav-filters div button.nouveau-search-submit{padding:5px .8em 6px}.buddypress-wrap .subnav-filters div button#user_messages_search_submit{padding:7px .8em}.buddypress-wrap .subnav-filters .component-filters{margin-top:10px}.buddypress-wrap .subnav-filters .feed{margin-left:15px}.buddypress-wrap .subnav-filters .last.filter label{display:inline}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap:after,.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap:before{content:" ";display:table}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap:after{clear:both}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap.bp-show{display:inline-block}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions-wrap.bp-hide{display:none}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .select-wrap{border:0}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .select-wrap:focus,.buddypress-wrap .subnav-filters .user-messages-bulk-actions .select-wrap:hover{outline:1px solid #d6d6d6}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-actions{float:right}.buddypress-wrap .subnav-filters .user-messages-bulk-actions label{display:inline-block;font-weight:300;margin-left:25px;padding:5px 0}.buddypress-wrap .subnav-filters .user-messages-bulk-actions div select{-webkit-appearance:textfield}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-apply{border:0;border-radius:none;font-weight:400;line-height:1.8;margin:0 10px 0 0;padding:3px 5px;text-align:center;text-transform:none;width:auto}.buddypress-wrap .subnav-filters .user-messages-bulk-actions .bulk-apply span{vertical-align:middle}@media screen and (min-width:32em){.buddypress-wrap .subnav-filters li{margin-bottom:0}.buddypress-wrap .subnav-filters .bp-search,.buddypress-wrap .subnav-filters .dir-search,.buddypress-wrap .subnav-filters .feed,.buddypress-wrap .subnav-filters .group-act-search,.buddypress-wrap .subnav-filters .group-invites-search,.buddypress-wrap .subnav-filters .subnav-search,.buddypress-wrap .subnav-filters .subnav-search form,.buddypress-wrap .subnav-filters .user-messages-bulk-actions,.buddypress-wrap .subnav-filters .user-messages-search{float:right}.buddypress-wrap .subnav-filters .component-filters,.buddypress-wrap .subnav-filters .last{float:left;margin-top:0;width:auto}.buddypress-wrap .subnav-filters .component-filters select,.buddypress-wrap .subnav-filters .last select{max-width:250px}.buddypress-wrap .subnav-filters .user-messages-search{float:left}}.buddypress-wrap .notifications-options-nav input#notification-bulk-manage{border:0;border-radius:0;line-height:1.6}.buddypress-wrap .group-subnav-filters .group-invites-search{margin-bottom:1em}.buddypress-wrap .group-subnav-filters .last{text-align:center}.buddypress-wrap .bp-pagination{background:0 0;border:0;color:#767676;float:right;font-size:small;margin:0;padding:.5em 0;position:relative;width:100%}.buddypress-wrap .bp-pagination .pag-count{float:right}.buddypress-wrap .bp-pagination .bp-pagination-links{float:left;margin-left:10px}.buddypress-wrap .bp-pagination .bp-pagination-links a,.buddypress-wrap .bp-pagination .bp-pagination-links span{font-size:small;padding:0 5px}.buddypress-wrap .bp-pagination .bp-pagination-links a:focus,.buddypress-wrap .bp-pagination .bp-pagination-links a:hover{opacity:1}.buddypress-wrap .bp-pagination p{margin:0}.bp-list:after,.bp-list:before{content:" ";display:table}.bp-list:after{clear:both}.bp-list{box-sizing:border-box;border-top:1px solid #eaeaea;clear:both;list-style:none;margin:20px 0;padding:.5em 0;width:100%}.bp-list li:after,.bp-list li:before{content:" ";display:table}.bp-list li:after{clear:both}.bp-list>li{border-bottom:1px solid #eaeaea}.bp-list li{list-style:none;margin:10px 0;padding:.5em 0;position:relative}.bp-list li .item-avatar{text-align:center}.bp-list li .item-avatar img.avatar{display:inline-block;width:auto;height:auto}.bp-list li .item .group-details,.bp-list li .item .item-avatar,.bp-list li .item .item-meta,.bp-list li .item .list-title{text-align:center}.bp-list li .item .list-title{clear:none;font-size:22px;font-weight:400;line-height:1.1;margin:0 auto}@media screen and (min-width:46.8em){.bp-list li .item .list-title{font-size:26px}}.bp-list li .item-meta,.bp-list li .meta{color:#737373;font-size:12px;margin-bottom:10px;margin-top:10px}.bp-list li .last-post{text-align:center}.bp-list li .action{margin:0;text-align:center}.bp-list li .action .generic-button{display:inline-block;font-size:12px;margin:0 0 0 10px}.bp-list li .action div.generic-button{margin:10px 0}@media screen and (min-width:46.8em){.bp-list li .item-avatar{float:right;margin-left:5%}.bp-list li .item{margin:0;overflow:hidden}.bp-list li .item .item-block{float:right;margin-left:2%;width:50%}.bp-list li .item .item-meta,.bp-list li .item .list-title{float:right;text-align:right}.bp-list li .item .group-details,.bp-list li .item .last-post{text-align:right}.bp-list li .group-desc,.bp-list li .last-post,.bp-list li .user-update{clear:none;overflow:hidden;width:auto}.bp-list li .action{clear:right;padding:0;text-align:right}.bp-list li .action li.generic-button{margin-left:0}.bp-list li .action div.generic-button{margin:0 0 10px}.bp-list li .generic-button{display:block;margin:0 0 5px 0}}@media screen and (min-width:32em){#activity-stream{clear:both;padding-top:1em}}.activity-list.bp-list{background:#fafafa;border:1px solid #eee}.activity-list.bp-list .activity-item{background:#fff;border:1px solid #b7b7b7;box-shadow:0 0 6px #d2d2d2;margin:20px 0}.activity-list.bp-list li:first-child{margin-top:0}.friends-list{list-style-type:none}.friends-request-list .item-title,.membership-requests-list .item-title{text-align:center}@media screen and (min-width:46.8em){.friends-request-list li,.membership-requests-list li{display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row nowrap;flex-flow:row nowrap}.friends-request-list li .item,.membership-requests-list li .item{-moz-flex:1 1 auto;-o-flex:1 1 auto;flex:1 1 auto}.friends-request-list li .action,.membership-requests-list li .action{text-align:left}.friends-request-list li .item-title,.membership-requests-list li .item-title{font-size:22px;text-align:right}.friends-request-list li .item-title h3,.membership-requests-list li .item-title h3{margin:0}}#notifications-user-list{clear:both;padding-top:1em}@media screen and (min-width:46.8em){body:not(.logged-in) .bp-list .item{margin-left:0}}.activity-permalink .item-list,.activity-permalink .item-list li.activity-item{border:0}.activity-update-form{padding:10px 10px 0}.item-body .activity-update-form .activity-form{margin:0;padding:0}.activity-update-form{border:1px solid #ccc;box-shadow:inset 0 0 6px #eee;margin:15px 0}.activity-update-form #whats-new-avatar{margin:10px 0;text-align:center}.activity-update-form #whats-new-avatar img{box-shadow:none;display:inline-block;height:auto;width:auto}.activity-update-form #whats-new-content{padding:0 0 20px 0}.activity-update-form #whats-new-textarea textarea{background:#fff;box-sizing:border-box;color:#333;font-family:inherit;font-size:medium;height:2.2em;line-height:1.4;padding:6px;width:100%}.activity-update-form #whats-new-textarea textarea:focus{box-shadow:0 0 6px 0 #d6d6d6}.activity-update-form #whats-new-post-in-box{margin:10px 0}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items{list-style:none;margin:10px 0;padding-right:0}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items li{margin-bottom:10px}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items button.bp-remove-item{margin-right:10px;height:auto}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items #activity-autocomplete{padding:.3em;width:100%}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object{display:flex;align-items:center;padding:.2em}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object .avatar{width:30px;height:30px}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object span{padding-right:10px;vertical-align:middle}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object:focus,.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object:hover{background:#eaeaea;cursor:pointer}.activity-update-form #whats-new-post-in-box #whats-new-post-in-box-items .bp-activity-object.selected{border:1px solid #d6d6d6}.activity-update-form #whats-new-submit{margin:15px 0 10px}.activity-update-form #whats-new-submit input{font-size:14px;line-height:inherit;margin-bottom:10px;margin-left:10px;padding:.2em 0;text-align:center;width:100%}@media screen and (min-width:46.8em){.activity-update-form #whats-new-avatar{display:block;float:right;margin:0}.activity-update-form #whats-new-content,.activity-update-form #whats-new-post-in-box,.activity-update-form #whats-new-submit{margin-right:55px}.activity-update-form #whats-new-submit input{margin-bottom:0;margin-left:10px;width:8em}}.activity-list{padding:.5em}.activity-list .activity-item:after,.activity-list .activity-item:before{content:" ";display:table}.activity-list .activity-item:after{clear:both}.activity-list .activity-item{list-style:none;padding:1em}.activity-list .activity-item.has-comments{padding-bottom:1em}.activity-list .activity-item div.item-avatar{margin:0 auto;text-align:center;width:auto}.activity-list .activity-item div.item-avatar img{height:auto;max-width:40%}@media screen and (min-width:46.8em){.activity-list .activity-item div.item-avatar{margin:0 0 0 2%;text-align:right;width:15%}.activity-list .activity-item div.item-avatar img{max-width:80%}}.activity-list .activity-item.mini{font-size:13px;position:relative}.activity-list .activity-item.mini .activity-avatar{margin-right:0 auto;text-align:center;width:auto}.activity-list .activity-item.mini .activity-avatar img.FB_profile_pic,.activity-list .activity-item.mini .activity-avatar img.avatar{max-width:15%}@media screen and (min-width:46.8em){.activity-list .activity-item.mini .activity-avatar{margin-right:15px;text-align:right;width:15%}.activity-list .activity-item.mini .activity-avatar img.FB_profile_pic,.activity-list .activity-item.mini .activity-avatar img.avatar{max-width:60%}}.activity-list .activity-item.new_forum_post .activity-inner,.activity-list .activity-item.new_forum_topic .activity-inner{border-right:2px solid #eaeaea;margin-right:10px;padding-right:1em}.activity-list .activity-item.newest_blogs_activity,.activity-list .activity-item.newest_friends_activity,.activity-list .activity-item.newest_groups_activity,.activity-list .activity-item.newest_mentions_activity{background:rgba(31,179,221,.1)}.activity-list .activity-item .activity-inreplyto{color:#767676;font-size:13px}.activity-list .activity-item .activity-inreplyto>p{display:inline;margin:0}.activity-list .activity-item .activity-inreplyto .activity-inner,.activity-list .activity-item .activity-inreplyto blockquote{background:0 0;border:0;display:inline;margin:0;overflow:hidden;padding:0}.activity-list .activity-item .activity-header{margin:0 auto;width:80%}.activity-list .activity-item .activity-header a,.activity-list .activity-item .activity-header img{display:inline}.activity-list .activity-item .activity-header .avatar{display:inline-block;margin:0 5px;vertical-align:text-top;width:20px;height:20px}.activity-list .activity-item .activity-header .time-since{font-size:14px;color:#767676;text-decoration:none}.activity-list .activity-item .activity-header .time-since:hover{color:#767676;cursor:pointer;text-decoration:underline}.activity-list .activity-item .activity-content .activity-header,.activity-list .activity-item .activity-content .comment-header{color:#767676;margin-bottom:10px}.activity-list .activity-item .activity-content .activity-inner,.activity-list .activity-item .activity-content blockquote{background:#fafafa;margin:15px 0 10px;overflow:hidden;padding:1em}.activity-list .activity-item .activity-content p{margin:0}.activity-list .activity-item .activity-inner p{word-wrap:break-word}.activity-list .activity-item .activity-read-more{margin-right:1em;white-space:nowrap}.activity-list .activity-item ul.activity-meta{margin:0;padding-right:0}.activity-list .activity-item ul.activity-meta li{border:0;display:inline-block}.activity-list .activity-item .activity-meta.action{border:1px solid transparent;background:#fafafa;padding:2px;position:relative;text-align:right}.activity-list .activity-item .activity-meta.action div.generic-button{margin:0}.activity-list .activity-item .activity-meta.action .button{background:0 0;color:#555}.activity-list .activity-item .activity-meta.action a{padding:4px 8px}.activity-list .activity-item .activity-meta.action .button:focus,.activity-list .activity-item .activity-meta.action .button:hover{background:0 0}.activity-list .activity-item .activity-meta.action .button:before,.activity-list .activity-item .activity-meta.action .icons:before{font-family:dashicons;font-size:18px;vertical-align:middle}.activity-list .activity-item .activity-meta.action .acomment-reply.button:before{content:"\f101"}.activity-list .activity-item .activity-meta.action .view:before{content:"\f125"}.activity-list .activity-item .activity-meta.action .fav:before{content:"\f154"}.activity-list .activity-item .activity-meta.action .unfav:before{content:"\f155"}.activity-list .activity-item .activity-meta.action .delete-activity:before{content:"\f153"}.activity-list .activity-item .activity-meta.action .delete-activity:hover{color:#800}.activity-list .activity-item .activity-meta.action .button{border:0;box-shadow:none}.activity-list .activity-item .activity-meta.action .button span{background:0 0;color:#555;font-weight:700}@media screen and (min-width:46.8em){.activity-list.bp-list{padding:30px}.activity-list .activity-item .activity-content{margin:0;position:relative}.activity-list .activity-item .activity-content:after{clear:both;content:"";display:table}.activity-list .activity-item .activity-header{margin:0 0 0 15px;width:auto}}.buddypress-wrap .activity-list .load-more,.buddypress-wrap .activity-list .load-newest{background:#fafafa;border:1px solid #eee;font-size:110%;margin:15px 0;padding:0;text-align:center}.buddypress-wrap .activity-list .load-more a,.buddypress-wrap .activity-list .load-newest a{color:#555;display:block;padding:.5em 0}.buddypress-wrap .activity-list .load-more a:focus,.buddypress-wrap .activity-list .load-more a:hover,.buddypress-wrap .activity-list .load-newest a:focus,.buddypress-wrap .activity-list .load-newest a:hover{background:#fff;color:#333}.buddypress-wrap .activity-list .load-more:focus,.buddypress-wrap .activity-list .load-more:hover,.buddypress-wrap .activity-list .load-newest:focus,.buddypress-wrap .activity-list .load-newest:hover{border-color:#e1e1e1;box-shadow:0 0 6px 0 #eaeaea}body.activity-permalink .activity-list li{border-width:1px;padding:1em 0 0 0}body.activity-permalink .activity-list li:first-child{padding-top:0}body.activity-permalink .activity-list li.has-comments{padding-bottom:0}body.activity-permalink .activity-list .activity-avatar{width:auto}body.activity-permalink .activity-list .activity-avatar a{display:block}body.activity-permalink .activity-list .activity-avatar img{max-width:100%;background-color:#eaeaea}body.activity-permalink .activity-list .activity-content{border:0;font-size:100%;line-height:1.5;padding:0}body.activity-permalink .activity-list .activity-content .activity-header{margin:0;padding:.5em 0 0 0;text-align:center;width:100%}body.activity-permalink .activity-list .activity-content .activity-inner,body.activity-permalink .activity-list .activity-content blockquote{margin-right:0;margin-top:10px}body.activity-permalink .activity-list .activity-meta{margin:10px 0 10px}body.activity-permalink .activity-list .activity-comments{margin-bottom:10px}@media screen and (min-width:46.8em){body.activity-permalink .activity-list .activity-avatar{right:-20px;margin-left:0;position:relative;top:-20px}body.activity-permalink .activity-list .activity-avatar img{box-shadow:0 0 0 8px #fff}body.activity-permalink .activity-list .activity-content{margin-left:10px}body.activity-permalink .activity-list .activity-content .activity-header p{text-align:right}}.buddypress-wrap .activity-comments{clear:both;margin:0 5%;overflow:hidden;position:relative;width:auto}.buddypress-wrap .activity-comments ul{clear:both;list-style:none;margin:15px 0 0;padding:0}.buddypress-wrap .activity-comments ul li{border-top:1px solid #eee;border-bottom:0;padding:1em 0 0}.buddypress-wrap .activity-comments ul li ul{margin-right:5%}.buddypress-wrap .activity-comments ul li:first-child{border-top:0}.buddypress-wrap .activity-comments ul li:last-child{margin-bottom:0}.buddypress-wrap .activity-comments div.acomment-avatar{width:auto}.buddypress-wrap .activity-comments div.acomment-avatar img{border-width:1px;float:right;height:25px;max-width:none;width:25px}.buddypress-wrap .activity-comments .acomment-content p,.buddypress-wrap .activity-comments .acomment-meta{font-size:14px}.buddypress-wrap .activity-comments .acomment-meta{color:#555;overflow:hidden;padding-right:2%}.buddypress-wrap .activity-comments .acomment-content{border-right:1px solid #ccc;margin:15px 10% 0 0;padding:.5em 1em}.buddypress-wrap .activity-comments .acomment-content p{margin-bottom:.5em}.buddypress-wrap .activity-comments .acomment-options{float:right;margin:10px 20px 10px 0}.buddypress-wrap .activity-comments .acomment-options a{color:#767676;font-size:14px}.buddypress-wrap .activity-comments .acomment-options a:focus,.buddypress-wrap .activity-comments .acomment-options a:hover{color:inherit}.buddypress-wrap .activity-comments .activity-meta.action{background:0 0;margin-top:10px}.buddypress-wrap .activity-comments .activity-meta.action button{font-size:14px;font-weight:400;text-transform:none}.buddypress-wrap .activity-comments .show-all button{font-size:14px;text-decoration:underline;padding-right:.5em}.buddypress-wrap .activity-comments .show-all button span{text-decoration:none}.buddypress-wrap .activity-comments .show-all button:focus span,.buddypress-wrap .activity-comments .show-all button:hover span{color:#5087e5}.buddypress-wrap .mini .activity-comments{clear:both;margin-top:0}body.activity-permalink .activity-comments{background:0 0;width:auto}body.activity-permalink .activity-comments>ul{padding:0 1em 0 .5em}body.activity-permalink .activity-comments ul li>ul{margin-top:10px}form.ac-form{display:none;padding:1em}form.ac-form .ac-reply-avatar{float:right}form.ac-form .ac-reply-avatar img{border:1px solid #eee}form.ac-form .ac-reply-content{color:#767676;padding-right:1em}form.ac-form .ac-reply-content a{text-decoration:none}form.ac-form .ac-reply-content .ac-textarea{margin-bottom:15px;padding:0 .5em;overflow:hidden}form.ac-form .ac-reply-content .ac-textarea textarea{background:0 0;box-shadow:none;color:#555;font-family:inherit;font-size:100%;height:60px;margin:0;outline:0;padding:.5em;width:100%}form.ac-form .ac-reply-content .ac-textarea textarea:focus{box-shadow:0 0 6px #d6d6d6}form.ac-form .ac-reply-content input{margin-top:10px}.activity-comments li form.ac-form{clear:both;margin-left:15px}.activity-comments form.root{margin-right:0}@media screen and (min-width:46.8em){.buddypress-wrap .blogs-list li .item-block{float:none;width:auto}.buddypress-wrap .blogs-list li .item-meta{clear:right;float:none}}@media screen and (min-width:46.8em){.buddypress-wrap .bp-dir-vert-nav .blogs-list .list-title{width:auto}}.buddypress-wrap .groups-list li .list-title{text-align:center}.buddypress-wrap .groups-list li .group-details{clear:right}.buddypress-wrap .groups-list li .group-desc{border:1px solid #eaeaea;border-radius:10px;background-clip:padding-box;font-size:13px;color:#737373;font-style:italic;margin:10px auto 0;padding:1em}@media screen and (min-width:46.8em){.buddypress-wrap .groups-list li .group-desc{font-size:16px}}.buddypress-wrap .groups-list li p{margin:0 0 .5em}@media screen and (min-width:46.8em){.buddypress-wrap .groups-list li .item{margin-left:0}.buddypress-wrap .groups-list li .item-meta,.buddypress-wrap .groups-list li .list-title{text-align:right;width:auto}.buddypress-wrap .groups-list li .item-meta{margin-bottom:20px}.buddypress-wrap .groups-list li .last-activity{clear:right;margin-top:-20px}}.buddypress-wrap .groups-list li.group-no-avatar div.group-desc{margin-right:0}.buddypress-wrap .mygroups .groups-list.grid .wrap{min-height:450px;padding-bottom:0}@media screen and (min-width:46.8em){.buddypress-wrap .groups-list.grid.four .group-desc,.buddypress-wrap .groups-list.grid.three .group-desc{font-size:14px}}@media screen and (min-width:46.8em){.buddypress .bp-vertical-navs .groups-list .item-avatar{margin-left:3%;width:15%}}.buddypress-wrap .members-list li .member-name{margin-bottom:10px}.buddypress-wrap .members-list li .user-update{border:1px solid #eaeaea;border-radius:10px;background-clip:padding-box;color:#737373;font-style:italic;font-size:13px;margin:15px auto;padding:1em}@media screen and (min-width:46.8em){.buddypress-wrap .members-list li .user-update{font-size:16px}}.buddypress-wrap .members-list li .user-update .activity-read-more{display:block;font-size:12px;font-style:normal;margin-top:10px;padding-right:2px}@media screen and (min-width:46.8em){.buddypress-wrap .members-list li .last-activity{clear:right;margin-top:-10px}}@media screen and (min-width:46.8em){.buddypress-wrap .members-group-list li .joined{clear:right;float:none}}@media screen and (min-width:32em){body:not(.logged-in) .members-list .user-update{width:96%}}.register-page .register-section{box-sizing:border-box}.register-page .signup-form{margin-top:20px}.register-page .signup-form .default-profile input{margin-bottom:20px}.register-page .signup-form label,.register-page .signup-form legend{margin:10px 0 0}.register-page .signup-form .editfield{margin:15px 0}.register-page .signup-form .editfield fieldset{border:0;padding:0}.register-page .signup-form .editfield fieldset legend{margin:0 0 5px;text-indent:0}.register-page .signup-form .editfield .field-visibility-settings{padding:.5em}.register-page .signup-form .editfield .field-visibility-settings fieldset{margin:0 0 10px}.register-page .signup-form #signup-avatar img{margin:0 0 10px 15px}.register-page .signup-form .wp-pwd button{vertical-align:middle}.register-page .signup-form #pass-strength-result,.register-page .signup-form #pass1,.register-page .signup-form #pass1-text{width:10em}.register-page .signup-form #pass1{display:inline-block;margin-bottom:inherit}.register-page .signup-form #pass1-text,.register-page .signup-form .pw-weak{display:none}.register-page .signup-form .show-password #pass1-text{display:inline-block;margin-bottom:inherit}.register-page .signup-form .show-password #pass1{display:none}.register-page .signup-form .description.indicator-hint{font-size:14px}.register-page .signup-form #submit:disabled{color:#767676;opacity:.4}.register-page .signup-form .password-entry,.register-page .signup-form .password-entry-confirm{border:1px solid #eee}body.buddypress.register.js .user-pass2-wrap{display:none}body.buddypress.register.no-js .wp-hide-pw{display:none}@media screen and (min-width:46.8em){.buddypress-wrap .register-page .layout-wrap{display:flex;flex-flow:row wrap;justify-content:space-around}.buddypress-wrap .register-page .layout-wrap .default-profile{flex:1;padding-left:2em}.buddypress-wrap .register-page .layout-wrap .blog-details{flex:1;padding-right:2em}.buddypress-wrap .register-page .submit{clear:both}}@media screen and (min-width:46.8em){.buddypress-wrap.extended-default-reg .register-page .default-profile{min-width:14em;flex:1;padding-left:1em}.buddypress-wrap.extended-default-reg .register-page .extended-profile{flex:2;padding-right:1em}.buddypress-wrap.extended-default-reg .register-page .blog-details{flex:1 100%}}#group-create-body{padding:.5em}#group-create-body .creation-step-name{text-align:center}#group-create-body img.avatar{width:auto;height:auto}#group-create-body .avatar-nav-items{margin-top:15px}.single-headers:after,.single-headers:before{content:" ";display:table}.single-headers:after{clear:both}.single-headers{margin-bottom:15px}.single-headers #item-header-avatar a{display:block;text-align:center}.single-headers #item-header-avatar a img{float:none;width:auto;height:auto}.single-headers div#item-header-content{float:none}@media screen and (min-width:46.8em){.single-headers #item-header-avatar a{text-align:right}.single-headers #item-header-avatar a img{float:right}.single-headers #item-header-content{padding-right:2em}}.single-headers .activity,.single-headers .group-status{display:inline}.single-headers .group-status{font-size:18px;color:#333;padding-left:1em}.single-headers .activity{display:inline-block;font-size:12px;padding:0}.single-headers #sitewide-notice p,.single-headers div#message p{background-color:#ffd;border:1px solid #cb2;color:#440;font-weight:400;margin-top:3px;text-decoration:none}.single-headers h2{line-height:1.2;margin:0 0 5px}.single-headers h2 a{color:#767676;text-decoration:none}.single-headers h2 span.highlight{display:inline-block;font-size:60%;font-weight:400;line-height:1.7;vertical-align:middle}.single-headers h2 span.highlight span{background:#a1dcfa;color:#fff;cursor:pointer;font-size:80%;font-weight:700;margin-bottom:2px;padding:1px 4px;position:relative;left:-2px;top:-2px;vertical-align:middle}.single-headers img.avatar{float:right;margin:0 0 19px 15px}.single-headers .item-meta{color:#767676;font-size:14px;margin:15px 0 5px;padding-bottom:.5em}.single-headers ul{margin-bottom:15px}.single-headers ul li{float:left;list-style:none}.single-headers div.generic-button{text-align:center}.single-headers li.generic-button{display:inline-block;text-align:center}@media screen and (min-width:46.8em){.single-headers a.button,.single-headers div.generic-button,.single-headers li.generic-button{float:right}}.single-headers a.button,.single-headers div.generic-button{margin:10px 0 0 10px}.single-headers li.generic-button{margin:2px 10px}.single-headers li.generic-button:first-child{margin-right:0}.single-headers div#message.info{line-height:.8}body.no-js .single-item-header .js-self-profile-button{display:none}#cover-image-container{position:relative}#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}#item-header-cover-image{position:relative;z-index:2}#item-header-cover-image #item-header-avatar{padding:0 1em}.groups-header .bp-group-type-list{margin:0}.groups-header .bp-feedback{clear:both}.groups-header .group-item-actions{float:right;margin:0 15px 15px 0;padding-top:0;width:100%}.groups-header .moderators-lists{margin-top:0}.groups-header .moderators-lists .moderators-title{font-size:14px}.groups-header .moderators-lists .user-list{margin:0 0 5px}.groups-header .moderators-lists .user-list ul:after{clear:both;content:"";display:table}.groups-header .moderators-lists .user-list li{display:inline-block;float:none;margin-right:4px;padding:4px}.groups-header .moderators-lists img.avatar{box-shadow:none;float:none;height:30px;margin:0;max-width:100%;width:30px}@media screen and (min-width:46.8em){.groups-header div#item-header-content{float:right;margin-right:10%;text-align:right;padding-top:15px;width:42%}.groups-header .group-item-actions{float:left;margin:0 15px 15px 0;text-align:left;width:20%}.groups-header .groups-meta{clear:both}}.groups-header .desc-wrap{background:#eaeaea;border:1px solid #d6d6d6;margin:0 0 15px;padding:1em;text-align:center}.groups-header .desc-wrap .group-description{background:#fafafa;box-shadow:inset 0 0 9px #ccc;padding:1em;text-align:right}.groups-header .desc-wrap .group-description p{margin:0;padding:0}.bp-user .users-header .user-nicename{margin-bottom:5px}.bp-user .member-header-actions{overflow:hidden}.bp-user .member-header-actions *>*{display:block}.buddypress-wrap .item-body{margin:20px 0}.buddypress-wrap .item-body .screen-heading{font-size:20px;font-weight:400}.buddypress-wrap .item-body .button-tabs{margin:30px 0 15px;list-style:none}.buddypress-wrap.bp-single-vert-nav .bp-list:not(.grid) .item-entry{padding-right:.5em}.single-item.group-members .item-body .filters:not(.no-subnav){border-top:5px solid #eaeaea;padding-top:1em}.single-item.group-members .item-body .filters{margin-top:0}.buddypress-wrap .group-status-type ul{margin:0 20px 20px 0}.groups-manage-members-list{padding:.5em 0}.groups-manage-members-list dd{margin:0;padding:1em 0}.groups-manage-members-list .section-title{background:#eaeaea;padding-right:.3em}.groups-manage-members-list ul{list-style:none;margin-bottom:0}.groups-manage-members-list ul li{border-bottom:1px solid #eee;margin-bottom:10px;padding:.5em .3em .3em}.groups-manage-members-list ul li:last-child,.groups-manage-members-list ul li:only-child{border-bottom:0}.groups-manage-members-list ul li:nth-child(even){background:#fafafa}.groups-manage-members-list ul li.banned-user{background:#fad3d3}.groups-manage-members-list ul .member-name{margin-bottom:0;text-align:center}.groups-manage-members-list ul img{display:block;margin:0 auto;width:20%}@media screen and (min-width:32em){.groups-manage-members-list ul .member-name{text-align:right}.groups-manage-members-list ul img{display:inline;width:50px}}.groups-manage-members-list ul .members-manage-buttons:after,.groups-manage-members-list ul .members-manage-buttons:before{content:" ";display:table}.groups-manage-members-list ul .members-manage-buttons:after{clear:both}.groups-manage-members-list ul .members-manage-buttons{margin:15px 0 5px}.groups-manage-members-list ul .members-manage-buttons a.button{color:#767676;display:block;font-size:13px}@media screen and (min-width:32em){.groups-manage-members-list ul .members-manage-buttons a.button{display:inline-block}}.groups-manage-members-list ul .members-manage-buttons.text-links-list{margin-bottom:0}@media screen and (max-width:32em){.groups-manage-members-list ul .members-manage-buttons.text-links-list a.button{background:#fafafa;border:1px solid #eee;display:block;margin-bottom:10px}}.groups-manage-members-list ul .action:not(.text-links-list) a.button{font-size:12px}@media screen and (min-width:46.8em){.groups-manage-members-list ul li .avatar,.groups-manage-members-list ul li .member-name{float:right}.groups-manage-members-list ul li .avatar{margin-left:15px}.groups-manage-members-list ul li .action{clear:both;float:right}}#group-manage-members-ui #group-members-search-form button[type=submit]{float:left;font-size:inherit;font-weight:400;line-height:1.5;text-align:center;text-transform:none}#group-manage-members-ui #group-members-search-form button[type=submit] span{font-family:dashicons;font-size:18px;line-height:1.6}#group-manage-members-ui #group-members-pagination button:last-child{margin-left:2em}#group-manage-members-ui #bp-no-group-members td{border:none}.buddypress .bp-invites-content ul.item-list{border-top:0}.buddypress .bp-invites-content ul.item-list li{border:1px solid #eaeaea;margin:0 0 1%;padding-right:5px;padding-left:5px;position:relative;width:auto}.buddypress .bp-invites-content ul.item-list li .list-title{margin:0 auto;width:80%}.buddypress .bp-invites-content ul.item-list li .action{position:absolute;top:10px;left:10px}.buddypress .bp-invites-content ul.item-list li .action a.button.invite-button{border:0}.buddypress .bp-invites-content ul.item-list li .action a.button.invite-button:focus,.buddypress .bp-invites-content ul.item-list li .action a.button.invite-button:hover{color:#1fb3dd}.buddypress .bp-invites-content ul.item-list li.selected{box-shadow:inset 0 0 12px 0 rgba(237,187,52,.2)}.buddypress .bp-invites-content .group-inviters li,.buddypress .bp-invites-content .item-list .item-meta span{color:#767676}.buddypress .bp-invites-content li ul.group-inviters{clear:both;margin:0}.buddypress .bp-invites-content li ul.group-inviters li{border:0;float:right;font-size:20px;width:inherit}.buddypress .bp-invites-content li .status{font-size:20px;font-style:italic;clear:both;color:#555;margin:10px 0}.buddypress .bp-invites-content #send-invites-editor ul:after,.buddypress .bp-invites-content #send-invites-editor ul:before{content:" ";display:table}.buddypress .bp-invites-content #send-invites-editor ul:after{clear:both}.buddypress .bp-invites-content #send-invites-editor textarea{width:100%}.buddypress .bp-invites-content #send-invites-editor ul{clear:both;list-style:none;margin:10px 0}.buddypress .bp-invites-content #send-invites-editor ul li{float:right;margin:.5%;max-height:50px;max-width:50px}.buddypress .bp-invites-content #send-invites-editor #bp-send-invites-form{clear:both;margin-top:10px}.buddypress .bp-invites-content #send-invites-editor .action{margin-top:10px;padding-top:10px}.buddypress .bp-invites-content #send-invites-editor.bp-hide{display:none}@media screen and (min-width:46.8em){.buddypress .bp-invites-content ul.item-list>li{box-sizing:border-box;border:1px solid #eaeaea;float:right;padding-right:.5em;padding-left:.5em;width:49.5%}.buddypress .bp-invites-content ul.item-list>li:nth-child(odd){margin-left:.5%}.buddypress .bp-invites-content ul.item-list>li:nth-child(even){margin-right:.5%}.buddypress .bp-invites-content ul.item-list ul.group-inviters{float:right;width:auto}}@media screen and (min-width:46.8em){:not(.vertical)+.item-body #group-invites-container{display:-ms-grid;display:grid;-ms-grid-columns:25% auto;grid-template-columns:25% auto;grid-template-areas:"group-invites-nav group-invites-column"}:not(.vertical)+.item-body #group-invites-container .bp-invites-nav{-ms-grid-row:1;-ms-grid-column:1;grid-area:group-invites-nav}:not(.vertical)+.item-body #group-invites-container .bp-invites-nav li{display:block;float:none}:not(.vertical)+.item-body #group-invites-container .group-invites-column{-ms-grid-row:1;-ms-grid-column:2;grid-area:group-invites-column}}.buddypress.groups .activity-update-form{margin-top:0}.buddypress-wrap .profile{margin-top:30px}.buddypress-wrap .public .profile-fields td.label{width:30%}.buddypress-wrap .profile.edit ul.button-nav{list-style:none;margin:30px 0 10px;padding-right:0}.buddypress-wrap .profile.edit ul.button-nav li{display:inline-block;margin-left:10px}.buddypress-wrap .profile.edit ul.button-nav li a{padding:.5em}.buddypress-wrap .profile.edit .editfield{background:#fafafa;border:1px solid #eee;margin:15px 0;padding:1em}.buddypress-wrap .profile.edit .editfield fieldset{border:0}.buddypress-wrap .profile.edit .editfield fieldset label{font-weight:400}.buddypress-wrap .profile.edit .editfield fieldset label.xprofile-field-label{display:inline}.buddypress-wrap .profile.edit .editfield{display:flex;flex-direction:column}.buddypress-wrap .profile.edit .editfield .description{margin-top:10px;order:2}.buddypress-wrap .profile.edit .editfield>fieldset{order:1}.buddypress-wrap .profile.edit .editfield .field-visibility-settings,.buddypress-wrap .profile.edit .editfield .field-visibility-settings-toggle{order:3}body.no-js .buddypress-wrap .field-visibility-settings-close,body.no-js .buddypress-wrap .field-visibility-settings-toggle{display:none}body.no-js .buddypress-wrap .field-visibility-settings{display:block}.buddypress-wrap .field-visibility-settings{margin:10px 0}.buddypress-wrap .current-visibility-level{font-style:normal;font-weight:700}.buddypress-wrap .field-visibility-settings,.buddypress-wrap .field-visibility-settings-header{color:#737373}.buddypress-wrap .field-visibility-settings fieldset{margin:5px 0}.buddypress-wrap .standard-form .editfield fieldset{margin:0}.buddypress-wrap .standard-form .field-visibility-settings label{font-weight:400;margin:0}.buddypress-wrap .standard-form .field-visibility-settings .radio{list-style:none;margin-bottom:0}.buddypress-wrap .standard-form .field-visibility-settings .field-visibility-settings-close{font-size:12px}.buddypress-wrap .standard-form .wp-editor-container{border:1px solid #dedede}.buddypress-wrap .standard-form .wp-editor-container textarea{background:#fff;width:100%}.buddypress-wrap .standard-form .description{background:#fafafa;font-size:inherit}.buddypress-wrap .standard-form .field-visibility-settings legend,.buddypress-wrap .standard-form .field-visibility-settings-header{font-style:italic}.buddypress-wrap .standard-form .field-visibility-settings-header{font-size:14px}.buddypress-wrap .standard-form .field-visibility-settings label,.buddypress-wrap .standard-form .field-visibility-settings legend{font-size:14px}.buddypress-wrap .standard-form .field-visibility select{margin:0}.buddypress-wrap .html-active button.switch-html{background:#f5f5f5;border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0}.buddypress-wrap .tmce-active button.switch-tmce{background:#f5f5f5;border-bottom-color:transparent;border-bottom-right-radius:0;border-bottom-left-radius:0}.buddypress-wrap .profile.public .profile-group-title{border-bottom:1px solid #ccc}body.register .buddypress-wrap .page ul{list-style:none}.buddypress-wrap .profile .bp-avatar-nav{margin-top:20px}.message-action-delete:before,.message-action-star:before,.message-action-unstar:before,.message-action-view:before{font-family:dashicons;font-size:18px}.message-action-star:before{color:#aaa;content:"\f154"}.message-action-unstar:before{color:#fcdd77;content:"\f155"}.message-action-view:before{content:"\f473"}.message-action-delete:before{content:"\f153"}.message-action-delete:hover:before{color:#a00}.preview-content .actions a{text-decoration:none}.bp-messages-content{margin:15px 0}.bp-messages-content .avatar{box-shadow:none}.bp-messages-content .thread-participants{list-style:none}.bp-messages-content .thread-participants dd{margin-right:0}.bp-messages-content time{color:#737373;font-size:12px}#message-threads{border-top:1px solid #eaeaea;clear:both;list-style:none;margin:0;max-height:220px;overflow-x:hidden;overflow-y:auto;padding:0;width:100%}#message-threads li{border-bottom:1px solid #eaeaea;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-o-flex-flow:row nowrap;flex-flow:row nowrap;margin:0;overflow:hidden;padding:.5em 0}#message-threads li .thread-cb{display:flex;align-items:center;-moz-flex:1 2 5%;-o-flex:1 2 5%;flex:1 2 5%}#message-threads li .thread-from,#message-threads li .thread-to{-moz-flex:1 2 20%;-o-flex:1 2 20%;flex:1 2 20%}#message-threads li .thread-from img.avatar,#message-threads li .thread-to img.avatar{float:right;margin:0 0 0 10px}#message-threads li .thread-from .user-name,#message-threads li .thread-to .user-name{display:inline-block;line-height:1.1}#message-threads li .thread-from .num-recipients,#message-threads li .thread-to .num-recipients{color:#737373;font-weight:400;font-size:12px;margin:0}#message-threads li .thread-content{-moz-flex:1 2 60%;-o-flex:1 2 60%;flex:1 2 60%}#message-threads li .thread-date{-moz-flex:1 2 15%;-o-flex:1 2 15%;flex:1 2 15%}#message-threads li.selected{background-color:#fafafa}#message-threads li.selected .thread-subject .subject{color:#5087e5}#message-threads li.unread{font-weight:700}#message-threads li .thread-content .excerpt{color:#737373;font-size:12px;margin:0}#message-threads li .thread-content .thread-from,#message-threads li .thread-content .thread-subject,#message-threads li .thread-content .thread-to{font-size:13px}@media screen and (min-width:46.8em){#message-threads li .thread-content .thread-from,#message-threads li .thread-content .thread-subject,#message-threads li .thread-content .thread-to{font-size:16px}}#message-threads li .thread-content .thread-subject{vertical-align:top}#message-threads li .thread-content .thread-subject .excerpt{font-weight:400}#message-threads li .thread-date{padding-left:5px;text-align:left}.bp-messages-content .actions{float:left;max-width:30%;line-height:1}.bp-messages-content .actions .bp-icons:not(.bp-hide){display:inline-block;margin:0;padding:.3em .5em}.bp-messages-content .actions .bp-icons:not(.bp-hide):before{font-size:26px}.bp-messages-content #thread-preview{border:1px solid #eaeaea;margin-top:20px}.bp-messages-content #thread-preview .preview-message{overflow:hidden}.bp-messages-content #thread-preview .preview-content{margin:.5em}.bp-messages-content #thread-preview .preview-content .preview-message{background:#fafafa;margin:10px 0;padding:1em .3em .3em}.bp-messages-content #bp-message-thread-list{border-top:1px solid #eaeaea;clear:both;list-style:none;padding:1em 0 .3em}.bp-messages-content #bp-message-thread-list li{padding:.5em}.bp-messages-content #bp-message-thread-list li:nth-child(2n) .message-content{background:#fafafa}.bp-messages-content #bp-message-thread-list .message-metadata{border-bottom:1px solid #ccc;box-shadow:2px 1px 9px 0 #eee;display:table;padding:.2em;width:100%}.bp-messages-content #bp-message-thread-list .message-metadata .avatar{width:30px}.bp-messages-content #bp-message-thread-list .message-metadata .user-link{display:block;font-size:13px;float:right}@media screen and (min-width:46.8em){.bp-messages-content #bp-message-thread-list .message-metadata .user-link{font-size:16px}}.bp-messages-content #bp-message-thread-list .message-metadata time{color:#737373;font-size:12px;padding:0 .5em}.bp-messages-content #bp-message-thread-list .message-metadata button{padding:0 .3em}.bp-messages-content #bp-message-thread-list .message-metadata button:before{font-size:20px}.bp-messages-content #bp-message-thread-list .message-content{overflow:hidden;margin:1em auto 0;width:90%}.bp-messages-content #bp-message-thread-list img.avatar{float:right;margin:0 0 0 10px}.bp-messages-content #bp-message-thread-list .actions a:before{font-size:18px}.bp-messages-content form.send-reply .avatar-box{padding:.5em 0}.bp-messages-content .preview-pane-header,.bp-messages-content .single-message-thread-header{border-bottom:1px solid #eaeaea}.bp-messages-content .preview-pane-header:after,.bp-messages-content .single-message-thread-header:after{clear:both;content:"";display:table}.bp-messages-content .preview-thread-title,.bp-messages-content .single-thread-title{font-size:16px}.bp-messages-content .preview-thread-title .messages-title,.bp-messages-content .single-thread-title .messages-title{padding-right:2em}.bp-messages-content .thread-participants{float:right;margin:5px 0;width:70%}.bp-messages-content .thread-participants dd,.bp-messages-content .thread-participants ul{margin-bottom:10px}.bp-messages-content .thread-participants ul{list-style:none}.bp-messages-content .thread-participants ul:after{clear:both;content:"";display:table}.bp-messages-content .thread-participants li{float:right;margin-right:5px}.bp-messages-content .thread-participants img{width:30px;height:30px}.bp-messages-content #bp-message-thread-list li .message-content blockquote,.bp-messages-content #bp-message-thread-list li .message-content ol,.bp-messages-content #bp-message-thread-list li .message-content ul,.bp-messages-content #thread-preview .preview-message blockquote,.bp-messages-content #thread-preview .preview-message ol,.bp-messages-content #thread-preview .preview-message ul{list-style-position:inside;margin-right:0}.bp-messages-content #thread-preview:empty,.bp-messages-content ul#message-threads:empty{display:none}.bp-messages-content #bp-message-thread-header h2:first-child,.bp-messages-content #thread-preview h2:first-child{background-color:#eaeaea;color:#555;font-weight:700;margin:0;padding:.5em}.bp-messages-content #bp-message-thread-list li a.user-link,.bp-messages-content #message-threads .thread-content a{border:0;text-decoration:none}.bp-messages-content .standard-form #subject{margin-bottom:20px}div.bp-navs#subsubnav.bp-messages-filters .user-messages-bulk-actions{margin-left:15px;max-width:42.5%}.buddypress.settings .profile-settings.bp-tables-user select{width:100%}body.buddypress.settings .wp-pwd button{vertical-align:middle}body.buddypress.settings #pass-strength-result,body.buddypress.settings #pass1,body.buddypress.settings #pass1-text{width:16em}body.buddypress.settings #pass1{display:inline-block;margin-bottom:inherit}body.buddypress.settings #pass-strength-result,body.buddypress.settings #pass1-text,body.buddypress.settings .pw-weak{display:none}body.buddypress.settings .show-password #pass1-text{display:inline-block;margin-bottom:inherit}body.buddypress.settings .show-password #pass1{display:none}body.buddypress.settings #your-profile #submit:disabled{color:#767676;opacity:.4}body.buddypress.settings.js .user-pass2-wrap,body.buddypress.settings.js .wp-pwd{display:none}body.buddypress.settings.no-js .wp-cancel-pw,body.buddypress.settings.no-js .wp-generate-pw,body.buddypress.settings.no-js .wp-hide-pw{display:none}body.buddypress.settings.data #buddypress.buddypress-wrap .item-body p a{text-decoration:underline}.buddypress-wrap #whats-new-post-in-box select,.buddypress-wrap .filter select{border:1px solid #d6d6d6}.buddypress-wrap input.action[disabled]{cursor:pointer;opacity:.4}.buddypress-wrap #notification-bulk-manage[disabled]{display:none}.buddypress-wrap fieldset legend{font-size:inherit;font-weight:600}.buddypress-wrap input[type=email]:focus,.buddypress-wrap input[type=password]:focus,.buddypress-wrap input[type=tel]:focus,.buddypress-wrap input[type=text]:focus,.buddypress-wrap input[type=url]:focus,.buddypress-wrap textarea:focus{box-shadow:0 0 8px #eaeaea}.buddypress-wrap select{height:auto}.buddypress-wrap textarea{resize:vertical}.buddypress-wrap .standard-form .bp-controls-wrap{margin:1em 0}.buddypress-wrap .standard-form .groups-members-search input[type=search],.buddypress-wrap .standard-form .groups-members-search input[type=text],.buddypress-wrap .standard-form [data-bp-search] input[type=search],.buddypress-wrap .standard-form [data-bp-search] input[type=text],.buddypress-wrap .standard-form input[type=color],.buddypress-wrap .standard-form input[type=date],.buddypress-wrap .standard-form input[type=datetime-local],.buddypress-wrap .standard-form input[type=datetime],.buddypress-wrap .standard-form input[type=email],.buddypress-wrap .standard-form input[type=month],.buddypress-wrap .standard-form input[type=number],.buddypress-wrap .standard-form input[type=password],.buddypress-wrap .standard-form input[type=range],.buddypress-wrap .standard-form input[type=search],.buddypress-wrap .standard-form input[type=tel],.buddypress-wrap .standard-form input[type=text],.buddypress-wrap .standard-form input[type=time],.buddypress-wrap .standard-form input[type=url],.buddypress-wrap .standard-form input[type=week],.buddypress-wrap .standard-form select,.buddypress-wrap .standard-form textarea{background:#fafafa;border:1px solid #d6d6d6;border-radius:0;font:inherit;font-size:100%;padding:.5em}.buddypress-wrap .standard-form input[required],.buddypress-wrap .standard-form select[required],.buddypress-wrap .standard-form textarea[required]{box-shadow:none;border-width:2px;outline:0}.buddypress-wrap .standard-form input[required]:invalid,.buddypress-wrap .standard-form select[required]:invalid,.buddypress-wrap .standard-form textarea[required]:invalid{border-color:#b71717}.buddypress-wrap .standard-form input[required]:valid,.buddypress-wrap .standard-form select[required]:valid,.buddypress-wrap .standard-form textarea[required]:valid{border-color:#91cc2c}.buddypress-wrap .standard-form input[required]:focus,.buddypress-wrap .standard-form select[required]:focus,.buddypress-wrap .standard-form textarea[required]:focus{border-color:#d6d6d6;border-width:1px}.buddypress-wrap .standard-form input.invalid[required],.buddypress-wrap .standard-form select.invalid[required],.buddypress-wrap .standard-form textarea.invalid[required]{border-color:#b71717}.buddypress-wrap .standard-form input:not(.small),.buddypress-wrap .standard-form textarea{width:100%}.buddypress-wrap .standard-form input[type=checkbox],.buddypress-wrap .standard-form input[type=radio]{margin-left:5px;width:auto}.buddypress-wrap .standard-form select{padding:3px}.buddypress-wrap .standard-form textarea{height:120px}.buddypress-wrap .standard-form textarea#message_content{height:200px}.buddypress-wrap .standard-form input[type=password]{margin-bottom:5px}.buddypress-wrap .standard-form input:focus,.buddypress-wrap .standard-form select:focus,.buddypress-wrap .standard-form textarea:focus{background:#fafafa;color:#555;outline:0}.buddypress-wrap .standard-form label,.buddypress-wrap .standard-form span.label{display:block;font-weight:600;margin:15px 0 5px;width:auto}.buddypress-wrap .standard-form a.clear-value{display:block;margin-top:5px;outline:0}.buddypress-wrap .standard-form .submit{clear:both;padding:15px 0 0}.buddypress-wrap .standard-form p.submit{margin-bottom:0}.buddypress-wrap .standard-form div.submit input{margin-left:15px}.buddypress-wrap .standard-form #invite-list label,.buddypress-wrap .standard-form p label{font-weight:400;margin:auto}.buddypress-wrap .standard-form p.description{color:#737373;margin:5px 0}.buddypress-wrap .standard-form div.checkbox label:nth-child(n+2),.buddypress-wrap .standard-form div.radio div label{color:#737373;font-size:100%;font-weight:400;margin:5px 0 0}.buddypress-wrap .standard-form#send-reply textarea{width:97.5%}.buddypress-wrap .standard-form#sidebar-login-form label{margin-top:5px}.buddypress-wrap .standard-form#sidebar-login-form input[type=password],.buddypress-wrap .standard-form#sidebar-login-form input[type=text]{padding:4px;width:95%}.buddypress-wrap .standard-form.profile-edit input:focus{background:#fff}@media screen and (min-width:46.8em){.buddypress-wrap .standard-form .left-menu{float:right}.buddypress-wrap .standard-form #invite-list ul{list-style:none;margin:1%}.buddypress-wrap .standard-form #invite-list ul li{margin:0 1% 0 0}.buddypress-wrap .standard-form .main-column{margin-right:190px}.buddypress-wrap .standard-form .main-column ul#friend-list{clear:none;float:right}.buddypress-wrap .standard-form .main-column ul#friend-list h4{clear:none}}.buddypress-wrap .standard-form .bp-tables-user label{margin:0}.buddypress-wrap .signup-form label,.buddypress-wrap .signup-form legend{font-weight:400}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-wrap .wp-editor-wrap .wp-editor-wrap button,.buddypress-wrap .wp-editor-wrap .wp-editor-wrap input[type=button],.buddypress-wrap .wp-editor-wrap .wp-editor-wrap input[type=submit],.buddypress-wrap .wp-editor-wrap a.button,.buddypress-wrap .wp-editor-wrap input[type=reset]{padding:0 8px 1px}.buddypress-wrap .select-wrap{border:1px solid #eee}.buddypress-wrap .select-wrap label{display:inline}.buddypress-wrap .select-wrap select::-ms-expand{display:none}.buddypress-wrap .select-wrap select{-moz-appearance:none;-webkit-appearance:none;-o-appearance:none;appearance:none;border:0;cursor:pointer;margin-left:-25px;padding:6px 10px 6px 25px;position:relative;text-indent:-2px;z-index:1;width:auto}.buddypress-wrap .select-wrap select,.buddypress-wrap .select-wrap select:active,.buddypress-wrap .select-wrap select:focus{background:0 0}.buddypress-wrap .select-wrap span.select-arrow{display:inline-block;position:relative;z-index:0}.buddypress-wrap .select-wrap span.select-arrow:before{color:#ccc;content:"\25BC"}.buddypress-wrap .select-wrap:focus .select-arrow:before,.buddypress-wrap .select-wrap:hover .select-arrow:before{color:#a6a6a6}.buddypress-wrap .bp-search form:focus,.buddypress-wrap .bp-search form:hover,.buddypress-wrap .select-wrap:focus,.buddypress-wrap .select-wrap:hover{border:1px solid #d5d4d4;box-shadow:inset 0 0 3px #eee}@media screen and (min-width:32em){.buddypress-wrap .notifications-options-nav .select-wrap{float:right}}.buddypress-wrap .bp-dir-search-form,.buddypress-wrap .bp-messages-search-form:after,.buddypress-wrap .bp-messages-search-form:before{content:" ";display:table}.buddypress-wrap .bp-dir-search-form,.buddypress-wrap .bp-messages-search-form:after{clear:both}.buddypress-wrap form#group-members-search,.buddypress-wrap form.bp-dir-search-form,.buddypress-wrap form.bp-messages-search-form,.buddypress-wrap form[data-bp-search].bp-invites-search-form{border:1px solid #eee;width:100%}.buddypress-wrap form#group-members-search label,.buddypress-wrap form.bp-dir-search-form label,.buddypress-wrap form.bp-messages-search-form label,.buddypress-wrap form[data-bp-search].bp-invites-search-form label{margin:0}.buddypress-wrap form#group-members-search button[type=submit],.buddypress-wrap form#group-members-search input[type=search],.buddypress-wrap form#group-members-search input[type=text],.buddypress-wrap form.bp-dir-search-form button[type=submit],.buddypress-wrap form.bp-dir-search-form input[type=search],.buddypress-wrap form.bp-dir-search-form input[type=text],.buddypress-wrap form.bp-messages-search-form button[type=submit],.buddypress-wrap form.bp-messages-search-form input[type=search],.buddypress-wrap form.bp-messages-search-form input[type=text],.buddypress-wrap form[data-bp-search].bp-invites-search-form button[type=submit],.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=search],.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=text]{background:0 0;border:0;border-radius:0;background-clip:padding-box}.buddypress-wrap form#group-members-search input[type=search],.buddypress-wrap form#group-members-search input[type=text],.buddypress-wrap form.bp-dir-search-form input[type=search],.buddypress-wrap form.bp-dir-search-form input[type=text],.buddypress-wrap form.bp-messages-search-form input[type=search],.buddypress-wrap form.bp-messages-search-form input[type=text],.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=search],.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=text]{float:right;line-height:1.5;padding:3px 10px;width:80%}.buddypress-wrap form#group-members-search button[type=submit],.buddypress-wrap form.bp-dir-search-form button[type=submit],.buddypress-wrap form.bp-messages-search-form button[type=submit],.buddypress-wrap form[data-bp-search].bp-invites-search-form button[type=submit]{float:left;font-size:inherit;font-weight:400;line-height:1.5;padding:3px .7em;text-align:center;text-transform:none;width:20%}.buddypress-wrap form#group-members-search button[type=submit] span,.buddypress-wrap form.bp-dir-search-form button[type=submit] span,.buddypress-wrap form.bp-messages-search-form button[type=submit] span,.buddypress-wrap form[data-bp-search].bp-invites-search-form button[type=submit] span{font-family:dashicons;font-size:18px;line-height:1.6}.buddypress-wrap form#group-members-search button[type=submit].bp-show,.buddypress-wrap form.bp-dir-search-form button[type=submit].bp-show,.buddypress-wrap form.bp-messages-search-form button[type=submit].bp-show,.buddypress-wrap form[data-bp-search].bp-invites-search-form button[type=submit].bp-show{height:auto;right:0;overflow:visible;position:static;top:0}.buddypress-wrap form#group-members-search input[type=search]::-webkit-search-cancel-button,.buddypress-wrap form.bp-dir-search-form input[type=search]::-webkit-search-cancel-button,.buddypress-wrap form.bp-messages-search-form input[type=search]::-webkit-search-cancel-button,.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=search]::-webkit-search-cancel-button{-webkit-appearance:searchfield-cancel-button}.buddypress-wrap form#group-members-search input[type=search]::-webkit-search-results-button,.buddypress-wrap form#group-members-search input[type=search]::-webkit-search-results-decoration,.buddypress-wrap form.bp-dir-search-form input[type=search]::-webkit-search-results-button,.buddypress-wrap form.bp-dir-search-form input[type=search]::-webkit-search-results-decoration,.buddypress-wrap form.bp-messages-search-form input[type=search]::-webkit-search-results-button,.buddypress-wrap form.bp-messages-search-form input[type=search]::-webkit-search-results-decoration,.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=search]::-webkit-search-results-button,.buddypress-wrap form[data-bp-search].bp-invites-search-form input[type=search]::-webkit-search-results-decoration{display:none}.buddypress-wrap form#group-members-search:hover{border:1px solid #d5d4d4;box-shadow:inset 0 0 3px #eee}.buddypress-wrap ul.filters li form label input{line-height:1.4;padding:.1em .7em}.buddypress-wrap .current-member-type{font-style:italic}.buddypress-wrap .dir-form{clear:both}.budypress.no-js form.bp-dir-search-form button[type=submit]{height:auto;right:0;overflow:visible;position:static;top:0}.bp-user [data-bp-search] form input[type=search],.bp-user [data-bp-search] form input[type=text]{padding:6px 10px 7px}.buddypress-wrap .bp-tables-user,.buddypress-wrap table.forum,.buddypress-wrap table.wp-profile-fields{width:100%}.buddypress-wrap .bp-tables-user thead tr,.buddypress-wrap table.forum thead tr,.buddypress-wrap table.wp-profile-fields thead tr{background:0 0;border-bottom:2px solid #ccc}.buddypress-wrap .bp-tables-user tbody tr,.buddypress-wrap table.forum tbody tr,.buddypress-wrap table.wp-profile-fields tbody tr{background:#fafafa}.buddypress-wrap .bp-tables-user tr td,.buddypress-wrap .bp-tables-user tr th,.buddypress-wrap table.forum tr td,.buddypress-wrap table.forum tr th,.buddypress-wrap table.wp-profile-fields tr td,.buddypress-wrap table.wp-profile-fields tr th{padding:.5em;vertical-align:middle}.buddypress-wrap .bp-tables-user tr td.label,.buddypress-wrap table.forum tr td.label,.buddypress-wrap table.wp-profile-fields tr td.label{border-left:1px solid #eaeaea;font-weight:600;width:25%}.buddypress-wrap .bp-tables-user tr.alt td,.buddypress-wrap table.wp-profile-fields tr.alt td{background:#fafafa}.buddypress-wrap table.profile-fields .data{padding:.5em 1em}.buddypress-wrap table.profile-fields tr:last-child{border-bottom:none}.buddypress-wrap table.notifications td{padding:1em .5em}.buddypress-wrap table.notifications .bulk-select-all,.buddypress-wrap table.notifications .bulk-select-check{width:7%}.buddypress-wrap table.notifications .bulk-select-check{vertical-align:middle}.buddypress-wrap table.notifications .date,.buddypress-wrap table.notifications .notification-description,.buddypress-wrap table.notifications .notification-since,.buddypress-wrap table.notifications .title{width:39%}.buddypress-wrap table.notifications .actions,.buddypress-wrap table.notifications .notification-actions{width:15%}.buddypress-wrap table.notification-settings th.title,.buddypress-wrap table.profile-settings th.title{width:80%}.buddypress-wrap table.notifications .notification-actions a.delete,.buddypress-wrap table.notifications .notification-actions a.mark-read{display:inline-block}.buddypress-wrap table.notification-settings{margin-bottom:15px;text-align:right}.buddypress-wrap #groups-notification-settings{margin-bottom:0}.buddypress-wrap table.notification-settings td:first-child,.buddypress-wrap table.notification-settings th.icon,.buddypress-wrap table.notifications td:first-child,.buddypress-wrap table.notifications th.icon{display:none}.buddypress-wrap table.notification-settings .no,.buddypress-wrap table.notification-settings .yes{text-align:center;width:40px;vertical-align:middle}.buddypress-wrap table#message-threads{clear:both}.buddypress-wrap table#message-threads .thread-info{min-width:40%}.buddypress-wrap table#message-threads .thread-info p{margin:0}.buddypress-wrap table#message-threads .thread-info p.thread-excerpt{color:#737373;font-size:12px;margin-top:3px}.buddypress-wrap table.profile-fields{margin-bottom:20px}.buddypress-wrap table.profile-fields:last-child{margin-bottom:0}.buddypress-wrap table.profile-fields p{margin:0}.buddypress-wrap table.profile-fields p:last-child{margin-top:0}.bp-screen-reader-text{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.center-vert{display:flex;align-items:center}.bp-hide{display:none}.bp-show{height:auto;right:0;overflow:visible;position:static;top:0}.buddypress .buddypress-wrap .activity-read-more a,.buddypress .buddypress-wrap .comment-reply-link,.buddypress .buddypress-wrap .generic-button a,.buddypress .buddypress-wrap a.bp-title-button,.buddypress .buddypress-wrap a.button,.buddypress .buddypress-wrap button,.buddypress .buddypress-wrap input[type=button],.buddypress .buddypress-wrap input[type=reset],.buddypress .buddypress-wrap input[type=submit],.buddypress .buddypress-wrap ul.button-nav:not(.button-tabs) li a{background:#fff;border-color:#ccc;border-style:solid;border-width:1px;border-radius:0;color:#555;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:400;outline:0;padding:.3em .5em;text-align:center;text-decoration:none;width:auto;line-height:1}.buddypress .buddypress-wrap a.button.dashicons,.buddypress .buddypress-wrap button.dashicons{font-family:dashicons}.buddypress .buddypress-wrap .button-small[type=button]{padding:0 8px 1px}.buddypress .buddypress-wrap .activity-read-more a:focus,.buddypress .buddypress-wrap .activity-read-more a:hover,.buddypress .buddypress-wrap .button-nav li a:focus,.buddypress .buddypress-wrap .button-nav li a:hover,.buddypress .buddypress-wrap .button-nav li.current a,.buddypress .buddypress-wrap .comment-reply-link:focus,.buddypress .buddypress-wrap .comment-reply-link:hover,.buddypress .buddypress-wrap .generic-button a:focus,.buddypress .buddypress-wrap .generic-button a:hover,.buddypress .buddypress-wrap a.button:focus,.buddypress .buddypress-wrap a.button:hover,.buddypress .buddypress-wrap button:focus,.buddypress .buddypress-wrap button:hover,.buddypress .buddypress-wrap input[type=button]:focus,.buddypress .buddypress-wrap input[type=button]:hover,.buddypress .buddypress-wrap input[type=reset]:focus,.buddypress .b