BuddyPress - Version 2.7.5

Version Description

See: https://codex.buddypress.org/releases/version-2-7-5/

Download this release

Release Info

Developer dcavins
Plugin Icon 128x128 BuddyPress
Version 2.7.5
Comparing to
See all releases

Code changes from version 2.0.6 to 2.7.5

Files changed (46) hide show
  1. .travis.yml +0 -48
  2. bp-activity/admin/css/admin-rtl.css +87 -0
  3. bp-activity/admin/css/admin-rtl.min.css +1 -0
  4. bp-activity/admin/css/admin.css +7 -0
  5. bp-activity/admin/css/admin.min.css +1 -1
  6. bp-activity/admin/js/admin.js +20 -17
  7. bp-activity/admin/js/admin.min.js +1 -1
  8. bp-activity/bp-activity-actions.php +398 -197
  9. bp-activity/bp-activity-admin.php +289 -798
  10. bp-activity/bp-activity-adminbar.php +47 -0
  11. bp-activity/bp-activity-akismet.php +33 -588
  12. bp-activity/bp-activity-cache.php +35 -10
  13. bp-activity/bp-activity-classes.php +12 -1674
  14. bp-activity/bp-activity-cssjs.php +76 -0
  15. bp-activity/bp-activity-embeds.php +352 -0
  16. bp-activity/bp-activity-filters.php +374 -108
  17. bp-activity/bp-activity-functions.php +2533 -713
  18. bp-activity/bp-activity-loader.php +8 -351
  19. bp-activity/bp-activity-notifications.php +248 -302
  20. bp-activity/bp-activity-screens.php +174 -248
  21. bp-activity/bp-activity-template.php +1818 -1310
  22. bp-activity/classes/class-bp-activity-activity.php +1923 -0
  23. bp-activity/classes/class-bp-activity-component.php +388 -0
  24. bp-activity/classes/class-bp-activity-feed.php +468 -0
  25. bp-activity/classes/class-bp-activity-list-table.php +862 -0
  26. bp-activity/classes/class-bp-activity-oembed-extension.php +329 -0
  27. bp-activity/classes/class-bp-activity-query.php +247 -0
  28. bp-activity/classes/class-bp-activity-template.php +409 -0
  29. bp-activity/classes/class-bp-activity-theme-compat.php +180 -0
  30. bp-activity/classes/class-bp-akismet.php +651 -0
  31. bp-activity/css/mentions-rtl.css +92 -0
  32. bp-activity/css/mentions-rtl.min.css +1 -0
  33. bp-activity/css/mentions.css +93 -0
  34. bp-activity/css/mentions.min.css +1 -0
  35. bp-activity/js/mentions.js +255 -0
  36. bp-activity/js/mentions.min.js +1 -0
  37. bp-blogs/bp-blogs-actions.php +7 -7
  38. bp-blogs/bp-blogs-activity.php +778 -260
  39. bp-blogs/bp-blogs-buddybar.php +0 -78
  40. bp-blogs/bp-blogs-cache.php +20 -28
  41. bp-blogs/bp-blogs-classes.php +4 -518
  42. bp-blogs/bp-blogs-filters.php +105 -6
  43. bp-blogs/bp-blogs-functions.php +690 -599
  44. bp-blogs/bp-blogs-loader.php +12 -235
  45. bp-blogs/bp-blogs-screens.php +24 -178
  46. bp-blogs/bp-blogs-template.php +147 -308
.travis.yml DELETED
@@ -1,48 +0,0 @@
1
- language: php
2
-
3
- php:
4
- - 5.2
5
- - 5.3
6
- - 5.4
7
- - 5.5
8
-
9
- env:
10
- - WP_VERSION=trunk WP_MULTISITE=0
11
- - WP_VERSION=tags/3.8.1 WP_MULTISITE=0
12
- - WP_VERSION=tags/3.7.1 WP_MULTISITE=0
13
- - WP_VERSION=trunk WP_MULTISITE=1
14
- - WP_VERSION=tags/3.8.1 WP_MULTISITE=1
15
- - WP_VERSION=tags/3.7.1 WP_MULTISITE=1
16
-
17
- before_script:
18
- # set up WP install
19
- - WP_CORE_DIR=/tmp/wordpress/
20
- - mkdir -p $WP_CORE_DIR
21
- - svn co --ignore-externals https://develop.svn.wordpress.org/$WP_VERSION $WP_CORE_DIR
22
- - plugin_slug=$(basename $(pwd))
23
- - plugin_dir=$WP_CORE_DIR/src/wp-content/plugins/$plugin_slug
24
- - cd ..
25
- - mv $plugin_slug $plugin_dir
26
- # set up tests config
27
- - cd $WP_CORE_DIR
28
- - cp wp-tests-config-sample.php wp-tests-config.php
29
- - sed -i "s/youremptytestdbnamehere/wordpress_test/" wp-tests-config.php
30
- - sed -i "s/yourusernamehere/root/" wp-tests-config.php
31
- - sed -i "s/yourpasswordhere//" wp-tests-config.php
32
- # disable WP_DEBUG for PHP 5.5 due to ext/mysqli E_DEPRECATED errors
33
- - if [[ "$TRAVIS_PHP_VERSION" == 5.5* ]] ; then sed -i "s:define( 'WP_DEBUG://define( 'WP_DEBUG:" wp-tests-config.php; fi;
34
- # set up database
35
- - mysql -e 'CREATE DATABASE wordpress_test;' -uroot
36
- # prepare for running the tests
37
- - cd $plugin_dir/tests
38
-
39
- script: phpunit
40
-
41
- notifications:
42
- email: false
43
-
44
- irc:
45
- channels:
46
- - "irc.freenode.net#buddypress-dev"
47
- template:
48
- - "Build %{build_number} (%{branch} - %{commit}): %{message} %{build_url}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bp-activity/admin/css/admin-rtl.css ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .akismet-status {
2
+ float: left;
3
+ }
4
+ .akismet-status a {
5
+ color: #AAA;
6
+ font-style: italic;
7
+ }
8
+ .akismet-history {
9
+ margin: 13px;
10
+ }
11
+ .akismet-history div {
12
+ margin-bottom: 13px;
13
+ }
14
+ .akismet-history span {
15
+ color: #999;
16
+ }
17
+
18
+ #wp-bp-activities-wrap {
19
+ padding: 5px 0;
20
+ }
21
+ #bp-activities {
22
+ height: 120px;
23
+ }
24
+ #bp-replyhead {
25
+ font-size: 1em;
26
+ line-height: 1.4em;
27
+ margin: 0;
28
+ }
29
+ #bp-replysubmit {
30
+ margin: 0;
31
+ padding: 0 0 3px;
32
+ text-align: center;
33
+ }
34
+ #bp-replysubmit .error {
35
+ color: red;
36
+ line-height: 21px;
37
+ text-align: center;
38
+ vertical-align: center;
39
+ }
40
+ #bp-replysubmit img.waiting {
41
+ float: left;
42
+ padding: 4px 10px 0;
43
+ vertical-align: top;
44
+ }
45
+ #bp-activities-form .column-response img {
46
+ float: right;
47
+ margin-bottom: 5px;
48
+ margin-left: 10px;
49
+ margin-top: 1px;
50
+ }
51
+ .activity-errors {
52
+ list-style-type: disc;
53
+ margin-right: 2em;
54
+ }
55
+
56
+ #bp_activity_action div.inside,
57
+ #bp_activity_content div.inside {
58
+ line-height: 0;
59
+ }
60
+ #bp_activity_action h3,
61
+ #bp_activity_content h3 {
62
+ cursor: auto;
63
+ }
64
+ #bp_activity_action td.mceIframeContainer,
65
+ #bp_activity_content td.mceIframeContainer {
66
+ background-color: white;
67
+ }
68
+ #post-body #bp-activities-action_resize,
69
+ #post-body #bp-activities-content_resize {
70
+ position: inherit;
71
+ margin-top: -2px;
72
+ }
73
+ #bp_activity_link input {
74
+ width: 99%;
75
+ }
76
+ #bp-activities-primaryid {
77
+ margin-bottom: 1em;
78
+ }
79
+ .column-action {
80
+ width: 12%;
81
+ }
82
+
83
+ @media screen and (max-width: 782px) {
84
+ body.toplevel_page_bp-activity .wp-list-table tr:not(.inline-edit-row):not(.no-items) td:not(.check-column) {
85
+ display: table-cell;
86
+ }
87
+ }
bp-activity/admin/css/admin-rtl.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .akismet-status{float:left}.akismet-status a{color:#AAA;font-style:italic}.akismet-history{margin:13px}.akismet-history div{margin-bottom:13px}.akismet-history span{color:#999}#wp-bp-activities-wrap{padding:5px 0}#bp-activities{height:120px}#bp-replyhead{font-size:1em;line-height:1.4em;margin:0}#bp-replysubmit{margin:0;padding:0 0 3px;text-align:center}#bp-replysubmit .error{color:red;line-height:21px;text-align:center;vertical-align:center}#bp-replysubmit img.waiting{float:left;padding:4px 10px 0;vertical-align:top}#bp-activities-form .column-response img{float:right;margin-bottom:5px;margin-left:10px;margin-top:1px}.activity-errors{list-style-type:disc;margin-right:2em}#bp_activity_action div.inside,#bp_activity_content div.inside{line-height:0}#bp_activity_action h3,#bp_activity_content h3{cursor:auto}#bp_activity_action td.mceIframeContainer,#bp_activity_content td.mceIframeContainer{background-color:#fff}#post-body #bp-activities-action_resize,#post-body #bp-activities-content_resize{position:inherit;margin-top:-2px}#bp_activity_link input{width:99%}#bp-activities-primaryid{margin-bottom:1em}.column-action{width:12%}@media screen and (max-width:782px){body.toplevel_page_bp-activity .wp-list-table tr:not(.inline-edit-row):not(.no-items) td:not(.check-column){display:table-cell}}
bp-activity/admin/css/admin.css CHANGED
@@ -44,6 +44,7 @@
44
  }
45
  #bp-activities-form .column-response img {
46
  float: left;
 
47
  margin-right: 10px;
48
  margin-top: 1px;
49
  }
@@ -77,4 +78,10 @@
77
  }
78
  .column-action {
79
  width: 12%;
 
 
 
 
 
 
80
  }
44
  }
45
  #bp-activities-form .column-response img {
46
  float: left;
47
+ margin-bottom: 5px;
48
  margin-right: 10px;
49
  margin-top: 1px;
50
  }
78
  }
79
  .column-action {
80
  width: 12%;
81
+ }
82
+
83
+ @media screen and (max-width: 782px) {
84
+ body.toplevel_page_bp-activity .wp-list-table tr:not(.inline-edit-row):not(.no-items) td:not(.check-column) {
85
+ display: table-cell;
86
+ }
87
  }
bp-activity/admin/css/admin.min.css CHANGED
@@ -1 +1 @@
1
- .akismet-status{float:right}.akismet-status a{color:#AAA;font-style:italic}.akismet-history{margin:13px}.akismet-history div{margin-bottom:13px}.akismet-history span{color:#999}#wp-bp-activities-wrap{padding:5px 0}#bp-activities{height:120px}#bp-replyhead{font-size:1em;line-height:1.4em;margin:0}#bp-replysubmit{margin:0;padding:0 0 3px;text-align:center}#bp-replysubmit .error{color:red;line-height:21px;text-align:center;vertical-align:center}#bp-replysubmit img.waiting{float:right;padding:4px 10px 0;vertical-align:top}#bp-activities-form .column-response img{float:left;margin-right:10px;margin-top:1px}.activity-errors{list-style-type:disc;margin-left:2em}#bp_activity_action div.inside,#bp_activity_content div.inside{line-height:0}#bp_activity_action h3,#bp_activity_content h3{cursor:auto}#bp_activity_action td.mceIframeContainer,#bp_activity_content td.mceIframeContainer{background-color:white}#post-body #bp-activities-action_resize,#post-body #bp-activities-content_resize{position:inherit;margin-top:-2px}#bp_activity_link input{width:99%}#bp-activities-primaryid{margin-bottom:1em}.column-action{width:12%}
1
+ .akismet-status{float:right}.akismet-status a{color:#AAA;font-style:italic}.akismet-history{margin:13px}.akismet-history div{margin-bottom:13px}.akismet-history span{color:#999}#wp-bp-activities-wrap{padding:5px 0}#bp-activities{height:120px}#bp-replyhead{font-size:1em;line-height:1.4em;margin:0}#bp-replysubmit{margin:0;padding:0 0 3px;text-align:center}#bp-replysubmit .error{color:red;line-height:21px;text-align:center;vertical-align:center}#bp-replysubmit img.waiting{float:right;padding:4px 10px 0;vertical-align:top}#bp-activities-form .column-response img{float:left;margin-bottom:5px;margin-right:10px;margin-top:1px}.activity-errors{list-style-type:disc;margin-left:2em}#bp_activity_action div.inside,#bp_activity_content div.inside{line-height:0}#bp_activity_action h3,#bp_activity_content h3{cursor:auto}#bp_activity_action td.mceIframeContainer,#bp_activity_content td.mceIframeContainer{background-color:#fff}#post-body #bp-activities-action_resize,#post-body #bp-activities-content_resize{position:inherit;margin-top:-2px}#bp_activity_link input{width:99%}#bp-activities-primaryid{margin-bottom:1em}.column-action{width:12%}@media screen and (max-width:782px){body.toplevel_page_bp-activity .wp-list-table tr:not(.inline-edit-row):not(.no-items) td:not(.check-column){display:table-cell}}
bp-activity/admin/js/admin.js CHANGED
@@ -1,16 +1,17 @@
 
1
  (function( $ ) {
2
 
3
  /**
4
  * Activity reply object for the activity index screen
5
  *
6
- * @since BuddyPress (1.6)
7
  */
8
  var activityReply = {
9
 
10
  /**
11
  * Attach event handler functions to the relevant elements.
12
  *
13
- * @since BuddyPress (1.6)
14
  */
15
  init : function() {
16
  $(document).on( 'click', '.row-actions a.reply', activityReply.open );
@@ -19,7 +20,7 @@ var activityReply = {
19
 
20
  // Close textarea on escape
21
  $(document).on( 'keyup', '#bp-activities:visible', function( e ) {
22
- if ( 27 == e.which ) {
23
  activityReply.close();
24
  }
25
  });
@@ -28,9 +29,9 @@ var activityReply = {
28
  /**
29
  * Reveals the entire row when "reply" is pressed.
30
  *
31
- * @since BuddyPress (1.6)
32
  */
33
- open : function( e ) {
34
  // Hide the container row, and move it to the new location
35
  var box = $( '#bp-activities-container' ).hide();
36
  $( this ).parents( 'tr' ).after( box );
@@ -45,11 +46,11 @@ var activityReply = {
45
  /**
46
  * Hide and reset the entire row when "cancel", or escape, are pressed.
47
  *
48
- * @since BuddyPress (1.6)
49
  */
50
- close : function( e ) {
51
  // Hide the container row
52
- $('#bp-activities-container').fadeOut( '200', function () {
53
 
54
  // Empty and unfocus the text area
55
  $( '#bp-activities' ).val( '' ).blur();
@@ -65,9 +66,9 @@ var activityReply = {
65
  /**
66
  * Submits "form" via AJAX back to WordPress.
67
  *
68
- * @since BuddyPress (1.6)
69
  */
70
- send : function( e ) {
71
  // Hide any existing error message, and show the loading spinner
72
  $( '#bp-replysubmit .error' ).hide();
73
  $( '#bp-replysubmit .waiting' ).show();
@@ -99,7 +100,7 @@ var activityReply = {
99
  /**
100
  * send() error message handler
101
  *
102
- * @since BuddyPress (1.6)
103
  */
104
  error : function( r ) {
105
  var er = r.statusText;
@@ -117,13 +118,13 @@ var activityReply = {
117
  /**
118
  * send() success handler
119
  *
120
- * @since BuddyPress (1.6)
121
  */
122
  show : function ( xml ) {
123
  var bg, id, response;
124
 
125
  // Handle any errors in the response
126
- if ( typeof( xml ) == 'string' ) {
127
  activityReply.error( { 'responseText': xml } );
128
  return false;
129
  }
@@ -136,7 +137,7 @@ var activityReply = {
136
  response = response.responses[0];
137
 
138
  // Close and reset the reply row, and add the new Activity item into the list.
139
- $('#bp-activities-container').fadeOut( '200', function () {
140
 
141
  // Empty and unfocus the text area
142
  $( '#bp-activities' ).val( '' ).blur();
@@ -164,9 +165,11 @@ $(document).ready( function () {
164
  $( '#bp_activity_action h3, #bp_activity_content h3' ).unbind( 'click' );
165
 
166
  // redo the post box toggles to reset the one made by comment.js in favor
167
- // of activity administration page id so that metaboxes are still collapsible
168
  // in single Activity Administration screen.
169
- postboxes.add_postbox_toggles( bp_activity_admin_vars.page );
 
 
170
  });
171
 
172
- })(jQuery);
1
+ /* global bp_activity_admin_vars, postboxes, wpAjax */
2
  (function( $ ) {
3
 
4
  /**
5
  * Activity reply object for the activity index screen
6
  *
7
+ * @since 1.6.0
8
  */
9
  var activityReply = {
10
 
11
  /**
12
  * Attach event handler functions to the relevant elements.
13
  *
14
+ * @since 1.6.0
15
  */
16
  init : function() {
17
  $(document).on( 'click', '.row-actions a.reply', activityReply.open );
20
 
21
  // Close textarea on escape
22
  $(document).on( 'keyup', '#bp-activities:visible', function( e ) {
23
+ if ( 27 === e.which ) {
24
  activityReply.close();
25
  }
26
  });
29
  /**
30
  * Reveals the entire row when "reply" is pressed.
31
  *
32
+ * @since 1.6.0
33
  */
34
+ open : function() {
35
  // Hide the container row, and move it to the new location
36
  var box = $( '#bp-activities-container' ).hide();
37
  $( this ).parents( 'tr' ).after( box );
46
  /**
47
  * Hide and reset the entire row when "cancel", or escape, are pressed.
48
  *
49
+ * @since 1.6.0
50
  */
51
+ close : function() {
52
  // Hide the container row
53
+ $('#bp-activities-container').fadeOut( '200', function () {
54
 
55
  // Empty and unfocus the text area
56
  $( '#bp-activities' ).val( '' ).blur();
66
  /**
67
  * Submits "form" via AJAX back to WordPress.
68
  *
69
+ * @since 1.6.0
70
  */
71
+ send : function() {
72
  // Hide any existing error message, and show the loading spinner
73
  $( '#bp-replysubmit .error' ).hide();
74
  $( '#bp-replysubmit .waiting' ).show();
100
  /**
101
  * send() error message handler
102
  *
103
+ * @since 1.6.0
104
  */
105
  error : function( r ) {
106
  var er = r.statusText;
118
  /**
119
  * send() success handler
120
  *
121
+ * @since 1.6.0
122
  */
123
  show : function ( xml ) {
124
  var bg, id, response;
125
 
126
  // Handle any errors in the response
127
+ if ( typeof( xml ) === 'string' ) {
128
  activityReply.error( { 'responseText': xml } );
129
  return false;
130
  }
137
  response = response.responses[0];
138
 
139
  // Close and reset the reply row, and add the new Activity item into the list.
140
+ $('#bp-activities-container').fadeOut( '200', function () {
141
 
142
  // Empty and unfocus the text area
143
  $( '#bp-activities' ).val( '' ).blur();
165
  $( '#bp_activity_action h3, #bp_activity_content h3' ).unbind( 'click' );
166
 
167
  // redo the post box toggles to reset the one made by comment.js in favor
168
+ // of activity administration page id so that metaboxes are still collapsible
169
  // in single Activity Administration screen.
170
+ if ( typeof postboxes !== 'undefined' ) {
171
+ postboxes.add_postbox_toggles( bp_activity_admin_vars.page );
172
+ }
173
  });
174
 
175
+ })(jQuery);
bp-activity/admin/js/admin.min.js CHANGED
@@ -1 +1 @@
1
- (function(b){var a={init:function(){b(document).on("click",".row-actions a.reply",a.open);b(document).on("click","#bp-activities-container a.cancel",a.close);b(document).on("click","#bp-activities-container a.save",a.send);b(document).on("keyup","#bp-activities:visible",function(c){if(27==c.which){a.close()}})},open:function(d){var c=b("#bp-activities-container").hide();b(this).parents("tr").after(c);c.fadeIn("300");b("#bp-activities").focus();return false},close:function(c){b("#bp-activities-container").fadeOut("200",function(){b("#bp-activities").val("").blur();b("#bp-replysubmit .error").html("").hide();b("#bp-replysubmit .waiting").hide()});return false},send:function(d){b("#bp-replysubmit .error").hide();b("#bp-replysubmit .waiting").show();var c={};c["_ajax_nonce-bp-activity-admin-reply"]=b('#bp-activities-container input[name="_ajax_nonce-bp-activity-admin-reply"]').val();c.action="bp-activity-admin-reply";c.content=b("#bp-activities").val();c.parent_id=b("#bp-activities-container").prev().data("parent_id");c.root_id=b("#bp-activities-container").prev().data("root_id");b.ajax({data:c,type:"POST",url:ajaxurl,error:function(e){a.error(e)},success:function(e){a.show(e)}});return false},error:function(c){var d=c.statusText;b("#bp-replysubmit .waiting").hide();if(c.responseText){d=c.responseText.replace(/<.[^<>]*?>/g,"")}if(d){b("#bp-replysubmit .error").html(d).show()}},show:function(d){var e,f,c;if(typeof(d)=="string"){a.error({responseText:d});return false}c=wpAjax.parseAjaxResponse(d);if(c.errors){a.error({responseText:wpAjax.broken});return false}c=c.responses[0];b("#bp-activities-container").fadeOut("200",function(){b("#bp-activities").val("").blur();b("#bp-replysubmit .error").html("").hide();b("#bp-replysubmit .waiting").hide();b("#bp-activities-container").before(c.data);f=b("#activity-"+c.id);e=f.closest(".widefat").css("backgroundColor");f.animate({backgroundColor:"#CEB"},300).animate({backgroundColor:e},300)})}};b(document).ready(function(){a.init();b("#bp_activity_action h3, #bp_activity_content h3").unbind("click");postboxes.add_postbox_toggles(bp_activity_admin_vars.page)})})(jQuery);
1
+ !function(a){var b={init:function(){a(document).on("click",".row-actions a.reply",b.open),a(document).on("click","#bp-activities-container a.cancel",b.close),a(document).on("click","#bp-activities-container a.save",b.send),a(document).on("keyup","#bp-activities:visible",function(a){27===a.which&&b.close()})},open:function(){var b=a("#bp-activities-container").hide();return a(this).parents("tr").after(b),b.fadeIn("300"),a("#bp-activities").focus(),!1},close:function(){return a("#bp-activities-container").fadeOut("200",function(){a("#bp-activities").val("").blur(),a("#bp-replysubmit .error").html("").hide(),a("#bp-replysubmit .waiting").hide()}),!1},send:function(){a("#bp-replysubmit .error").hide(),a("#bp-replysubmit .waiting").show();var c={};return c["_ajax_nonce-bp-activity-admin-reply"]=a('#bp-activities-container input[name="_ajax_nonce-bp-activity-admin-reply"]').val(),c.action="bp-activity-admin-reply",c.content=a("#bp-activities").val(),c.parent_id=a("#bp-activities-container").prev().data("parent_id"),c.root_id=a("#bp-activities-container").prev().data("root_id"),a.ajax({data:c,type:"POST",url:ajaxurl,error:function(a){b.error(a)},success:function(a){b.show(a)}}),!1},error:function(b){var c=b.statusText;a("#bp-replysubmit .waiting").hide(),b.responseText&&(c=b.responseText.replace(/<.[^<>]*?>/g,"")),c&&a("#bp-replysubmit .error").html(c).show()},show:function(c){var d,e,f;return"string"==typeof c?(b.error({responseText:c}),!1):(f=wpAjax.parseAjaxResponse(c),f.errors?(b.error({responseText:wpAjax.broken}),!1):(f=f.responses[0],void a("#bp-activities-container").fadeOut("200",function(){a("#bp-activities").val("").blur(),a("#bp-replysubmit .error").html("").hide(),a("#bp-replysubmit .waiting").hide(),a("#bp-activities-container").before(f.data),e=a("#activity-"+f.id),d=e.closest(".widefat").css("backgroundColor"),e.animate({backgroundColor:"#CEB"},300).animate({backgroundColor:d},300)})))}};a(document).ready(function(){b.init(),a("#bp_activity_action h3, #bp_activity_content h3").unbind("click"),"undefined"!=typeof postboxes&&postboxes.add_postbox_toggles(bp_activity_admin_vars.page)})}(jQuery);
bp-activity/bp-activity-actions.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * Action functions are exactly the same as screen functions, however they do
5
  * not have a template screen associated with them. Usually they will send the
@@ -7,19 +6,25 @@
7
  *
8
  * @package BuddyPress
9
  * @subpackage ActivityActions
 
10
  */
11
 
12
- // Exit if accessed directly
13
- if ( !defined( 'ABSPATH' ) ) exit;
14
 
15
  /**
16
  * Allow core components and dependent plugins to register activity actions.
17
  *
18
- * @since BuddyPress (1.2)
19
  *
20
- * @uses do_action() To call 'bp_register_activity_actions' hook.
21
  */
22
  function bp_register_activity_actions() {
 
 
 
 
 
 
23
  do_action( 'bp_register_activity_actions' );
24
  }
25
  add_action( 'bp_init', 'bp_register_activity_actions', 8 );
@@ -27,34 +32,21 @@ add_action( 'bp_init', 'bp_register_activity_actions', 8 );
27
  /**
28
  * Catch and route requests for single activity item permalinks.
29
  *
30
- * @since BuddyPress (1.2)
31
- *
32
- * @global object $bp BuddyPress global settings
33
- * @uses bp_is_activity_component()
34
- * @uses bp_is_current_action()
35
- * @uses bp_action_variable()
36
- * @uses bp_activity_get_specific()
37
- * @uses bp_is_active()
38
- * @uses bp_core_get_user_domain()
39
- * @uses groups_get_group()
40
- * @uses bp_get_group_permalink()
41
- * @uses apply_filters_ref_array() To call the 'bp_activity_permalink_redirect_url' hook.
42
- * @uses bp_core_redirect()
43
- * @uses bp_get_root_domain()
44
  *
45
  * @return bool False on failure.
46
  */
47
  function bp_activity_action_permalink_router() {
48
 
49
- // Not viewing activity
50
  if ( ! bp_is_activity_component() || ! bp_is_current_action( 'p' ) )
51
  return false;
52
 
53
- // No activity to display
54
  if ( ! bp_action_variable( 0 ) || ! is_numeric( bp_action_variable( 0 ) ) )
55
  return false;
56
 
57
- // Get the activity details
58
  $activity = bp_activity_get_specific( array( 'activity_ids' => bp_action_variable( 0 ), 'show_hidden' => true ) );
59
 
60
  // 404 if activity does not exist
@@ -65,43 +57,49 @@ function bp_activity_action_permalink_router() {
65
  $activity = $activity['activities'][0];
66
  }
67
 
68
- // Do not redirect at default
69
  $redirect = false;
70
 
71
- // Redirect based on the type of activity
72
  if ( bp_is_active( 'groups' ) && $activity->component == buddypress()->groups->id ) {
73
 
74
- // Activity is a user update
75
  if ( ! empty( $activity->user_id ) ) {
76
  $redirect = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . bp_get_activity_slug() . '/' . $activity->id . '/';
77
 
78
- // Activity is something else
79
  } else {
80
 
81
- // Set redirect to group activity stream
82
- if ( $group = groups_get_group( array( 'group_id' => $activity->item_id ) ) ) {
83
  $redirect = bp_get_group_permalink( $group ) . bp_get_activity_slug() . '/' . $activity->id . '/';
84
  }
85
  }
86
 
87
- // Set redirect to users' activity stream
88
- } else if ( ! empty( $activity->user_id ) ) {
89
  $redirect = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . bp_get_activity_slug() . '/' . $activity->id . '/';
90
  }
91
 
92
- // If set, add the original query string back onto the redirect URL
93
  if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
94
  $query_frags = array();
95
  wp_parse_str( $_SERVER['QUERY_STRING'], $query_frags );
96
  $redirect = add_query_arg( urlencode_deep( $query_frags ), $redirect );
97
  }
98
 
99
- // Allow redirect to be filtered
 
 
 
 
 
 
100
  if ( ! $redirect = apply_filters_ref_array( 'bp_activity_permalink_redirect_url', array( $redirect, &$activity ) ) ) {
101
  bp_core_redirect( bp_get_root_domain() );
102
  }
103
 
104
- // Redirect to the actual activity permalink page
105
  bp_core_redirect( $redirect );
106
  }
107
  add_action( 'bp_actions', 'bp_activity_action_permalink_router' );
@@ -109,59 +107,62 @@ add_action( 'bp_actions', 'bp_activity_action_permalink_router' );
109
  /**
110
  * Delete specific activity item and redirect to previous page.
111
  *
112
- * @since BuddyPress (1.1)
113
  *
114
  * @param int $activity_id Activity id to be deleted. Defaults to 0.
115
- *
116
- * @uses bp_is_activity_component()
117
- * @uses bp_is_current_action()
118
- * @uses bp_action_variable()
119
- * @uses check_admin_referer()
120
- * @uses bp_activity_user_can_delete()
121
- * @uses do_action() Calls 'bp_activity_before_action_delete_activity' hook to allow actions to be taken before the activity is deleted.
122
- * @uses bp_activity_delete()
123
- * @uses bp_core_add_message()
124
- * @uses do_action() Calls 'bp_activity_action_delete_activity' hook to allow actions to be taken after the activity is deleted.
125
- * @uses bp_core_redirect()
126
- *
127
  * @return bool False on failure.
128
  */
129
  function bp_activity_action_delete_activity( $activity_id = 0 ) {
130
 
131
- // Not viewing activity or action is not delete
132
  if ( !bp_is_activity_component() || !bp_is_current_action( 'delete' ) )
133
  return false;
134
 
135
  if ( empty( $activity_id ) && bp_action_variable( 0 ) )
136
  $activity_id = (int) bp_action_variable( 0 );
137
 
138
- // Not viewing a specific activity item
139
  if ( empty( $activity_id ) )
140
  return false;
141
 
142
- // Check the nonce
143
  check_admin_referer( 'bp_activity_delete_link' );
144
 
145
- // Load up the activity item
146
  $activity = new BP_Activity_Activity( $activity_id );
147
 
148
- // Check access
149
  if ( ! bp_activity_user_can_delete( $activity ) )
150
  return false;
151
 
152
- // Call the action before the delete so plugins can still fetch information about it
 
 
 
 
 
 
 
153
  do_action( 'bp_activity_before_action_delete_activity', $activity_id, $activity->user_id );
154
 
155
- // Delete the activity item and provide user feedback
156
  if ( bp_activity_delete( array( 'id' => $activity_id, 'user_id' => $activity->user_id ) ) )
157
  bp_core_add_message( __( 'Activity deleted successfully', 'buddypress' ) );
158
  else
159
  bp_core_add_message( __( 'There was an error when deleting that activity', 'buddypress' ), 'error' );
160
 
 
 
 
 
 
 
 
 
161
  do_action( 'bp_activity_action_delete_activity', $activity_id, $activity->user_id );
162
 
163
- // Check for the redirect query arg, otherwise let WP handle things
164
- if ( !empty( $_GET['redirect_to'] ) )
165
  bp_core_redirect( esc_url( $_GET['redirect_to'] ) );
166
  else
167
  bp_core_redirect( wp_get_referer() );
@@ -171,23 +172,22 @@ add_action( 'bp_actions', 'bp_activity_action_delete_activity' );
171
  /**
172
  * Mark specific activity item as spam and redirect to previous page.
173
  *
174
- * @since BuddyPress (1.6)
175
  *
176
- * @global object $bp BuddyPress global settings
177
  * @param int $activity_id Activity id to be deleted. Defaults to 0.
178
  * @return bool False on failure.
179
  */
180
  function bp_activity_action_spam_activity( $activity_id = 0 ) {
181
- global $bp;
182
 
183
- // Not viewing activity, or action is not spam, or Akismet isn't present
184
  if ( !bp_is_activity_component() || !bp_is_current_action( 'spam' ) || empty( $bp->activity->akismet ) )
185
  return false;
186
 
187
  if ( empty( $activity_id ) && bp_action_variable( 0 ) )
188
  $activity_id = (int) bp_action_variable( 0 );
189
 
190
- // Not viewing a specific activity item
191
  if ( empty( $activity_id ) )
192
  return false;
193
 
@@ -195,28 +195,43 @@ function bp_activity_action_spam_activity( $activity_id = 0 ) {
195
  if ( !bp_activity_user_can_mark_spam() )
196
  return false;
197
 
198
- // Load up the activity item
199
  $activity = new BP_Activity_Activity( $activity_id );
200
  if ( empty( $activity->id ) )
201
  return false;
202
 
203
- // Check nonce
204
  check_admin_referer( 'bp_activity_akismet_spam_' . $activity->id );
205
 
206
- // Call an action before the spamming so plugins can modify things if they want to
 
 
 
 
 
 
 
207
  do_action( 'bp_activity_before_action_spam_activity', $activity->id, $activity );
208
 
209
- // Mark as spam
210
  bp_activity_mark_as_spam( $activity );
211
  $activity->save();
212
 
213
- // Tell the user the spamming has been succesful
214
  bp_core_add_message( __( 'The activity item has been marked as spam and is no longer visible.', 'buddypress' ) );
215
 
 
 
 
 
 
 
 
 
216
  do_action( 'bp_activity_action_spam_activity', $activity_id, $activity->user_id );
217
 
218
- // Check for the redirect query arg, otherwise let WP handle things
219
- if ( !empty( $_GET['redirect_to'] ) )
220
  bp_core_redirect( esc_url( $_GET['redirect_to'] ) );
221
  else
222
  bp_core_redirect( wp_get_referer() );
@@ -226,72 +241,89 @@ add_action( 'bp_actions', 'bp_activity_action_spam_activity' );
226
  /**
227
  * Post user/group activity update.
228
  *
229
- * @since BuddyPress (1.2)
230
- *
231
- * @uses is_user_logged_in()
232
- * @uses bp_is_activity_component()
233
- * @uses bp_is_current_action()
234
- * @uses check_admin_referer()
235
- * @uses apply_filters() To call 'bp_activity_post_update_content' hook.
236
- * @uses apply_filters() To call 'bp_activity_post_update_object' hook.
237
- * @uses apply_filters() To call 'bp_activity_post_update_item_id' hook.
238
- * @uses bp_core_add_message()
239
- * @uses bp_core_redirect()
240
- * @uses bp_activity_post_update()
241
- * @uses groups_post_update()
242
- * @uses bp_core_redirect()
243
- * @uses apply_filters() To call 'bp_activity_custom_update' hook.
244
  *
245
  * @return bool False on failure.
246
  */
247
  function bp_activity_action_post_update() {
248
 
249
- // Do not proceed if user is not logged in, not viewing activity, or not posting
250
  if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'post' ) )
251
  return false;
252
 
253
- // Check the nonce
254
  check_admin_referer( 'post_update', '_wpnonce_post_update' );
255
 
256
- // Get activity info
 
 
 
 
 
 
257
  $content = apply_filters( 'bp_activity_post_update_content', $_POST['whats-new'] );
258
 
259
  if ( ! empty( $_POST['whats-new-post-object'] ) ) {
 
 
 
 
 
 
 
 
260
  $object = apply_filters( 'bp_activity_post_update_object', $_POST['whats-new-post-object'] );
261
  }
262
 
263
  if ( ! empty( $_POST['whats-new-post-in'] ) ) {
 
 
 
 
 
 
 
 
264
  $item_id = apply_filters( 'bp_activity_post_update_item_id', $_POST['whats-new-post-in'] );
265
  }
266
 
267
- // No activity content so provide feedback and redirect
268
  if ( empty( $content ) ) {
269
  bp_core_add_message( __( 'Please enter some content to post.', 'buddypress' ), 'error' );
270
  bp_core_redirect( wp_get_referer() );
271
  }
272
 
273
- // No existing item_id
274
  if ( empty( $item_id ) ) {
275
  $activity_id = bp_activity_post_update( array( 'content' => $content ) );
276
 
277
- // Post to groups object
278
- } else if ( 'groups' == $object && bp_is_active( 'groups' ) ) {
279
  if ( (int) $item_id ) {
280
  $activity_id = groups_post_update( array( 'content' => $content, 'group_id' => $item_id ) );
281
  }
282
 
283
- // Special circumstance so let filters handle it
284
  } else {
 
 
 
 
 
 
 
 
 
 
285
  $activity_id = apply_filters( 'bp_activity_custom_update', $object, $item_id, $content );
286
  }
287
 
288
- // Provide user feedback
289
  if ( !empty( $activity_id ) )
290
  bp_core_add_message( __( 'Update Posted!', 'buddypress' ) );
291
  else
292
- bp_core_add_message( __( 'There was an error when posting your update, please try again.', 'buddypress' ), 'error' );
293
 
294
- // Redirect
295
  bp_core_redirect( wp_get_referer() );
296
  }
297
  add_action( 'bp_actions', 'bp_activity_action_post_update' );
@@ -299,18 +331,7 @@ add_action( 'bp_actions', 'bp_activity_action_post_update' );
299
  /**
300
  * Post new activity comment.
301
  *
302
- * @since BuddyPress (1.2)
303
- *
304
- * @uses is_user_logged_in()
305
- * @uses bp_is_activity_component()
306
- * @uses bp_is_current_action()
307
- * @uses check_admin_referer()
308
- * @uses apply_filters() To call 'bp_activity_post_comment_activity_id' hook.
309
- * @uses apply_filters() To call 'bp_activity_post_comment_content' hook.
310
- * @uses bp_core_add_message()
311
- * @uses bp_core_redirect()
312
- * @uses bp_activity_new_comment()
313
- * @uses wp_get_referer()
314
  *
315
  * @return bool False on failure.
316
  */
@@ -319,10 +340,25 @@ function bp_activity_action_post_comment() {
319
  if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'reply' ) )
320
  return false;
321
 
322
- // Check the nonce
323
  check_admin_referer( 'new_activity_comment', '_wpnonce_new_activity_comment' );
324
 
 
 
 
 
 
 
 
325
  $activity_id = apply_filters( 'bp_activity_post_comment_activity_id', $_POST['comment_form_id'] );
 
 
 
 
 
 
 
 
326
  $content = apply_filters( 'bp_activity_post_comment_content', $_POST['ac_input_' . $activity_id] );
327
 
328
  if ( empty( $content ) ) {
@@ -339,7 +375,7 @@ function bp_activity_action_post_comment() {
339
  if ( !empty( $comment_id ) )
340
  bp_core_add_message( __( 'Reply Posted!', 'buddypress' ) );
341
  else
342
- bp_core_add_message( __( 'There was an error posting that reply, please try again.', 'buddypress' ), 'error' );
343
 
344
  bp_core_redirect( wp_get_referer() . '#ac-form-' . $activity_id );
345
  }
@@ -348,17 +384,7 @@ add_action( 'bp_actions', 'bp_activity_action_post_comment' );
348
  /**
349
  * Mark activity as favorite.
350
  *
351
- * @since BuddyPress (1.2)
352
- *
353
- * @uses is_user_logged_in()
354
- * @uses bp_is_activity_component()
355
- * @uses bp_is_current_action()
356
- * @uses check_admin_referer()
357
- * @uses bp_activity_add_user_favorite()
358
- * @uses bp_action_variable()
359
- * @uses bp_core_add_message()
360
- * @uses bp_core_redirect()
361
- * @uses wp_get_referer()
362
  *
363
  * @return bool False on failure.
364
  */
@@ -367,13 +393,13 @@ function bp_activity_action_mark_favorite() {
367
  if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'favorite' ) )
368
  return false;
369
 
370
- // Check the nonce
371
  check_admin_referer( 'mark_favorite' );
372
 
373
  if ( bp_activity_add_user_favorite( bp_action_variable( 0 ) ) )
374
  bp_core_add_message( __( 'Activity marked as favorite.', 'buddypress' ) );
375
  else
376
- bp_core_add_message( __( 'There was an error marking that activity as a favorite, please try again.', 'buddypress' ), 'error' );
377
 
378
  bp_core_redirect( wp_get_referer() . '#activity-' . bp_action_variable( 0 ) );
379
  }
@@ -382,17 +408,7 @@ add_action( 'bp_actions', 'bp_activity_action_mark_favorite' );
382
  /**
383
  * Remove activity from favorites.
384
  *
385
- * @since BuddyPress (1.2)
386
- *
387
- * @uses is_user_logged_in()
388
- * @uses bp_is_activity_component()
389
- * @uses bp_is_current_action()
390
- * @uses check_admin_referer()
391
- * @uses bp_activity_remove_user_favorite()
392
- * @uses bp_action_variable()
393
- * @uses bp_core_add_message()
394
- * @uses bp_core_redirect()
395
- * @uses wp_get_referer()
396
  *
397
  * @return bool False on failure.
398
  */
@@ -401,13 +417,13 @@ function bp_activity_action_remove_favorite() {
401
  if ( ! is_user_logged_in() || ! bp_is_activity_component() || ! bp_is_current_action( 'unfavorite' ) )
402
  return false;
403
 
404
- // Check the nonce
405
  check_admin_referer( 'unmark_favorite' );
406
 
407
  if ( bp_activity_remove_user_favorite( bp_action_variable( 0 ) ) )
408
  bp_core_add_message( __( 'Activity removed as favorite.', 'buddypress' ) );
409
  else
410
- bp_core_add_message( __( 'There was an error removing that activity as a favorite, please try again.', 'buddypress' ), 'error' );
411
 
412
  bp_core_redirect( wp_get_referer() . '#activity-' . bp_action_variable( 0 ) );
413
  }
@@ -416,28 +432,22 @@ add_action( 'bp_actions', 'bp_activity_action_remove_favorite' );
416
  /**
417
  * Load the sitewide activity feed.
418
  *
419
- * @since BuddyPress (1.0)
420
- *
421
- * @global object $bp BuddyPress global settings
422
- * @uses bp_is_activity_component()
423
- * @uses bp_is_current_action()
424
- * @uses bp_is_user()
425
- * @uses status_header()
426
  *
427
  * @return bool False on failure.
428
  */
429
  function bp_activity_action_sitewide_feed() {
430
- global $bp;
431
 
432
  if ( ! bp_is_activity_component() || ! bp_is_current_action( 'feed' ) || bp_is_user() || ! empty( $bp->groups->current_group ) )
433
  return false;
434
 
435
- // setup the feed
436
  buddypress()->activity->feed = new BP_Activity_Feed( array(
437
  'id' => 'sitewide',
438
 
439
  /* translators: Sitewide activity RSS title - "[Site Name] | Site Wide Activity" */
440
- 'title' => sprintf( __( '%s | Site Wide Activity', 'buddypress' ), bp_get_site_name() ),
441
 
442
  'link' => bp_get_activity_directory_permalink(),
443
  'description' => __( 'Activity feed for the entire site.', 'buddypress' ),
@@ -449,11 +459,7 @@ add_action( 'bp_actions', 'bp_activity_action_sitewide_feed' );
449
  /**
450
  * Load a user's personal activity feed.
451
  *
452
- * @since BuddyPress (1.0)
453
- *
454
- * @uses bp_is_user_activity()
455
- * @uses bp_is_current_action()
456
- * @uses status_header()
457
  *
458
  * @return bool False on failure.
459
  */
@@ -462,7 +468,7 @@ function bp_activity_action_personal_feed() {
462
  return false;
463
  }
464
 
465
- // setup the feed
466
  buddypress()->activity->feed = new BP_Activity_Feed( array(
467
  'id' => 'personal',
468
 
@@ -479,14 +485,7 @@ add_action( 'bp_actions', 'bp_activity_action_personal_feed' );
479
  /**
480
  * Load a user's friends' activity feed.
481
  *
482
- * @since BuddyPress (1.0)
483
- *
484
- * @uses bp_is_active()
485
- * @uses bp_is_user_activity()
486
- * @uses bp_is_current_action()
487
- * @uses bp_get_friends_slug()
488
- * @uses bp_is_action_variable()
489
- * @uses status_header()
490
  *
491
  * @return bool False on failure.
492
  */
@@ -495,7 +494,7 @@ function bp_activity_action_friends_feed() {
495
  return false;
496
  }
497
 
498
- // setup the feed
499
  buddypress()->activity->feed = new BP_Activity_Feed( array(
500
  'id' => 'friends',
501
 
@@ -512,14 +511,7 @@ add_action( 'bp_actions', 'bp_activity_action_friends_feed' );
512
  /**
513
  * Load the activity feed for a user's groups.
514
  *
515
- * @since BuddyPress (1.2)
516
- *
517
- * @uses bp_is_active()
518
- * @uses bp_is_user_activity()
519
- * @uses bp_is_current_action()
520
- * @uses bp_get_groups_slug()
521
- * @uses bp_is_action_variable()
522
- * @uses status_header()
523
  *
524
  * @return bool False on failure.
525
  */
@@ -528,11 +520,11 @@ function bp_activity_action_my_groups_feed() {
528
  return false;
529
  }
530
 
531
- // get displayed user's group IDs
532
  $groups = groups_get_user_groups();
533
  $group_ids = implode( ',', $groups['groups'] );
534
 
535
- // setup the feed
536
  buddypress()->activity->feed = new BP_Activity_Feed( array(
537
  'id' => 'mygroups',
538
 
@@ -540,7 +532,7 @@ function bp_activity_action_my_groups_feed() {
540
  'title' => sprintf( __( '%1$s | %2$s | Group Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
541
 
542
  'link' => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() ),
543
- 'description' => sprintf( __( "Public group activity feed of which %s is a member of.", 'buddypress' ), bp_get_displayed_user_fullname() ),
544
  'activity_args' => array(
545
  'object' => buddypress()->groups->id,
546
  'primary_id' => $group_ids,
@@ -553,12 +545,7 @@ add_action( 'bp_actions', 'bp_activity_action_my_groups_feed' );
553
  /**
554
  * Load a user's @mentions feed.
555
  *
556
- * @since BuddyPress (1.2)
557
- *
558
- * @uses bp_is_user_activity()
559
- * @uses bp_is_current_action()
560
- * @uses bp_is_action_variable()
561
- * @uses status_header()
562
  *
563
  * @return bool False on failure.
564
  */
@@ -571,7 +558,7 @@ function bp_activity_action_mentions_feed() {
571
  return false;
572
  }
573
 
574
- // setup the feed
575
  buddypress()->activity->feed = new BP_Activity_Feed( array(
576
  'id' => 'mentions',
577
 
@@ -590,12 +577,7 @@ add_action( 'bp_actions', 'bp_activity_action_mentions_feed' );
590
  /**
591
  * Load a user's favorites feed.
592
  *
593
- * @since BuddyPress (1.2)
594
- *
595
- * @uses bp_is_user_activity()
596
- * @uses bp_is_current_action()
597
- * @uses bp_is_action_variable()
598
- * @uses status_header()
599
  *
600
  * @return bool False on failure.
601
  */
@@ -604,11 +586,11 @@ function bp_activity_action_favorites_feed() {
604
  return false;
605
  }
606
 
607
- // get displayed user's favorite activity IDs
608
  $favs = bp_activity_get_user_favorites( bp_displayed_user_id() );
609
  $fav_ids = implode( ',', (array) $favs );
610
 
611
- // setup the feed
612
  buddypress()->activity->feed = new BP_Activity_Feed( array(
613
  'id' => 'favorites',
614
 
@@ -623,27 +605,246 @@ function bp_activity_action_favorites_feed() {
623
  add_action( 'bp_actions', 'bp_activity_action_favorites_feed' );
624
 
625
  /**
626
- * Loads Akismet filtering for activity.
627
  *
628
- * @since BuddyPress (1.6)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
629
  *
630
- * @global object $bp BuddyPress global settings
 
 
631
  */
632
- function bp_activity_setup_akismet() {
633
- global $bp;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
 
635
- // Bail if Akismet is not active
636
- if ( ! defined( 'AKISMET_VERSION' ) )
637
  return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
 
639
- // Bail if no Akismet key is set
640
- if ( ! bp_get_option( 'wordpress_api_key' ) && ! defined( 'WPCOM_API_KEY' ) )
641
  return;
 
642
 
643
- // Bail if BuddyPress Activity Akismet support has been disabled by another plugin
644
- if ( ! apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) )
 
645
  return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
 
647
- // Instantiate Akismet for BuddyPress
648
- $bp->activity->akismet = new BP_Akismet();
649
  }
 
1
  <?php
 
2
  /**
3
  * Action functions are exactly the same as screen functions, however they do
4
  * not have a template screen associated with them. Usually they will send the
6
  *
7
  * @package BuddyPress
8
  * @subpackage ActivityActions
9
+ * @since 1.5.0
10
  */
11
 
12
+ // Exit if accessed directly.
13
+ defined( 'ABSPATH' ) || exit;
14
 
15
  /**
16
  * Allow core components and dependent plugins to register activity actions.
17
  *
18
+ * @since 1.2.0
19
  *
 
20
  */
21
  function bp_register_activity_actions() {
22
+
23
+ /**
24
+ * Fires on bp_init to allow core components and dependent plugins to register activity actions.
25
+ *
26
+ * @since 1.2.0
27
+ */
28
  do_action( 'bp_register_activity_actions' );
29
  }
30
  add_action( 'bp_init', 'bp_register_activity_actions', 8 );
32
  /**
33
  * Catch and route requests for single activity item permalinks.
34
  *
35
+ * @since 1.2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  *
37
  * @return bool False on failure.
38
  */
39
  function bp_activity_action_permalink_router() {
40
 
41
+ // Not viewing activity.
42
  if ( ! bp_is_activity_component() || ! bp_is_current_action( 'p' ) )
43
  return false;
44
 
45
+ // No activity to display.
46
  if ( ! bp_action_variable( 0 ) || ! is_numeric( bp_action_variable( 0 ) ) )
47
  return false;
48
 
49
+ // Get the activity details.
50
  $activity = bp_activity_get_specific( array( 'activity_ids' => bp_action_variable( 0 ), 'show_hidden' => true ) );
51
 
52
  // 404 if activity does not exist
57
  $activity = $activity['activities'][0];
58
  }
59
 
60
+ // Do not redirect at default.
61
  $redirect = false;
62
 
63
+ // Redirect based on the type of activity.
64
  if ( bp_is_active( 'groups' ) && $activity->component == buddypress()->groups->id ) {
65
 
66
+ // Activity is a user update.
67
  if ( ! empty( $activity->user_id ) ) {
68
  $redirect = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . bp_get_activity_slug() . '/' . $activity->id . '/';
69
 
70
+ // Activity is something else.
71
  } else {
72
 
73
+ // Set redirect to group activity stream.
74
+ if ( $group = groups_get_group( $activity->item_id ) ) {
75
  $redirect = bp_get_group_permalink( $group ) . bp_get_activity_slug() . '/' . $activity->id . '/';
76
  }
77
  }
78
 
79
+ // Set redirect to users' activity stream.
80
+ } elseif ( ! empty( $activity->user_id ) ) {
81
  $redirect = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . bp_get_activity_slug() . '/' . $activity->id . '/';
82
  }
83
 
84
+ // If set, add the original query string back onto the redirect URL.
85
  if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
86
  $query_frags = array();
87
  wp_parse_str( $_SERVER['QUERY_STRING'], $query_frags );
88
  $redirect = add_query_arg( urlencode_deep( $query_frags ), $redirect );
89
  }
90
 
91
+ /**
92
+ * Filter the intended redirect url before the redirect occurs for the single activity item.
93
+ *
94
+ * @since 1.2.2
95
+ *
96
+ * @param array $value Array with url to redirect to and activity related to the redirect.
97
+ */
98
  if ( ! $redirect = apply_filters_ref_array( 'bp_activity_permalink_redirect_url', array( $redirect, &$activity ) ) ) {
99
  bp_core_redirect( bp_get_root_domain() );
100
  }
101
 
102
+ // Redirect to the actual activity permalink page.
103
  bp_core_redirect( $redirect );
104
  }
105
  add_action( 'bp_actions', 'bp_activity_action_permalink_router' );
107
  /**
108
  * Delete specific activity item and redirect to previous page.
109
  *
110
+ * @since 1.1.0
111
  *
112
  * @param int $activity_id Activity id to be deleted. Defaults to 0.
 
 
 
 
 
 
 
 
 
 
 
 
113
  * @return bool False on failure.
114
  */
115
  function bp_activity_action_delete_activity( $activity_id = 0 ) {
116
 
117
+ // Not viewing activity or action is not delete.
118
  if ( !bp_is_activity_component() || !bp_is_current_action( 'delete' ) )
119
  return false;
120
 
121
  if ( empty( $activity_id ) && bp_action_variable( 0 ) )
122
  $activity_id = (int) bp_action_variable( 0 );
123
 
124
+ // Not viewing a specific activity item.
125
  if ( empty( $activity_id ) )
126
  return false;
127
 
128
+ // Check the nonce.
129
  check_admin_referer( 'bp_activity_delete_link' );
130
 
131
+ // Load up the activity item.
132
  $activity = new BP_Activity_Activity( $activity_id );
133
 
134
+ // Check access.
135
  if ( ! bp_activity_user_can_delete( $activity ) )
136
  return false;
137
 
138
+ /**
139
+ * Fires before the deletion so plugins can still fetch information about it.
140
+ *
141
+ * @since 1.5.0
142
+ *
143
+ * @param int $activity_id The activity ID.
144
+ * @param int $user_id The user associated with the activity.
145
+ */
146
  do_action( 'bp_activity_before_action_delete_activity', $activity_id, $activity->user_id );
147
 
148
+ // Delete the activity item and provide user feedback.
149
  if ( bp_activity_delete( array( 'id' => $activity_id, 'user_id' => $activity->user_id ) ) )
150
  bp_core_add_message( __( 'Activity deleted successfully', 'buddypress' ) );
151
  else
152
  bp_core_add_message( __( 'There was an error when deleting that activity', 'buddypress' ), 'error' );
153
 
154
+ /**
155
+ * Fires after the deletion so plugins can act afterwards based on the activity.
156
+ *
157
+ * @since 1.1.0
158
+ *
159
+ * @param int $activity_id The activity ID.
160
+ * @param int $user_id The user associated with the activity.
161
+ */
162
  do_action( 'bp_activity_action_delete_activity', $activity_id, $activity->user_id );
163
 
164
+ // Check for the redirect query arg, otherwise let WP handle things.
165
+ if ( !empty( $_GET['redirect_to'] ) )
166
  bp_core_redirect( esc_url( $_GET['redirect_to'] ) );
167
  else
168
  bp_core_redirect( wp_get_referer() );
172
  /**
173
  * Mark specific activity item as spam and redirect to previous page.
174
  *
175
+ * @since 1.6.0
176
  *
 
177
  * @param int $activity_id Activity id to be deleted. Defaults to 0.
178
  * @return bool False on failure.
179
  */
180
  function bp_activity_action_spam_activity( $activity_id = 0 ) {
181
+ $bp = buddypress();
182
 
183
+ // Not viewing activity, or action is not spam, or Akismet isn't present.
184
  if ( !bp_is_activity_component() || !bp_is_current_action( 'spam' ) || empty( $bp->activity->akismet ) )
185
  return false;
186
 
187
  if ( empty( $activity_id ) && bp_action_variable( 0 ) )
188
  $activity_id = (int) bp_action_variable( 0 );
189
 
190
+ // Not viewing a specific activity item.
191
  if ( empty( $activity_id ) )
192
  return false;
193
 
195
  if ( !bp_activity_user_can_mark_spam() )
196
  return false;
197
 
198
+ // Load up the activity item.
199
  $activity = new BP_Activity_Activity( $activity_id );
200
  if ( empty( $activity->id ) )
201
  return false;
202
 
203
+ // Check nonce.
204
  check_admin_referer( 'bp_activity_akismet_spam_' . $activity->id );
205
 
206
+ /**
207
+ * Fires before the marking activity as spam so plugins can modify things if they want to.
208
+ *
209
+ * @since 1.6.0
210
+ *
211
+ * @param int $activity_id Activity ID to be marked as spam.
212
+ * @param object $activity Activity object for the ID to be marked as spam.
213
+ */
214
  do_action( 'bp_activity_before_action_spam_activity', $activity->id, $activity );
215
 
216
+ // Mark as spam.
217
  bp_activity_mark_as_spam( $activity );
218
  $activity->save();
219
 
220
+ // Tell the user the spamming has been successful.
221
  bp_core_add_message( __( 'The activity item has been marked as spam and is no longer visible.', 'buddypress' ) );
222
 
223
+ /**
224
+ * Fires after the marking activity as spam so plugins can act afterwards based on the activity.
225
+ *
226
+ * @since 1.6.0
227
+ *
228
+ * @param int $activity_id Activity ID that was marked as spam.
229
+ * @param int $user_id User ID associated with activity.
230
+ */
231
  do_action( 'bp_activity_action_spam_activity', $activity_id, $activity->user_id );
232
 
233
+ // Check for the redirect query arg, otherwise let WP handle things.
234
+ if ( !empty( $_GET['redirect_to'] ) )
235
  bp_core_redirect( esc_url( $_GET['redirect_to'] ) );
236
  else
237
  bp_core_redirect( wp_get_referer() );
241
  /**
242
  * Post user/group activity update.
243
  *
244
+ * @since 1.2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  *
246
  * @return bool False on failure.
247
  */
248
  function bp_activity_action_post_update() {
249
 
250
+ // Do not proceed if user is not logged in, not viewing activity, or not posting.
251
  if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'post' ) )
252
  return false;
253
 
254
+ // Check the nonce.
255
  check_admin_referer( 'post_update', '_wpnonce_post_update' );
256
 
257
+ /**
258
+ * Filters the content provided in the activity input field.
259
+ *
260
+ * @since 1.2.0
261
+ *
262
+ * @param string $value Activity message being posted.
263
+ */
264
  $content = apply_filters( 'bp_activity_post_update_content', $_POST['whats-new'] );
265
 
266
  if ( ! empty( $_POST['whats-new-post-object'] ) ) {
267
+
268
+ /**
269
+ * Filters the item type that the activity update should be associated with.
270
+ *
271
+ * @since 1.2.0
272
+ *
273
+ * @param string $value Item type to associate with.
274
+ */
275
  $object = apply_filters( 'bp_activity_post_update_object', $_POST['whats-new-post-object'] );
276
  }
277
 
278
  if ( ! empty( $_POST['whats-new-post-in'] ) ) {
279
+
280
+ /**
281
+ * Filters what component the activity is being to.
282
+ *
283
+ * @since 1.2.0
284
+ *
285
+ * @param string $value Chosen component to post activity to.
286
+ */
287
  $item_id = apply_filters( 'bp_activity_post_update_item_id', $_POST['whats-new-post-in'] );
288
  }
289
 
290
+ // No activity content so provide feedback and redirect.
291
  if ( empty( $content ) ) {
292
  bp_core_add_message( __( 'Please enter some content to post.', 'buddypress' ), 'error' );
293
  bp_core_redirect( wp_get_referer() );
294
  }
295
 
296
+ // No existing item_id.
297
  if ( empty( $item_id ) ) {
298
  $activity_id = bp_activity_post_update( array( 'content' => $content ) );
299
 
300
+ // Post to groups object.
301
+ } elseif ( 'groups' == $object && bp_is_active( 'groups' ) ) {
302
  if ( (int) $item_id ) {
303
  $activity_id = groups_post_update( array( 'content' => $content, 'group_id' => $item_id ) );
304
  }
305
 
 
306
  } else {
307
+
308
+ /**
309
+ * Filters activity object for BuddyPress core and plugin authors before posting activity update.
310
+ *
311
+ * @since 1.2.0
312
+ *
313
+ * @param string $object Activity item being associated to.
314
+ * @param string $item_id Component ID being posted to.
315
+ * @param string $content Activity content being posted.
316
+ */
317
  $activity_id = apply_filters( 'bp_activity_custom_update', $object, $item_id, $content );
318
  }
319
 
320
+ // Provide user feedback.
321
  if ( !empty( $activity_id ) )
322
  bp_core_add_message( __( 'Update Posted!', 'buddypress' ) );
323
  else
324
+ bp_core_add_message( __( 'There was an error when posting your update. Please try again.', 'buddypress' ), 'error' );
325
 
326
+ // Redirect.
327
  bp_core_redirect( wp_get_referer() );
328
  }
329
  add_action( 'bp_actions', 'bp_activity_action_post_update' );
331
  /**
332
  * Post new activity comment.
333
  *
334
+ * @since 1.2.0
 
 
 
 
 
 
 
 
 
 
 
335
  *
336
  * @return bool False on failure.
337
  */
340
  if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'reply' ) )
341
  return false;
342
 
343
+ // Check the nonce.
344
  check_admin_referer( 'new_activity_comment', '_wpnonce_new_activity_comment' );
345
 
346
+ /**
347
+ * Filters the activity ID a comment will be in reply to.
348
+ *
349
+ * @since 1.2.0
350
+ *
351
+ * @param string $value ID of the activity being replied to.
352
+ */
353
  $activity_id = apply_filters( 'bp_activity_post_comment_activity_id', $_POST['comment_form_id'] );
354
+
355
+ /**
356
+ * Filters the comment content for a comment reply.
357
+ *
358
+ * @since 1.2.0
359
+ *
360
+ * @param string $value Comment content being posted.
361
+ */
362
  $content = apply_filters( 'bp_activity_post_comment_content', $_POST['ac_input_' . $activity_id] );
363
 
364
  if ( empty( $content ) ) {
375
  if ( !empty( $comment_id ) )
376
  bp_core_add_message( __( 'Reply Posted!', 'buddypress' ) );
377
  else
378
+ bp_core_add_message( __( 'There was an error posting that reply. Please try again.', 'buddypress' ), 'error' );
379
 
380
  bp_core_redirect( wp_get_referer() . '#ac-form-' . $activity_id );
381
  }
384
  /**
385
  * Mark activity as favorite.
386
  *
387
+ * @since 1.2.0
 
 
 
 
 
 
 
 
 
 
388
  *
389
  * @return bool False on failure.
390
  */
393
  if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'favorite' ) )
394
  return false;
395
 
396
+ // Check the nonce.
397
  check_admin_referer( 'mark_favorite' );
398
 
399
  if ( bp_activity_add_user_favorite( bp_action_variable( 0 ) ) )
400
  bp_core_add_message( __( 'Activity marked as favorite.', 'buddypress' ) );
401
  else
402
+ bp_core_add_message( __( 'There was an error marking that activity as a favorite. Please try again.', 'buddypress' ), 'error' );
403
 
404
  bp_core_redirect( wp_get_referer() . '#activity-' . bp_action_variable( 0 ) );
405
  }
408
  /**
409
  * Remove activity from favorites.
410
  *
411
+ * @since 1.2.0
 
 
 
 
 
 
 
 
 
 
412
  *
413
  * @return bool False on failure.
414
  */
417
  if ( ! is_user_logged_in() || ! bp_is_activity_component() || ! bp_is_current_action( 'unfavorite' ) )
418
  return false;
419
 
420
+ // Check the nonce.
421
  check_admin_referer( 'unmark_favorite' );
422
 
423
  if ( bp_activity_remove_user_favorite( bp_action_variable( 0 ) ) )
424
  bp_core_add_message( __( 'Activity removed as favorite.', 'buddypress' ) );
425
  else
426
+ bp_core_add_message( __( 'There was an error removing that activity as a favorite. Please try again.', 'buddypress' ), 'error' );
427
 
428
  bp_core_redirect( wp_get_referer() . '#activity-' . bp_action_variable( 0 ) );
429
  }
432
  /**
433
  * Load the sitewide activity feed.
434
  *
435
+ * @since 1.0.0
 
 
 
 
 
 
436
  *
437
  * @return bool False on failure.
438
  */
439
  function bp_activity_action_sitewide_feed() {
440
+ $bp = buddypress();
441
 
442
  if ( ! bp_is_activity_component() || ! bp_is_current_action( 'feed' ) || bp_is_user() || ! empty( $bp->groups->current_group ) )
443
  return false;
444
 
445
+ // Setup the feed.
446
  buddypress()->activity->feed = new BP_Activity_Feed( array(
447
  'id' => 'sitewide',
448
 
449
  /* translators: Sitewide activity RSS title - "[Site Name] | Site Wide Activity" */
450
+ 'title' => sprintf( __( '%s | Site-Wide Activity', 'buddypress' ), bp_get_site_name() ),
451
 
452
  'link' => bp_get_activity_directory_permalink(),
453
  'description' => __( 'Activity feed for the entire site.', 'buddypress' ),
459
  /**
460
  * Load a user's personal activity feed.
461
  *
462
+ * @since 1.0.0
 
 
 
 
463
  *
464
  * @return bool False on failure.
465
  */
468
  return false;
469
  }
470
 
471
+ // Setup the feed.
472
  buddypress()->activity->feed = new BP_Activity_Feed( array(
473
  'id' => 'personal',
474
 
485
  /**
486
  * Load a user's friends' activity feed.
487
  *
488
+ * @since 1.0.0
 
 
 
 
 
 
 
489
  *
490
  * @return bool False on failure.
491
  */
494
  return false;
495
  }
496
 
497
+ // Setup the feed.
498
  buddypress()->activity->feed = new BP_Activity_Feed( array(
499
  'id' => 'friends',
500
 
511
  /**
512
  * Load the activity feed for a user's groups.
513
  *
514
+ * @since 1.2.0
 
 
 
 
 
 
 
515
  *
516
  * @return bool False on failure.
517
  */
520
  return false;
521
  }
522
 
523
+ // Get displayed user's group IDs.
524
  $groups = groups_get_user_groups();
525
  $group_ids = implode( ',', $groups['groups'] );
526
 
527
+ // Setup the feed.
528
  buddypress()->activity->feed = new BP_Activity_Feed( array(
529
  'id' => 'mygroups',
530
 
532
  'title' => sprintf( __( '%1$s | %2$s | Group Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
533
 
534
  'link' => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() ),
535
+ 'description' => sprintf( __( "Public group activity feed of which %s is a member.", 'buddypress' ), bp_get_displayed_user_fullname() ),
536
  'activity_args' => array(
537
  'object' => buddypress()->groups->id,
538
  'primary_id' => $group_ids,
545
  /**
546
  * Load a user's @mentions feed.
547
  *
548
+ * @since 1.2.0
 
 
 
 
 
549
  *
550
  * @return bool False on failure.
551
  */
558
  return false;
559
  }
560
 
561
+ // Setup the feed.
562
  buddypress()->activity->feed = new BP_Activity_Feed( array(
563
  'id' => 'mentions',
564
 
577
  /**
578
  * Load a user's favorites feed.
579
  *
580
+ * @since 1.2.0
 
 
 
 
 
581
  *
582
  * @return bool False on failure.
583
  */
586
  return false;
587
  }
588
 
589
+ // Get displayed user's favorite activity IDs.
590
  $favs = bp_activity_get_user_favorites( bp_displayed_user_id() );
591
  $fav_ids = implode( ',', (array) $favs );
592
 
593
+ // Setup the feed.
594
  buddypress()->activity->feed = new BP_Activity_Feed( array(
595
  'id' => 'favorites',
596
 
605
  add_action( 'bp_actions', 'bp_activity_action_favorites_feed' );
606
 
607
  /**
608
+ * AJAX endpoint for Suggestions API lookups.
609
  *
610
+ * @since 2.1.0
611
+ */
612
+ function bp_ajax_get_suggestions() {
613
+ if ( ! bp_is_user_active() || empty( $_GET['term'] ) || empty( $_GET['type'] ) ) {
614
+ wp_send_json_error( 'missing_parameter' );
615
+ exit;
616
+ }
617
+
618
+ $args = array(
619
+ 'term' => sanitize_text_field( $_GET['term'] ),
620
+ 'type' => sanitize_text_field( $_GET['type'] ),
621
+ );
622
+
623
+ // Support per-Group suggestions.
624
+ if ( ! empty( $_GET['group-id'] ) ) {
625
+ $args['group_id'] = absint( $_GET['group-id'] );
626
+ }
627
+
628
+ $results = bp_core_get_suggestions( $args );
629
+
630
+ if ( is_wp_error( $results ) ) {
631
+ wp_send_json_error( $results->get_error_message() );
632
+ exit;
633
+ }
634
+
635
+ wp_send_json_success( $results );
636
+ }
637
+ add_action( 'wp_ajax_bp_get_suggestions', 'bp_ajax_get_suggestions' );
638
+
639
+ /**
640
+ * Detect a change in post type status, and initiate an activity update if necessary.
641
+ *
642
+ * @since 2.2.0
643
+ *
644
+ * @todo Support untrashing better.
645
  *
646
+ * @param string $new_status New status for the post.
647
+ * @param string $old_status Old status for the post.
648
+ * @param object $post Post data.
649
  */
650
+ function bp_activity_catch_transition_post_type_status( $new_status, $old_status, $post ) {
651
+ if ( ! post_type_supports( $post->post_type, 'buddypress-activity' ) ) {
652
+ return;
653
+ }
654
+
655
+ // This is an edit.
656
+ if ( $new_status === $old_status ) {
657
+ // An edit of an existing post should update the existing activity item.
658
+ if ( $new_status == 'publish' ) {
659
+ $edit = bp_activity_post_type_update( $post );
660
+
661
+ // Post was never recorded into activity stream, so record it now!
662
+ if ( null === $edit ) {
663
+ bp_activity_post_type_publish( $post->ID, $post );
664
+ }
665
+
666
+ // Allow plugins to eventually deal with other post statuses.
667
+ } else {
668
+ /**
669
+ * Fires when editing the post and the new status is not 'publish'.
670
+ *
671
+ * This is a variable filter that is dependent on the post type
672
+ * being untrashed.
673
+ *
674
+ * @since 2.5.0
675
+ *
676
+ * @param WP_Post $post Post data.
677
+ * @param string $new_status New status for the post.
678
+ * @param string $old_status Old status for the post.
679
+ */
680
+ do_action( 'bp_activity_post_type_edit_' . $post->post_type, $post, $new_status, $old_status );
681
+ }
682
 
 
 
683
  return;
684
+ }
685
+
686
+ // Publishing a previously unpublished post.
687
+ if ( 'publish' === $new_status ) {
688
+ // Untrashing the post type - nothing here yet.
689
+ if ( 'trash' == $old_status ) {
690
+
691
+ /**
692
+ * Fires if untrashing post in a post type.
693
+ *
694
+ * This is a variable filter that is dependent on the post type
695
+ * being untrashed.
696
+ *
697
+ * @since 2.2.0
698
+ *
699
+ * @param WP_Post $post Post data.
700
+ */
701
+ do_action( 'bp_activity_post_type_untrash_' . $post->post_type, $post );
702
+ } else {
703
+ // Record the post.
704
+ bp_activity_post_type_publish( $post->ID, $post );
705
+ }
706
+
707
+ // Unpublishing a previously published post.
708
+ } elseif ( 'publish' === $old_status ) {
709
+ // Some form of pending status - only remove the activity entry.
710
+ bp_activity_post_type_unpublish( $post->ID, $post );
711
+
712
+ // For any other cases, allow plugins to eventually deal with it.
713
+ } else {
714
+ /**
715
+ * Fires when the old and the new post status are not 'publish'.
716
+ *
717
+ * This is a variable filter that is dependent on the post type
718
+ * being untrashed.
719
+ *
720
+ * @since 2.5.0
721
+ *
722
+ * @param WP_Post $post Post data.
723
+ * @param string $new_status New status for the post.
724
+ * @param string $old_status Old status for the post.
725
+ */
726
+ do_action( 'bp_activity_post_type_transition_status_' . $post->post_type, $post, $new_status, $old_status );
727
+ }
728
+ }
729
+ add_action( 'transition_post_status', 'bp_activity_catch_transition_post_type_status', 10, 3 );
730
+
731
+ /**
732
+ * When a post type comment status transition occurs, update the relevant activity's status.
733
+ *
734
+ * @since 2.5.0
735
+ *
736
+ * @param string $new_status New comment status.
737
+ * @param string $old_status Previous comment status.
738
+ * @param WP_Comment $comment Comment data.
739
+ */
740
+ function bp_activity_transition_post_type_comment_status( $new_status, $old_status, $comment ) {
741
+ $post_type = get_post_type( $comment->comment_post_ID );
742
+ if ( ! $post_type ) {
743
+ return;
744
+ }
745
+
746
+ // Get the post type tracking args.
747
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type );
748
+
749
+ // Bail if the activity type does not exist
750
+ if ( empty( $activity_post_object->comments_tracking->action_id ) ) {
751
+ return false;
752
+
753
+ // Set the $activity_comment_object
754
+ } else {
755
+ $activity_comment_object = $activity_post_object->comments_tracking;
756
+ }
757
+
758
+ // Init an empty activity ID
759
+ $activity_id = 0;
760
+
761
+ /**
762
+ * Activity currently doesn't have any concept of a trash, or an unapproved/approved state.
763
+ *
764
+ * If a blog comment transitions to a "delete" or "hold" status, delete the activity item.
765
+ * If a blog comment transitions to trashed, or spammed, mark the activity as spam.
766
+ * If a blog comment transitions to approved (and the activity exists), mark the activity as ham.
767
+ * If a blog comment transitions to unapproved (and the activity exists), mark the activity as spam.
768
+ * Otherwise, record the comment into the activity stream.
769
+ */
770
+
771
+ // This clause handles delete/hold.
772
+ if ( in_array( $new_status, array( 'delete', 'hold' ) ) ) {
773
+ return bp_activity_post_type_remove_comment( $comment->comment_ID, $activity_post_object );
774
+
775
+ // These clauses handle trash, spam, and un-spams.
776
+ } elseif ( in_array( $new_status, array( 'trash', 'spam', 'unapproved' ) ) ) {
777
+ $action = 'spam_activity';
778
+ } elseif ( 'approved' == $new_status ) {
779
+ $action = 'ham_activity';
780
+ }
781
+
782
+ // Get the activity
783
+ if ( bp_disable_blogforum_comments() ) {
784
+ $activity_id = bp_activity_get_activity_id( array(
785
+ 'component' => $activity_comment_object->component_id,
786
+ 'item_id' => get_current_blog_id(),
787
+ 'secondary_item_id' => $comment->comment_ID,
788
+ 'type' => $activity_comment_object->action_id,
789
+ ) );
790
+ } else {
791
+ $activity_id = get_comment_meta( $comment->comment_ID, 'bp_activity_comment_id', true );
792
+ }
793
+
794
+ /**
795
+ * Leave a chance to plugins to manage activity comments differently.
796
+ *
797
+ * @since 2.5.0
798
+ *
799
+ * @param bool $value True to override BuddyPress management.
800
+ * @param string $post_type The post type name.
801
+ * @param int $activity_id The post type activity (0 if not found).
802
+ * @param string $new_status The new status of the post type comment.
803
+ * @param string $old_status The old status of the post type comment.
804
+ * @param WP_Comment $comment Comment data.
805
+ */
806
+ if ( true === apply_filters( 'bp_activity_pre_transition_post_type_comment_status', false, $post_type, $activity_id, $new_status, $old_status, $comment ) ) {
807
+ return false;
808
+ }
809
+
810
+ // Check activity item exists
811
+ if ( empty( $activity_id ) ) {
812
+ // If no activity exists, but the comment has been approved, record it into the activity table.
813
+ if ( 'approved' == $new_status ) {
814
+ return bp_activity_post_type_comment( $comment->comment_ID, true, $activity_post_object );
815
+ }
816
 
 
 
817
  return;
818
+ }
819
 
820
+ // Create an activity object
821
+ $activity = new BP_Activity_Activity( $activity_id );
822
+ if ( empty( $activity->component ) ) {
823
  return;
824
+ }
825
+
826
+ // Spam/ham the activity if it's not already in that state
827
+ if ( 'spam_activity' === $action && ! $activity->is_spam ) {
828
+ bp_activity_mark_as_spam( $activity );
829
+ } elseif ( 'ham_activity' == $action) {
830
+ bp_activity_mark_as_ham( $activity );
831
+ }
832
+
833
+ // Add "new_post_type_comment" to the whitelisted activity types, so that the activity's Akismet history is generated
834
+ $post_type_comment_action = $activity_comment_object->action_id;
835
+ $comment_akismet_history = create_function( '$t', '$t[] = $post_type_comment_action; return $t;' );
836
+ add_filter( 'bp_akismet_get_activity_types', $comment_akismet_history );
837
+
838
+ // Make sure the activity change won't edit the comment if sync is on
839
+ remove_action( 'bp_activity_before_save', 'bp_blogs_sync_activity_edit_to_post_comment', 20 );
840
+
841
+ // Save the updated activity
842
+ $activity->save();
843
+
844
+ // Restore the action
845
+ add_action( 'bp_activity_before_save', 'bp_blogs_sync_activity_edit_to_post_comment', 20 );
846
 
847
+ // Remove the "new_blog_comment" activity type whitelist so we don't break anything
848
+ remove_filter( 'bp_akismet_get_activity_types', $comment_akismet_history );
849
  }
850
+ add_action( 'transition_comment_status', 'bp_activity_transition_post_type_comment_status', 10, 3 );
bp-activity/bp-activity-admin.php CHANGED
@@ -6,31 +6,35 @@
6
  * help text, on which this implementation is heavily based.
7
  *
8
  * @package BuddyPress
9
- * @since BuddyPress (1.6.0)
10
- * @subpackage Activity
11
  */
12
 
13
- // Exit if accessed directly
14
- if ( !defined( 'ABSPATH' ) ) exit;
15
 
16
- // Include WP's list table class
17
  if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
18
 
19
- // per_page screen option. Has to be hooked in extremely early.
 
 
 
 
20
  if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-activity' == $_REQUEST['page'] )
21
  add_filter( 'set-screen-option', 'bp_activity_admin_screen_options', 10, 3 );
22
 
23
  /**
24
  * Register the Activity component admin screen.
25
  *
26
- * @since BuddyPress (1.6)
27
  */
28
  function bp_activity_add_admin_menu() {
29
 
30
- // Add our screen
31
  $hook = add_menu_page(
32
- __( 'Activity', 'buddypress' ),
33
- __( 'Activity', 'buddypress' ),
34
  'bp_moderate',
35
  'bp-activity',
36
  'bp_activity_admin',
@@ -49,10 +53,10 @@ add_action( bp_core_admin_hook(), 'bp_activity_add_admin_menu' );
49
  * which all appear together in the middle of the Dashboard menu. This function
50
  * adds the Activity page to the array of these menu items.
51
  *
52
- * @since BuddyPress (1.7.0)
53
  *
54
  * @param array $custom_menus The list of top-level BP menu items.
55
- * @return array $custom_menus List of top-level BP menu items, with Activity added
56
  */
57
  function bp_activity_admin_menu_order( $custom_menus = array() ) {
58
  array_push( $custom_menus, 'bp-activity' );
@@ -66,10 +70,10 @@ add_filter( 'bp_admin_menu_order', 'bp_activity_admin_menu_order' );
66
  * Processes requests to add new activity comments, and echoes HTML for a new
67
  * table row.
68
  *
69
- * @since BuddyPress (1.6.0)
70
  */
71
  function bp_activity_admin_reply() {
72
- // Check nonce
73
  check_ajax_referer( 'bp-activity-admin-reply', '_ajax_nonce-bp-activity-admin-reply' );
74
 
75
  $parent_id = ! empty( $_REQUEST['parent_id'] ) ? (int) $_REQUEST['parent_id'] : 0;
@@ -79,15 +83,15 @@ function bp_activity_admin_reply() {
79
  if ( empty( $parent_id ) )
80
  die( '-1' );
81
 
82
- // If $root_id not set (e.g. for root items), use $parent_id
83
  if ( empty( $root_id ) )
84
  $root_id = $parent_id;
85
 
86
- // Check that a reply has been entered
87
  if ( empty( $_REQUEST['content'] ) )
88
  die( __( 'ERROR: Please type a reply.', 'buddypress' ) );
89
 
90
- // Check parent activity exists
91
  $parent_activity = new BP_Activity_Activity( $parent_id );
92
  if ( empty( $parent_activity->component ) )
93
  die( __( 'ERROR: The item you are trying to reply to cannot be found, or it has been deleted.', 'buddypress' ) );
@@ -97,25 +101,25 @@ function bp_activity_admin_reply() {
97
  if ( ! current_user_can( 'bp_moderate' ) )
98
  die( '-1' );
99
 
100
- // Add new activity comment
101
  $new_activity_id = bp_activity_new_comment( array(
102
- 'activity_id' => $root_id, // ID of the root activity item
103
  'content' => $_REQUEST['content'],
104
- 'parent_id' => $parent_id, // ID of a parent comment
105
  ) );
106
 
107
- // Fetch the new activity item, as we need it to create table markup to return
108
  $new_activity = new BP_Activity_Activity( $new_activity_id );
109
 
110
- // This needs to be set for the BP_Activity_List_Table constructor to work
111
  set_current_screen( 'toplevel_page_bp-activity' );
112
 
113
- // Set up an output buffer
114
  ob_start();
115
  $list_table = new BP_Activity_List_Table();
116
  $list_table->single_row( (array) $new_activity );
117
 
118
- // Get table markup
119
  $response = array(
120
  'data' => ob_get_contents(),
121
  'id' => $new_activity_id,
@@ -124,7 +128,7 @@ function bp_activity_admin_reply() {
124
  );
125
  ob_end_clean();
126
 
127
- // Send response
128
  $r = new WP_Ajax_Response();
129
  $r->add( $response );
130
  $r->send();
@@ -136,11 +140,10 @@ add_action( 'wp_ajax_bp-activity-admin-reply', 'bp_activity_admin_reply' );
136
  /**
137
  * Handle save/update of screen options for the Activity component admin screen.
138
  *
139
- * @since BuddyPress (1.6.0)
140
  *
141
- * @param string $value Will always be false unless another plugin filters it
142
- * first.
143
- * @param string $option Screen option name.
144
  * @param string $new_value Screen option form value.
145
  * @return string Option value. False to abandon update.
146
  */
@@ -148,7 +151,7 @@ function bp_activity_admin_screen_options( $value, $option, $new_value ) {
148
  if ( 'toplevel_page_bp_activity_per_page' != $option && 'toplevel_page_bp_activity_network_per_page' != $option )
149
  return $value;
150
 
151
- // Per page
152
  $new_value = (int) $new_value;
153
  if ( $new_value < 1 || $new_value > 999 )
154
  return $value;
@@ -159,8 +162,9 @@ function bp_activity_admin_screen_options( $value, $option, $new_value ) {
159
  /**
160
  * Hide the advanced edit meta boxes by default, so we don't clutter the screen.
161
  *
162
- * @since BuddyPress (1.6.0)
163
  *
 
164
  * @param WP_Screen $screen Screen identifier.
165
  * @return array Hidden Meta Boxes.
166
  */
@@ -168,9 +172,17 @@ function bp_activity_admin_edit_hidden_metaboxes( $hidden, $screen ) {
168
  if ( empty( $screen->id ) || 'toplevel_page_bp-activity' != $screen->id && 'toplevel_page_bp-activity_network' != $screen->id )
169
  return $hidden;
170
 
171
- // Hide the primary link meta box by default
172
  $hidden = array_merge( (array) $hidden, array( 'bp_activity_itemids', 'bp_activity_link', 'bp_activity_type', 'bp_activity_userid', ) );
173
 
 
 
 
 
 
 
 
 
174
  return apply_filters( 'bp_hide_meta_boxes', array_unique( $hidden ), $screen );
175
  }
176
  add_filter( 'default_hidden_meta_boxes', 'bp_activity_admin_edit_hidden_metaboxes', 10, 2 );
@@ -180,30 +192,33 @@ add_filter( 'default_hidden_meta_boxes', 'bp_activity_admin_edit_hidden_metaboxe
180
  *
181
  * Does the following:
182
  * - Register contextual help and screen options for this admin page.
183
- * - Enqueues scripts and styles
184
- * - Catches POST and GET requests related to Activity
185
  *
186
- * @since BuddyPress (1.6.0)
187
  *
188
- * @global object $bp BuddyPress global settings.
189
  * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list table.
190
  */
191
  function bp_activity_admin_load() {
192
  global $bp_activity_list_table;
193
 
194
- $bp = buddypress();
195
-
196
- // Decide whether to load the dev version of the CSS and JavaScript
197
- $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : 'min.';
198
-
199
  $doaction = bp_admin_list_table_current_bulk_action();
 
200
 
201
- // Call an action for plugins to hook in early
 
 
 
 
 
 
202
  do_action( 'bp_activity_admin_load', $doaction );
203
 
204
- // Edit screen
205
  if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) ) {
206
- // columns screen option
207
  add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) );
208
 
209
  get_current_screen()->add_help_tab( array(
@@ -220,16 +235,16 @@ function bp_activity_admin_load() {
220
  'title' => __( 'Item, Link, Type', 'buddypress' ),
221
  'content' =>
222
  '<p>' . __( '<strong>Primary Item/Secondary Item</strong> - These identify the object that created the activity. For example, the fields could reference a comment left on a specific site. Some types of activity may only use one, or none, of these fields.', 'buddypress' ) . '</p>' .
223
- '<p>' . __( '<strong>Link</strong> - Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item. Some types of activity may not use this field, even if it has been set.', 'buddypress' ) . '</p>' .
224
  '<p>' . __( '<strong>Type</strong> - Each distinct kind of activity has its own type. For example, <code>created_group</code> is used when a group is created and <code>joined_group</code> is used when a user joins a group.', 'buddypress' ) . '</p>' .
225
  '<p>' . __( 'For information about when and how BuddyPress uses all of these settings, see the Managing Activity link in the panel to the side.', 'buddypress' ) . '</p>'
226
  ) );
227
 
228
- // Help panel - sidebar links
229
  get_current_screen()->set_help_sidebar(
230
  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
231
- '<p>' . __( '<a href="http://codex.buddypress.org/buddypress-site-administration/managing-activity/">Managing Activity</a>', 'buddypress' ) . '</p>' .
232
- '<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
233
  );
234
 
235
  // Register metaboxes for the edit screen.
@@ -239,20 +254,27 @@ function bp_activity_admin_load() {
239
  add_meta_box( 'bp_activity_type', _x( 'Type', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_type', get_current_screen()->id, 'normal', 'core' );
240
  add_meta_box( 'bp_activity_userid', _x( 'Author ID', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_userid', get_current_screen()->id, 'normal', 'core' );
241
 
242
- // Enqueue javascripts
 
 
 
 
 
 
 
243
  wp_enqueue_script( 'postbox' );
244
  wp_enqueue_script( 'dashboard' );
245
  wp_enqueue_script( 'comment' );
246
 
247
- // Index screen
248
  } else {
249
- // Create the Activity screen list table
250
  $bp_activity_list_table = new BP_Activity_List_Table();
251
 
252
- // per_page screen option
253
  add_screen_option( 'per_page', array( 'label' => _x( 'Activity', 'Activity items per page (screen options)', 'buddypress' )) );
254
 
255
- // Help panel - overview text
256
  get_current_screen()->add_help_tab( array(
257
  'id' => 'bp-activity-overview',
258
  'title' => __( 'Overview', 'buddypress' ),
@@ -261,7 +283,7 @@ function bp_activity_admin_load() {
261
  '<p>' . __( 'There are many different types of activities. Some are generated automatically by BuddyPress and other plugins, and some are entered directly by a user in the form of status update. To help manage the different activity types, use the filter dropdown box to switch between them.', 'buddypress' ) . '</p>'
262
  ) );
263
 
264
- // Help panel - moderation text
265
  get_current_screen()->add_help_tab( array(
266
  'id' => 'bp-activity-moderating',
267
  'title' => __( 'Moderating Activity', 'buddypress' ),
@@ -270,61 +292,86 @@ function bp_activity_admin_load() {
270
  '<p>' . __( "In the <strong>In Response To</strong> column, if the activity was in reply to another activity, it shows that activity's author's picture and name, and a link to that activity on your live site. If there is a small bubble, the number in it shows how many other activities are related to this one; these are usually comments. Clicking the bubble will filter the activity screen to show only related activity items.", 'buddypress' ) . '</p>'
271
  ) );
272
 
273
- // Help panel - sidebar links
274
  get_current_screen()->set_help_sidebar(
275
  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
276
- '<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
277
  );
 
 
 
 
 
 
 
 
278
  }
279
 
280
- // Enqueue CSS and JavaScript
281
- wp_enqueue_script( 'bp_activity_admin_js', $bp->plugin_url . "bp-activity/admin/js/admin.{$min}js", array( 'jquery', 'wp-ajax-response' ), bp_get_version(), true );
282
  wp_localize_script( 'bp_activity_admin_js', 'bp_activity_admin_vars', array(
283
- 'page' => get_current_screen()->id
284
- ) );
285
- wp_enqueue_style( 'bp_activity_admin_css', $bp->plugin_url . "bp-activity/admin/css/admin.{$min}css", array(), bp_get_version() );
 
 
 
 
 
286
 
287
- // Handle spam/un-spam/delete of activities
 
 
 
 
 
 
 
288
  if ( !empty( $doaction ) && ! in_array( $doaction, array( '-1', 'edit', 'save', ) ) ) {
289
 
290
- // Build redirection URL
291
  $redirect_to = remove_query_arg( array( 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), wp_get_referer() );
292
  $redirect_to = add_query_arg( 'paged', $bp_activity_list_table->get_pagenum(), $redirect_to );
293
 
294
- // Get activity IDs
295
  $activity_ids = array_map( 'absint', (array) $_REQUEST['aid'] );
296
 
297
- // Call a filter for plugins to modify the requested activities to load
 
 
 
 
 
 
298
  $activity_ids = apply_filters( 'bp_activity_admin_action_activity_ids', $activity_ids );
299
 
300
  // Is this a bulk request?
301
  if ( 'bulk_' == substr( $doaction, 0, 5 ) && ! empty( $_REQUEST['aid'] ) ) {
302
- // Check this is a valid form submission
303
  check_admin_referer( 'bulk-activities' );
304
 
305
- // Trim 'bulk_' off the action name to avoid duplicating a ton of code
306
  $doaction = substr( $doaction, 5 );
307
 
308
  // This is a request to delete, spam, or un-spam, a single item.
309
  } elseif ( !empty( $_REQUEST['aid'] ) ) {
310
 
311
- // Check this is a valid form submission
312
  check_admin_referer( 'spam-activity_' . $activity_ids[0] );
313
  }
314
 
315
- // Initialise counters for how many of each type of item we perform an action on
316
  $deleted = $spammed = $unspammed = 0;
317
 
318
- // Store any errors that occurs when updating the database items
319
  $errors = array();
320
 
321
  // "We'd like to shoot the monster, could you move, please?"
322
  foreach ( $activity_ids as $activity_id ) {
323
  // @todo: Check the permissions on each
324
- //if ( ! current_user_can( 'bp_edit_activity', $activity_id ) )
325
- // continue;
326
-
327
- // Get the activity from the database
328
  $activity = new BP_Activity_Activity( $activity_id );
329
  if ( empty( $activity->component ) ) {
330
  $errors[] = $activity_id;
@@ -352,7 +399,7 @@ function bp_activity_admin_load() {
352
  bp_activity_mark_as_ham( $activity );
353
  $result = $activity->save();
354
 
355
- // Check for any error during activity save
356
  if ( ! $result )
357
  $errors[] = $activity->id;
358
  else
@@ -363,7 +410,7 @@ function bp_activity_admin_load() {
363
  bp_activity_mark_as_spam( $activity );
364
  $result = $activity->save();
365
 
366
- // Check for any error during activity save
367
  if ( ! $result )
368
  $errors[] = $activity->id;
369
  else
@@ -374,11 +421,21 @@ function bp_activity_admin_load() {
374
  break;
375
  }
376
 
377
- // Release memory
378
  unset( $activity );
379
  }
380
 
381
- // Call actions for plugins to do something before we redirect
 
 
 
 
 
 
 
 
 
 
382
  do_action( 'bp_activity_admin_action_after', array( $spammed, $unspammed, $deleted, $errors ), $redirect_to, $activity_ids );
383
 
384
  // Add arguments to the redirect URL so that on page reload, we can easily display what we've just done.
@@ -391,82 +448,87 @@ function bp_activity_admin_load() {
391
  if ( $deleted )
392
  $redirect_to = add_query_arg( 'deleted', $deleted, $redirect_to );
393
 
394
- // If an error occurred, pass back the activity ID that failed
395
  if ( ! empty( $errors ) )
396
  $redirect_to = add_query_arg( 'error', implode ( ',', array_map( 'absint', $errors ) ), $redirect_to );
397
 
398
- // Redirect
 
 
 
 
 
 
399
  wp_redirect( apply_filters( 'bp_activity_admin_action_redirect', $redirect_to ) );
400
  exit;
401
 
402
 
403
- // Save the edit
404
  } elseif ( $doaction && 'save' == $doaction ) {
405
- // Build redirection URL
406
  $redirect_to = remove_query_arg( array( 'action', 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );
407
 
408
- // Get activity ID
409
  $activity_id = (int) $_REQUEST['aid'];
410
 
411
- // Check this is a valid form submission
412
  check_admin_referer( 'edit-activity_' . $activity_id );
413
 
414
- // Get the activity from the database
415
  $activity = new BP_Activity_Activity( $activity_id );
416
 
417
- // If the activity doesn't exist, just redirect back to the index
418
  if ( empty( $activity->component ) ) {
419
  wp_redirect( $redirect_to );
420
  exit;
421
  }
422
 
423
- // Check the form for the updated properties
424
-
425
- // Store any error that occurs when updating the database item
426
  $error = 0;
427
 
428
- // Activity spam status
429
  $prev_spam_status = $new_spam_status = false;
430
  if ( ! empty( $_POST['activity_status'] ) ) {
431
  $prev_spam_status = $activity->is_spam;
432
  $new_spam_status = ( 'spam' == $_POST['activity_status'] ) ? true : false;
433
  }
434
 
435
- // Activity action
436
  if ( isset( $_POST['bp-activities-action'] ) )
437
  $activity->action = $_POST['bp-activities-action'];
438
 
439
- // Activity content
440
  if ( isset( $_POST['bp-activities-content'] ) )
441
  $activity->content = $_POST['bp-activities-content'];
442
 
443
- // Activity primary link
444
  if ( ! empty( $_POST['bp-activities-link'] ) )
445
  $activity->primary_link = $_POST['bp-activities-link'];
446
 
447
- // Activity user ID
448
  if ( ! empty( $_POST['bp-activities-userid'] ) )
449
  $activity->user_id = (int) $_POST['bp-activities-userid'];
450
 
451
- // Activity item primary ID
452
  if ( isset( $_POST['bp-activities-primaryid'] ) )
453
  $activity->item_id = (int) $_POST['bp-activities-primaryid'];
454
 
455
- // Activity item secondary ID
456
  if ( isset( $_POST['bp-activities-secondaryid'] ) )
457
  $activity->secondary_item_id = (int) $_POST['bp-activities-secondaryid'];
458
 
459
- // Activity type
460
  if ( ! empty( $_POST['bp-activities-type'] ) ) {
461
  $actions = bp_activity_admin_get_activity_actions();
462
 
463
- // Check that the new type is a registered activity type
464
  if ( in_array( $_POST['bp-activities-type'], $actions ) ) {
465
  $activity->type = $_POST['bp-activities-type'];
466
  }
467
  }
468
 
469
- // Activity timestamp
470
  if ( ! empty( $_POST['aa'] ) && ! empty( $_POST['mm'] ) && ! empty( $_POST['jj'] ) && ! empty( $_POST['hh'] ) && ! empty( $_POST['mn'] ) && ! empty( $_POST['ss'] ) ) {
471
  $aa = $_POST['aa'];
472
  $mm = $_POST['mm'];
@@ -482,7 +544,7 @@ function bp_activity_admin_load() {
482
  $mn = ( $mn > 59 ) ? $mn -60 : $mn;
483
  $ss = ( $ss > 59 ) ? $ss -60 : $ss;
484
 
485
- // Reconstruct the date into a timestamp
486
  $gmt_date = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
487
 
488
  $activity->date_recorded = $gmt_date;
@@ -496,26 +558,38 @@ function bp_activity_admin_load() {
496
  bp_activity_mark_as_ham( $activity );
497
  }
498
 
499
- // Save
500
  $result = $activity->save();
501
 
502
- // Clear the activity stream first page cache, in case this activity's timestamp was changed
503
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
504
 
505
- // Check for any error during activity save
506
  if ( false === $result )
507
  $error = $activity->id;
508
 
509
- // Call actions for plugins to do something before we redirect
 
 
 
 
 
 
510
  do_action_ref_array( 'bp_activity_admin_edit_after', array( &$activity, $error ) );
511
 
512
- // If an error occurred, pass back the activity ID that failed
513
  if ( $error )
514
- $redirect_to = add_query_arg( 'error', (int) $error, $redirect_to );
515
  else
516
- $redirect_to = add_query_arg( 'updated', (int) $activity->id, $redirect_to );
517
 
518
- // Redirect
 
 
 
 
 
 
519
  wp_redirect( apply_filters( 'bp_activity_admin_edit_redirect', $redirect_to ) );
520
  exit;
521
 
@@ -530,17 +604,17 @@ function bp_activity_admin_load() {
530
  /**
531
  * Output the Activity component admin screens.
532
  *
533
- * @since BuddyPress (1.6.0)
534
  */
535
  function bp_activity_admin() {
536
- // Decide whether to load the index or edit screen
537
  $doaction = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
538
 
539
- // Display the single activity edit screen
540
  if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) )
541
  bp_activity_admin_edit();
542
 
543
- // Otherwise, display the Activity index screen
544
  else
545
  bp_activity_admin_index();
546
  }
@@ -548,7 +622,7 @@ function bp_activity_admin() {
548
  /**
549
  * Display the single activity edit screen.
550
  *
551
- * @since BuddyPress (1.6.0)
552
  */
553
  function bp_activity_admin_edit() {
554
 
@@ -557,7 +631,7 @@ function bp_activity_admin_edit() {
557
  if ( ! is_super_admin() )
558
  die( '-1' );
559
 
560
- // Get the activity from the database
561
  $activity = bp_activity_get( array(
562
  'in' => ! empty( $_REQUEST['aid'] ) ? (int) $_REQUEST['aid'] : 0,
563
  'max' => 1,
@@ -569,42 +643,55 @@ function bp_activity_admin_edit() {
569
  if ( ! empty( $activity['activities'][0] ) ) {
570
  $activity = $activity['activities'][0];
571
 
572
- // Workaround to use WP's touch_time() without duplicating that function
573
  $GLOBALS['comment'] = new stdClass;
574
  $GLOBALS['comment']->comment_date = $activity->date_recorded;
575
  } else {
576
  $activity = '';
577
  }
578
 
579
- // Construct URL for form
580
  $form_url = remove_query_arg( array( 'action', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );
581
  $form_url = add_query_arg( 'action', 'save', $form_url );
582
 
583
- // Call an action for plugins to modify the activity before we display the edit form
 
 
 
 
 
 
584
  do_action_ref_array( 'bp_activity_admin_edit', array( &$activity ) ); ?>
585
 
586
  <div class="wrap">
587
- <?php screen_icon( 'buddypress-activity' ); ?>
588
- <h2><?php printf( __( 'Editing Activity (ID #%s)', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?></h2>
589
 
590
  <?php if ( ! empty( $activity ) ) : ?>
591
 
592
- <form action="<?php echo esc_attr( $form_url ); ?>" id="bp-activities-edit-form" method="post">
593
  <div id="poststuff">
594
 
595
  <div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
596
  <div id="post-body-content">
597
  <div id="postdiv">
598
  <div id="bp_activity_action" class="postbox">
599
- <h3><?php _e( 'Action', 'buddypress' ); ?></h3>
600
  <div class="inside">
 
 
 
 
601
  <?php wp_editor( stripslashes( $activity->action ), 'bp-activities-action', array( 'media_buttons' => false, 'textarea_rows' => 7, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
602
  </div>
603
  </div>
604
 
605
  <div id="bp_activity_content" class="postbox">
606
- <h3><?php _e( 'Content', 'buddypress' ); ?></h3>
607
  <div class="inside">
 
 
 
 
608
  <?php wp_editor( stripslashes( $activity->content ), 'bp-activities-content', array( 'media_buttons' => false, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
609
  </div>
610
  </div>
@@ -628,7 +715,16 @@ function bp_activity_admin_edit() {
628
  </form>
629
 
630
  <?php else : ?>
631
- <p><?php printf( __( 'No activity found with this ID. <a href="%s">Go back and try again</a>.', 'buddypress' ), esc_url( bp_get_admin_url( 'admin.php?page=bp-activity' ) ) ); ?></p>
 
 
 
 
 
 
 
 
 
632
  <?php endif; ?>
633
 
634
  </div><!-- .wrap -->
@@ -639,7 +735,7 @@ function bp_activity_admin_edit() {
639
  /**
640
  * Status metabox for the Activity admin edit screen.
641
  *
642
- * @since BuddyPress (1.6.0)
643
  *
644
  * @param object $item Activity item.
645
  */
@@ -659,17 +755,17 @@ function bp_activity_admin_edit_metabox_status( $item ) {
659
 
660
  <div id="misc-publishing-actions">
661
  <div class="misc-pub-section" id="comment-status-radio">
662
- <label class="approved"><input type="radio" name="activity_status" value="ham" <?php checked( $item->is_spam, 0 ); ?>><?php _e( 'Approved', 'buddypress' ); ?></label><br />
663
- <label class="spam"><input type="radio" name="activity_status" value="spam" <?php checked( $item->is_spam, 1 ); ?>><?php _e( 'Spam', 'buddypress' ); ?></label>
664
  </div>
665
 
666
  <div class="misc-pub-section curtime misc-pub-section-last">
667
  <?php
668
- // translators: Publish box date format, see http://php.net/date
669
  $datef = __( 'M j, Y @ G:i', 'buddypress' );
670
  $date = date_i18n( $datef, strtotime( $item->date_recorded ) );
671
  ?>
672
- <span id="timestamp"><?php printf( __( 'Submitted on: <strong>%1$s</strong>', 'buddypress' ), $date ); ?></span>&nbsp;<a href="#edit_timestamp" class="edit-timestamp hide-if-no-js" tabindex='4'><?php _e( 'Edit', 'buddypress' ); ?></a>
673
 
674
  <div id='timestampdiv' class='hide-if-js'>
675
  <?php touch_time( 1, 0, 5 ); ?>
@@ -682,7 +778,7 @@ function bp_activity_admin_edit_metabox_status( $item ) {
682
 
683
  <div id="major-publishing-actions">
684
  <div id="publishing-action">
685
- <?php submit_button( __( 'Update', 'buddypress' ), 'primary', 'save', false, array( 'tabindex' => '4' ) ); ?>
686
  </div>
687
  <div class="clear"></div>
688
  </div><!-- #major-publishing-actions -->
@@ -695,16 +791,19 @@ function bp_activity_admin_edit_metabox_status( $item ) {
695
  /**
696
  * Primary link metabox for the Activity admin edit screen.
697
  *
698
- * @since BuddyPress (1.6.0)
699
  *
700
  * @param object $item Activity item.
701
  */
702
  function bp_activity_admin_edit_metabox_link( $item ) {
703
  ?>
704
 
705
- <label class="screen-reader-text" for="bp-activities-link"><?php _e( 'Link', 'buddypress' ); ?></label>
706
- <input type="url" name="bp-activities-link" value="<?php echo esc_url( $item->primary_link ); ?>" />
707
- <p><?php _e( 'Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item.', 'buddypress' ); ?></p>
 
 
 
708
 
709
  <?php
710
  }
@@ -712,15 +811,18 @@ function bp_activity_admin_edit_metabox_link( $item ) {
712
  /**
713
  * User ID metabox for the Activity admin edit screen.
714
  *
715
- * @since BuddyPress (1.6.0)
716
  *
717
  * @param object $item Activity item.
718
  */
719
  function bp_activity_admin_edit_metabox_userid( $item ) {
720
  ?>
721
 
722
- <label class="screen-reader-text" for="bp-activities-userid"><?php _e( 'Author ID', 'buddypress' ); ?></label>
723
- <input type="number" name="bp-activities-userid" value="<?php echo esc_attr( $item->user_id ); ?>" min="1" />
 
 
 
724
 
725
  <?php
726
  }
@@ -730,15 +832,15 @@ function bp_activity_admin_edit_metabox_userid( $item ) {
730
  *
731
  * Format is [activity_type] => Pretty name for activity type.
732
  *
733
- * @since BuddyPress (2.0.0)
734
  *
735
- * @return array
736
  */
737
  function bp_activity_admin_get_activity_actions() {
738
  $actions = array();
739
 
740
  // Walk through the registered actions, and build an array of actions/values.
741
- foreach ( buddypress()->activity->actions as $action ) {
742
  $action = array_values( (array) $action );
743
 
744
  for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
@@ -746,47 +848,47 @@ function bp_activity_admin_get_activity_actions() {
746
  }
747
  }
748
 
749
- // This was a mis-named activity type from before BP 1.6
750
  unset( $actions['friends_register_activity_action'] );
751
 
752
- // Sort array by the human-readable value
753
  natsort( $actions );
754
 
755
  return $actions;
756
  }
757
 
758
  /**
759
- * Activity type metabox for the Activity admin edit screen
760
  *
761
- * @since BuddyPress (1.6.0)
762
- *
763
- * @global object $bp BuddyPress global settings.
764
  *
765
  * @param object $item Activity item.
766
  */
767
  function bp_activity_admin_edit_metabox_type( $item ) {
768
- global $bp;
769
 
770
  $actions = array();
771
  $selected = $item->type;
772
 
773
  // Walk through the registered actions, and build an array of actions/values.
774
- foreach ( $bp->activity->actions as $action ) {
775
  $action = array_values( (array) $action );
776
 
777
  for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
778
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
779
  }
780
 
781
- // This was a mis-named activity type from before BP 1.6
782
  unset( $actions['friends_register_activity_action'] );
783
 
784
- // Sort array by the human-readable value
785
  natsort( $actions );
786
 
787
- // If the activity type is not registered properly (eg, a plugin has
788
- // not called bp_activity_set_action()), add the raw type to the end
789
- // of the list
 
 
790
  if ( ! isset( $actions[ $selected ] ) ) {
791
  _doing_it_wrong( __FUNCTION__, sprintf( __( 'This activity item has a type (%s) that is not registered using bp_activity_set_action(), so no label is available.', 'buddypress' ), $selected ), '2.0.0' );
792
  $actions[ $selected ] = $selected;
@@ -794,7 +896,11 @@ function bp_activity_admin_edit_metabox_type( $item ) {
794
 
795
  ?>
796
 
797
- <select name="bp-activities-type">
 
 
 
 
798
  <?php foreach ( $actions as $k => $v ) : ?>
799
  <option value="<?php echo esc_attr( $k ); ?>" <?php selected( $k, $selected ); ?>><?php echo esc_html( $v ); ?></option>
800
  <?php endforeach; ?>
@@ -806,7 +912,7 @@ function bp_activity_admin_edit_metabox_type( $item ) {
806
  /**
807
  * Primary item ID/Secondary item ID metabox for the Activity admin edit screen.
808
  *
809
- * @since BuddyPress (1.6.0)
810
  *
811
  * @param object $item Activity item.
812
  */
@@ -828,18 +934,17 @@ function bp_activity_admin_edit_metabox_itemids( $item ) {
828
  /**
829
  * Display the Activity admin index screen, which contains a list of all the activities.
830
  *
831
- * @since BuddyPress (1.6.0)
832
  *
833
- * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list
834
- * table.
835
- * @global string $plugin_page The current plugin page.
836
  */
837
  function bp_activity_admin_index() {
838
  global $bp_activity_list_table, $plugin_page;
839
 
840
  $messages = array();
841
 
842
- // If the user has just made a change to an activity item, build status messages
843
  if ( ! empty( $_REQUEST['deleted'] ) || ! empty( $_REQUEST['spammed'] ) || ! empty( $_REQUEST['unspammed'] ) || ! empty( $_REQUEST['error'] ) || ! empty( $_REQUEST['updated'] ) ) {
844
  $deleted = ! empty( $_REQUEST['deleted'] ) ? (int) $_REQUEST['deleted'] : 0;
845
  $errors = ! empty( $_REQUEST['error'] ) ? $_REQUEST['error'] : '';
@@ -849,14 +954,14 @@ function bp_activity_admin_index() {
849
 
850
  $errors = array_map( 'absint', explode( ',', $errors ) );
851
 
852
- // Make sure we don't get any empty values in $errors
853
  for ( $i = 0, $errors_count = count( $errors ); $i < $errors_count; $i++ ) {
854
  if ( 0 === $errors[$i] ) {
855
  unset( $errors[$i] );
856
  }
857
  }
858
 
859
- // Reindex array
860
  $errors = array_values( $errors );
861
 
862
  if ( $deleted > 0 )
@@ -870,9 +975,9 @@ function bp_activity_admin_index() {
870
  $error_msg = __( 'Errors occurred when trying to update these activity items:', 'buddypress' );
871
  $error_msg .= '<ul class="activity-errors">';
872
 
873
- // Display each error as a list item
874
  foreach ( $errors as $error ) {
875
- // Translators: This is a bulleted list of item IDs
876
  $error_msg .= '<li>' . sprintf( __( '#%s', 'buddypress' ), number_format_i18n( $error ) ) . '</li>';
877
  }
878
 
@@ -888,35 +993,40 @@ function bp_activity_admin_index() {
888
  $messages[] = sprintf( _n( '%s activity item has been successfully unspammed.', '%s activity items have been successfully unspammed.', $unspammed, 'buddypress' ), number_format_i18n( $unspammed ) );
889
 
890
  if ( $updated > 0 )
891
- $messages[] = __( 'The activity item has been updated succesfully.', 'buddypress' );
892
  }
893
 
894
- // Prepare the activity items for display
895
  $bp_activity_list_table->prepare_items();
896
 
897
- // Call an action for plugins to modify the activity before we display the edit form
 
 
 
 
 
 
898
  do_action( 'bp_activity_admin_index', $messages ); ?>
899
 
900
  <div class="wrap">
901
- <?php screen_icon( 'buddypress-activity' ); ?>
902
- <h2>
903
  <?php if ( !empty( $_REQUEST['aid'] ) ) : ?>
904
  <?php printf( __( 'Activity related to ID #%s', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?>
905
  <?php else : ?>
906
- <?php _e( 'Activity', 'buddypress' ); ?>
907
  <?php endif; ?>
908
 
909
  <?php if ( !empty( $_REQUEST['s'] ) ) : ?>
910
  <span class="subtitle"><?php printf( __( 'Search results for &#8220;%s&#8221;', 'buddypress' ), wp_html_excerpt( esc_html( stripslashes( $_REQUEST['s'] ) ), 50 ) ); ?></span>
911
  <?php endif; ?>
912
- </h2>
913
 
914
- <?php // If the user has just made a change to an activity item, display the status messages ?>
915
  <?php if ( !empty( $messages ) ) : ?>
916
  <div id="moderated" class="<?php echo ( ! empty( $_REQUEST['error'] ) ) ? 'error' : 'updated'; ?>"><p><?php echo implode( "<br/>\n", $messages ); ?></p></div>
917
  <?php endif; ?>
918
 
919
- <?php // Display each activity on its own row ?>
920
  <?php $bp_activity_list_table->views(); ?>
921
 
922
  <form id="bp-activities-form" action="" method="get">
@@ -925,20 +1035,24 @@ function bp_activity_admin_index() {
925
  <?php $bp_activity_list_table->display(); ?>
926
  </form>
927
 
928
- <?php // This markup is used for the reply form ?>
929
  <table style="display: none;">
930
  <tr id="bp-activities-container" style="display: none;">
931
  <td colspan="4">
932
  <form method="get" action="">
933
 
934
- <h5 id="bp-replyhead"><?php _e( 'Reply to Activity', 'buddypress' ); ?></h5>
 
 
 
 
935
  <?php wp_editor( '', 'bp-activities', array( 'dfw' => false, 'media_buttons' => false, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ), 'tinymce' => false, ) ); ?>
936
 
937
  <p id="bp-replysubmit" class="submit">
938
  <a href="#" class="cancel button-secondary alignleft"><?php _e( 'Cancel', 'buddypress' ); ?></a>
939
  <a href="#" class="save button-primary alignright"><?php _e( 'Reply', 'buddypress' ); ?></a>
940
 
941
- <img class="waiting" style="display:none;" src="<?php echo esc_url( bp_get_admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
942
  <span class="error" style="display:none;"></span>
943
  <br class="clear" />
944
  </p>
@@ -953,626 +1067,3 @@ function bp_activity_admin_index() {
953
 
954
  <?php
955
  }
956
-
957
- /**
958
- * List table class for the Activity component admin page.
959
- *
960
- * @since BuddyPress (1.6)
961
- */
962
- class BP_Activity_List_Table extends WP_List_Table {
963
-
964
- /**
965
- * What type of view is being displayed?
966
- *
967
- * e.g. "all", "pending", "approved", "spam"...
968
- *
969
- * @since BuddyPress (1.6.0)
970
- * @var string
971
- */
972
- public $view = 'all';
973
-
974
- /**
975
- * How many activity items have been marked as spam.
976
- *
977
- * @since BuddyPress (1.6.0)
978
- * @var int
979
- */
980
- public $spam_count = 0;
981
-
982
- /**
983
- * Store activity-to-user-ID mappings for use in the In Response To column.
984
- *
985
- * @since BuddyPress (1.6.0)
986
- * @var array
987
- */
988
- protected $activity_user_id = array();
989
-
990
- /**
991
- * Constructor.
992
- *
993
- * @since BuddyPress (1.6.0)
994
- */
995
- public function __construct() {
996
-
997
- // See if activity commenting is enabled for blog / forum activity items
998
- $this->disable_blogforum_comments = bp_disable_blogforum_comments();
999
-
1000
- // Define singular and plural labels, as well as whether we support AJAX.
1001
- parent::__construct( array(
1002
- 'ajax' => false,
1003
- 'plural' => 'activities',
1004
- 'singular' => 'activity',
1005
- 'screen' => get_current_screen(),
1006
- ) );
1007
- }
1008
-
1009
- /**
1010
- * Handle filtering of data, sorting, pagination, and any other data manipulation prior to rendering.
1011
- *
1012
- * @since BuddyPress (1.6.0)
1013
- */
1014
- function prepare_items() {
1015
-
1016
- // Option defaults
1017
- $filter = array();
1018
- $include_id = false;
1019
- $search_terms = false;
1020
- $sort = 'DESC';
1021
- $spam = 'ham_only';
1022
-
1023
- // Set current page
1024
- $page = $this->get_pagenum();
1025
-
1026
- // Set per page from the screen options
1027
- $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );
1028
-
1029
- // Check if we're on the "Spam" view
1030
- if ( !empty( $_REQUEST['activity_status'] ) && 'spam' == $_REQUEST['activity_status'] ) {
1031
- $spam = 'spam_only';
1032
- $this->view = 'spam';
1033
- }
1034
-
1035
- // Sort order
1036
- if ( !empty( $_REQUEST['order'] ) && 'desc' != $_REQUEST['order'] )
1037
- $sort = 'ASC';
1038
-
1039
- // Order by
1040
- /*if ( !empty( $_REQUEST['orderby'] ) ) {
1041
- }*/
1042
-
1043
- // Filter
1044
- if ( !empty( $_REQUEST['activity_type'] ) )
1045
- $filter = array( 'action' => $_REQUEST['activity_type'] );
1046
-
1047
- // Are we doing a search?
1048
- if ( !empty( $_REQUEST['s'] ) )
1049
- $search_terms = $_REQUEST['s'];
1050
-
1051
- // Check if user has clicked on a specific activity (if so, fetch only that, and any related, activity).
1052
- if ( !empty( $_REQUEST['aid'] ) )
1053
- $include_id = (int) $_REQUEST['aid'];
1054
-
1055
- // Get the spam total (ignoring any search query or filter)
1056
- $spams = bp_activity_get( array(
1057
- 'display_comments' => 'stream',
1058
- 'show_hidden' => true,
1059
- 'spam' => 'spam_only',
1060
- ) );
1061
- $this->spam_count = $spams['total'];
1062
- unset( $spams );
1063
-
1064
- // Get the activities from the database
1065
- $activities = bp_activity_get( array(
1066
- 'display_comments' => 'stream',
1067
- 'filter' => $filter,
1068
- 'in' => $include_id,
1069
- 'page' => $page,
1070
- 'per_page' => $per_page,
1071
- 'search_terms' => $search_terms,
1072
- 'show_hidden' => true,
1073
- //'sort' => $sort,
1074
- 'spam' => $spam,
1075
- ) );
1076
-
1077
- // If we're viewing a specific activity, flatten all activites into a single array.
1078
- if ( $include_id ) {
1079
- $activities['activities'] = BP_Activity_List_Table::flatten_activity_array( $activities['activities'] );
1080
- $activities['total'] = count( $activities['activities'] );
1081
-
1082
- // Sort the array by the activity object's date_recorded value
1083
- usort( $activities['activities'], create_function( '$a, $b', 'return $a->date_recorded > $b->date_recorded;' ) );
1084
- }
1085
-
1086
- // bp_activity_get returns an array of objects; cast these to arrays for WP_List_Table.
1087
- $new_activities = array();
1088
- foreach ( $activities['activities'] as $activity_item ) {
1089
- $new_activities[] = (array) $activity_item;
1090
-
1091
- // Build an array of activity-to-user ID mappings for better efficency in the In Response To column
1092
- $this->activity_user_id[$activity_item->id] = $activity_item->user_id;
1093
- }
1094
-
1095
- // Set raw data to display
1096
- $this->items = $new_activities;
1097
-
1098
- // Store information needed for handling table pagination
1099
- $this->set_pagination_args( array(
1100
- 'per_page' => $per_page,
1101
- 'total_items' => $activities['total'],
1102
- 'total_pages' => ceil( $activities['total'] / $per_page )
1103
- ) );
1104
-
1105
- // Don't truncate activity items; bp_activity_truncate_entry() needs to be used inside a BP_Activity_Template loop.
1106
- remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
1107
- }
1108
-
1109
- /**
1110
- * Get an array of all the columns on the page.
1111
- *
1112
- * @since BuddyPress (1.6.0)
1113
- *
1114
- * @return array Column headers.
1115
- */
1116
- function get_column_info() {
1117
- $this->_column_headers = array(
1118
- $this->get_columns(),
1119
- array(),
1120
- $this->get_sortable_columns(),
1121
- );
1122
-
1123
- return $this->_column_headers;
1124
- }
1125
-
1126
- /**
1127
- * Display a message on screen when no items are found (e.g. no search matches).
1128
- *
1129
- * @since BuddyPress (1.6.0)
1130
- */
1131
- function no_items() {
1132
- _e( 'No activities found.', 'buddypress' );
1133
- }
1134
-
1135
- /**
1136
- * Output the Activity data table.
1137
- *
1138
- * @since BuddyPress (1.6.0)
1139
- */
1140
- function display() {
1141
- extract( $this->_args );
1142
-
1143
- $this->display_tablenav( 'top' ); ?>
1144
-
1145
- <table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
1146
- <thead>
1147
- <tr>
1148
- <?php $this->print_column_headers(); ?>
1149
- </tr>
1150
- </thead>
1151
-
1152
- <tfoot>
1153
- <tr>
1154
- <?php $this->print_column_headers( false ); ?>
1155
- </tr>
1156
- </tfoot>
1157
-
1158
- <tbody id="the-comment-list">
1159
- <?php $this->display_rows_or_placeholder(); ?>
1160
- </tbody>
1161
- </table>
1162
- <?php
1163
-
1164
- $this->display_tablenav( 'bottom' );
1165
- }
1166
-
1167
- /**
1168
- * Generate content for a single row of the table.
1169
- *
1170
- * @since BuddyPress (1.6.0)
1171
- *
1172
- * @param object $item The current item.
1173
- */
1174
- function single_row( $item ) {
1175
- static $even = false;
1176
-
1177
- if ( $even ) {
1178
- $row_class = ' class="even"';
1179
- } else {
1180
- $row_class = ' class="alternate odd"';
1181
- }
1182
-
1183
- if ( 'activity_comment' === $item['type'] ) {
1184
- $root_id = $item['item_id'];
1185
- } else {
1186
- $root_id = $item['id'];
1187
- }
1188
-
1189
- echo '<tr' . $row_class . ' id="activity-' . esc_attr( $item['id'] ) . '" data-parent_id="' . esc_attr( $item['id'] ) . '" data-root_id="' . esc_attr( $root_id ) . '">';
1190
- echo $this->single_row_columns( $item );
1191
- echo '</tr>';
1192
-
1193
- $even = ! $even;
1194
- }
1195
-
1196
- /**
1197
- * Get the list of views available on this table (e.g. "all", "spam").
1198
- *
1199
- * @since BuddyPress (1.6.0)
1200
- */
1201
- function get_views() {
1202
- $url_base = bp_get_admin_url( 'admin.php?page=bp-activity' ); ?>
1203
-
1204
- <ul class="subsubsub">
1205
- <li class="all"><a href="<?php echo esc_attr( esc_url( $url_base ) ); ?>" class="<?php if ( 'spam' != $this->view ) echo 'current'; ?>"><?php _e( 'All', 'buddypress' ); ?></a> |</li>
1206
- <li class="spam"><a href="<?php echo esc_attr( esc_url( add_query_arg( 'activity_status', 'spam', $url_base ) ) ); ?>" class="<?php if ( 'spam' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Spam <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->spam_count ) ); ?></a></li>
1207
-
1208
- <?php do_action( 'bp_activity_list_table_get_views', $url_base, $this->view ); ?>
1209
- </ul>
1210
- <?php
1211
- }
1212
-
1213
- /**
1214
- * Get bulk actions.
1215
- *
1216
- * @since BuddyPress (1.6.0)
1217
- *
1218
- * @return array Key/value pairs for the bulk actions dropdown.
1219
- */
1220
- function get_bulk_actions() {
1221
- $actions = array();
1222
- $actions['bulk_spam'] = __( 'Mark as Spam', 'buddypress' );
1223
- $actions['bulk_ham'] = __( 'Not Spam', 'buddypress' );
1224
- $actions['bulk_delete'] = __( 'Delete Permanently', 'buddypress' );
1225
-
1226
- return apply_filters( 'bp_activity_list_table_get_bulk_actions', $actions );
1227
- }
1228
-
1229
- /**
1230
- * Get the table column titles.
1231
- *
1232
- * @since BuddyPress (1.6.0)
1233
- *
1234
- * @see WP_List_Table::single_row_columns()
1235
- *
1236
- * @return array The columns to appear in the Activity list table.
1237
- */
1238
- function get_columns() {
1239
- return array(
1240
- 'cb' => '<input name type="checkbox" />',
1241
- 'author' => __( 'Author', 'buddypress' ),
1242
- 'comment' => __( 'Activity', 'buddypress' ),
1243
- 'action' => __( 'Action', 'buddypress' ),
1244
- 'response' => __( 'In Response To', 'buddypress' ),
1245
- );
1246
- }
1247
-
1248
- /**
1249
- * Get the column names for sortable columns.
1250
- *
1251
- * Currently, returns an empty array (no columns are sortable).
1252
- *
1253
- * @since BuddyPress (1.6.0)
1254
- * @todo For this to work, BP_Activity_Activity::get() needs updating
1255
- * to support ordering by specific fields.
1256
- *
1257
- * @return array The columns that can be sorted on the Activity screen.
1258
- */
1259
- function get_sortable_columns() {
1260
- return array();
1261
-
1262
- /*return array(
1263
- 'author' => array( 'activity_author', false ), // Intentionally not using "=>"
1264
- );*/
1265
- }
1266
-
1267
- /**
1268
- * Markup for the "filter" part of the form (i.e. which activity type to display).
1269
- *
1270
- * @since BuddyPress (1.6.0)
1271
- *
1272
- * @param string $which 'top' or 'bottom'.
1273
- */
1274
- function extra_tablenav( $which ) {
1275
- if ( 'bottom' == $which )
1276
- return;
1277
-
1278
- $selected = !empty( $_REQUEST['activity_type'] ) ? $_REQUEST['activity_type'] : '';
1279
-
1280
- // Get all types of activities, and sort alphabetically.
1281
- $actions = bp_activity_get_types();
1282
- natsort( $actions );
1283
- ?>
1284
-
1285
- <div class="alignleft actions">
1286
- <select name="activity_type">
1287
- <option value="" <?php selected( !$selected ); ?>><?php _e( 'Show all activity types', 'buddypress' ); ?></option>
1288
-
1289
- <?php foreach ( $actions as $k => $v ) : ?>
1290
- <option value="<?php echo esc_attr( $k ); ?>" <?php selected( $k, $selected ); ?>><?php echo esc_html( $v ); ?></option>
1291
- <?php endforeach; ?>
1292
- </select>
1293
-
1294
- <?php submit_button( __( 'Filter', 'buddypress' ), 'secondary', false, false, array( 'id' => 'post-query-submit' ) ); ?>
1295
- </div>
1296
-
1297
- <?php
1298
- }
1299
-
1300
- /**
1301
- * Checkbox column markup.
1302
- *
1303
- * @since BuddyPress (1.6.0)
1304
- *
1305
- * @see WP_List_Table::single_row_columns()
1306
- *
1307
- * @param array $item A singular item (one full row).
1308
- */
1309
- function column_cb( $item ) {
1310
- printf( '<label class="screen-reader-text" for="aid-%1$d">' . __( 'Select activity item %1$d', 'buddypress' ) . '</label><input type="checkbox" name="aid[]" value="%1$d" id="aid-%1$d" />', $item['id'] );
1311
- }
1312
-
1313
- /**
1314
- * Author column markup.
1315
- *
1316
- * @since BuddyPress (1.6.0)
1317
- *
1318
- * @see WP_List_Table::single_row_columns()
1319
- *
1320
- * @param array $item A singular item (one full row).
1321
- */
1322
- function column_author( $item ) {
1323
- echo '<strong>' . get_avatar( $item['user_id'], '32' ) . ' ' . bp_core_get_userlink( $item['user_id'] ) . '</strong>';
1324
- }
1325
-
1326
- /**
1327
- * Action column markup.
1328
- *
1329
- * @since BuddyPress (2.0.0)
1330
- *
1331
- * @see WP_List_Table::single_row_columns()
1332
- *
1333
- * @param array $item A singular item (one full row).
1334
- */
1335
- function column_action( $item ) {
1336
- $actions = bp_activity_admin_get_activity_actions();
1337
-
1338
- if ( isset( $actions[ $item['type'] ] ) ) {
1339
- echo $actions[ $item['type'] ];
1340
- } else {
1341
- printf( __( 'Unregistered action - %s', 'buddypress' ), $item['type'] );
1342
- }
1343
- }
1344
-
1345
- /**
1346
- * Content column, and "quick admin" rollover actions.
1347
- *
1348
- * Called "comment" in the CSS so we can re-use some WP core CSS.
1349
- *
1350
- * @since BuddyPress (1.6.0)
1351
- *
1352
- * @see WP_List_Table::single_row_columns()
1353
- *
1354
- * @param array $item A singular item (one full row).
1355
- */
1356
- function column_comment( $item ) {
1357
- // Determine what type of item (row) we're dealing with
1358
- if ( $item['is_spam'] )
1359
- $item_status = 'spam';
1360
- else
1361
- $item_status = 'all';
1362
-
1363
- // Preorder items: Reply | Edit | Spam | Delete Permanently
1364
- $actions = array(
1365
- 'reply' => '',
1366
- 'edit' => '',
1367
- 'spam' => '', 'unspam' => '',
1368
- 'delete' => '',
1369
- );
1370
-
1371
- // Build actions URLs
1372
- $base_url = bp_get_admin_url( 'admin.php?page=bp-activity&amp;aid=' . $item['id'] );
1373
- $spam_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'spam-activity_' . $item['id'] ) );
1374
-
1375
- $delete_url = $base_url . "&amp;action=delete&amp;$spam_nonce";
1376
- $edit_url = $base_url . '&amp;action=edit';
1377
- $ham_url = $base_url . "&amp;action=ham&amp;$spam_nonce";
1378
- $spam_url = $base_url . "&amp;action=spam&amp;$spam_nonce";
1379
-
1380
- // Rollover actions
1381
-
1382
- // Reply - javascript only; implemented by AJAX.
1383
- if ( 'spam' != $item_status ) {
1384
- if ( $this->can_comment( $item ) ) {
1385
- $actions['reply'] = sprintf( '<a href="#" class="reply hide-if-no-js">%s</a>', __( 'Reply', 'buddypress' ) );
1386
- } else {
1387
- $actions['reply'] = sprintf( '<span class="form-input-tip" title="%s">%s</span>', __( 'Replies are disabled for this activity item', 'buddypress' ), __( 'Replies disabled', 'buddypress' ) );
1388
- }
1389
-
1390
- // Edit
1391
- $actions['edit'] = sprintf( '<a href="%s">%s</a>', $edit_url, __( 'Edit', 'buddypress' ) );
1392
- }
1393
-
1394
- // Spam/unspam
1395
- if ( 'spam' == $item_status )
1396
- $actions['unspam'] = sprintf( '<a href="%s">%s</a>', $ham_url, __( 'Not Spam', 'buddypress' ) );
1397
- else
1398
- $actions['spam'] = sprintf( '<a href="%s">%s</a>', $spam_url, __( 'Spam', 'buddypress' ) );
1399
-
1400
- // Delete
1401
- $actions['delete'] = sprintf( '<a href="%s" onclick="%s">%s</a>', $delete_url, "javascript:return confirm('" . esc_js( __( 'Are you sure?', 'buddypress' ) ) . "'); ", __( 'Delete Permanently', 'buddypress' ) );
1402
-
1403
- // Start timestamp
1404
- echo '<div class="submitted-on">';
1405
-
1406
- // Other plugins can filter which actions are shown
1407
- $actions = apply_filters( 'bp_activity_admin_comment_row_actions', array_filter( $actions ), $item );
1408
-
1409
- /* translators: 2: activity admin ui date/time */
1410
- printf( __( 'Submitted on <a href="%1$s">%2$s at %3$s</a>', 'buddypress' ), bp_activity_get_permalink( $item['id'] ), get_date_from_gmt( $item['date_recorded'], get_option( 'date_format' ) ), get_date_from_gmt( $item['date_recorded'], get_option( 'time_format' ) ) );
1411
-
1412
- // End timestamp
1413
- echo '</div>';
1414
-
1415
- // Get activity content - if not set, use the action
1416
- if ( ! empty( $item['content'] ) ) {
1417
- $content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $item['content'] ) );
1418
- } else {
1419
- $content = apply_filters_ref_array( 'bp_get_activity_action', array( $item['action'] ) );
1420
- }
1421
-
1422
- echo $content . ' ' . $this->row_actions( $actions );
1423
- }
1424
-
1425
- /**
1426
- * "In response to" column markup.
1427
- *
1428
- * @since BuddyPress (1.6.0)
1429
- *
1430
- * @see WP_List_Table::single_row_columns()
1431
- *
1432
- * @param array $item A singular item (one full row).
1433
- */
1434
- function column_response( $item ) {
1435
- // Is $item is a root activity?
1436
- if ( empty( $item['item_id'] ) || ! in_array( $item['type'], apply_filters( 'bp_activity_admin_root_activity_types', array( 'activity_comment' ), $item ) ) ) {
1437
- $comment_count = !empty( $item['children'] ) ? bp_activity_recurse_comment_count( (object) $item ) : 0;
1438
- $root_activity_url = bp_get_admin_url( 'admin.php?page=bp-activity&amp;aid=' . $item['id'] );
1439
-
1440
- // If the activity has comments, display a link to the activity's permalink, with its comment count in a speech bubble
1441
- if ( $comment_count ) {
1442
- $title_attr = sprintf( _n( '%s related activity', '%s related activities', $comment_count, 'buddypress' ), number_format_i18n( $comment_count ) );
1443
- printf( '<a href="%1$s" title="%2$s" class="post-com-count"><span class="comment-count">%3$s</span></a>', esc_url( $root_activity_url ), esc_attr( $title_attr ), number_format_i18n( $comment_count ) );
1444
- }
1445
-
1446
- // For non-root activities, display a link to the replied-to activity's author's profile
1447
- } else {
1448
- echo '<strong>' . get_avatar( $this->get_activity_user_id( $item['item_id'] ), '32' ) . ' ' . bp_core_get_userlink( $this->get_activity_user_id( $item['item_id'] ) ) . '</strong><br />';
1449
- }
1450
-
1451
- // Activity permalink
1452
- if ( ! $item['is_spam'] )
1453
- printf( __( '<a href="%1$s">View Activity</a>', 'buddypress' ), bp_activity_get_permalink( $item['id'], (object) $item ) );
1454
- }
1455
-
1456
- /**
1457
- * Get the user id associated with a given activity item.
1458
- *
1459
- * Wraps bp_activity_get_specific(), with some additional logic for
1460
- * avoiding duplicate queries.
1461
- *
1462
- * @since BuddyPress (1.6.0)
1463
- *
1464
- * @param int $activity_id Activity ID to retrieve User ID for.
1465
- * @return int User ID of the activity item in question.
1466
- */
1467
- protected function get_activity_user_id( $activity_id ) {
1468
- // If there is an existing activity/user ID mapping, just return the user ID.
1469
- if ( ! empty( $this->activity_user_id[$activity_id] ) ) {
1470
- return $this->activity_user_id[$activity_id];
1471
-
1472
- /**
1473
- * We don't have a mapping. This means the $activity_id is not on the current
1474
- * page of results, so fetch its details from the database.
1475
- */
1476
- } else {
1477
- $activity = bp_activity_get_specific( array( 'activity_ids' => $activity_id, 'show_hidden' => true, 'spam' => 'all', ) );
1478
-
1479
- /**
1480
- * If, somehow, the referenced activity has been deleted, leaving its associated
1481
- * activites as orphans, use the logged in user's ID to avoid errors.
1482
- */
1483
- if ( empty( $activity['activities'] ) )
1484
- return bp_loggedin_user_id();
1485
-
1486
- // Store the new activity/user ID mapping for any later re-use
1487
- $this->activity_user_id[ $activity['activities'][0]->id ] = $activity['activities'][0]->user_id;
1488
-
1489
- // Return the user ID
1490
- return $activity['activities'][0]->user_id;
1491
- }
1492
- }
1493
-
1494
- /**
1495
- * Checks if an activity item can be replied to.
1496
- *
1497
- * This method merges functionality from {@link bp_activity_can_comment()} and
1498
- * {@link bp_blogs_disable_activity_commenting()}. This is done because the activity
1499
- * list table doesn't use a BuddyPress activity loop, which prevents those
1500
- * functions from working as intended.
1501
- *
1502
- * @since BuddyPress (2.0.0)
1503
- *
1504
- * @param array $item An array version of the BP_Activity_Activity object.
1505
- * @return bool
1506
- */
1507
- protected function can_comment( $item ) {
1508
- $can_comment = true;
1509
-
1510
- if ( $this->disable_blogforum_comments ) {
1511
- switch ( $item['type'] ) {
1512
- case 'new_blog_post' :
1513
- case 'new_blog_comment' :
1514
- case 'new_forum_topic' :
1515
- case 'new_forum_post' :
1516
- $can_comment = false;
1517
- break;
1518
- }
1519
-
1520
- // activity comments supported
1521
- } else {
1522
- // activity comment
1523
- if ( 'activity_comment' == $item['type'] ) {
1524
- // blogs
1525
- if ( bp_is_active( 'blogs' ) ) {
1526
- // grab the parent activity entry
1527
- $parent_activity = new BP_Activity_Activity( $item['item_id'] );
1528
-
1529
- // fetch blog post comment depth and if the blog post's comments are open
1530
- bp_blogs_setup_activity_loop_globals( $parent_activity );
1531
-
1532
- // check if the activity item can be replied to
1533
- if ( false === bp_blogs_can_comment_reply( true, $item ) ) {
1534
- $can_comment = false;
1535
- }
1536
- }
1537
-
1538
- // blog post
1539
- } elseif ( 'new_blog_post' == $item['type'] ) {
1540
- if ( bp_is_active( 'blogs' ) ) {
1541
- bp_blogs_setup_activity_loop_globals( (object) $item );
1542
-
1543
- if ( empty( buddypress()->blogs->allow_comments[$item['id']] ) ) {
1544
- $can_comment = false;
1545
- }
1546
- }
1547
- }
1548
- }
1549
-
1550
- return apply_filters( 'bp_activity_list_table_can_comment', $can_comment );
1551
- }
1552
-
1553
- /**
1554
- * Flatten the activity array.
1555
- *
1556
- * In some cases, BuddyPress gives us a structured tree of activity
1557
- * items plus their comments. This method converts it to a flat array.
1558
- *
1559
- * @since BuddyPress (1.6.0)
1560
- *
1561
- * @param array $tree Source array.
1562
- * @return array Flattened array.
1563
- */
1564
- public static function flatten_activity_array( $tree ){
1565
- foreach ( (array) $tree as $node ) {
1566
- if ( isset( $node->children ) ) {
1567
-
1568
- foreach ( BP_Activity_List_Table::flatten_activity_array( $node->children ) as $child ) {
1569
- $tree[] = $child;
1570
- }
1571
-
1572
- unset( $node->children );
1573
- }
1574
- }
1575
-
1576
- return $tree;
1577
- }
1578
- }
6
  * help text, on which this implementation is heavily based.
7
  *
8
  * @package BuddyPress
9
+ * @subpackage ActivityAdmin
10
+ * @since 1.6.0
11
  */
12
 
13
+ // Exit if accessed directly.
14
+ defined( 'ABSPATH' ) || exit;
15
 
16
+ // Include WP's list table class.
17
  if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
18
 
19
+ if ( ! buddypress()->do_autoload ) {
20
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-list-table.php';
21
+ }
22
+
23
+ // Per_page screen option. Has to be hooked in extremely early.
24
  if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-activity' == $_REQUEST['page'] )
25
  add_filter( 'set-screen-option', 'bp_activity_admin_screen_options', 10, 3 );
26
 
27
  /**
28
  * Register the Activity component admin screen.
29
  *
30
+ * @since 1.6.0
31
  */
32
  function bp_activity_add_admin_menu() {
33
 
34
+ // Add our screen.
35
  $hook = add_menu_page(
36
+ _x( 'Activity', 'Admin Dashbord SWA page title', 'buddypress' ),
37
+ _x( 'Activity', 'Admin Dashbord SWA menu', 'buddypress' ),
38
  'bp_moderate',
39
  'bp-activity',
40
  'bp_activity_admin',
53
  * which all appear together in the middle of the Dashboard menu. This function
54
  * adds the Activity page to the array of these menu items.
55
  *
56
+ * @since 1.7.0
57
  *
58
  * @param array $custom_menus The list of top-level BP menu items.
59
+ * @return array $custom_menus List of top-level BP menu items, with Activity added.
60
  */
61
  function bp_activity_admin_menu_order( $custom_menus = array() ) {
62
  array_push( $custom_menus, 'bp-activity' );
70
  * Processes requests to add new activity comments, and echoes HTML for a new
71
  * table row.
72
  *
73
+ * @since 1.6.0
74
  */
75
  function bp_activity_admin_reply() {
76
+ // Check nonce.
77
  check_ajax_referer( 'bp-activity-admin-reply', '_ajax_nonce-bp-activity-admin-reply' );
78
 
79
  $parent_id = ! empty( $_REQUEST['parent_id'] ) ? (int) $_REQUEST['parent_id'] : 0;
83
  if ( empty( $parent_id ) )
84
  die( '-1' );
85
 
86
+ // If $root_id not set (e.g. for root items), use $parent_id.
87
  if ( empty( $root_id ) )
88
  $root_id = $parent_id;
89
 
90
+ // Check that a reply has been entered.
91
  if ( empty( $_REQUEST['content'] ) )
92
  die( __( 'ERROR: Please type a reply.', 'buddypress' ) );
93
 
94
+ // Check parent activity exists.
95
  $parent_activity = new BP_Activity_Activity( $parent_id );
96
  if ( empty( $parent_activity->component ) )
97
  die( __( 'ERROR: The item you are trying to reply to cannot be found, or it has been deleted.', 'buddypress' ) );
101
  if ( ! current_user_can( 'bp_moderate' ) )
102
  die( '-1' );
103
 
104
+ // Add new activity comment.
105
  $new_activity_id = bp_activity_new_comment( array(
106
+ 'activity_id' => $root_id, // ID of the root activity item.
107
  'content' => $_REQUEST['content'],
108
+ 'parent_id' => $parent_id, // ID of a parent comment.
109
  ) );
110
 
111
+ // Fetch the new activity item, as we need it to create table markup to return.
112
  $new_activity = new BP_Activity_Activity( $new_activity_id );
113
 
114
+ // This needs to be set for the BP_Activity_List_Table constructor to work.
115
  set_current_screen( 'toplevel_page_bp-activity' );
116
 
117
+ // Set up an output buffer.
118
  ob_start();
119
  $list_table = new BP_Activity_List_Table();
120
  $list_table->single_row( (array) $new_activity );
121
 
122
+ // Get table markup.
123
  $response = array(
124
  'data' => ob_get_contents(),
125
  'id' => $new_activity_id,
128
  );
129
  ob_end_clean();
130
 
131
+ // Send response.
132
  $r = new WP_Ajax_Response();
133
  $r->add( $response );
134
  $r->send();
140
  /**
141
  * Handle save/update of screen options for the Activity component admin screen.
142
  *
143
+ * @since 1.6.0
144
  *
145
+ * @param string $value Will always be false unless another plugin filters it first.
146
+ * @param string $option Screen option name.
 
147
  * @param string $new_value Screen option form value.
148
  * @return string Option value. False to abandon update.
149
  */
151
  if ( 'toplevel_page_bp_activity_per_page' != $option && 'toplevel_page_bp_activity_network_per_page' != $option )
152
  return $value;
153
 
154
+ // Per page.
155
  $new_value = (int) $new_value;
156
  if ( $new_value < 1 || $new_value > 999 )
157
  return $value;
162
  /**
163
  * Hide the advanced edit meta boxes by default, so we don't clutter the screen.
164
  *
165
+ * @since 1.6.0
166
  *
167
+ * @param array $hidden Array of items to hide.
168
  * @param WP_Screen $screen Screen identifier.
169
  * @return array Hidden Meta Boxes.
170
  */
172
  if ( empty( $screen->id ) || 'toplevel_page_bp-activity' != $screen->id && 'toplevel_page_bp-activity_network' != $screen->id )
173
  return $hidden;
174
 
175
+ // Hide the primary link meta box by default.
176
  $hidden = array_merge( (array) $hidden, array( 'bp_activity_itemids', 'bp_activity_link', 'bp_activity_type', 'bp_activity_userid', ) );
177
 
178
+ /**
179
+ * Filters default hidden metaboxes so plugins can alter list.
180
+ *
181
+ * @since 1.6.0
182
+ *
183
+ * @param array $hidden Default metaboxes to hide.
184
+ * @param WP_Screen $screen Screen identifier.
185
+ */
186
  return apply_filters( 'bp_hide_meta_boxes', array_unique( $hidden ), $screen );
187
  }
188
  add_filter( 'default_hidden_meta_boxes', 'bp_activity_admin_edit_hidden_metaboxes', 10, 2 );
192
  *
193
  * Does the following:
194
  * - Register contextual help and screen options for this admin page.
195
+ * - Enqueues scripts and styles.
196
+ * - Catches POST and GET requests related to Activity.
197
  *
198
+ * @since 1.6.0
199
  *
200
+ * @global object $bp BuddyPress global settings.
201
  * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list table.
202
  */
203
  function bp_activity_admin_load() {
204
  global $bp_activity_list_table;
205
 
206
+ $bp = buddypress();
 
 
 
 
207
  $doaction = bp_admin_list_table_current_bulk_action();
208
+ $min = bp_core_get_minified_asset_suffix();
209
 
210
+ /**
211
+ * Fires at top of Activity admin page.
212
+ *
213
+ * @since 1.6.0
214
+ *
215
+ * @param string $doaction Current $_GET action being performed in admin screen.
216
+ */
217
  do_action( 'bp_activity_admin_load', $doaction );
218
 
219
+ // Edit screen.
220
  if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) ) {
221
+ // Columns screen option.
222
  add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) );
223
 
224
  get_current_screen()->add_help_tab( array(
235
  'title' => __( 'Item, Link, Type', 'buddypress' ),
236
  'content' =>
237
  '<p>' . __( '<strong>Primary Item/Secondary Item</strong> - These identify the object that created the activity. For example, the fields could reference a comment left on a specific site. Some types of activity may only use one, or none, of these fields.', 'buddypress' ) . '</p>' .
238
+ '<p>' . __( '<strong>Link</strong> - Used by some types of activity (e.g blog posts and comments, and forum topics and replies) to store a link back to the original content.', 'buddypress' ) . '</p>' .
239
  '<p>' . __( '<strong>Type</strong> - Each distinct kind of activity has its own type. For example, <code>created_group</code> is used when a group is created and <code>joined_group</code> is used when a user joins a group.', 'buddypress' ) . '</p>' .
240
  '<p>' . __( 'For information about when and how BuddyPress uses all of these settings, see the Managing Activity link in the panel to the side.', 'buddypress' ) . '</p>'
241
  ) );
242
 
243
+ // Help panel - sidebar links.
244
  get_current_screen()->set_help_sidebar(
245
  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
246
+ '<p>' . __( '<a href="https://codex.buddypress.org/administrator-guide/activity-stream-management-panels/">Managing Activity</a>', 'buddypress' ) . '</p>' .
247
+ '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
248
  );
249
 
250
  // Register metaboxes for the edit screen.
254
  add_meta_box( 'bp_activity_type', _x( 'Type', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_type', get_current_screen()->id, 'normal', 'core' );
255
  add_meta_box( 'bp_activity_userid', _x( 'Author ID', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_userid', get_current_screen()->id, 'normal', 'core' );
256
 
257
+ /**
258
+ * Fires after the registration of all of the default activity meta boxes.
259
+ *
260
+ * @since 2.4.0
261
+ */
262
+ do_action( 'bp_activity_admin_meta_boxes' );
263
+
264
+ // Enqueue JavaScript files.
265
  wp_enqueue_script( 'postbox' );
266
  wp_enqueue_script( 'dashboard' );
267
  wp_enqueue_script( 'comment' );
268
 
269
+ // Index screen.
270
  } else {
271
+ // Create the Activity screen list table.
272
  $bp_activity_list_table = new BP_Activity_List_Table();
273
 
274
+ // The per_page screen option.
275
  add_screen_option( 'per_page', array( 'label' => _x( 'Activity', 'Activity items per page (screen options)', 'buddypress' )) );
276
 
277
+ // Help panel - overview text.
278
  get_current_screen()->add_help_tab( array(
279
  'id' => 'bp-activity-overview',
280
  'title' => __( 'Overview', 'buddypress' ),
283
  '<p>' . __( 'There are many different types of activities. Some are generated automatically by BuddyPress and other plugins, and some are entered directly by a user in the form of status update. To help manage the different activity types, use the filter dropdown box to switch between them.', 'buddypress' ) . '</p>'
284
  ) );
285
 
286
+ // Help panel - moderation text.
287
  get_current_screen()->add_help_tab( array(
288
  'id' => 'bp-activity-moderating',
289
  'title' => __( 'Moderating Activity', 'buddypress' ),
292
  '<p>' . __( "In the <strong>In Response To</strong> column, if the activity was in reply to another activity, it shows that activity's author's picture and name, and a link to that activity on your live site. If there is a small bubble, the number in it shows how many other activities are related to this one; these are usually comments. Clicking the bubble will filter the activity screen to show only related activity items.", 'buddypress' ) . '</p>'
293
  ) );
294
 
295
+ // Help panel - sidebar links.
296
  get_current_screen()->set_help_sidebar(
297
  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
298
+ '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
299
  );
300
+
301
+ // Add accessible hidden heading and text for Activity screen pagination.
302
+ if ( bp_get_major_wp_version() >= 4.4 ) {
303
+ get_current_screen()->set_screen_reader_content( array(
304
+ /* translators: accessibility text */
305
+ 'heading_pagination' => __( 'Activity list navigation', 'buddypress' ),
306
+ ) );
307
+ }
308
  }
309
 
310
+ // Enqueue CSS and JavaScript.
311
+ wp_enqueue_script( 'bp_activity_admin_js', $bp->plugin_url . "bp-activity/admin/js/admin{$min}.js", array( 'jquery', 'wp-ajax-response' ), bp_get_version(), true );
312
  wp_localize_script( 'bp_activity_admin_js', 'bp_activity_admin_vars', array(
313
+ 'page' => get_current_screen()->id
314
+ ) );
315
+ wp_enqueue_style( 'bp_activity_admin_css', $bp->plugin_url . "bp-activity/admin/css/admin{$min}.css", array(), bp_get_version() );
316
+
317
+ wp_style_add_data( 'bp_activity_admin_css', 'rtl', true );
318
+ if ( $min ) {
319
+ wp_style_add_data( 'bp_activity_admin_css', 'suffix', $min );
320
+ }
321
 
322
+ /**
323
+ * Fires after the activity js and style has been enqueued.
324
+ *
325
+ * @since 2.4.0
326
+ */
327
+ do_action( 'bp_activity_admin_enqueue_scripts' );
328
+
329
+ // Handle spam/un-spam/delete of activities.
330
  if ( !empty( $doaction ) && ! in_array( $doaction, array( '-1', 'edit', 'save', ) ) ) {
331
 
332
+ // Build redirection URL.
333
  $redirect_to = remove_query_arg( array( 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), wp_get_referer() );
334
  $redirect_to = add_query_arg( 'paged', $bp_activity_list_table->get_pagenum(), $redirect_to );
335
 
336
+ // Get activity IDs.
337
  $activity_ids = array_map( 'absint', (array) $_REQUEST['aid'] );
338
 
339
+ /**
340
+ * Filters list of IDs being spammed/un-spammed/deleted.
341
+ *
342
+ * @since 1.6.0
343
+ *
344
+ * @param array $activity_ids Activity IDs to spam/un-spam/delete.
345
+ */
346
  $activity_ids = apply_filters( 'bp_activity_admin_action_activity_ids', $activity_ids );
347
 
348
  // Is this a bulk request?
349
  if ( 'bulk_' == substr( $doaction, 0, 5 ) && ! empty( $_REQUEST['aid'] ) ) {
350
+ // Check this is a valid form submission.
351
  check_admin_referer( 'bulk-activities' );
352
 
353
+ // Trim 'bulk_' off the action name to avoid duplicating a ton of code.
354
  $doaction = substr( $doaction, 5 );
355
 
356
  // This is a request to delete, spam, or un-spam, a single item.
357
  } elseif ( !empty( $_REQUEST['aid'] ) ) {
358
 
359
+ // Check this is a valid form submission.
360
  check_admin_referer( 'spam-activity_' . $activity_ids[0] );
361
  }
362
 
363
+ // Initialise counters for how many of each type of item we perform an action on.
364
  $deleted = $spammed = $unspammed = 0;
365
 
366
+ // Store any errors that occurs when updating the database items.
367
  $errors = array();
368
 
369
  // "We'd like to shoot the monster, could you move, please?"
370
  foreach ( $activity_ids as $activity_id ) {
371
  // @todo: Check the permissions on each
372
+ // if ( ! current_user_can( 'bp_edit_activity', $activity_id ) )
373
+ // continue;
374
+ // Get the activity from the database.
 
375
  $activity = new BP_Activity_Activity( $activity_id );
376
  if ( empty( $activity->component ) ) {
377
  $errors[] = $activity_id;
399
  bp_activity_mark_as_ham( $activity );
400
  $result = $activity->save();
401
 
402
+ // Check for any error during activity save.
403
  if ( ! $result )
404
  $errors[] = $activity->id;
405
  else
410
  bp_activity_mark_as_spam( $activity );
411
  $result = $activity->save();
412
 
413
+ // Check for any error during activity save.
414
  if ( ! $result )
415
  $errors[] = $activity->id;
416
  else
421
  break;
422
  }
423
 
424
+ // Release memory.
425
  unset( $activity );
426
  }
427
 
428
+ /**
429
+ * Fires before redirect for plugins to do something with activity.
430
+ *
431
+ * Passes an activity array counts how many were spam, not spam, deleted, and IDs that were errors.
432
+ *
433
+ * @since 1.6.0
434
+ *
435
+ * @param array $value Array holding spam, not spam, deleted counts, error IDs.
436
+ * @param string $redirect_to URL to redirect to.
437
+ * @param array $activity_ids Original array of activity IDs.
438
+ */
439
  do_action( 'bp_activity_admin_action_after', array( $spammed, $unspammed, $deleted, $errors ), $redirect_to, $activity_ids );
440
 
441
  // Add arguments to the redirect URL so that on page reload, we can easily display what we've just done.
448
  if ( $deleted )
449
  $redirect_to = add_query_arg( 'deleted', $deleted, $redirect_to );
450
 
451
+ // If an error occurred, pass back the activity ID that failed.
452
  if ( ! empty( $errors ) )
453
  $redirect_to = add_query_arg( 'error', implode ( ',', array_map( 'absint', $errors ) ), $redirect_to );
454
 
455
+ /**
456
+ * Filters redirect URL after activity spamming/un-spamming/deletion occurs.
457
+ *
458
+ * @since 1.6.0
459
+ *
460
+ * @param string $redirect_to URL to redirect to.
461
+ */
462
  wp_redirect( apply_filters( 'bp_activity_admin_action_redirect', $redirect_to ) );
463
  exit;
464
 
465
 
466
+ // Save the edit.
467
  } elseif ( $doaction && 'save' == $doaction ) {
468
+ // Build redirection URL.
469
  $redirect_to = remove_query_arg( array( 'action', 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );
470
 
471
+ // Get activity ID.
472
  $activity_id = (int) $_REQUEST['aid'];
473
 
474
+ // Check this is a valid form submission.
475
  check_admin_referer( 'edit-activity_' . $activity_id );
476
 
477
+ // Get the activity from the database.
478
  $activity = new BP_Activity_Activity( $activity_id );
479
 
480
+ // If the activity doesn't exist, just redirect back to the index.
481
  if ( empty( $activity->component ) ) {
482
  wp_redirect( $redirect_to );
483
  exit;
484
  }
485
 
486
+ // Check the form for the updated properties.
487
+ // Store any error that occurs when updating the database item.
 
488
  $error = 0;
489
 
490
+ // Activity spam status.
491
  $prev_spam_status = $new_spam_status = false;
492
  if ( ! empty( $_POST['activity_status'] ) ) {
493
  $prev_spam_status = $activity->is_spam;
494
  $new_spam_status = ( 'spam' == $_POST['activity_status'] ) ? true : false;
495
  }
496
 
497
+ // Activity action.
498
  if ( isset( $_POST['bp-activities-action'] ) )
499
  $activity->action = $_POST['bp-activities-action'];
500
 
501
+ // Activity content.
502
  if ( isset( $_POST['bp-activities-content'] ) )
503
  $activity->content = $_POST['bp-activities-content'];
504
 
505
+ // Activity primary link.
506
  if ( ! empty( $_POST['bp-activities-link'] ) )
507
  $activity->primary_link = $_POST['bp-activities-link'];
508
 
509
+ // Activity user ID.
510
  if ( ! empty( $_POST['bp-activities-userid'] ) )
511
  $activity->user_id = (int) $_POST['bp-activities-userid'];
512
 
513
+ // Activity item primary ID.
514
  if ( isset( $_POST['bp-activities-primaryid'] ) )
515
  $activity->item_id = (int) $_POST['bp-activities-primaryid'];
516
 
517
+ // Activity item secondary ID.
518
  if ( isset( $_POST['bp-activities-secondaryid'] ) )
519
  $activity->secondary_item_id = (int) $_POST['bp-activities-secondaryid'];
520
 
521
+ // Activity type.
522
  if ( ! empty( $_POST['bp-activities-type'] ) ) {
523
  $actions = bp_activity_admin_get_activity_actions();
524
 
525
+ // Check that the new type is a registered activity type.
526
  if ( in_array( $_POST['bp-activities-type'], $actions ) ) {
527
  $activity->type = $_POST['bp-activities-type'];
528
  }
529
  }
530
 
531
+ // Activity timestamp.
532
  if ( ! empty( $_POST['aa'] ) && ! empty( $_POST['mm'] ) && ! empty( $_POST['jj'] ) && ! empty( $_POST['hh'] ) && ! empty( $_POST['mn'] ) && ! empty( $_POST['ss'] ) ) {
533
  $aa = $_POST['aa'];
534
  $mm = $_POST['mm'];
544
  $mn = ( $mn > 59 ) ? $mn -60 : $mn;
545
  $ss = ( $ss > 59 ) ? $ss -60 : $ss;
546
 
547
+ // Reconstruct the date into a timestamp.
548
  $gmt_date = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
549
 
550
  $activity->date_recorded = $gmt_date;
558
  bp_activity_mark_as_ham( $activity );
559
  }
560
 
561
+ // Save.
562
  $result = $activity->save();
563
 
564
+ // Clear the activity stream first page cache, in case this activity's timestamp was changed.
565
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
566
 
567
+ // Check for any error during activity save.
568
  if ( false === $result )
569
  $error = $activity->id;
570
 
571
+ /**
572
+ * Fires before redirect so plugins can do something first on save action.
573
+ *
574
+ * @since 1.6.0
575
+ *
576
+ * @param array $value Array holding activity object and ID that holds error.
577
+ */
578
  do_action_ref_array( 'bp_activity_admin_edit_after', array( &$activity, $error ) );
579
 
580
+ // If an error occurred, pass back the activity ID that failed.
581
  if ( $error )
582
+ $redirect_to = add_query_arg( 'error', $error, $redirect_to );
583
  else
584
+ $redirect_to = add_query_arg( 'updated', $activity->id, $redirect_to );
585
 
586
+ /**
587
+ * Filters URL to redirect to after saving.
588
+ *
589
+ * @since 1.6.0
590
+ *
591
+ * @param string $redirect_to URL to redirect to.
592
+ */
593
  wp_redirect( apply_filters( 'bp_activity_admin_edit_redirect', $redirect_to ) );
594
  exit;
595
 
604
  /**
605
  * Output the Activity component admin screens.
606
  *
607
+ * @since 1.6.0
608
  */
609
  function bp_activity_admin() {
610
+ // Decide whether to load the index or edit screen.
611
  $doaction = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
612
 
613
+ // Display the single activity edit screen.
614
  if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) )
615
  bp_activity_admin_edit();
616
 
617
+ // Otherwise, display the Activity index screen.
618
  else
619
  bp_activity_admin_index();
620
  }
622
  /**
623
  * Display the single activity edit screen.
624
  *
625
+ * @since 1.6.0
626
  */
627
  function bp_activity_admin_edit() {
628
 
631
  if ( ! is_super_admin() )
632
  die( '-1' );
633
 
634
+ // Get the activity from the database.
635
  $activity = bp_activity_get( array(
636
  'in' => ! empty( $_REQUEST['aid'] ) ? (int) $_REQUEST['aid'] : 0,
637
  'max' => 1,
643
  if ( ! empty( $activity['activities'][0] ) ) {
644
  $activity = $activity['activities'][0];
645
 
646
+ // Workaround to use WP's touch_time() without duplicating that function.
647
  $GLOBALS['comment'] = new stdClass;
648
  $GLOBALS['comment']->comment_date = $activity->date_recorded;
649
  } else {
650
  $activity = '';
651
  }
652
 
653
+ // Construct URL for form.
654
  $form_url = remove_query_arg( array( 'action', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );
655
  $form_url = add_query_arg( 'action', 'save', $form_url );
656
 
657
+ /**
658
+ * Fires before activity edit form is displays so plugins can modify the activity.
659
+ *
660
+ * @since 1.6.0
661
+ *
662
+ * @param array $value Array holding single activity object that was passed by reference.
663
+ */
664
  do_action_ref_array( 'bp_activity_admin_edit', array( &$activity ) ); ?>
665
 
666
  <div class="wrap">
667
+ <h1><?php printf( __( 'Editing Activity (ID #%s)', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?></h1>
 
668
 
669
  <?php if ( ! empty( $activity ) ) : ?>
670
 
671
+ <form action="<?php echo esc_url( $form_url ); ?>" id="bp-activities-edit-form" method="post">
672
  <div id="poststuff">
673
 
674
  <div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
675
  <div id="post-body-content">
676
  <div id="postdiv">
677
  <div id="bp_activity_action" class="postbox">
678
+ <h2><?php _e( 'Action', 'buddypress' ); ?></h2>
679
  <div class="inside">
680
+ <label for="bp-activities-action" class="screen-reader-text"><?php
681
+ /* translators: accessibility text */
682
+ _e( 'Edit activity action', 'buddypress' );
683
+ ?></label>
684
  <?php wp_editor( stripslashes( $activity->action ), 'bp-activities-action', array( 'media_buttons' => false, 'textarea_rows' => 7, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
685
  </div>
686
  </div>
687
 
688
  <div id="bp_activity_content" class="postbox">
689
+ <h2><?php _e( 'Content', 'buddypress' ); ?></h2>
690
  <div class="inside">
691
+ <label for="bp-activities-content" class="screen-reader-text"><?php
692
+ /* translators: accessibility text */
693
+ _e( 'Edit activity content', 'buddypress' );
694
+ ?></label>
695
  <?php wp_editor( stripslashes( $activity->content ), 'bp-activities-content', array( 'media_buttons' => false, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
696
  </div>
697
  </div>
715
  </form>
716
 
717
  <?php else : ?>
718
+
719
+ <p><?php
720
+ printf(
721
+ '%1$s <a href="%2$s">%3$s</a>',
722
+ __( 'No activity found with this ID.', 'buddypress' ),
723
+ esc_url( bp_get_admin_url( 'admin.php?page=bp-activity' ) ),
724
+ __( 'Go back and try again.', 'buddypress' )
725
+ );
726
+ ?></p>
727
+
728
  <?php endif; ?>
729
 
730
  </div><!-- .wrap -->
735
  /**
736
  * Status metabox for the Activity admin edit screen.
737
  *
738
+ * @since 1.6.0
739
  *
740
  * @param object $item Activity item.
741
  */
755
 
756
  <div id="misc-publishing-actions">
757
  <div class="misc-pub-section" id="comment-status-radio">
758
+ <label class="approved" for="activity-status-approved"><input type="radio" name="activity_status" id="activity-status-approved" value="ham" <?php checked( $item->is_spam, 0 ); ?>><?php _e( 'Approved', 'buddypress' ); ?></label><br />
759
+ <label class="spam" for="activity-status-spam"><input type="radio" name="activity_status" id="activity-status-spam" value="spam" <?php checked( $item->is_spam, 1 ); ?>><?php _e( 'Spam', 'buddypress' ); ?></label>
760
  </div>
761
 
762
  <div class="misc-pub-section curtime misc-pub-section-last">
763
  <?php
764
+ // Translators: Publish box date format, see http://php.net/date.
765
  $datef = __( 'M j, Y @ G:i', 'buddypress' );
766
  $date = date_i18n( $datef, strtotime( $item->date_recorded ) );
767
  ?>
768
+ <span id="timestamp"><?php printf( __( 'Submitted on: %s', 'buddypress' ), '<strong>' . $date . '</strong>' ); ?></span>&nbsp;<a href="#edit_timestamp" class="edit-timestamp hide-if-no-js" tabindex='4'><?php _e( 'Edit', 'buddypress' ); ?></a>
769
 
770
  <div id='timestampdiv' class='hide-if-js'>
771
  <?php touch_time( 1, 0, 5 ); ?>
778
 
779
  <div id="major-publishing-actions">
780
  <div id="publishing-action">
781
+ <?php submit_button( __( 'Update', 'buddypress' ), 'primary', 'save', false ); ?>
782
  </div>
783
  <div class="clear"></div>
784
  </div><!-- #major-publishing-actions -->
791
  /**
792
  * Primary link metabox for the Activity admin edit screen.
793
  *
794
+ * @since 1.6.0
795
  *
796
  * @param object $item Activity item.
797
  */
798
  function bp_activity_admin_edit_metabox_link( $item ) {
799
  ?>
800
 
801
+ <label class="screen-reader-text" for="bp-activities-link"><?php
802
+ /* translators: accessibility text */
803
+ _e( 'Link', 'buddypress' );
804
+ ?></label>
805
+ <input type="url" name="bp-activities-link" id="bp-activities-link" value="<?php echo esc_url( $item->primary_link ); ?>" aria-describedby="bp-activities-link-description" />
806
+ <p id="bp-activities-link-description"><?php _e( 'Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item.', 'buddypress' ); ?></p>
807
 
808
  <?php
809
  }
811
  /**
812
  * User ID metabox for the Activity admin edit screen.
813
  *
814
+ * @since 1.6.0
815
  *
816
  * @param object $item Activity item.
817
  */
818
  function bp_activity_admin_edit_metabox_userid( $item ) {
819
  ?>
820
 
821
+ <label class="screen-reader-text" for="bp-activities-userid"><?php
822
+ /* translators: accessibility text */
823
+ _e( 'Author ID', 'buddypress' );
824
+ ?></label>
825
+ <input type="number" name="bp-activities-userid" id="bp-activities-userid" value="<?php echo esc_attr( $item->user_id ); ?>" min="1" />
826
 
827
  <?php
828
  }
832
  *
833
  * Format is [activity_type] => Pretty name for activity type.
834
  *
835
+ * @since 2.0.0
836
  *
837
+ * @return array $actions
838
  */
839
  function bp_activity_admin_get_activity_actions() {
840
  $actions = array();
841
 
842
  // Walk through the registered actions, and build an array of actions/values.
843
+ foreach ( bp_activity_get_actions() as $action ) {
844
  $action = array_values( (array) $action );
845
 
846
  for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
848
  }
849
  }
850
 
851
+ // This was a mis-named activity type from before BP 1.6.
852
  unset( $actions['friends_register_activity_action'] );
853
 
854
+ // Sort array by the human-readable value.
855
  natsort( $actions );
856
 
857
  return $actions;
858
  }
859
 
860
  /**
861
+ * Activity type metabox for the Activity admin edit screen.
862
  *
863
+ * @since 1.6.0
 
 
864
  *
865
  * @param object $item Activity item.
866
  */
867
  function bp_activity_admin_edit_metabox_type( $item ) {
868
+ $bp = buddypress();
869
 
870
  $actions = array();
871
  $selected = $item->type;
872
 
873
  // Walk through the registered actions, and build an array of actions/values.
874
+ foreach ( bp_activity_get_actions() as $action ) {
875
  $action = array_values( (array) $action );
876
 
877
  for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
878
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
879
  }
880
 
881
+ // This was a mis-named activity type from before BP 1.6.
882
  unset( $actions['friends_register_activity_action'] );
883
 
884
+ // Sort array by the human-readable value.
885
  natsort( $actions );
886
 
887
+ /*
888
+ * If the activity type is not registered properly (eg, a plugin has
889
+ * not called bp_activity_set_action()), add the raw type to the end
890
+ * of the list.
891
+ */
892
  if ( ! isset( $actions[ $selected ] ) ) {
893
  _doing_it_wrong( __FUNCTION__, sprintf( __( 'This activity item has a type (%s) that is not registered using bp_activity_set_action(), so no label is available.', 'buddypress' ), $selected ), '2.0.0' );
894
  $actions[ $selected ] = $selected;
896
 
897
  ?>
898
 
899
+ <label for="bp-activities-type" class="screen-reader-text"><?php
900
+ /* translators: accessibility text */
901
+ esc_html_e( 'Select activity type', 'buddypress' );
902
+ ?></label>
903
+ <select name="bp-activities-type" id="bp-activities-type">
904
  <?php foreach ( $actions as $k => $v ) : ?>
905
  <option value="<?php echo esc_attr( $k ); ?>" <?php selected( $k, $selected ); ?>><?php echo esc_html( $v ); ?></option>
906
  <?php endforeach; ?>
912
  /**
913
  * Primary item ID/Secondary item ID metabox for the Activity admin edit screen.
914
  *
915
+ * @since 1.6.0
916
  *
917
  * @param object $item Activity item.
918
  */
934
  /**
935
  * Display the Activity admin index screen, which contains a list of all the activities.
936
  *
937
+ * @since 1.6.0
938
  *
939
+ * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list table.
940
+ * @global string $plugin_page The current plugin page.
 
941
  */
942
  function bp_activity_admin_index() {
943
  global $bp_activity_list_table, $plugin_page;
944
 
945
  $messages = array();
946
 
947
+ // If the user has just made a change to an activity item, build status messages.
948
  if ( ! empty( $_REQUEST['deleted'] ) || ! empty( $_REQUEST['spammed'] ) || ! empty( $_REQUEST['unspammed'] ) || ! empty( $_REQUEST['error'] ) || ! empty( $_REQUEST['updated'] ) ) {
949
  $deleted = ! empty( $_REQUEST['deleted'] ) ? (int) $_REQUEST['deleted'] : 0;
950
  $errors = ! empty( $_REQUEST['error'] ) ? $_REQUEST['error'] : '';
954
 
955
  $errors = array_map( 'absint', explode( ',', $errors ) );
956
 
957
+ // Make sure we don't get any empty values in $errors.
958
  for ( $i = 0, $errors_count = count( $errors ); $i < $errors_count; $i++ ) {
959
  if ( 0 === $errors[$i] ) {
960
  unset( $errors[$i] );
961
  }
962
  }
963
 
964
+ // Reindex array.
965
  $errors = array_values( $errors );
966
 
967
  if ( $deleted > 0 )
975
  $error_msg = __( 'Errors occurred when trying to update these activity items:', 'buddypress' );
976
  $error_msg .= '<ul class="activity-errors">';
977
 
978
+ // Display each error as a list item.
979
  foreach ( $errors as $error ) {
980
+ // Translators: This is a bulleted list of item IDs.
981
  $error_msg .= '<li>' . sprintf( __( '#%s', 'buddypress' ), number_format_i18n( $error ) ) . '</li>';
982
  }
983
 
993
  $messages[] = sprintf( _n( '%s activity item has been successfully unspammed.', '%s activity items have been successfully unspammed.', $unspammed, 'buddypress' ), number_format_i18n( $unspammed ) );
994
 
995
  if ( $updated > 0 )
996
+ $messages[] = __( 'The activity item has been updated successfully.', 'buddypress' );
997
  }
998
 
999
+ // Prepare the activity items for display.
1000
  $bp_activity_list_table->prepare_items();
1001
 
1002
+ /**
1003
+ * Fires before edit form is displayed so plugins can modify the activity messages.
1004
+ *
1005
+ * @since 1.6.0
1006
+ *
1007
+ * @param array $messages Array of messages to display at top of page.
1008
+ */
1009
  do_action( 'bp_activity_admin_index', $messages ); ?>
1010
 
1011
  <div class="wrap">
1012
+ <h1>
 
1013
  <?php if ( !empty( $_REQUEST['aid'] ) ) : ?>
1014
  <?php printf( __( 'Activity related to ID #%s', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?>
1015
  <?php else : ?>
1016
+ <?php _ex( 'Activity', 'Admin SWA page', 'buddypress' ); ?>
1017
  <?php endif; ?>
1018
 
1019
  <?php if ( !empty( $_REQUEST['s'] ) ) : ?>
1020
  <span class="subtitle"><?php printf( __( 'Search results for &#8220;%s&#8221;', 'buddypress' ), wp_html_excerpt( esc_html( stripslashes( $_REQUEST['s'] ) ), 50 ) ); ?></span>
1021
  <?php endif; ?>
1022
+ </h1>
1023
 
1024
+ <?php // If the user has just made a change to an activity item, display the status messages. ?>
1025
  <?php if ( !empty( $messages ) ) : ?>
1026
  <div id="moderated" class="<?php echo ( ! empty( $_REQUEST['error'] ) ) ? 'error' : 'updated'; ?>"><p><?php echo implode( "<br/>\n", $messages ); ?></p></div>
1027
  <?php endif; ?>
1028
 
1029
+ <?php // Display each activity on its own row. ?>
1030
  <?php $bp_activity_list_table->views(); ?>
1031
 
1032
  <form id="bp-activities-form" action="" method="get">
1035
  <?php $bp_activity_list_table->display(); ?>
1036
  </form>
1037
 
1038
+ <?php // This markup is used for the reply form. ?>
1039
  <table style="display: none;">
1040
  <tr id="bp-activities-container" style="display: none;">
1041
  <td colspan="4">
1042
  <form method="get" action="">
1043
 
1044
+ <h3 id="bp-replyhead"><?php _e( 'Reply to Activity', 'buddypress' ); ?></h3>
1045
+ <label for="bp-activities" class="screen-reader-text"><?php
1046
+ /* translators: accessibility text */
1047
+ _e( 'Reply', 'buddypress' );
1048
+ ?></label>
1049
  <?php wp_editor( '', 'bp-activities', array( 'dfw' => false, 'media_buttons' => false, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ), 'tinymce' => false, ) ); ?>
1050
 
1051
  <p id="bp-replysubmit" class="submit">
1052
  <a href="#" class="cancel button-secondary alignleft"><?php _e( 'Cancel', 'buddypress' ); ?></a>
1053
  <a href="#" class="save button-primary alignright"><?php _e( 'Reply', 'buddypress' ); ?></a>
1054
 
1055
+ <img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
1056
  <span class="error" style="display:none;"></span>
1057
  <br class="clear" />
1058
  </p>
1067
 
1068
  <?php
1069
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bp-activity/bp-activity-adminbar.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Toolbar.
4
+ *
5
+ * Handles the activity functions related to the WordPress Toolbar.
6
+ *
7
+ * @package BuddyPress
8
+ * @subpackage Activity
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ /**
15
+ * Add the Activity top-level menu link when viewing single activity item.
16
+ *
17
+ * @since 2.6.0
18
+ *
19
+ * @return null Null if user does not have access to editing functionality.
20
+ */
21
+ function bp_activity_admin_menu() {
22
+ global $wp_admin_bar;
23
+
24
+ // Only show if viewing a single activity item.
25
+ if ( ! bp_is_single_activity() ) {
26
+ return;
27
+ }
28
+
29
+ // Only show this menu to super admins
30
+ if ( ! bp_current_user_can( 'bp_moderate' ) ) {
31
+ return;
32
+ }
33
+
34
+ $activity_edit_link = add_query_arg( array(
35
+ 'page' => 'bp-activity',
36
+ 'aid' => bp_current_action(),
37
+ 'action' => 'edit'
38
+ ), bp_get_admin_url( 'admin.php' ) );
39
+
40
+ // Add the top-level Edit Activity button.
41
+ $wp_admin_bar->add_menu( array(
42
+ 'id' => 'activity-admin',
43
+ 'title' => __( 'Edit Activity', 'buddypress' ),
44
+ 'href' => esc_url( $activity_edit_link ),
45
+ ) );
46
+ }
47
+ add_action( 'admin_bar_menu', 'bp_activity_admin_menu', 99 );
bp-activity/bp-activity-akismet.php CHANGED
@@ -3,620 +3,65 @@
3
  * Akismet support for BuddyPress' Activity Stream.
4
  *
5
  * @package BuddyPress
6
- * @since BuddyPress (1.6)
7
- * @subpackage Activity
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
 
 
 
 
12
 
13
  /**
14
- * Akismet support for the Activity component.
15
  *
16
- * @since BuddyPress (1.6)
 
17
  */
18
- class BP_Akismet {
19
- /**
20
- * The activity last marked as spam.
21
- *
22
- * @access protected
23
- * @var BP_Activity_Activity
24
- * @since BuddyPress (1.6)
25
- */
26
- protected $last_activity = null;
27
-
28
- /**
29
- * Constructor.
30
- *
31
- * @since BuddyPress (1.6)
32
- */
33
- public function __construct() {
34
- $this->setup_actions();
35
- }
36
-
37
- /**
38
- * Hook Akismet into the activity stream.
39
- *
40
- * @since BuddyPress (1.6)
41
- */
42
- protected function setup_actions() {
43
- // Add nonces to activity stream lists
44
- add_action( 'bp_after_activity_post_form', array( $this, 'add_activity_stream_nonce' ) );
45
- add_action( 'bp_activity_entry_comments', array( $this, 'add_activity_stream_nonce' ) );
46
-
47
- // Add a "mark as spam" button to individual activity items
48
- add_action( 'bp_activity_entry_meta', array( $this, 'add_activity_spam_button' ) );
49
- add_action( 'bp_activity_comment_options', array( $this, 'add_activity_comment_spam_button' ) );
50
-
51
- // Check activity for spam
52
- add_action( 'bp_activity_before_save', array( $this, 'check_activity' ), 4, 1 );
53
-
54
- // Tidy up member's latest (activity) update
55
- add_action( 'bp_activity_posted_update', array( $this, 'check_member_activity_update' ), 1, 3 );
56
-
57
- // Hooks to extend Activity core spam/ham functions for Akismet
58
- add_action( 'bp_activity_mark_as_spam', array( $this, 'mark_as_spam' ), 10, 2 );
59
- add_action( 'bp_activity_mark_as_ham', array( $this, 'mark_as_ham' ), 10, 2 );
60
-
61
- // Hook into the Activity wp-admin screen
62
- add_action( 'bp_activity_admin_comment_row_actions', array( $this, 'comment_row_action' ), 10, 2 );
63
- add_action( 'bp_activity_admin_load', array( $this, 'add_history_metabox' ) );
64
- }
65
-
66
- /**
67
- * Add a history item to the hover links in an activity's row.
68
- *
69
- * This function lifted with love from the Akismet WordPress plugin's
70
- * akismet_comment_row_action() function. Thanks!
71
- *
72
- * @since BuddyPress (1.6)
73
- *
74
- * @param array $actions The hover links.
75
- * @param array $activity The activity for the current row being processed.
76
- * @return array The hover links.
77
- */
78
- function comment_row_action( $actions, $activity ) {
79
- $akismet_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_result' );
80
- $user_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_user_result' );
81
- $desc = '';
82
-
83
- if ( !$user_result || $user_result == $akismet_result ) {
84
- // Show the original Akismet result if the user hasn't overridden it, or if their decision was the same
85
- if ( 'true' == $akismet_result && $activity['is_spam'] )
86
- $desc = __( 'Flagged as spam by Akismet', 'buddypress' );
87
-
88
- elseif ( 'false' == $akismet_result && !$activity['is_spam'] )
89
- $desc = __( 'Cleared by Akismet', 'buddypress' );
90
-
91
- } else {
92
- $who = bp_activity_get_meta( $activity['id'], '_bp_akismet_user' );
93
-
94
- if ( 'true' == $user_result )
95
- $desc = sprintf( __( 'Flagged as spam by %s', 'buddypress' ), $who );
96
- else
97
- $desc = sprintf( __( 'Un-spammed by %s', 'buddypress' ), $who );
98
- }
99
-
100
- // add a History item to the hover links, just after Edit
101
- if ( $akismet_result ) {
102
- $b = array();
103
- foreach ( $actions as $k => $item ) {
104
- $b[ $k ] = $item;
105
- if ( $k == 'edit' )
106
- $b['history'] = '<a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&amp;action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history"> '. __( 'History', 'buddypress' ) . '</a>';
107
- }
108
-
109
- $actions = $b;
110
- }
111
-
112
- if ( $desc )
113
- echo '<span class="akismet-status"><a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&amp;action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history">' . htmlspecialchars( $desc ) . '</a></span>';
114
-
115
- return apply_filters( 'bp_akismet_comment_row_action', $actions );
116
- }
117
-
118
- /**
119
- * Generate nonces for activity forms.
120
- *
121
- * These nonces appear in the member profile status form, as well as in
122
- * the reply form of each activity item. The nonces are, in turn, used
123
- * by Akismet to help detect spam activity.
124
- *
125
- * @since BuddyPress (1.6)
126
- *
127
- * @see http://plugins.trac.wordpress.org/ticket/1232
128
- */
129
- public function add_activity_stream_nonce() {
130
- $form_id = '_bp_as_nonce';
131
- $value = '_bp_as_nonce_' . bp_loggedin_user_id();
132
-
133
- // If we're in the activity stream loop, we can use the current item's ID to make the nonce unique
134
- if ( 'bp_activity_entry_comments' == current_filter() ) {
135
- $form_id .= '_' . bp_get_activity_id();
136
- $value .= '_' . bp_get_activity_id();
137
- }
138
-
139
- wp_nonce_field( $value, $form_id, false );
140
- }
141
-
142
- /**
143
- * Clean up the bp_latest_update usermeta in case of spamming.
144
- *
145
- * Run just after an update is posted, this method check to see whether
146
- * the newly created update has been marked as spam by Akismet. If so,
147
- * the cached update is cleared from the user's 'bp_latest_update'
148
- * usermeta, ensuring that it won't appear in the member header and
149
- * elsewhere in the theme.
150
- *
151
- * This can't be done in BP_Akismet::check_activity() due to the
152
- * default AJAX implementation; see bp_dtheme_post_update().
153
- *
154
- * @since BuddyPress (1.6)
155
- *
156
- * @see bp_dtheme_post_update()
157
- *
158
- * @param string $content Activity update text.
159
- * @param int $user_id User ID.
160
- * @param int $activity_id Activity ID.
161
- */
162
- public function check_member_activity_update( $content, $user_id, $activity_id ) {
163
- // By default, only handle activity updates and activity comments.
164
- if ( empty( $this->last_activity ) || !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )
165
- return;
166
-
167
- // Was this $activity_id just marked as spam? If not, bail out.
168
- if ( !$this->last_activity->id || $activity_id != $this->last_activity->id || 'false' == $this->last_activity->akismet_submission['bp_as_result'] )
169
- return;
170
-
171
- // It was, so delete the member's latest activity update.
172
- bp_delete_user_meta( $user_id, 'bp_latest_update' );
173
- }
174
-
175
- /**
176
- * Adds a "mark as spam" button to each activity item for site admins.
177
- *
178
- * This function is intended to be used inside the activity stream loop.
179
- *
180
- * @since BuddyPress (1.6)
181
- */
182
- public function add_activity_spam_button() {
183
- if ( !bp_activity_user_can_mark_spam() )
184
- return;
185
-
186
- // By default, only handle activity updates and activity comments.
187
- if ( !in_array( bp_get_activity_type(), BP_Akismet::get_activity_types() ) )
188
- return;
189
-
190
- bp_button(
191
- array(
192
- 'block_self' => false,
193
- 'component' => 'activity',
194
- 'id' => 'activity_make_spam_' . bp_get_activity_id(),
195
- 'link_class' => 'bp-secondary-action spam-activity confirm button item-button',
196
- 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_id() . '/', 'bp_activity_akismet_spam_' . bp_get_activity_id() ),
197
- 'link_text' => __( 'Spam', 'buddypress' ),
198
- 'wrapper' => false,
199
- )
200
- );
201
- }
202
-
203
- /**
204
- * Adds a "mark as spam" button to each activity COMMENT item for site admins.
205
- *
206
- * This function is intended to be used inside the activity stream loop.
207
- *
208
- * @since BuddyPress (1.6)
209
- */
210
- public function add_activity_comment_spam_button() {
211
- if ( !bp_activity_user_can_mark_spam() )
212
- return;
213
-
214
- // By default, only handle activity updates and activity comments.
215
- $current_comment = bp_activity_current_comment();
216
- if ( empty( $current_comment ) || !in_array( $current_comment->type, BP_Akismet::get_activity_types() ) )
217
- return;
218
-
219
- bp_button(
220
- array(
221
- 'block_self' => false,
222
- 'component' => 'activity',
223
- 'id' => 'activity_make_spam_' . bp_get_activity_comment_id(),
224
- 'link_class' => 'bp-secondary-action spam-activity-comment confirm',
225
- 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_comment_id() . '/?cid=' . bp_get_activity_comment_id(), 'bp_activity_akismet_spam_' . bp_get_activity_comment_id() ),
226
- 'link_text' => __( 'Spam', 'buddypress' ),
227
- 'wrapper' => false,
228
- )
229
- );
230
- }
231
-
232
- /**
233
- * Get a filterable list of activity types that Akismet should automatically check for spam.
234
- *
235
- * @since BuddyPress (1.6)
236
- *
237
- * @static
238
- *
239
- * @return array List of activity types.
240
- */
241
- public static function get_activity_types() {
242
- return apply_filters( 'bp_akismet_get_activity_types', array( 'activity_comment', 'activity_update' ) );
243
- }
244
-
245
- /**
246
- * Mark activity item as spam.
247
- *
248
- * @since BuddyPress (1.6)
249
- *
250
- * @param BP_Activity_Activity $activity
251
- * @param string $source Either "by_a_person" (e.g. a person has manually marked the activity as spam) or "by_akismet" (automatically spammed).
252
- */
253
- public function mark_as_spam( $activity, $source ) {
254
- // Record this item so we can do some tidyup in BP_Akismet::check_member_activity_update()
255
- $this->last_activity = $activity;
256
-
257
- do_action( 'bp_activity_akismet_mark_as_spam', $activity, $source );
258
- }
259
-
260
- /**
261
- * Mark activity item as ham.
262
- *
263
- * @since BuddyPress (1.6)
264
- *
265
- * @param BP_Activity_Activity $activity
266
- * @param string $source Either "by_a_person" (e.g. a person has manually marked the activity as ham) or "by_akismet" (automatically hammed).
267
- */
268
- public function mark_as_ham( $activity, $source ) {
269
- // If the activity was, originally, automatically marked as spam by Akismet, run the @mentions filter as it would have been skipped.
270
- if ( 'true' == bp_activity_get_meta( $activity->id, '_bp_akismet_result' ) && !bp_activity_get_meta( $activity->id, '_bp_akismet_user_result' ) )
271
- $activity->content = bp_activity_at_name_filter( $activity->content, $activity->id );
272
-
273
- do_action( 'bp_activity_akismet_mark_as_ham', $activity, $source );
274
- }
275
-
276
- /**
277
- * Build a data package for the Akismet service to inspect.
278
- *
279
- * @since BuddyPress (1.6)
280
- *
281
- * @see http://akismet.com/development/api/#comment-check
282
- * @static
283
- *
284
- * @param BP_Activity_Activity $activity Activity item data.
285
- */
286
- public static function build_akismet_data_package( $activity ) {
287
- $userdata = get_userdata( $activity->user_id );
288
-
289
- $activity_data = array();
290
- $activity_data['akismet_comment_nonce'] = 'inactive';
291
- $activity_data['comment_author'] = $userdata->display_name;
292
- $activity_data['comment_author_email'] = $userdata->user_email;
293
- $activity_data['comment_author_url'] = bp_core_get_userlink( $userdata->ID, false, true);
294
- $activity_data['comment_content'] = $activity->content;
295
- $activity_data['comment_type'] = $activity->type;
296
- $activity_data['permalink'] = bp_activity_get_permalink( $activity->id, $activity );
297
- $activity_data['user_ID'] = $userdata->ID;
298
- $activity_data['user_role'] = akismet_get_user_roles( $userdata->ID );
299
-
300
- /**
301
- * Get the nonce if the new activity was submitted through the "what's up, Paul?" form.
302
- * This helps Akismet ensure that the update was a valid form submission.
303
- */
304
- if ( !empty( $_POST['_bp_as_nonce'] ) )
305
- $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST['_bp_as_nonce'], "_bp_as_nonce_{$userdata->ID}" ) ? 'passed' : 'failed';
306
-
307
- /**
308
- * If the new activity was a reply to an existing item, check the nonce with the activity parent ID.
309
- * This helps Akismet ensure that the update was a valid form submission.
310
- */
311
- elseif ( !empty( $activity->secondary_item_id ) && !empty( $_POST['_bp_as_nonce_' . $activity->secondary_item_id] ) )
312
- $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST["_bp_as_nonce_{$activity->secondary_item_id}"], "_bp_as_nonce_{$userdata->ID}_{$activity->secondary_item_id}" ) ? 'passed' : 'failed';
313
-
314
- return apply_filters( 'bp_akismet_build_akismet_data_package', $activity_data, $activity );
315
- }
316
-
317
- /**
318
- * Check if the activity item is spam or ham.
319
- *
320
- * @since BuddyPress (1.6)
321
- *
322
- * @see http://akismet.com/development/api/
323
- * @todo Spam counter?
324
- * @todo Auto-delete old spam?
325
- *
326
- * @param BP_Activity_Activity $activity The activity item to check.
327
- */
328
- public function check_activity( $activity ) {
329
- // By default, only handle activity updates and activity comments.
330
- if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
331
- return;
332
-
333
- // Make sure last_activity is clear to avoid any confusion
334
- $this->last_activity = null;
335
-
336
- // Build data package for Akismet
337
- $activity_data = BP_Akismet::build_akismet_data_package( $activity );
338
-
339
- // Check with Akismet to see if this is spam
340
- $activity_data = $this->send_akismet_request( $activity_data, 'check', 'spam' );
341
-
342
- // Record this item
343
- $this->last_activity = $activity;
344
-
345
- // Store a copy of the data that was submitted to Akismet
346
- $this->last_activity->akismet_submission = $activity_data;
347
-
348
- // Spam
349
- if ( 'true' == $activity_data['bp_as_result'] ) {
350
- // Action for plugin authors
351
- do_action_ref_array( 'bp_activity_akismet_spam_caught', array( &$activity, $activity_data ) );
352
-
353
- // Mark as spam
354
- bp_activity_mark_as_spam( $activity, 'by_akismet' );
355
- }
356
-
357
- // Update activity meta after a spam check
358
- add_action( 'bp_activity_after_save', array( $this, 'update_activity_akismet_meta' ), 1, 1 );
359
- }
360
-
361
  /**
362
- * Update activity meta after a manual spam change (user-initiated).
363
  *
364
- * @since BuddyPress (1.6)
365
  *
366
- * @param BP_Activity_Activity $activity The activity to check.
367
  */
368
- public function update_activity_spam_meta( $activity ) {
369
- // By default, only handle activity updates and activity comments.
370
- if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
371
- return;
372
-
373
- $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-spam' );
374
- bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'true' );
375
- bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );
376
- }
377
-
378
- /**
379
- * Update activity meta after a manual ham change (user-initiated).
380
- *
381
- * @since BuddyPress (1.6)
382
- *
383
- * @param BP_Activity_Activity $activity The activity to check.
384
- */
385
- public function update_activity_ham_meta( $activity ) {
386
- // By default, only handle activity updates and activity comments.
387
- if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
388
- return;
389
-
390
- $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as not spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-ham' );
391
- bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'false' );
392
- bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );
393
  }
394
 
395
- /**
396
- * Update activity meta after an automatic spam check (not user-initiated).
397
- *
398
- * @since BuddyPress (1.6)
399
- *
400
- * @param BP_Activity_Activity $activity The activity to check.
401
- */
402
- public function update_activity_akismet_meta( $activity ) {
403
- // Check we're dealing with what was last updated by Akismet
404
- if ( empty( $this->last_activity ) || !empty( $this->last_activity ) && $activity->id != $this->last_activity->id )
405
- return;
406
-
407
- // By default, only handle activity updates and activity comments.
408
- if ( !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )
409
- return;
410
-
411
- // Spam
412
- if ( 'true' == $this->last_activity->akismet_submission['bp_as_result'] ) {
413
- bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'true' );
414
- $this->update_activity_history( $activity->id, __( 'Akismet caught this item as spam', 'buddypress' ), 'check-spam' );
415
-
416
- // Not spam
417
- } elseif ( 'false' == $this->last_activity->akismet_submission['bp_as_result'] ) {
418
- bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'false' );
419
- $this->update_activity_history( $activity->id, __( 'Akismet cleared this item', 'buddypress' ), 'check-ham' );
420
-
421
- // Uh oh, something's gone horribly wrong. Unexpected result.
422
- } else {
423
- bp_activity_update_meta( $activity->id, '_bp_akismet_error', bp_core_current_time() );
424
- $this->update_activity_history( $activity->id, sprintf( __( 'Akismet was unable to check this item (response: %s), will automatically retry again later.', 'buddypress' ), $this->last_activity->akismet_submission['bp_as_result'] ), 'check-error' );
425
- }
426
-
427
- // Record the original data which was submitted to Akismet for checking
428
- bp_activity_update_meta( $activity->id, '_bp_akismet_submission', $this->last_activity->akismet_submission );
429
- }
430
-
431
- /**
432
- * Contact Akismet to check if this is spam or ham.
433
- *
434
- * Props to WordPress core Akismet plugin for alot of this.
435
- *
436
- * @since BuddyPress (1.6)
437
- *
438
- * @global string $akismet_api_host
439
- * @global string $akismet_api_port
440
- *
441
- * @param array $activity_data Packet of information to submit to Akismet.
442
- * @param string $check "check" or "submit".
443
- * @param string $spam "spam" or "ham".
444
- * @return array $activity_data Activity data, with Akismet data added.
445
- */
446
- public function send_akismet_request( $activity_data, $check = 'check', $spam = 'spam' ) {
447
- global $akismet_api_host, $akismet_api_port;
448
-
449
- // Check that host and port are set, if not, set them
450
- if ( function_exists( 'akismet_init' ) && ( empty( $akismet_api_host ) || empty( $akismet_api_port ) ) )
451
- akismet_init();
452
-
453
- $query_string = $path = $response = '';
454
-
455
- $activity_data['blog'] = bp_get_option( 'home' );
456
- $activity_data['blog_charset'] = bp_get_option( 'blog_charset' );
457
- $activity_data['blog_lang'] = get_locale();
458
- $activity_data['referrer'] = $_SERVER['HTTP_REFERER'];
459
- $activity_data['user_agent'] = bp_core_current_user_ua();
460
- $activity_data['user_ip'] = bp_core_current_user_ip();
461
-
462
- if ( akismet_test_mode() )
463
- $activity_data['is_test'] = 'true';
464
-
465
- // Loop through _POST args and rekey strings
466
- foreach ( $_POST as $key => $value )
467
- if ( is_string( $value ) && 'cookie' != $key )
468
- $activity_data['POST_' . $key] = $value;
469
-
470
- // Keys to ignore
471
- $ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );
472
-
473
- // Loop through _SERVER args and remove whitelisted keys
474
- foreach ( $_SERVER as $key => $value ) {
475
-
476
- // Key should not be ignored
477
- if ( !in_array( $key, $ignore ) && is_string( $value ) ) {
478
- $activity_data[$key] = $value;
479
-
480
- // Key should be ignored
481
- } else {
482
- $activity_data[$key] = '';
483
- }
484
- }
485
-
486
- foreach ( $activity_data as $key => $data )
487
- $query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
488
-
489
- if ( 'check' == $check )
490
- $path = '/1.1/comment-check';
491
- elseif ( 'submit' == $check )
492
- $path = '/1.1/submit-' . $spam;
493
-
494
- // Send to Akismet
495
- add_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );
496
- $response = akismet_http_post( $query_string, $akismet_api_host, $path, $akismet_api_port );
497
- remove_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );
498
-
499
- // Get the response
500
- if ( ! empty( $response[1] ) && ! is_wp_error( $response[1] ) )
501
- $activity_data['bp_as_result'] = $response[1];
502
- else
503
- $activity_data['bp_as_result'] = false;
504
-
505
- // Perform a daily tidy up
506
- if ( ! wp_next_scheduled( 'bp_activity_akismet_delete_old_metadata' ) )
507
- wp_schedule_event( time(), 'daily', 'bp_activity_akismet_delete_old_metadata' );
508
-
509
- return $activity_data;
510
- }
511
-
512
- /**
513
- * Filters user agent when sending to Akismet to add BuddyPress info.
514
- *
515
- * @since BuddyPress (1.6)
516
- *
517
- * @param string $user_agent User agent string, as generated by Akismet.
518
- * @return string $user_agent Modified user agent string.
519
- */
520
- public function buddypress_ua( $user_agent ) {
521
- $user_agent = 'BuddyPress/' . bp_get_version() . ' | Akismet/'. constant( 'AKISMET_VERSION' );
522
- return $user_agent;
523
- }
524
-
525
- /**
526
- * Adds a "History" meta box to the activity edit screen.
527
- *
528
- * @since BuddyPress (1.6)
529
- *
530
- * @param string $screen_action The type of screen that has been requested.
531
- */
532
- function add_history_metabox( $screen_action ) {
533
- // Only proceed if we're on the edit screen
534
- if ( 'edit' != $screen_action )
535
- return;
536
-
537
- // Display meta box with a low priority (low position on screen by default)
538
- add_meta_box( 'bp_activity_history', __( 'Activity History', 'buddypress' ), array( $this, 'history_metabox' ), get_current_screen()->id, 'normal', 'low' );
539
- }
540
-
541
- /**
542
- * History meta box for the Activity admin edit screen.
543
- *
544
- * @since BuddyPress (1.6)
545
- *
546
- * @see http://buddypress.trac.wordpress.org/ticket/3907
547
- * @todo Update activity meta to allow >1 record with the same key (iterate through $history).
548
- *
549
- * @param object $item Activity item.
550
- */
551
- function history_metabox( $item ) {
552
- $history = BP_Akismet::get_activity_history( $item->id );
553
-
554
- if ( empty( $history ) )
555
- return;
556
-
557
- echo '<div class="akismet-history"><div>';
558
- printf( _x( '<span>%1$s</span> &mdash; %2$s', 'x hours ago - akismet cleared this item', 'buddypress' ), bp_core_time_since( $history[2] ), esc_html( $history[1] ) );
559
- echo '</div></div>';
560
- }
561
-
562
- /**
563
- * Update an activity item's Akismet history.
564
- *
565
- * @since BuddyPress (1.6)
566
- *
567
- * @param int $activity_id Activity item ID.
568
- * @param string $message Human-readable description of what's changed.
569
- * @param string $event The type of check we were carrying out.
570
- */
571
- public function update_activity_history( $activity_id = 0, $message = '', $event = '' ) {
572
- $event = array(
573
- 'event' => $event,
574
- 'message' => $message,
575
- 'time' => akismet_microtime(),
576
- 'user' => bp_loggedin_user_id(),
577
- );
578
-
579
- // Save the history data
580
- bp_activity_update_meta( $activity_id, '_bp_akismet_history', $event );
581
- }
582
-
583
- /**
584
- * Get an activity item's Akismet history.
585
- *
586
- * @since BuddyPress (1.6)
587
- *
588
- * @param int $activity_id Activity item ID.
589
- * @return array The activity item's Akismet history.
590
- */
591
- public function get_activity_history( $activity_id = 0 ) {
592
- $history = bp_activity_get_meta( $activity_id, '_bp_akismet_history' );
593
- if ( $history === false )
594
- $history = array();
595
-
596
- // Sort it by the time recorded
597
- usort( $history, 'akismet_cmp_time' );
598
-
599
- return $history;
600
- }
601
  }
 
602
 
603
  /**
604
- * Delete old spam activity meta data
605
  *
606
  * This is done as a clean-up mechanism, as _bp_akismet_submission meta can
607
  * grow to be quite large.
608
  *
609
- * @since BuddyPress (1.6)
610
  *
611
- * @global object $bp BuddyPress global settings.
612
  * @global wpdb $wpdb WordPress database object.
613
  */
614
  function bp_activity_akismet_delete_old_metadata() {
615
- global $bp, $wpdb;
 
 
616
 
 
 
 
 
 
 
 
617
  $interval = apply_filters( 'bp_activity_akismet_delete_meta_interval', 15 );
618
 
619
- // Enforce a minimum of 1 day
620
  $interval = max( 1, absint( $interval ) );
621
 
622
  // _bp_akismet_submission meta values are large, so expire them after $interval days regardless of the activity status
3
  * Akismet support for BuddyPress' Activity Stream.
4
  *
5
  * @package BuddyPress
6
+ * @subpackage ActivityAkismet
7
+ * @since 1.6.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ if ( ! buddypress()->do_autoload ) {
14
+ require dirname( __FILE__ ) . '/classes/class-bp-akismet.php';
15
+ }
16
 
17
  /**
18
+ * Loads Akismet filtering for activity.
19
  *
20
+ * @since 1.6.0
21
+ * @since 2.3.0 We only support Akismet 3+.
22
  */
23
+ function bp_activity_setup_akismet() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  /**
25
+ * Filters if BuddyPress Activity Akismet support has been disabled by another plugin.
26
  *
27
+ * @since 1.6.0
28
  *
29
+ * @param bool $value Return value of bp_is_akismet_active boolean function.
30
  */
31
+ if ( ! apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
32
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
+ // Instantiate Akismet for BuddyPress.
36
+ buddypress()->activity->akismet = new BP_Akismet();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
+ add_action( 'bp_activity_setup_globals', 'bp_activity_setup_akismet' );
39
 
40
  /**
41
+ * Delete old spam activity meta data.
42
  *
43
  * This is done as a clean-up mechanism, as _bp_akismet_submission meta can
44
  * grow to be quite large.
45
  *
46
+ * @since 1.6.0
47
  *
 
48
  * @global wpdb $wpdb WordPress database object.
49
  */
50
  function bp_activity_akismet_delete_old_metadata() {
51
+ global $wpdb;
52
+
53
+ $bp = buddypress();
54
 
55
+ /**
56
+ * Filters the threshold for how many days old Akismet metadata needs to be before being automatically deleted.
57
+ *
58
+ * @since 1.6.0
59
+ *
60
+ * @param integer 15 How many days old metadata needs to be.
61
+ */
62
  $interval = apply_filters( 'bp_activity_akismet_delete_meta_interval', 15 );
63
 
64
+ // Enforce a minimum of 1 day.
65
  $interval = max( 1, absint( $interval ) );
66
 
67
  // _bp_akismet_submission meta values are large, so expire them after $interval days regardless of the activity status
bp-activity/bp-activity-cache.php CHANGED
@@ -1,13 +1,14 @@
1
  <?php
2
-
3
  /**
4
  * Functions related to the BuddyPress Activity component and the WP Cache.
5
  *
6
- * @since BuddyPress (1.6)
 
 
7
  */
8
 
9
- // Exit if accessed directly
10
- if ( !defined( 'ABSPATH' ) ) exit;
11
 
12
  /**
13
  * Slurp up activitymeta for a specified set of activity items.
@@ -16,11 +17,13 @@ if ( !defined( 'ABSPATH' ) ) exit;
16
  * in $activity_ids and adds it to the WP cache. This improves efficiency when
17
  * using querying activitymeta inline.
18
  *
19
- * @param int|str|array $activity_ids Accepts a single activity ID, or a comma-
20
- * separated list or array of activity ids
 
 
21
  */
22
  function bp_activity_update_meta_cache( $activity_ids = false ) {
23
- global $bp;
24
 
25
  $cache_args = array(
26
  'object_ids' => $activity_ids,
@@ -37,19 +40,20 @@ function bp_activity_update_meta_cache( $activity_ids = false ) {
37
  /**
38
  * Clear a cached activity item when that item is updated.
39
  *
40
- * @since 2.0
41
  *
42
- * @param BP_Activity_Activity $activity
43
  */
44
  function bp_activity_clear_cache_for_activity( $activity ) {
45
  wp_cache_delete( $activity->id, 'bp_activity' );
 
46
  }
47
  add_action( 'bp_activity_after_save', 'bp_activity_clear_cache_for_activity' );
48
 
49
  /**
50
  * Clear cached data for deleted activity items.
51
  *
52
- * @since 2.0
53
  *
54
  * @param array $deleted_ids IDs of deleted activity items.
55
  */
@@ -59,3 +63,24 @@ function bp_activity_clear_cache_for_deleted_activity( $deleted_ids ) {
59
  }
60
  }
61
  add_action( 'bp_activity_deleted_activities', 'bp_activity_clear_cache_for_deleted_activity' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * Functions related to the BuddyPress Activity component and the WP Cache.
4
  *
5
+ * @package BuddyPress
6
+ * @subpackage ActivityCache
7
+ * @since 1.6.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
 
13
  /**
14
  * Slurp up activitymeta for a specified set of activity items.
17
  * in $activity_ids and adds it to the WP cache. This improves efficiency when
18
  * using querying activitymeta inline.
19
  *
20
+ * @since 1.6.0
21
+ *
22
+ * @param int|string|array|bool $activity_ids Accepts a single activity ID, or a comma-
23
+ * separated list or array of activity ids.
24
  */
25
  function bp_activity_update_meta_cache( $activity_ids = false ) {
26
+ $bp = buddypress();
27
 
28
  $cache_args = array(
29
  'object_ids' => $activity_ids,
40
  /**
41
  * Clear a cached activity item when that item is updated.
42
  *
43
+ * @since 2.0.0
44
  *
45
+ * @param BP_Activity_Activity $activity Activity object.
46
  */
47
  function bp_activity_clear_cache_for_activity( $activity ) {
48
  wp_cache_delete( $activity->id, 'bp_activity' );
49
+ wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
50
  }
51
  add_action( 'bp_activity_after_save', 'bp_activity_clear_cache_for_activity' );
52
 
53
  /**
54
  * Clear cached data for deleted activity items.
55
  *
56
+ * @since 2.0.0
57
  *
58
  * @param array $deleted_ids IDs of deleted activity items.
59
  */
63
  }
64
  }
65
  add_action( 'bp_activity_deleted_activities', 'bp_activity_clear_cache_for_deleted_activity' );
66
+
67
+ /**
68
+ * Reset cache incrementor for the Activity component.
69
+ *
70
+ * Called whenever an activity item is created, updated, or deleted, this
71
+ * function effectively invalidates all cached results of activity queries.
72
+ *
73
+ * @since 2.7.0
74
+ *
75
+ * @return bool True on success, false on failure.
76
+ */
77
+ function bp_activity_reset_cache_incrementor() {
78
+ $without_last_activity = bp_core_reset_incrementor( 'bp_activity' );
79
+ $with_last_activity = bp_core_reset_incrementor( 'bp_activity_with_last_activity' );
80
+ return $without_last_activity && $with_last_activity;
81
+ }
82
+ add_action( 'bp_activity_delete', 'bp_activity_reset_cache_incrementor' );
83
+ add_action( 'bp_activity_add', 'bp_activity_reset_cache_incrementor' );
84
+ add_action( 'added_activity_meta', 'bp_activity_reset_cache_incrementor' );
85
+ add_action( 'updated_activity_meta', 'bp_activity_reset_cache_incrementor' );
86
+ add_action( 'deleted_activity_meta', 'bp_activity_reset_cache_incrementor' );
bp-activity/bp-activity-classes.php CHANGED
@@ -1,1682 +1,20 @@
1
  <?php
2
  /**
3
- * BuddyPress Activity Classes
4
  *
5
  * @package BuddyPress
6
- * @subpackage Activity
 
7
  */
8
 
9
- // Exit if accessed directly
10
- if ( !defined( 'ABSPATH' ) ) exit;
11
 
12
- /**
13
- * Database interaction class for the BuddyPress activity component.
14
- *
15
- * Instance methods are available for creating/editing an activity,
16
- * static methods for querying activities.
17
- *
18
- * @since BuddyPress (1.0)
19
- */
20
- class BP_Activity_Activity {
21
-
22
- /** Properties ************************************************************/
23
-
24
- /**
25
- * ID of the activity item.
26
- *
27
- * @var int
28
- */
29
- var $id;
30
-
31
- /**
32
- * ID of the associated item.
33
- *
34
- * @var int
35
- */
36
- var $item_id;
37
-
38
- /**
39
- * ID of the associated secondary item.
40
- *
41
- * @var int
42
- */
43
- var $secondary_item_id;
44
-
45
- /**
46
- * ID of user associated with the activity item.
47
- *
48
- * @var int
49
- */
50
- var $user_id;
51
-
52
- /**
53
- * The primary URL for the activity in RSS feeds.
54
- *
55
- * @var string
56
- */
57
- var $primary_link;
58
-
59
- /**
60
- * BuddyPress component the activity item relates to.
61
- *
62
- * @var string
63
- */
64
- var $component;
65
-
66
- /**
67
- * Activity type, eg 'new_blog_post'.
68
- *
69
- * @var string
70
- */
71
- var $type;
72
-
73
- /**
74
- * Description of the activity, eg 'Alex updated his profile.'
75
- *
76
- * @var string
77
- */
78
- var $action;
79
-
80
- /**
81
- * The content of the activity item.
82
- *
83
- * @var string
84
- */
85
- var $content;
86
-
87
- /**
88
- * The date the activity item was recorded, in 'Y-m-d h:i:s' format.
89
- *
90
- * @var string
91
- */
92
- var $date_recorded;
93
-
94
- /**
95
- * Whether the item should be hidden in sitewide streams.
96
- *
97
- * @var int
98
- */
99
- var $hide_sitewide = false;
100
-
101
- /**
102
- * Node boundary start for activity or activity comment.
103
- *
104
- * @var int
105
- */
106
- var $mptt_left;
107
-
108
- /**
109
- * Node boundary end for activity or activity comment.
110
- *
111
- * @var int
112
- */
113
- var $mptt_right;
114
-
115
- /**
116
- * Whether this item is marked as spam.
117
- *
118
- * @var int
119
- */
120
- var $is_spam;
121
-
122
- /**
123
- * Constructor method.
124
- *
125
- * @param int $id Optional. The ID of a specific activity item.
126
- */
127
- public function __construct( $id = false ) {
128
- if ( !empty( $id ) ) {
129
- $this->id = $id;
130
- $this->populate();
131
- }
132
- }
133
-
134
- /**
135
- * Populate the object with data about the specific activity item.
136
- */
137
- public function populate() {
138
- global $wpdb, $bp;
139
-
140
- $row = wp_cache_get( $this->id, 'bp_activity' );
141
-
142
- if ( false === $row ) {
143
- $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->activity->table_name} WHERE id = %d", $this->id ) );
144
-
145
- wp_cache_set( $this->id, $row, 'bp_activity' );
146
- }
147
-
148
- if ( ! empty( $row ) ) {
149
- $this->id = $row->id;
150
- $this->item_id = $row->item_id;
151
- $this->secondary_item_id = $row->secondary_item_id;
152
- $this->user_id = $row->user_id;
153
- $this->primary_link = $row->primary_link;
154
- $this->component = $row->component;
155
- $this->type = $row->type;
156
- $this->action = $row->action;
157
- $this->content = $row->content;
158
- $this->date_recorded = $row->date_recorded;
159
- $this->hide_sitewide = $row->hide_sitewide;
160
- $this->mptt_left = $row->mptt_left;
161
- $this->mptt_right = $row->mptt_right;
162
- $this->is_spam = $row->is_spam;
163
- }
164
-
165
- // Generate dynamic 'action' when possible
166
- $action = bp_activity_generate_action_string( $this );
167
- if ( false !== $action ) {
168
- $this->action = $action;
169
-
170
- // If no callback is available, use the literal string from
171
- // the database row
172
- } else if ( ! empty( $row->action ) ) {
173
- $this->action = $row->action;
174
-
175
- // Provide a fallback to avoid PHP notices
176
- } else {
177
- $this->action = '';
178
- }
179
- }
180
-
181
- /**
182
- * Save the activity item to the database.
183
- *
184
- * @return bool True on success.
185
- */
186
- public function save() {
187
- global $wpdb, $bp;
188
-
189
- $this->id = apply_filters_ref_array( 'bp_activity_id_before_save', array( $this->id, &$this ) );
190
- $this->item_id = apply_filters_ref_array( 'bp_activity_item_id_before_save', array( $this->item_id, &$this ) );
191
- $this->secondary_item_id = apply_filters_ref_array( 'bp_activity_secondary_item_id_before_save', array( $this->secondary_item_id, &$this ) );
192
- $this->user_id = apply_filters_ref_array( 'bp_activity_user_id_before_save', array( $this->user_id, &$this ) );
193
- $this->primary_link = apply_filters_ref_array( 'bp_activity_primary_link_before_save', array( $this->primary_link, &$this ) );
194
- $this->component = apply_filters_ref_array( 'bp_activity_component_before_save', array( $this->component, &$this ) );
195
- $this->type = apply_filters_ref_array( 'bp_activity_type_before_save', array( $this->type, &$this ) );
196
- $this->action = apply_filters_ref_array( 'bp_activity_action_before_save', array( $this->action, &$this ) );
197
- $this->content = apply_filters_ref_array( 'bp_activity_content_before_save', array( $this->content, &$this ) );
198
- $this->date_recorded = apply_filters_ref_array( 'bp_activity_date_recorded_before_save', array( $this->date_recorded, &$this ) );
199
- $this->hide_sitewide = apply_filters_ref_array( 'bp_activity_hide_sitewide_before_save', array( $this->hide_sitewide, &$this ) );
200
- $this->mptt_left = apply_filters_ref_array( 'bp_activity_mptt_left_before_save', array( $this->mptt_left, &$this ) );
201
- $this->mptt_right = apply_filters_ref_array( 'bp_activity_mptt_right_before_save', array( $this->mptt_right, &$this ) );
202
- $this->is_spam = apply_filters_ref_array( 'bp_activity_is_spam_before_save', array( $this->is_spam, &$this ) );
203
-
204
- // Use this, not the filters above
205
- do_action_ref_array( 'bp_activity_before_save', array( &$this ) );
206
-
207
- if ( !$this->component || !$this->type )
208
- return false;
209
-
210
- if ( !$this->primary_link )
211
- $this->primary_link = bp_loggedin_user_domain();
212
-
213
- // If we have an existing ID, update the activity item, otherwise insert it.
214
- if ( $this->id )
215
- $q = $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET user_id = %d, component = %s, type = %s, action = %s, content = %s, primary_link = %s, date_recorded = %s, item_id = %d, secondary_item_id = %d, hide_sitewide = %d, is_spam = %d WHERE id = %d", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam, $this->id );
216
- else
217
- $q = $wpdb->prepare( "INSERT INTO {$bp->activity->table_name} ( user_id, component, type, action, content, primary_link, date_recorded, item_id, secondary_item_id, hide_sitewide, is_spam ) VALUES ( %d, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d )", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam );
218
-
219
- if ( false === $wpdb->query( $q ) )
220
- return false;
221
-
222
- // If this is a new activity item, set the $id property
223
- if ( empty( $this->id ) )
224
- $this->id = $wpdb->insert_id;
225
-
226
- // If an existing activity item, prevent any changes to the content generating new @mention notifications.
227
- else
228
- add_filter( 'bp_activity_at_name_do_notifications', '__return_false' );
229
-
230
- do_action_ref_array( 'bp_activity_after_save', array( &$this ) );
231
-
232
- return true;
233
- }
234
-
235
- /** Static Methods ***************************************************/
236
-
237
- /**
238
- * Get activity items, as specified by parameters
239
- *
240
- * @see BP_Activity_Activity::get_filter_sql() for a description of the
241
- * 'filter' parameter.
242
- * @see WP_Meta_Query::queries for a description of the 'meta_query'
243
- * parameter format.
244
- *
245
- * @param array $args {
246
- * An array of arguments. All items are optional.
247
- * @type int $page Which page of results to fetch. Using page=1
248
- * without per_page will result in no pagination.
249
- * Default: 1.
250
- * @type int|bool $per_page Number of results per page. Default: 25.
251
- * @type int|bool $max Maximum number of results to return.
252
- * Default: false (unlimited).
253
- * @type string $sort ASC or DESC. Default: 'DESC'.
254
- * @type array $exclude Array of activity IDs to exclude.
255
- * Default: false.
256
- * @type array $in Array of ids to limit query by (IN).
257
- * Default: false.
258
- * @type array $meta_query An array of meta_query conditions.
259
- * See WP_Meta_Query::queries for description.
260
- * @type array $filter See BP_Activity_Activity::get_filter_sql().
261
- * @type string $search_terms Limit results by a search term.
262
- * Default: false.
263
- * @type bool $display_comments Whether to include activity comments.
264
- * Default: false.
265
- * @type bool $show_hidden Whether to show items marked hide_sitewide.
266
- * Default: false.
267
- * @type string $spam Spam status. Default: 'ham_only'.
268
- * @type bool $update_meta_cache Whether to pre-fetch metadata for
269
- * queried activity items. Default: true.
270
- * }
271
- * @return array The array returned has two keys:
272
- * - 'total' is the count of located activities
273
- * - 'activities' is an array of the located activities
274
- */
275
- public static function get( $args = array() ) {
276
- global $wpdb, $bp;
277
-
278
- // Backward compatibility with old method of passing arguments
279
- if ( !is_array( $args ) || func_num_args() > 1 ) {
280
- _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__ ) );
281
-
282
- $old_args_keys = array(
283
- 0 => 'max',
284
- 1 => 'page',
285
- 2 => 'per_page',
286
- 3 => 'sort',
287
- 4 => 'search_terms',
288
- 5 => 'filter',
289
- 6 => 'display_comments',
290
- 7 => 'show_hidden',
291
- 8 => 'exclude',
292
- 9 => 'in',
293
- 10 => 'spam'
294
- );
295
-
296
- $func_args = func_get_args();
297
- $args = bp_core_parse_args_array( $old_args_keys, $func_args );
298
- }
299
-
300
- $defaults = array(
301
- 'page' => 1, // The current page
302
- 'per_page' => 25, // Activity items per page
303
- 'max' => false, // Max number of items to return
304
- 'sort' => 'DESC', // ASC or DESC
305
- 'exclude' => false, // Array of ids to exclude
306
- 'in' => false, // Array of ids to limit query by (IN)
307
- 'meta_query' => false, // Filter by activitymeta
308
- 'filter' => false, // See self::get_filter_sql()
309
- 'search_terms' => false, // Terms to search by
310
- 'display_comments' => false, // Whether to include activity comments
311
- 'show_hidden' => false, // Show items marked hide_sitewide
312
- 'spam' => 'ham_only', // Spam status
313
- 'update_meta_cache' => true,
314
- );
315
- $r = wp_parse_args( $args, $defaults );
316
- extract( $r );
317
-
318
- // Select conditions
319
- $select_sql = "SELECT DISTINCT a.id";
320
-
321
- $from_sql = " FROM {$bp->activity->table_name} a";
322
-
323
- $join_sql = '';
324
-
325
- // Where conditions
326
- $where_conditions = array();
327
-
328
- // Spam
329
- if ( 'ham_only' == $spam )
330
- $where_conditions['spam_sql'] = 'a.is_spam = 0';
331
- elseif ( 'spam_only' == $spam )
332
- $where_conditions['spam_sql'] = 'a.is_spam = 1';
333
-
334
- // Searching
335
- if ( $search_terms ) {
336
- $search_terms = esc_sql( $search_terms );
337
- $where_conditions['search_sql'] = "a.content LIKE '%%" . esc_sql( like_escape( $search_terms ) ) . "%%'";
338
- }
339
-
340
- // Filtering
341
- if ( $filter && $filter_sql = BP_Activity_Activity::get_filter_sql( $filter ) )
342
- $where_conditions['filter_sql'] = $filter_sql;
343
-
344
- // Sorting
345
- if ( $sort != 'ASC' && $sort != 'DESC' )
346
- $sort = 'DESC';
347
-
348
- // Hide Hidden Items?
349
- if ( !$show_hidden )
350
- $where_conditions['hidden_sql'] = "a.hide_sitewide = 0";
351
-
352
- // Exclude specified items
353
- if ( !empty( $exclude ) ) {
354
- $exclude = implode( ',', wp_parse_id_list( $exclude ) );
355
- $where_conditions['exclude'] = "a.id NOT IN ({$exclude})";
356
- }
357
-
358
- // The specific ids to which you want to limit the query
359
- if ( !empty( $in ) ) {
360
- $in = implode( ',', wp_parse_id_list( $in ) );
361
- $where_conditions['in'] = "a.id IN ({$in})";
362
- }
363
-
364
- // Process meta_query into SQL
365
- $meta_query_sql = self::get_meta_query_sql( $meta_query );
366
-
367
- if ( ! empty( $meta_query_sql['join'] ) ) {
368
- $join_sql .= $meta_query_sql['join'];
369
- }
370
-
371
- if ( ! empty( $meta_query_sql['where'] ) ) {
372
- $where_conditions[] = $meta_query_sql['where'];
373
- }
374
-
375
- // Alter the query based on whether we want to show activity item
376
- // comments in the stream like normal comments or threaded below
377
- // the activity.
378
- if ( false === $display_comments || 'threaded' === $display_comments ) {
379
- $where_conditions[] = "a.type != 'activity_comment'";
380
- }
381
-
382
- // Exclude 'last_activity' items unless the 'action' filter has
383
- // been explicitly set
384
- if ( empty( $filter['object'] ) ) {
385
- $where_conditions[] = "a.type != 'last_activity'";
386
- }
387
-
388
- // Filter the where conditions
389
- $where_conditions = apply_filters( 'bp_activity_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql );
390
-
391
- // Join the where conditions together
392
- $where_sql = 'WHERE ' . join( ' AND ', $where_conditions );
393
-
394
- // Define the preferred order for indexes
395
- $indexes = apply_filters( 'bp_activity_preferred_index_order', array( 'user_id', 'item_id', 'secondary_item_id', 'date_recorded', 'component', 'type', 'hide_sitewide', 'is_spam' ) );
396
-
397
- foreach( $indexes as $key => $index ) {
398
- if ( false !== strpos( $where_sql, $index ) ) {
399
- $the_index = $index;
400
- break; // Take the first one we find
401
- }
402
- }
403
-
404
- if ( !empty( $the_index ) ) {
405
- $index_hint_sql = "USE INDEX ({$the_index})";
406
- } else {
407
- $index_hint_sql = '';
408
- }
409
-
410
- // Sanitize page and per_page parameters
411
- $page = absint( $page );
412
- $per_page = absint( $per_page );
413
-
414
- // Filter and return true to use the legacy query structure (not recommended)
415
- if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, $r ) ) {
416
-
417
- // Legacy queries joined against the user table
418
- $select_sql = "SELECT DISTINCT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name";
419
- $from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID";
420
-
421
- if ( ! empty( $page ) && ! empty( $per_page ) ) {
422
- $pag_sql = $wpdb->prepare( "LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page );
423
- $activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql ) );
424
- } else {
425
- $activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}", $select_sql, $from_sql, $where_sql, $sort ) );
426
- }
427
-
428
- } else {
429
-
430
- // Query first for activity IDs
431
- $activity_ids_sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}";
432
-
433
- if ( ! empty( $per_page ) && ! empty( $page ) ) {
434
- $activity_ids_sql .= $wpdb->prepare( " LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page );
435
- }
436
-
437
- $activity_ids_sql = apply_filters( 'bp_activity_paged_activities_sql', $activity_ids_sql, $r );
438
-
439
- $activity_ids = $wpdb->get_col( $activity_ids_sql );
440
- $activities = self::get_activity_data( $activity_ids );
441
- }
442
-
443
- $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort );
444
- $total_activities = $wpdb->get_var( $total_activities_sql );
445
-
446
- // Get the fullnames of users so we don't have to query in the loop
447
- $activities = self::append_user_fullnames( $activities );
448
-
449
- // Get activity meta
450
- $activity_ids = array();
451
- foreach ( (array) $activities as $activity ) {
452
- $activity_ids[] = $activity->id;
453
- }
454
-
455
- if ( ! empty( $activity_ids ) && $update_meta_cache ) {
456
- bp_activity_update_meta_cache( $activity_ids );
457
- }
458
-
459
- if ( $activities && $display_comments )
460
- $activities = BP_Activity_Activity::append_comments( $activities, $spam );
461
-
462
- // Pre-fetch data associated with activity users and other objects
463
- BP_Activity_Activity::prefetch_object_data( $activities );
464
-
465
- // Generate action strings
466
- $activities = BP_Activity_Activity::generate_action_strings( $activities );
467
-
468
- // If $max is set, only return up to the max results
469
- if ( !empty( $max ) ) {
470
- if ( (int) $total_activities > (int) $max )
471
- $total_activities = $max;
472
- }
473
-
474
- return array( 'activities' => $activities, 'total' => (int) $total_activities );
475
- }
476
-
477
- /**
478
- * Convert activity IDs to activity objects, as expected in template loop.
479
- *
480
- * @since 2.0
481
- *
482
- * @param array $activity_ids Array of activity IDs.
483
- * @return array
484
- */
485
- protected static function get_activity_data( $activity_ids = array() ) {
486
- global $wpdb;
487
-
488
- // Bail if no activity ID's passed
489
- if ( empty( $activity_ids ) ) {
490
- return array();
491
- }
492
-
493
- // Get BuddyPress
494
- $bp = buddypress();
495
-
496
- $activities = array();
497
- $uncached_ids = bp_get_non_cached_ids( $activity_ids, 'bp_activity' );
498
-
499
- // Prime caches as necessary
500
- if ( ! empty( $uncached_ids ) ) {
501
- // Format the activity ID's for use in the query below
502
- $uncached_ids_sql = implode( ',', wp_parse_id_list( $uncached_ids ) );
503
-
504
- // Fetch data from activity table, preserving order
505
- $queried_adata = $wpdb->get_results( "SELECT * FROM {$bp->activity->table_name} WHERE id IN ({$uncached_ids_sql})");
506
-
507
- // Put that data into the placeholders created earlier,
508
- // and add it to the cache
509
- foreach ( (array) $queried_adata as $adata ) {
510
- wp_cache_set( $adata->id, $adata, 'bp_activity' );
511
- }
512
- }
513
-
514
- // Now fetch data from the cache
515
- foreach ( $activity_ids as $activity_id ) {
516
- $activities[] = wp_cache_get( $activity_id, 'bp_activity' );
517
- }
518
-
519
- // Then fetch user data
520
- $user_query = new BP_User_Query( array(
521
- 'user_ids' => wp_list_pluck( $activities, 'user_id' ),
522
- 'populate_extras' => false,
523
- ) );
524
-
525
- // Associated located user data with activity items
526
- foreach ( $activities as $a_index => $a_item ) {
527
- $a_user_id = intval( $a_item->user_id );
528
- $a_user = isset( $user_query->results[ $a_user_id ] ) ? $user_query->results[ $a_user_id ] : '';
529
-
530
- if ( !empty( $a_user ) ) {
531
- $activities[ $a_index ]->user_email = $a_user->user_email;
532
- $activities[ $a_index ]->user_nicename = $a_user->user_nicename;
533
- $activities[ $a_index ]->user_login = $a_user->user_login;
534
- $activities[ $a_index ]->display_name = $a_user->display_name;
535
- }
536
- }
537
-
538
- return $activities;
539
- }
540
-
541
- /**
542
- * Append xProfile fullnames to an activity array.
543
- *
544
- * @since BuddyPress (2.0.0)
545
- *
546
- * @param array $activities Activities array.
547
- * @return array
548
- */
549
- protected static function append_user_fullnames( $activities ) {
550
- global $wpdb;
551
-
552
- if ( bp_is_active( 'xprofile' ) && ! empty( $activities ) ) {
553
- $activity_user_ids = wp_list_pluck( $activities, 'user_id' );
554
-
555
- if ( ! empty( $activity_user_ids ) ) {
556
- $fullnames = bp_core_get_user_displaynames( $activity_user_ids );
557
- if ( ! empty( $fullnames ) ) {
558
- foreach ( (array) $activities as $i => $activity ) {
559
- if ( ! empty( $fullnames[ $activity->user_id ] ) ) {
560
- $activities[ $i ]->user_fullname = $fullnames[ $activity->user_id ];
561
- }
562
- }
563
- }
564
- }
565
- }
566
-
567
- return $activities;
568
- }
569
-
570
- /**
571
- * Pre-fetch data for objects associated with activity items.
572
- *
573
- * Activity items are associated with users, and often with other
574
- * BuddyPress data objects. Here, we pre-fetch data about these
575
- * associated objects, so that inline lookups - done primarily when
576
- * building action strings - do not result in excess database queries.
577
- *
578
- * The only object data required for activity component activity types
579
- * (activity_update and activity_comment) is related to users, and that
580
- * info is fetched separately in BP_Activity_Activity::get_activity_data().
581
- * So this method contains nothing but a filter that allows other
582
- * components, such as bp-friends and bp-groups, to hook in and prime
583
- * their own caches at the beginning of an activity loop.
584
- *
585
- * @since BuddyPress (2.0.0)
586
- *
587
- * @param array $activities Array of activities.
588
- */
589
- protected static function prefetch_object_data( $activities ) {
590
- return apply_filters( 'bp_activity_prefetch_object_data', $activities );
591
- }
592
-
593
- /**
594
- * Generate action strings for the activities located in BP_Activity_Activity::get().
595
- *
596
- * If no string can be dynamically generated for a given item
597
- * (typically because the activity type has not been properly
598
- * registered), the static 'action' value pulled from the database will
599
- * be left in place.
600
- *
601
- * @since BuddyPress (2.0.0)
602
- *
603
- * @param array $activities Array of activities.
604
- * @return array
605
- */
606
- protected static function generate_action_strings( $activities ) {
607
- foreach ( $activities as $key => $activity ) {
608
- $generated_action = bp_activity_generate_action_string( $activity );
609
- if ( false !== $generated_action ) {
610
- $activity->action = $generated_action;
611
- }
612
-
613
- $activities[ $key ] = $activity;
614
- }
615
-
616
- return $activities;
617
- }
618
-
619
- /**
620
- * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get().
621
- *
622
- * We use WP_Meta_Query to do the heavy lifting of parsing the
623
- * meta_query array and creating the necessary SQL clauses. However,
624
- * since BP_Activity_Activity::get() builds its SQL differently than
625
- * WP_Query, we have to alter the return value (stripping the leading
626
- * AND keyword from the 'where' clause).
627
- *
628
- * @since BuddyPress (1.8)
629
- *
630
- * @param array $meta_query An array of meta_query filters. See the
631
- * documentation for WP_Meta_Query for details.
632
- * @return array $sql_array 'join' and 'where' clauses.
633
- */
634
- public static function get_meta_query_sql( $meta_query = array() ) {
635
- global $wpdb;
636
-
637
- $sql_array = array(
638
- 'join' => '',
639
- 'where' => '',
640
- );
641
-
642
- if ( ! empty( $meta_query ) ) {
643
- $activity_meta_query = new WP_Meta_Query( $meta_query );
644
-
645
- // WP_Meta_Query expects the table name at
646
- // $wpdb->activitymeta
647
- $wpdb->activitymeta = buddypress()->activity->table_name_meta;
648
-
649
- $meta_sql = $activity_meta_query->get_sql( 'activity', 'a', 'id' );
650
-
651
- // Strip the leading AND - BP handles it in get()
652
- $sql_array['where'] = preg_replace( '/^\sAND/', '', $meta_sql['where'] );
653
- $sql_array['join'] = $meta_sql['join'];
654
- }
655
-
656
- return $sql_array;
657
- }
658
-
659
- /**
660
- * In BuddyPress 1.2.x, this was used to retrieve specific activity stream items (for example, on an activity's permalink page).
661
- *
662
- * As of 1.5.x, use BP_Activity_Activity::get() with an 'in' parameter instead.
663
- *
664
- * @since BuddyPress (1.2)
665
- *
666
- * @deprecated 1.5
667
- * @deprecated Use BP_Activity_Activity::get() with an 'in' parameter instead.
668
- *
669
- * @param mixed $activity_ids Array or comma-separated string of activity IDs to retrieve
670
- * @param int $max Maximum number of results to return. (Optional; default is no maximum)
671
- * @param int $page The set of results that the user is viewing. Used in pagination. (Optional; default is 1)
672
- * @param int $per_page Specifies how many results per page. Used in pagination. (Optional; default is 25)
673
- * @param string MySQL column sort; ASC or DESC. (Optional; default is DESC)
674
- * @param bool $display_comments Retrieve an activity item's associated comments or not. (Optional; default is false)
675
- * @return array
676
- */
677
- public static function get_specific( $activity_ids, $max = false, $page = 1, $per_page = 25, $sort = 'DESC', $display_comments = false ) {
678
- _deprecated_function( __FUNCTION__, '1.5', 'Use BP_Activity_Activity::get() with the "in" parameter instead.' );
679
- return BP_Activity_Activity::get( $max, $page, $per_page, $sort, false, false, $display_comments, false, false, $activity_ids );
680
- }
681
-
682
- /**
683
- * Get the first activity ID that matches a set of criteria.
684
- *
685
- * @param int $user_id The user ID to filter by.
686
- * @param string $component The component to filter by.
687
- * @param string $type The activity type to filter by.
688
- * @param int $item_id The associated item to filter by.
689
- * @param int $secondary_item_id The secondary associated item to filter by.
690
- * @param string $action The action to filter by.
691
- * @param string $content The content to filter by.
692
- * @param string $date_recorded The date to filter by.
693
- * @return int|bool Activity ID on success, false if none is found.
694
- */
695
- public static function get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) {
696
- global $bp, $wpdb;
697
-
698
- $where_args = false;
699
-
700
- if ( !empty( $user_id ) )
701
- $where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
702
-
703
- if ( !empty( $component ) )
704
- $where_args[] = $wpdb->prepare( "component = %s", $component );
705
-
706
- if ( !empty( $type ) )
707
- $where_args[] = $wpdb->prepare( "type = %s", $type );
708
-
709
- if ( !empty( $item_id ) )
710
- $where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
711
-
712
- if ( !empty( $secondary_item_id ) )
713
- $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
714
-
715
- if ( !empty( $action ) )
716
- $where_args[] = $wpdb->prepare( "action = %s", $action );
717
-
718
- if ( !empty( $content ) )
719
- $where_args[] = $wpdb->prepare( "content = %s", $content );
720
-
721
- if ( !empty( $date_recorded ) )
722
- $where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
723
-
724
- if ( !empty( $where_args ) )
725
- $where_sql = 'WHERE ' . join( ' AND ', $where_args );
726
- else
727
- return false;
728
-
729
- return $wpdb->get_var( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
730
- }
731
-
732
- /**
733
- * Delete activity items from the database.
734
- *
735
- * To delete a specific activity item, pass an 'id' parameter.
736
- * Otherwise use the filters.
737
- *
738
- * @since BuddyPress (1.2)
739
- *
740
- * @param array $args {
741
- * @int $id Optional. The ID of a specific item to delete.
742
- * @string $action Optional. The action to filter by.
743
- * @string $content Optional. The content to filter by.
744
- * @string $component Optional. The component name to filter by.
745
- * @string $type Optional. The activity type to filter by.
746
- * @string $primary_link Optional. The primary URL to filter by.
747
- * @int $user_id Optional. The user ID to filter by.
748
- * @int $item_id Optional. The associated item ID to filter by.
749
- * @int $secondary_item_id Optional. The secondary associated item ID to filter by.
750
- * @string $date_recorded Optional. The date to filter by.
751
- * @int $hide_sitewide Optional. Default: false.
752
- * }
753
- * @return array|bool An array of deleted activity IDs on success, false on failure.
754
- */
755
- public static function delete( $args = array() ) {
756
- global $wpdb, $bp;
757
-
758
- $defaults = array(
759
- 'id' => false,
760
- 'action' => false,
761
- 'content' => false,
762
- 'component' => false,
763
- 'type' => false,
764
- 'primary_link' => false,
765
- 'user_id' => false,
766
- 'item_id' => false,
767
- 'secondary_item_id' => false,
768
- 'date_recorded' => false,
769
- 'hide_sitewide' => false
770
- );
771
- $params = wp_parse_args( $args, $defaults );
772
- extract( $params );
773
-
774
- $where_args = false;
775
-
776
- if ( !empty( $id ) )
777
- $where_args[] = $wpdb->prepare( "id = %d", $id );
778
-
779
- if ( !empty( $user_id ) )
780
- $where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
781
-
782
- if ( !empty( $action ) )
783
- $where_args[] = $wpdb->prepare( "action = %s", $action );
784
-
785
- if ( !empty( $content ) )
786
- $where_args[] = $wpdb->prepare( "content = %s", $content );
787
-
788
- if ( !empty( $component ) )
789
- $where_args[] = $wpdb->prepare( "component = %s", $component );
790
-
791
- if ( !empty( $type ) )
792
- $where_args[] = $wpdb->prepare( "type = %s", $type );
793
-
794
- if ( !empty( $primary_link ) )
795
- $where_args[] = $wpdb->prepare( "primary_link = %s", $primary_link );
796
-
797
- if ( !empty( $item_id ) )
798
- $where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
799
-
800
- if ( !empty( $secondary_item_id ) )
801
- $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
802
-
803
- if ( !empty( $date_recorded ) )
804
- $where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
805
-
806
- if ( !empty( $hide_sitewide ) )
807
- $where_args[] = $wpdb->prepare( "hide_sitewide = %d", $hide_sitewide );
808
-
809
- if ( !empty( $where_args ) )
810
- $where_sql = 'WHERE ' . join( ' AND ', $where_args );
811
- else
812
- return false;
813
-
814
- // Fetch the activity IDs so we can delete any comments for this activity item
815
- $activity_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
816
-
817
- if ( ! $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$where_sql}" ) ) {
818
- return false;
819
- }
820
-
821
- // Handle accompanying activity comments and meta deletion
822
- if ( $activity_ids ) {
823
- $activity_ids_comma = implode( ',', wp_parse_id_list( $activity_ids ) );
824
- $activity_comments_where_sql = "WHERE type = 'activity_comment' AND item_id IN ({$activity_ids_comma})";
825
-
826
- // Fetch the activity comment IDs for our deleted activity items
827
- $activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} {$activity_comments_where_sql}" );
828
-
829
- // We have activity comments!
830
- if ( ! empty( $activity_comment_ids ) ) {
831
- // Delete activity comments
832
- $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$activity_comments_where_sql}" );
833
-
834
- // Merge activity IDs with activity comment IDs
835
- $activity_ids = array_merge( $activity_ids, $activity_comment_ids );
836
- }
837
-
838
- // Delete all activity meta entries for activity items and activity comments
839
- BP_Activity_Activity::delete_activity_meta_entries( $activity_ids );
840
- }
841
-
842
- return $activity_ids;
843
- }
844
-
845
- /**
846
- * Delete the comments associated with a set of activity items.
847
- *
848
- * @since BuddyPress (1.2)
849
- *
850
- * @todo Mark as deprecated? Method is no longer used internally.
851
- *
852
- * @param array $activity_ids Activity IDs whose comments should be deleted.
853
- * @param bool $delete_meta Should we delete the activity meta items for these comments?
854
- * @return bool True on success.
855
- */
856
- public static function delete_activity_item_comments( $activity_ids = array(), $delete_meta = true ) {
857
- global $bp, $wpdb;
858
-
859
- $delete_meta = (bool) $delete_meta;
860
-
861
- $activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
862
-
863
- if ( $delete_meta ) {
864
- // Fetch the activity comment IDs for our deleted activity items
865
- $activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
866
-
867
- if ( ! empty( $activity_comment_ids ) ) {
868
- self::delete_activity_meta_entries( $activity_comment_ids );
869
- }
870
- }
871
-
872
- return $wpdb->query( "DELETE FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
873
- }
874
-
875
- /**
876
- * Delete the meta entries associated with a set of activity items.
877
- *
878
- * @since BuddyPress (1.2)
879
- *
880
- * @param array $activity_ids Activity IDs whose meta should be deleted.
881
- * @return bool True on success.
882
- */
883
- public static function delete_activity_meta_entries( $activity_ids = array() ) {
884
- $activity_ids = wp_parse_id_list( $activity_ids );
885
-
886
- foreach ( $activity_ids as $activity_id ) {
887
- bp_activity_delete_meta( $activity_id );
888
- }
889
-
890
- return true;
891
- }
892
-
893
- /**
894
- * Append activity comments to their associated activity items.
895
- *
896
- * @since BuddyPress (1.2)
897
- *
898
- * @global wpdb $wpdb WordPress database object
899
- *
900
- * @param array $activities Activities to fetch comments for.
901
- * @param bool $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
902
- * @return array The updated activities with nested comments.
903
- */
904
- public static function append_comments( $activities, $spam = 'ham_only' ) {
905
- $activity_comments = array();
906
-
907
- // Now fetch the activity comments and parse them into the correct position in the activities array.
908
- foreach ( (array) $activities as $activity ) {
909
- $top_level_parent_id = 'activity_comment' == $activity->type ? $activity->item_id : 0;
910
- $activity_comments[$activity->id] = BP_Activity_Activity::get_activity_comments( $activity->id, $activity->mptt_left, $activity->mptt_right, $spam, $top_level_parent_id );
911
- }
912
-
913
- // Merge the comments with the activity items
914
- foreach ( (array) $activities as $key => $activity ) {
915
- if ( isset( $activity_comments[$activity->id] ) ) {
916
- $activities[$key]->children = $activity_comments[$activity->id];
917
- }
918
- }
919
-
920
- return $activities;
921
- }
922
-
923
- /**
924
- * Get activity comments that are associated with a specific activity ID.
925
- *
926
- * @since BuddyPress (1.2)
927
- *
928
- * @global BuddyPress $bp The one true BuddyPress instance.
929
- * @global wpdb $wpdb WordPress database object.
930
- *
931
- * @param int $activity_id Activity ID to fetch comments for.
932
- * @param int $left Left-most node boundary.
933
- * @param into $right Right-most node boundary.
934
- * @param bool $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
935
- * @param int $top_level_parent_id Optional. The id of the root-level parent activity item.
936
- * @return array The updated activities with nested comments.
937
- */
938
- public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
939
- global $wpdb, $bp;
940
-
941
- if ( empty( $top_level_parent_id ) ) {
942
- $top_level_parent_id = $activity_id;
943
- }
944
-
945
- $comments = wp_cache_get( $activity_id, 'bp_activity_comments' );
946
-
947
- // We store the string 'none' to cache the fact that the
948
- // activity item has no comments
949
- if ( 'none' === $comments ) {
950
- $comments = false;
951
-
952
- // A true cache miss
953
- } else if ( empty( $comments ) ) {
954
-
955
- // Select the user's fullname with the query
956
- if ( bp_is_active( 'xprofile' ) ) {
957
- $fullname_select = ", pd.value as user_fullname";
958
- $fullname_from = ", {$bp->profile->table_name_data} pd ";
959
- $fullname_where = "AND pd.user_id = a.user_id AND pd.field_id = 1";
960
-
961
- // Prevent debug errors
962
- } else {
963
- $fullname_select = $fullname_from = $fullname_where = '';
964
- }
965
-
966
- // Don't retrieve activity comments marked as spam
967
- if ( 'ham_only' == $spam ) {
968
- $spam_sql = 'AND a.is_spam = 0';
969
- } elseif ( 'spam_only' == $spam ) {
970
- $spam_sql = 'AND a.is_spam = 1';
971
- } else {
972
- $spam_sql = '';
973
- }
974
-
975
- // Legacy query - not recommended
976
- $func_args = func_get_args();
977
- if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, $func_args ) ) {
978
- $sql = apply_filters( 'bp_activity_comments_user_join_filter', $wpdb->prepare( "SELECT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name{$fullname_select} FROM {$bp->activity->table_name} a, {$wpdb->users} u{$fullname_from} WHERE u.ID = a.user_id {$fullname_where} AND a.type = 'activity_comment' {$spam_sql} AND a.item_id = %d AND a.mptt_left > %d AND a.mptt_left < %d ORDER BY a.date_recorded ASC", $top_level_parent_id, $left, $right ), $activity_id, $left, $right, $spam_sql );
979
-
980
- $descendants = $wpdb->get_results( $sql );
981
-
982
- // We use the mptt BETWEEN clause to limit returned
983
- // descendants to the correct part of the tree.
984
- } else {
985
- $sql = $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} a WHERE a.type = 'activity_comment' {$spam_sql} AND a.item_id = %d and a.mptt_left > %d AND a.mptt_left < %d ORDER BY a.date_recorded ASC", $top_level_parent_id, $left, $right );
986
-
987
- $descendant_ids = $wpdb->get_col( $sql );
988
- $descendants = self::get_activity_data( $descendant_ids );
989
- $descendants = self::append_user_fullnames( $descendants );
990
- }
991
-
992
- $ref = array();
993
-
994
- // Loop descendants and build an assoc array
995
- foreach ( (array) $descendants as $d ) {
996
- $d->children = array();
997
-
998
- // If we have a reference on the parent
999
- if ( isset( $ref[ $d->secondary_item_id ] ) ) {
1000
- $ref[ $d->secondary_item_id ]->children[ $d->id ] = $d;
1001
- $ref[ $d->id ] =& $ref[ $d->secondary_item_id ]->children[ $d->id ];
1002
-
1003
- // If we don't have a reference on the parent, put in the root level
1004
- } else {
1005
- $comments[ $d->id ] = $d;
1006
- $ref[ $d->id ] =& $comments[ $d->id ];
1007
- }
1008
- }
1009
-
1010
- // Calculate depth for each item
1011
- foreach ( $ref as &$r ) {
1012
- $depth = 1;
1013
- $parent_id = $r->secondary_item_id;
1014
- while ( $parent_id !== $r->item_id ) {
1015
- $depth++;
1016
-
1017
- // When display_comments=stream, the
1018
- // parent comment may not be part of
1019
- // the returned results, so we manually
1020
- // fetch it
1021
- if ( empty( $ref[ $parent_id ] ) ) {
1022
- $direct_parent = new BP_Activity_Activity( $parent_id );
1023
- if ( isset( $direct_parent->secondary_item_id ) ) {
1024
- $parent_id = $direct_parent->secondary_item_id;
1025
- } else {
1026
- // Something went wrong
1027
- // Short-circuit the
1028
- // depth calculation
1029
- $parent_id = $r->item_id;
1030
- }
1031
- } else {
1032
- $parent_id = $ref[ $parent_id ]->secondary_item_id;
1033
- }
1034
- }
1035
- $r->depth = $depth;
1036
- }
1037
-
1038
- // If we cache a value of false, it'll count as a cache
1039
- // miss the next time the activity comments are fetched.
1040
- // Storing the string 'none' is a hack workaround to
1041
- // avoid unnecessary queries.
1042
- if ( false === $comments ) {
1043
- $cache_value = 'none';
1044
- } else {
1045
- $cache_value = $comments;
1046
- }
1047
-
1048
- wp_cache_set( $activity_id, $cache_value, 'bp_activity_comments' );
1049
- }
1050
-
1051
- return $comments;
1052
- }
1053
-
1054
- /**
1055
- * Rebuild nested comment tree under an activity or activity comment.
1056
- *
1057
- * @since BuddyPress (1.2)
1058
- *
1059
- * @global BuddyPress $bp The one true BuddyPress instance.
1060
- * @global wpdb $wpdb WordPress database object.
1061
- *
1062
- * @param int $parent_id ID of an activty or activity comment.
1063
- * @param int $left Node boundary start for activity or activity comment.
1064
- * @return int Right node boundary of activity or activity comment.
1065
- */
1066
- public static function rebuild_activity_comment_tree( $parent_id, $left = 1 ) {
1067
- global $wpdb, $bp;
1068
-
1069
- // The right value of this node is the left value + 1
1070
- $right = $left + 1;
1071
-
1072
- // Get all descendants of this node
1073
- $descendants = BP_Activity_Activity::get_child_comments( $parent_id );
1074
-
1075
- // Loop the descendants and recalculate the left and right values
1076
- foreach ( (array) $descendants as $descendant )
1077
- $right = BP_Activity_Activity::rebuild_activity_comment_tree( $descendant->id, $right );
1078
-
1079
- // We've got the left value, and now that we've processed the children
1080
- // of this node we also know the right value
1081
- if ( 1 == $left )
1082
- $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE id = %d", $left, $right, $parent_id ) );
1083
- else
1084
- $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE type = 'activity_comment' AND id = %d", $left, $right, $parent_id ) );
1085
-
1086
- // Return the right value of this node + 1
1087
- return $right + 1;
1088
- }
1089
-
1090
- /**
1091
- * Get child comments of an activity or activity comment.
1092
- *
1093
- * @since BuddyPress (1.2)
1094
- *
1095
- * @global BuddyPress $bp The one true BuddyPress instance.
1096
- * @global wpdb $wpdb WordPress database object.
1097
- *
1098
- * @param int $parent_id ID of an activty or activity comment.
1099
- * @return object Numerically indexed array of child comments.
1100
- */
1101
- public static function get_child_comments( $parent_id ) {
1102
- global $bp, $wpdb;
1103
-
1104
- return $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND secondary_item_id = %d", $parent_id ) );
1105
- }
1106
-
1107
- /**
1108
- * Get a list of components that have recorded activity associated with them.
1109
- *
1110
- * @param bool $skip_last_activity If true, components will not be
1111
- * included if the only activity type associated with them is
1112
- * 'last_activity'. (Since 2.0.0, 'last_activity' is stored in
1113
- * the activity table, but these items are not full-fledged
1114
- * activity items.) Default: true.
1115
- * @return array List of component names.
1116
- */
1117
- public static function get_recorded_components( $skip_last_activity = true ) {
1118
- global $wpdb, $bp;
1119
-
1120
- if ( $skip_last_activity ) {
1121
- $components = $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} WHERE action != '' AND action != 'last_activity' ORDER BY component ASC" );
1122
- } else {
1123
- $components = $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} ORDER BY component ASC" );
1124
- }
1125
-
1126
- return $components;
1127
- }
1128
-
1129
- /**
1130
- * Get sitewide activity items for use in an RSS feed.
1131
- *
1132
- * @param int $limit Optional. Number of items to fetch. Default: 35.
1133
- * @return array $activity_feed List of activity items, with RSS data added.
1134
- */
1135
- public static function get_sitewide_items_for_feed( $limit = 35 ) {
1136
- $activities = bp_activity_get_sitewide( array( 'max' => $limit ) );
1137
- $activity_feed = array();
1138
-
1139
- for ( $i = 0, $count = count( $activities ); $i < $count; ++$i ) {
1140
- $title = explode( '<span', $activities[$i]['content'] );
1141
- $activity_feed[$i]['title'] = trim( strip_tags( $title[0] ) );
1142
- $activity_feed[$i]['link'] = $activities[$i]['primary_link'];
1143
- $activity_feed[$i]['description'] = @sprintf( $activities[$i]['content'], '' );
1144
- $activity_feed[$i]['pubdate'] = $activities[$i]['date_recorded'];
1145
- }
1146
-
1147
- return $activity_feed;
1148
- }
1149
-
1150
- /**
1151
- * Create SQL IN clause for filter queries.
1152
- *
1153
- * @since BuddyPress (1.5)
1154
- *
1155
- * @see BP_Activity_Activity::get_filter_sql()
1156
- *
1157
- * @param string $field The database field.
1158
- * @param array|bool $items The values for the IN clause, or false when none are found.
1159
- */
1160
- public static function get_in_operator_sql( $field, $items ) {
1161
- global $wpdb;
1162
-
1163
- // split items at the comma
1164
- if ( ! is_array( $items ) ) {
1165
- $items = explode( ',', $items );
1166
- }
1167
-
1168
- // array of prepared integers or quoted strings
1169
- $items_prepared = array();
1170
-
1171
- // clean up and format each item
1172
- foreach ( $items as $item ) {
1173
- // clean up the string
1174
- $item = trim( $item );
1175
- // pass everything through prepare for security and to safely quote strings
1176
- $items_prepared[] = ( is_numeric( $item ) ) ? $wpdb->prepare( '%d', $item ) : $wpdb->prepare( '%s', $item );
1177
- }
1178
-
1179
- // build IN operator sql syntax
1180
- if ( count( $items_prepared ) )
1181
- return sprintf( '%s IN ( %s )', trim( $field ), implode( ',', $items_prepared ) );
1182
- else
1183
- return false;
1184
- }
1185
-
1186
- /**
1187
- * Create filter SQL clauses.
1188
- *
1189
- * @since BuddyPress (1.5.0)
1190
- *
1191
- * @param array $filter_array {
1192
- * Fields and values to filter by.
1193
- * @type array|string|id $user_id User ID(s).
1194
- * @type array|string $object Corresponds to the 'component'
1195
- * column in the database.
1196
- * @type array|string $action Corresponds to the 'type' column
1197
- * in the database.
1198
- * @type array|string|int $primary_id Corresponds to the 'item_id'
1199
- * column in the database.
1200
- * @type array|string|int $secondary_id Corresponds to the
1201
- * 'secondary_item_id' column in the database.
1202
- * @type int $offset Return only those items with an ID greater
1203
- * than the offset value.
1204
- * @type string $since Return only those items that have a
1205
- * date_recorded value greater than a given MySQL-formatted
1206
- * date.
1207
- * }
1208
- * @return string The filter clause, for use in a SQL query.
1209
- */
1210
- public static function get_filter_sql( $filter_array ) {
1211
-
1212
- $filter_sql = array();
1213
-
1214
- if ( !empty( $filter_array['user_id'] ) ) {
1215
- $user_sql = BP_Activity_Activity::get_in_operator_sql( 'a.user_id', $filter_array['user_id'] );
1216
- if ( !empty( $user_sql ) )
1217
- $filter_sql[] = $user_sql;
1218
- }
1219
-
1220
- if ( !empty( $filter_array['object'] ) ) {
1221
- $object_sql = BP_Activity_Activity::get_in_operator_sql( 'a.component', $filter_array['object'] );
1222
- if ( !empty( $object_sql ) )
1223
- $filter_sql[] = $object_sql;
1224
- }
1225
-
1226
- if ( !empty( $filter_array['action'] ) ) {
1227
- $action_sql = BP_Activity_Activity::get_in_operator_sql( 'a.type', $filter_array['action'] );
1228
- if ( ! empty( $action_sql ) )
1229
- $filter_sql[] = $action_sql;
1230
- }
1231
-
1232
- if ( !empty( $filter_array['primary_id'] ) ) {
1233
- $pid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.item_id', $filter_array['primary_id'] );
1234
- if ( !empty( $pid_sql ) )
1235
- $filter_sql[] = $pid_sql;
1236
- }
1237
-
1238
- if ( !empty( $filter_array['secondary_id'] ) ) {
1239
- $sid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.secondary_item_id', $filter_array['secondary_id'] );
1240
- if ( !empty( $sid_sql ) )
1241
- $filter_sql[] = $sid_sql;
1242
- }
1243
-
1244
- if ( ! empty( $filter_array['offset'] ) ) {
1245
- $sid_sql = absint( $filter_array['offset'] );
1246
- $filter_sql[] = "a.id >= {$sid_sql}";
1247
- }
1248
-
1249
- if ( ! empty( $filter_array['since'] ) ) {
1250
- // Validate that this is a proper Y-m-d H:i:s date
1251
- // Trick: parse to UNIX date then translate back
1252
- $translated_date = date( 'Y-m-d H:i:s', strtotime( $filter_array['since'] ) );
1253
- if ( $translated_date === $filter_array['since'] ) {
1254
- $filter_sql[] = "a.date_recorded > '{$translated_date}'";
1255
- }
1256
- }
1257
-
1258
- if ( empty( $filter_sql ) )
1259
- return false;
1260
-
1261
- return join( ' AND ', $filter_sql );
1262
- }
1263
-
1264
- /**
1265
- * Get the date/time of last recorded activity.
1266
- *
1267
- * @since BuddyPress (1.2)
1268
- *
1269
- * @return string ISO timestamp.
1270
- */
1271
- public static function get_last_updated() {
1272
- global $bp, $wpdb;
1273
-
1274
- return $wpdb->get_var( "SELECT date_recorded FROM {$bp->activity->table_name} ORDER BY date_recorded DESC LIMIT 1" );
1275
- }
1276
-
1277
- /**
1278
- * Get favorite count for a given user.
1279
- *
1280
- * @since BuddyPress (1.2)
1281
- *
1282
- * @param int The ID of the user whose favorites you're counting.
1283
- * @return int A count of the user's favorites.
1284
- */
1285
- public static function total_favorite_count( $user_id ) {
1286
- if ( !$favorite_activity_entries = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ) )
1287
- return 0;
1288
-
1289
- return count( maybe_unserialize( $favorite_activity_entries ) );
1290
- }
1291
-
1292
- /**
1293
- * Check whether an activity item exists with a given string content.
1294
- *
1295
- * @param string $content The content to filter by.
1296
- * @return int|bool The ID of the first matching item if found, otherwise false.
1297
- */
1298
- public static function check_exists_by_content( $content ) {
1299
- global $wpdb, $bp;
1300
-
1301
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE content = %s", $content ) );
1302
- }
1303
-
1304
- /**
1305
- * Hide all activity for a given user.
1306
- *
1307
- * @param int $user_id The ID of the user whose activity you want to mark hidden.
1308
- * @param int
1309
- */
1310
- public static function hide_all_for_user( $user_id ) {
1311
- global $wpdb, $bp;
1312
-
1313
- return $wpdb->get_var( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET hide_sitewide = 1 WHERE user_id = %d", $user_id ) );
1314
- }
1315
- }
1316
-
1317
- /**
1318
- * Create a RSS feed using the activity component.
1319
- *
1320
- * You should only construct a new feed when you've validated that you're on
1321
- * the appropriate screen.
1322
- *
1323
- * See {@link bp_activity_action_sitewide_feed()} as an example.
1324
- *
1325
- * Accepted parameters:
1326
- * id - internal id for the feed; should be alphanumeric only
1327
- * (required)
1328
- * title - RSS feed title
1329
- * link - Relevant link for the RSS feed
1330
- * description - RSS feed description
1331
- * ttl - Time-to-live (see inline doc in constructor)
1332
- * update_period - Part of the syndication module (see inline doc in
1333
- * constructor for more info)
1334
- * update_frequency - Part of the syndication module (see inline doc in
1335
- * constructor for more info)
1336
- * max - Number of feed items to display
1337
- * activity_args - Arguments passed to {@link bp_has_activities()}
1338
- *
1339
- * @since BuddyPress (1.8)
1340
- */
1341
- class BP_Activity_Feed {
1342
- /**
1343
- * Holds our custom class properties.
1344
- *
1345
- * These variables are stored in a protected array that is magically
1346
- * updated using PHP 5.2+ methods.
1347
- *
1348
- * @see BP_Feed::__construct() This is where $data is added
1349
- * @var array
1350
- */
1351
- protected $data;
1352
-
1353
- /**
1354
- * Magic method for checking the existence of a certain data variable.
1355
- *
1356
- * @param string $key
1357
- */
1358
- public function __isset( $key ) { return isset( $this->data[$key] ); }
1359
-
1360
- /**
1361
- * Magic method for getting a certain data variable.
1362
- *
1363
- * @param string $key
1364
- */
1365
- public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
1366
-
1367
- /**
1368
- * Constructor.
1369
- *
1370
- * @param array $args Optional
1371
- */
1372
- public function __construct( $args = array() ) {
1373
- // If feeds are disabled, stop now!
1374
- if ( false === (bool) apply_filters( 'bp_activity_enable_feeds', true ) ) {
1375
- global $wp_query;
1376
-
1377
- // set feed flag to false
1378
- $wp_query->is_feed = false;
1379
-
1380
- return false;
1381
- }
1382
-
1383
- // Setup data
1384
- $this->data = wp_parse_args( $args, array(
1385
- // Internal identifier for the RSS feed - should be alphanumeric only
1386
- 'id' => '',
1387
-
1388
- // RSS title - should be plain-text
1389
- 'title' => '',
1390
-
1391
- // relevant link for the RSS feed
1392
- 'link' => '',
1393
-
1394
- // RSS description - should be plain-text
1395
- 'description' => '',
1396
-
1397
- // Time-to-live - number of minutes to cache the data before an aggregator
1398
- // requests it again. This is only acknowledged if the RSS client supports it
1399
- //
1400
- // See: http://www.rssboard.org/rss-profile#element-channel-ttl
1401
- // http://www.kbcafe.com/rss/rssfeedstate.html#ttl
1402
- 'ttl' => '30',
1403
-
1404
- // Syndication module - similar to ttl, but not really supported by RSS
1405
- // clients
1406
- //
1407
- // See: http://web.resource.org/rss/1.0/modules/syndication/#description
1408
- // http://www.kbcafe.com/rss/rssfeedstate.html#syndicationmodule
1409
- 'update_period' => 'hourly',
1410
- 'update_frequency' => 2,
1411
-
1412
- // Number of items to display
1413
- 'max' => 50,
1414
-
1415
- // Activity arguments passed to bp_has_activities()
1416
- 'activity_args' => array()
1417
- ) );
1418
-
1419
- // Plugins can use this filter to modify the feed before it is setup
1420
- do_action_ref_array( 'bp_activity_feed_prefetch', array( &$this ) );
1421
-
1422
- // Setup class properties
1423
- $this->setup_properties();
1424
-
1425
- // Check if id is valid
1426
- if ( empty( $this->id ) ) {
1427
- _doing_it_wrong( 'BP_Activity_Feed', __( "RSS feed 'id' must be defined", 'buddypress' ), 'BP 1.8' );
1428
- return false;
1429
- }
1430
-
1431
- // Plugins can use this filter to modify the feed after it's setup
1432
- do_action_ref_array( 'bp_activity_feed_postfetch', array( &$this ) );
1433
-
1434
- // Setup feed hooks
1435
- $this->setup_hooks();
1436
-
1437
- // Output the feed
1438
- $this->output();
1439
-
1440
- // Kill the rest of the output
1441
- die();
1442
- }
1443
-
1444
- /** SETUP ****************************************************************/
1445
-
1446
- /**
1447
- * Setup and validate the class properties.
1448
- *
1449
- * @access protected
1450
- */
1451
- protected function setup_properties() {
1452
- $this->id = sanitize_title( $this->id );
1453
- $this->title = strip_tags( $this->title );
1454
- $this->link = esc_url_raw( $this->link );
1455
- $this->description = strip_tags( $this->description );
1456
- $this->ttl = (int) $this->ttl;
1457
- $this->update_period = strip_tags( $this->update_period );
1458
- $this->update_frequency = (int) $this->update_frequency;
1459
-
1460
- $this->activity_args = wp_parse_args( $this->activity_args, array(
1461
- 'max' => $this->max,
1462
- 'per_page' => $this->max,
1463
- 'display_comments' => 'stream'
1464
- ) );
1465
-
1466
- }
1467
-
1468
- /**
1469
- * Setup some hooks that are used in the feed.
1470
- *
1471
- * Currently, these hooks are used to maintain backwards compatibility with
1472
- * the RSS feeds previous to BP 1.8.
1473
- *
1474
- * @access protected
1475
- */
1476
- protected function setup_hooks() {
1477
- add_action( 'bp_activity_feed_rss_attributes', array( $this, 'backpat_rss_attributes' ) );
1478
- add_action( 'bp_activity_feed_channel_elements', array( $this, 'backpat_channel_elements' ) );
1479
- add_action( 'bp_activity_feed_item_elements', array( $this, 'backpat_item_elements' ) );
1480
- }
1481
-
1482
- /** BACKPAT HOOKS ********************************************************/
1483
-
1484
- /**
1485
- * Fire a hook to ensure backward compatibility for RSS attributes.
1486
- */
1487
- public function backpat_rss_attributes() {
1488
- do_action( 'bp_activity_' . $this->id . '_feed' );
1489
- }
1490
-
1491
- /**
1492
- * Fire a hook to ensure backward compatibility for channel elements.
1493
- */
1494
- public function backpat_channel_elements() {
1495
- do_action( 'bp_activity_' . $this->id . '_feed_head' );
1496
- }
1497
-
1498
- /**
1499
- * Fire a hook to ensure backward compatibility for item elements.
1500
- */
1501
- public function backpat_item_elements() {
1502
- switch ( $this->id ) {
1503
-
1504
- // sitewide and friends feeds use the 'personal' hook
1505
- case 'sitewide' :
1506
- case 'friends' :
1507
- $id = 'personal';
1508
-
1509
- break;
1510
-
1511
- default :
1512
- $id = $this->id;
1513
-
1514
- break;
1515
- }
1516
-
1517
- do_action( 'bp_activity_' . $id . '_feed_item' );
1518
- }
1519
-
1520
- /** HELPERS **************************************************************/
1521
-
1522
- /**
1523
- * Output the feed's item content.
1524
- *
1525
- * @access protected
1526
- */
1527
- protected function feed_content() {
1528
- bp_activity_content_body();
1529
-
1530
- switch ( $this->id ) {
1531
-
1532
- // also output parent activity item if we're on a specific feed
1533
- case 'favorites' :
1534
- case 'friends' :
1535
- case 'mentions' :
1536
- case 'personal' :
1537
-
1538
- if ( 'activity_comment' == bp_get_activity_action_name() ) :
1539
- ?>
1540
- <strong><?php _e( 'In reply to', 'buddypress' ) ?></strong> -
1541
- <?php bp_activity_parent_content() ?>
1542
- <?php
1543
- endif;
1544
-
1545
- break;
1546
- }
1547
- }
1548
-
1549
- /**
1550
- * Sets various HTTP headers related to Content-Type and browser caching.
1551
- *
1552
- * Most of this class method is derived from {@link WP::send_headers()}.
1553
- *
1554
- * @since BuddyPress (1.9.0)
1555
- *
1556
- * @access protected
1557
- */
1558
- protected function http_headers() {
1559
- // set up some additional headers if not on a directory page
1560
- // this is done b/c BP uses pseudo-pages
1561
- if ( ! bp_is_directory() ) {
1562
- global $wp_query;
1563
-
1564
- $wp_query->is_404 = false;
1565
- status_header( 200 );
1566
- }
1567
-
1568
- // Set content-type
1569
- @header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
1570
-
1571
- // Cache-related variables
1572
- $last_modified = mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false );
1573
- $modified_timestamp = strtotime( $last_modified );
1574
- $etag = md5( $last_modified );
1575
-
1576
- // Set cache-related headers
1577
- @header( 'Last-Modified: ' . $last_modified );
1578
- @header( 'Pragma: no-cache' );
1579
- @header( 'ETag: ' . '"' . $etag . '"' );
1580
-
1581
- // First commit of BuddyPress! (Easter egg)
1582
- @header( 'Expires: Tue, 25 Mar 2008 17:13:55 GMT');
1583
-
1584
- // Get ETag from supported user agents
1585
- if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
1586
- $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
1587
-
1588
- // Remove quotes from ETag
1589
- $client_etag = trim( $client_etag, '"' );
1590
-
1591
- // Strip suffixes from ETag if they exist (eg. "-gzip")
1592
- if ( $etag_suffix_pos = strpos( $client_etag, '-' ) ) {
1593
- $client_etag = substr( $client_etag, 0, $etag_suffix_pos );
1594
- }
1595
-
1596
- // No ETag found
1597
- } else {
1598
- $client_etag = false;
1599
- }
1600
-
1601
- // Get client last modified timestamp from supported user agents
1602
- $client_last_modified = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
1603
- $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
1604
-
1605
- // Set 304 status if feed hasn't been updated since last fetch
1606
- if ( ( $client_last_modified && $client_etag ) ?
1607
- ( ( $client_modified_timestamp >= $modified_timestamp ) && ( $client_etag == $etag ) ) :
1608
- ( ( $client_modified_timestamp >= $modified_timestamp ) || ( $client_etag == $etag ) ) ) {
1609
- $status = 304;
1610
- } else {
1611
- $status = false;
1612
- }
1613
-
1614
- // If feed hasn't changed as reported by the user agent, set 304 status header
1615
- if ( ! empty( $status ) ) {
1616
- status_header( $status );
1617
-
1618
- // cached response, so stop now!
1619
- if ( $status == 304 ) {
1620
- exit();
1621
- }
1622
- }
1623
- }
1624
-
1625
- /** OUTPUT ***************************************************************/
1626
-
1627
- /**
1628
- * Output the RSS feed.
1629
- *
1630
- * @access protected
1631
- */
1632
- protected function output() {
1633
- $this->http_headers();
1634
- echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?'.'>';
1635
- ?>
1636
-
1637
- <rss version="2.0"
1638
- xmlns:content="http://purl.org/rss/1.0/modules/content/"
1639
- xmlns:atom="http://www.w3.org/2005/Atom"
1640
- xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
1641
- xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
1642
- <?php do_action( 'bp_activity_feed_rss_attributes' ); ?>
1643
- >
1644
-
1645
- <channel>
1646
- <title><?php echo $this->title; ?></title>
1647
- <link><?php echo $this->link; ?></link>
1648
- <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
1649
- <description><?php echo $this->description ?></description>
1650
- <lastBuildDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false ); ?></lastBuildDate>
1651
- <generator>http://buddypress.org/?v=<?php bp_version(); ?></generator>
1652
- <language><?php bloginfo_rss( 'language' ); ?></language>
1653
- <ttl><?php echo $this->ttl; ?></ttl>
1654
- <sy:updatePeriod><?php echo $this->update_period; ?></sy:updatePeriod>
1655
- <sy:updateFrequency><?php echo $this->update_frequency; ?></sy:updateFrequency>
1656
- <?php do_action( 'bp_activity_feed_channel_elements' ); ?>
1657
-
1658
- <?php if ( bp_has_activities( $this->activity_args ) ) : ?>
1659
- <?php while ( bp_activities() ) : bp_the_activity(); ?>
1660
- <item>
1661
- <guid isPermaLink="false"><?php bp_activity_feed_item_guid(); ?></guid>
1662
- <title><?php echo stripslashes( bp_get_activity_feed_item_title() ); ?></title>
1663
- <link><?php bp_activity_thread_permalink() ?></link>
1664
- <pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_get_activity_feed_item_date(), false ); ?></pubDate>
1665
-
1666
- <?php if ( bp_get_activity_feed_item_description() ) : ?>
1667
- <content:encoded><![CDATA[<?php $this->feed_content(); ?>]]></content:encoded>
1668
- <?php endif; ?>
1669
-
1670
- <?php if ( bp_activity_can_comment() ) : ?>
1671
- <slash:comments><?php bp_activity_comment_count(); ?></slash:comments>
1672
- <?php endif; ?>
1673
-
1674
- <?php do_action( 'bp_activity_feed_item_elements' ); ?>
1675
- </item>
1676
- <?php endwhile; ?>
1677
 
1678
- <?php endif; ?>
1679
- </channel>
1680
- </rss><?php
1681
- }
1682
- }
1
  <?php
2
  /**
3
+ * BuddyPress Activity Classes.
4
  *
5
  * @package BuddyPress
6
+ * @subpackage ActivityClasses
7
+ * @since 1.0.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
 
13
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-activity.php';
14
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-feed.php';
15
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-query.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ // Embeds - only applicable for WP 4.5+
18
+ if ( version_compare( $GLOBALS['wp_version'], '4.5', '>=' ) && bp_is_active( 'activity', 'embeds' ) ) {
19
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-oembed-extension.php';
20
+ }
 
bp-activity/bp-activity-cssjs.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Activity component CSS/JS
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage ActivityScripts
7
+ * @since 1.0.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Enqueue @mentions JS.
15
+ *
16
+ * @since 2.1.0
17
+ */
18
+ function bp_activity_mentions_script() {
19
+ if ( ! bp_activity_maybe_load_mentions_scripts() ) {
20
+ return;
21
+ }
22
+
23
+ // Special handling for New/Edit screens in wp-admin.
24
+ if ( is_admin() ) {
25
+ if (
26
+ ! get_current_screen() ||
27
+ ! in_array( get_current_screen()->base, array( 'page', 'post' ) ) ||
28
+ ! post_type_supports( get_current_screen()->post_type, 'editor' ) ) {
29
+ return;
30
+ }
31
+ }
32
+
33
+
34
+ $min = bp_core_get_minified_asset_suffix();
35
+
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
+ }
43
+
44
+ // If the script has been enqueued, let's attach our mentions TinyMCE init callback.
45
+ add_filter( 'tiny_mce_before_init', 'bp_add_mentions_on_tinymce_init', 10, 2 );
46
+
47
+ /**
48
+ * Fires at the end of the Activity Mentions script.
49
+ *
50
+ * This is the hook where BP components can add their own prefetched results
51
+ * friends to the page for quicker @mentions lookups.
52
+ *
53
+ * @since 2.1.0
54
+ */
55
+ do_action( 'bp_activity_mentions_prime_results' );
56
+ }
57
+ add_action( 'bp_enqueue_scripts', 'bp_activity_mentions_script' );
58
+ add_action( 'bp_admin_enqueue_scripts', 'bp_activity_mentions_script' );
59
+
60
+ /**
61
+ * Bind the mentions listener to a wp_editor instance when TinyMCE initializes.
62
+ *
63
+ * @since 2.3.3
64
+ *
65
+ * @param array $settings An array with TinyMCE config.
66
+ * @param string $editor_id Unique editor identifier, e.g. 'content'.
67
+ * @return array $mceInit An array with TinyMCE config.
68
+ */
69
+ function bp_add_mentions_on_tinymce_init( $settings, $editor_id ) {
70
+ // We only apply the mentions init to the visual post editor in the WP dashboard.
71
+ if ( 'content' === $editor_id ) {
72
+ $settings['init_instance_callback'] = 'window.bp.mentions.tinyMCEinit';
73
+ }
74
+
75
+ return $settings;
76
+ }
bp-activity/bp-activity-embeds.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Functions related to embedding single activity items externally.
4
+ *
5
+ * Relies on WordPress 4.5.
6
+ *
7
+ * @since 2.6.0
8
+ *
9
+ * @package BuddyPress
10
+ * @subpackage ActivityEmbeds
11
+ */
12
+
13
+ // Exit if accessed directly.
14
+ defined( 'ABSPATH' ) || exit;
15
+
16
+ /**
17
+ * Loads our activity oEmbed component.
18
+ *
19
+ * @since 2.6.0
20
+ */
21
+ function bp_activity_setup_oembed() {
22
+ if ( version_compare( $GLOBALS['wp_version'], '4.5', '>=' ) && bp_is_active( 'activity', 'embeds' ) ) {
23
+ buddypress()->activity->oembed = new BP_Activity_oEmbed_Extension;
24
+ }
25
+ }
26
+ add_action( 'bp_loaded', 'bp_activity_setup_oembed' );
27
+
28
+ /**
29
+ * Catch links in embed excerpt so top.location.href can be added.
30
+ *
31
+ * Due to <iframe sandbox="allow-top-navigation">, links in embeds can only be
32
+ * clicked if invoked with top.location.href via JS.
33
+ *
34
+ * @since 2.6.0
35
+ *
36
+ * @param string $text Embed excerpt
37
+ * @return string
38
+ */
39
+ function bp_activity_embed_excerpt_onclick_location_filter( $text ) {
40
+ return preg_replace_callback( '/<a\s+[^>]*href=\"([^\"]*)\"/iU', 'bp_activity_embed_excerpt_onclick_location_filter_callback', $text );
41
+ }
42
+ /**
43
+ * Add onclick="top.location.href" to a link.
44
+ *
45
+ * @since 2.6.0
46
+ *
47
+ * @param array $matches Items matched by bp_activity_embed_excerpt_onclick_location_filter().
48
+ * @return string
49
+ */
50
+ function bp_activity_embed_excerpt_onclick_location_filter_callback( $matches ) {
51
+ return sprintf( '<a href="%1$s" onclick="top.location.href=\'%1$s\'"', $matches[1] );
52
+ }
53
+
54
+ /**
55
+ * Add inline styles for BP activity embeds.
56
+ *
57
+ * @since 2.6.0
58
+ */
59
+ function bp_activity_embed_add_inline_styles() {
60
+ if ( false === bp_is_single_activity() ) {
61
+ return;
62
+ }
63
+
64
+ $min = bp_core_get_minified_asset_suffix();
65
+
66
+ if ( is_rtl() ) {
67
+ $css = bp_locate_template_asset( "css/embeds-activity-rtl{$min}.css" );
68
+ } else {
69
+ $css = bp_locate_template_asset( "css/embeds-activity{$min}.css" );
70
+ }
71
+
72
+ // Bail if file wasn't found.
73
+ if ( false === $css ) {
74
+ return;
75
+ }
76
+
77
+ // Grab contents of CSS file and do some rudimentary CSS protection.
78
+ $css = file_get_contents( $css['file'] );
79
+ $css = wp_kses( $css, array( "\'", '\"' ) );
80
+
81
+ printf( '<style type="text/css">%s</style>', $css );
82
+ }
83
+ add_action( 'embed_head', 'bp_activity_embed_add_inline_styles', 20 );
84
+
85
+ /**
86
+ * Query for the activity item on the activity embed template.
87
+ *
88
+ * Basically a wrapper for {@link bp_has_activities()}, but allows us to
89
+ * use the activity loop without requerying for it again.
90
+ *
91
+ * @since 2.6.0
92
+ *
93
+ * @param int $activity_id The activity ID.
94
+ * @return bool
95
+ */
96
+ function bp_activity_embed_has_activity( $activity_id = 0 ) {
97
+ global $activities_template;
98
+
99
+ if ( empty( $activity_id ) ) {
100
+ return false;
101
+ }
102
+
103
+ if ( ! empty( $activities_template->activities ) ) {
104
+ $activity = (array) $activities_template->activities;
105
+ $activity = reset( $activity );
106
+
107
+ // No need to requery if we already got the embed activity
108
+ if ( (int) $activity_id === $activity->id ) {
109
+ return $activities_template->has_activities();
110
+ }
111
+ }
112
+
113
+ return bp_has_activities( array(
114
+ 'display_comments' => 'threaded',
115
+ 'show_hidden' => true,
116
+ 'include' => (int) $activity_id,
117
+ ) );
118
+ }
119
+
120
+ /**
121
+ * Outputs excerpt for an activity embed item.
122
+ *
123
+ * @since 2.6.0
124
+ */
125
+ function bp_activity_embed_excerpt( $content = '' ) {
126
+ echo bp_activity_get_embed_excerpt( $content = '' );
127
+ }
128
+
129
+ /**
130
+ * Generates excerpt for an activity embed item.
131
+ *
132
+ * @since 2.6.0
133
+ *
134
+ * @param string $content The content to generate an excerpt for.
135
+ * @return string
136
+ */
137
+ function bp_activity_get_embed_excerpt( $content = '' ) {
138
+ if ( empty( $content ) && ! empty( $GLOBALS['activities_template']->in_the_loop ) ) {
139
+ $content = $GLOBALS['activities_template']->activity->content;
140
+ }
141
+
142
+ /*
143
+ * bp_activity_truncate_entry() includes the 'Read More' link, which is why
144
+ * we're using this instead of bp_create_excerpt().
145
+ */
146
+ $content = html_entity_decode( $content );
147
+ $content = bp_activity_truncate_entry( $content, array(
148
+ 'html' => false,
149
+ 'filter_shortcodes' => true,
150
+ 'strip_tags' => true,
151
+ 'force_truncate' => true
152
+ ) );
153
+
154
+ /**
155
+ * Filter the activity embed excerpt.
156
+ *
157
+ * @since 2.6.0
158
+ *
159
+ * @var string $content Embed Excerpt.
160
+ * @var string $unmodified_content Unmodified activity content.
161
+ */
162
+ return apply_filters( 'bp_activity_get_embed_excerpt', $content, $GLOBALS['activities_template']->activity->content );
163
+ }
164
+
165
+ /**
166
+ * Outputs the first embedded item in the activity oEmbed template.
167
+ *
168
+ * @since 2.6.0
169
+ */
170
+ function bp_activity_embed_media() {
171
+ // Bail if oEmbed request explicitly hides media.
172
+ if ( isset( $_GET['hide_media'] ) && true == wp_validate_boolean( $_GET['hide_media'] ) ) {
173
+ /**
174
+ * Do something after media is rendered for an activity oEmbed item.
175
+ *
176
+ * @since 2.6.0
177
+ */
178
+ do_action( 'bp_activity_embed_after_media' );
179
+
180
+ return;
181
+ }
182
+
183
+ /**
184
+ * Should we display media in the oEmbed template?
185
+ *
186
+ * @since 2.6.0
187
+ *
188
+ * @param bool $retval Defaults to true.
189
+ */
190
+ $allow_media = apply_filters( 'bp_activity_embed_display_media', true );
191
+
192
+ // Find oEmbeds from only WP registered providers.
193
+ bp_remove_all_filters( 'oembed_providers' );
194
+ $media = bp_core_extract_media_from_content( $GLOBALS['activities_template']->activity->content, 'embeds' );
195
+ bp_restore_all_filters( 'oembed_providers' );
196
+
197
+ // oEmbeds have precedence over inline video / audio.
198
+ if ( isset( $media['embeds'] ) && true === $allow_media ) {
199
+ // Autoembed first URL.
200
+ $oembed_defaults = wp_embed_defaults();
201
+ $oembed_args = array(
202
+ 'width' => $oembed_defaults['width'],
203
+ 'height' => $oembed_defaults['height'],
204
+ 'discover' => true
205
+ );
206
+ $url = $media['embeds'][0]['url'];
207
+ $cachekey = '_oembed_response_' . md5( $url . serialize( $oembed_args ) );
208
+
209
+ // Try to fetch oEmbed response from meta.
210
+ $oembed = bp_activity_get_meta( bp_get_activity_id(), $cachekey );
211
+
212
+ // No cache, so fetch full oEmbed response now!
213
+ if ( '' === $oembed ) {
214
+ $o = _wp_oembed_get_object();
215
+ $oembed = $o->fetch( $o->get_provider( $url, $oembed_args ), $url, $oembed_args );
216
+
217
+ // Cache oEmbed response.
218
+ bp_activity_update_meta( bp_get_activity_id(), $cachekey, $oembed );
219
+ }
220
+
221
+ $content = '';
222
+
223
+ /**
224
+ * Filters the default embed display max width.
225
+ *
226
+ * This is used if the oEmbed response does not return a thumbnail width.
227
+ *
228
+ * @since 2.6.0
229
+ *
230
+ * @param int $width.
231
+ */
232
+ $width = (int) apply_filters( 'bp_activity_embed_display_media_width', 550 );
233
+
234
+ // Set thumbnail.
235
+ if ( 'photo' === $oembed->type ) {
236
+ $thumbnail = $oembed->url;
237
+ } elseif ( isset( $oembed->thumbnail_url ) ) {
238
+ $thumbnail = $oembed->thumbnail_url;
239
+
240
+ /* Non-oEmbed standard attributes */
241
+ // Mixcloud
242
+ } elseif ( isset( $oembed->image ) ) {
243
+ $thumbnail = $oembed->image;
244
+ // ReverbNation
245
+ } elseif ( isset( $oembed->{'thumbnail-url'} ) ) {
246
+ $thumbnail = $oembed->{'thumbnail-url'};
247
+ }
248
+
249
+ // Display thumb and related oEmbed meta.
250
+ if ( true === isset ( $thumbnail ) ) {
251
+ $play_icon = $caption = '';
252
+
253
+ // Add play icon for non-photos.
254
+ if ( 'photo' !== $oembed->type ) {
255
+ /**
256
+ * ion-play icon from Ionicons.
257
+ *
258
+ * @link http://ionicons.com/
259
+ * @license MIT
260
+ */
261
+ $play_icon = <<<EOD
262
+ <svg id="Layer_1" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"/></svg>
263
+ EOD;
264
+
265
+ $play_icon = sprintf( '<a rel="nofollow" class="play-btn" href="%1$s" onclick="top.location.href=\'%1$s\'">%2$s</a>', esc_url( $url ), $play_icon );
266
+ }
267
+
268
+ // Thumb width
269
+ $thumb_width = isset( $oembed->thumbnail_width ) && 'photo' !== $oembed->type && (int) $oembed->thumbnail_width < 550 ? (int) $oembed->thumbnail_width : $width;
270
+
271
+ $float_width = 350;
272
+
273
+ // Set up thumb.
274
+ $content = sprintf( '<div class="thumb" style="max-width:%1$spx">%2$s<a href="%3$s" rel="nofollow" onclick="top.location.href=\'%3$s\'"><img src="%4$s" /></a></div>', $thumb_width, $play_icon, esc_url( $url ), esc_url( $thumbnail ) );
275
+
276
+ // Show title.
277
+ if ( isset( $oembed->title ) ) {
278
+ $caption .= sprintf( '<p class="caption-title"><strong>%s</strong></p>', apply_filters( 'single_post_title', $oembed->title ) );
279
+ }
280
+
281
+ // Show description (non-oEmbed standard)
282
+ if ( isset( $oembed->description ) ) {
283
+ $caption .= sprintf( '<div class="caption-description">%s</div>', apply_filters( 'bp_activity_get_embed_excerpt', $oembed->description ) );
284
+ }
285
+
286
+ // Show author info.
287
+ if ( isset( $oembed->provider_name ) && isset( $oembed->author_name ) ) {
288
+ /* translators: By [oEmbed author] on [oEmbed provider]. eg. By BuddyPress on YouTube. */
289
+ $anchor_text = sprintf( __( 'By %1$s on %2$s', 'buddypress' ), $oembed->author_name, $oembed->provider_name );
290
+
291
+ } elseif ( isset( $oembed->provider_name ) ) {
292
+ $anchor_text = sprintf( __( 'View on %s', 'buddypress' ), $oembed->provider_name );
293
+ }
294
+
295
+ if ( true === isset( $anchor_text ) ) {
296
+ $caption .= sprintf( '<a rel="nofollow" href="%1$s" onclick="top.location.href=\'%1$s\'">%2$s</a>', esc_url( $url ), apply_filters( 'the_title', $anchor_text ) );
297
+ }
298
+
299
+ // Set up caption.
300
+ if ( '' !== $caption ) {
301
+ $css_class = isset( $oembed->provider_name ) ? sprintf( ' provider-%s', sanitize_html_class( strtolower( $oembed->provider_name ) ) ) : '';
302
+ $caption = sprintf( '<div class="caption%1$s" style="width:%2$s">%3$s</div>',
303
+ $css_class,
304
+ $thumb_width > $float_width ? 100 . '%' : round( ( $width - (int) $thumb_width ) / $width * 100 ) . '%',
305
+ $caption
306
+ );
307
+
308
+ $content .= $caption;
309
+ }
310
+ }
311
+
312
+ // Print rich content.
313
+ if ( '' !== $content ) {
314
+ printf( '<div class="bp-activity-embed-display-media %s" style="max-width:%spx">%s</div>',
315
+ $thumb_width < $float_width ? 'two-col' : 'one-col',
316
+ $thumb_width < $float_width ? $width : $thumb_width,
317
+ $content
318
+ );
319
+ }
320
+
321
+ // Video / audio.
322
+ } elseif ( true === $allow_media ) {
323
+ // Call BP_Embed if it hasn't already loaded.
324
+ bp_embed_init();
325
+
326
+ // Run shortcode and embed routine.
327
+ $content = buddypress()->embed->run_shortcode( $GLOBALS['activities_template']->activity->content );
328
+ $content = buddypress()->embed->autoembed( $content );
329
+
330
+ // Try to find inline video / audio.
331
+ $media = bp_core_extract_media_from_content( $content, 96 );
332
+
333
+ // Video takes precedence. HTML5-only.
334
+ if ( isset( $media['videos'] ) && 'shortcodes' === $media['videos'][0]['source'] ) {
335
+ printf( '<video controls preload="metadata"><source src="%1$s"><p>%2$s</p></video>',
336
+ esc_url( $media['videos'][0]['url'] ),
337
+ esc_html__( 'Your browser does not support HTML5 video', 'buddypress' )
338
+ );
339
+
340
+ // No video? Try audio. HTML5-only.
341
+ } elseif ( isset( $media['audio'] ) && 'shortcodes' === $media['audio'][0]['source'] ) {
342
+ printf( '<audio controls preload="metadata"><source src="%1$s"><p>%2$s</p></audio>',
343
+ esc_url( $media['audio'][0]['url'] ),
344
+ esc_html__( 'Your browser does not support HTML5 audio', 'buddypress' )
345
+ );
346
+ }
347
+
348
+ }
349
+
350
+ /** This hook is documented in /bp-activity/bp-activity-embeds.php */
351
+ do_action( 'bp_activity_embed_after_media' );
352
+ }
bp-activity/bp-activity-filters.php CHANGED
@@ -1,18 +1,18 @@
1
  <?php
2
-
3
  /**
4
  * Filters related to the Activity component.
5
  *
6
  * @package BuddyPress
7
  * @subpackage ActivityFilters
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
12
 
13
- /** Filters *******************************************************************/
14
 
15
- // Apply WordPress defined filters
16
  add_filter( 'bp_get_activity_action', 'bp_activity_filter_kses', 1 );
17
  add_filter( 'bp_get_activity_content_body', 'bp_activity_filter_kses', 1 );
18
  add_filter( 'bp_get_activity_content', 'bp_activity_filter_kses', 1 );
@@ -22,7 +22,7 @@ add_filter( 'bp_get_activity_latest_update_excerpt', 'bp_activity_filter_kses',
22
  add_filter( 'bp_get_activity_feed_item_description', 'bp_activity_filter_kses', 1 );
23
  add_filter( 'bp_activity_content_before_save', 'bp_activity_filter_kses', 1 );
24
  add_filter( 'bp_activity_action_before_save', 'bp_activity_filter_kses', 1 );
25
- add_filter( 'bp_activity_latest_update_content', 'wp_filter_kses', 1 );
26
 
27
  add_filter( 'bp_get_activity_action', 'force_balance_tags' );
28
  add_filter( 'bp_get_activity_content_body', 'force_balance_tags' );
@@ -33,12 +33,17 @@ add_filter( 'bp_get_activity_feed_item_description', 'force_balance_tags' );
33
  add_filter( 'bp_activity_content_before_save', 'force_balance_tags' );
34
  add_filter( 'bp_activity_action_before_save', 'force_balance_tags' );
35
 
 
 
 
 
36
  add_filter( 'bp_get_activity_action', 'wptexturize' );
37
  add_filter( 'bp_get_activity_content_body', 'wptexturize' );
38
  add_filter( 'bp_get_activity_content', 'wptexturize' );
39
  add_filter( 'bp_get_activity_parent_content', 'wptexturize' );
40
  add_filter( 'bp_get_activity_latest_update', 'wptexturize' );
41
  add_filter( 'bp_get_activity_latest_update_excerpt', 'wptexturize' );
 
42
 
43
  add_filter( 'bp_get_activity_action', 'convert_smilies' );
44
  add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
@@ -46,6 +51,7 @@ add_filter( 'bp_get_activity_content', 'convert_smilies' );
46
  add_filter( 'bp_get_activity_parent_content', 'convert_smilies' );
47
  add_filter( 'bp_get_activity_latest_update', 'convert_smilies' );
48
  add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_smilies' );
 
49
 
50
  add_filter( 'bp_get_activity_action', 'convert_chars' );
51
  add_filter( 'bp_get_activity_content_body', 'convert_chars' );
@@ -53,11 +59,13 @@ add_filter( 'bp_get_activity_content', 'convert_chars' );
53
  add_filter( 'bp_get_activity_parent_content', 'convert_chars' );
54
  add_filter( 'bp_get_activity_latest_update', 'convert_chars' );
55
  add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_chars' );
 
56
 
57
  add_filter( 'bp_get_activity_action', 'wpautop' );
58
  add_filter( 'bp_get_activity_content_body', 'wpautop' );
59
  add_filter( 'bp_get_activity_content', 'wpautop' );
60
  add_filter( 'bp_get_activity_feed_item_description', 'wpautop' );
 
61
 
62
  add_filter( 'bp_get_activity_action', 'make_clickable', 9 );
63
  add_filter( 'bp_get_activity_content_body', 'make_clickable', 9 );
@@ -66,6 +74,7 @@ add_filter( 'bp_get_activity_parent_content', 'make_clickable', 9 );
66
  add_filter( 'bp_get_activity_latest_update', 'make_clickable', 9 );
67
  add_filter( 'bp_get_activity_latest_update_excerpt', 'make_clickable', 9 );
68
  add_filter( 'bp_get_activity_feed_item_description', 'make_clickable', 9 );
 
69
 
70
  add_filter( 'bp_acomment_name', 'stripslashes_deep', 5 );
71
  add_filter( 'bp_get_activity_action', 'stripslashes_deep', 5 );
@@ -78,7 +87,7 @@ add_filter( 'bp_get_activity_feed_item_description', 'stripslashes_deep', 5 );
78
 
79
  add_filter( 'bp_activity_primary_link_before_save', 'esc_url_raw' );
80
 
81
- // Apply BuddyPress-defined filters
82
  add_filter( 'bp_get_activity_content', 'bp_activity_make_nofollow_filter' );
83
  add_filter( 'bp_get_activity_content_body', 'bp_activity_make_nofollow_filter' );
84
  add_filter( 'bp_get_activity_parent_content', 'bp_activity_make_nofollow_filter' );
@@ -90,18 +99,24 @@ add_filter( 'pre_comment_content', 'bp_activity_at_name_filter
90
  add_filter( 'group_forum_topic_text_before_save', 'bp_activity_at_name_filter' );
91
  add_filter( 'group_forum_post_text_before_save', 'bp_activity_at_name_filter' );
92
  add_filter( 'the_content', 'bp_activity_at_name_filter' );
 
93
 
94
  add_filter( 'bp_get_activity_parent_content', 'bp_create_excerpt' );
95
 
96
  add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
97
  add_filter( 'bp_get_activity_content', 'bp_activity_truncate_entry', 5 );
98
 
99
- /** Actions *******************************************************************/
 
 
 
100
 
101
- // At-name filter
 
 
102
  add_action( 'bp_activity_before_save', 'bp_activity_at_name_filter_updates' );
103
 
104
- // Activity stream moderation
105
  add_action( 'bp_activity_before_save', 'bp_activity_check_moderation_keys', 2, 1 );
106
  add_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys', 2, 1 );
107
 
@@ -110,7 +125,7 @@ add_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys', 2, 1
110
  /**
111
  * Types of activity stream items to moderate.
112
  *
113
- * @since BuddyPress (1.6)
114
  *
115
  * @return array $types List of the activity types to moderate.
116
  */
@@ -119,53 +134,71 @@ function bp_activity_get_moderated_activity_types() {
119
  'activity_comment',
120
  'activity_update'
121
  );
 
 
 
 
 
 
 
 
122
  return apply_filters( 'bp_activity_check_activity_types', $types );
123
  }
124
 
125
  /**
126
  * Moderate the posted activity item, if it contains moderate keywords.
127
  *
128
- * @since BuddyPress (1.6)
129
  *
130
  * @param BP_Activity_Activity $activity The activity object to check.
131
  */
132
  function bp_activity_check_moderation_keys( $activity ) {
133
 
134
- // Only check specific types of activity updates
135
- if ( !in_array( $activity->type, bp_activity_get_moderated_activity_types() ) )
136
  return;
 
 
 
 
 
 
 
137
 
138
- // Unset the activity component so activity stream update fails
139
- // @todo This is temporary until some kind of moderation is built
140
- if ( !bp_core_check_for_moderation( $activity->user_id, '', $activity->content ) )
141
  $activity->component = false;
 
142
  }
143
 
144
  /**
145
  * Mark the posted activity as spam, if it contains blacklist keywords.
146
  *
147
- * @since BuddyPress (1.6)
148
  *
149
  * @param BP_Activity_Activity $activity The activity object to check.
150
  */
151
  function bp_activity_check_blacklist_keys( $activity ) {
152
 
153
- // Only check specific types of activity updates
154
- if ( ! in_array( $activity->type, bp_activity_get_moderated_activity_types() ) )
155
  return;
 
 
 
 
 
 
 
156
 
157
- // Mark as spam
158
- if ( ! bp_core_check_for_blacklist( $activity->user_id, '', $activity->content ) )
159
- bp_activity_mark_as_spam( $activity, 'by_blacklist' );
160
  }
161
 
162
  /**
163
  * Custom kses filtering for activity content.
164
  *
165
- * @since BuddyPress (1.1)
166
- *
167
- * @uses apply_filters() To call the 'bp_activity_allowed_tags' hook.
168
- * @uses wp_kses()
169
  *
170
  * @param string $content The activity content.
171
  * @return string $content Filtered activity content.
@@ -174,11 +207,15 @@ function bp_activity_filter_kses( $content ) {
174
  global $allowedtags;
175
 
176
  $activity_allowedtags = $allowedtags;
177
- $activity_allowedtags['span'] = array();
178
- $activity_allowedtags['span']['class'] = array();
179
- $activity_allowedtags['a']['class'] = array();
180
- $activity_allowedtags['a']['id'] = array();
181
- $activity_allowedtags['a']['rel'] = array();
 
 
 
 
182
  $activity_allowedtags['img'] = array();
183
  $activity_allowedtags['img']['src'] = array();
184
  $activity_allowedtags['img']['alt'] = array();
@@ -187,8 +224,19 @@ function bp_activity_filter_kses( $content ) {
187
  $activity_allowedtags['img']['class'] = array();
188
  $activity_allowedtags['img']['id'] = array();
189
  $activity_allowedtags['img']['title'] = array();
190
- $activity_allowedtags['code'] = array();
191
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  $activity_allowedtags = apply_filters( 'bp_activity_allowed_tags', $activity_allowedtags );
193
  return wp_kses( $content, $activity_allowedtags );
194
  }
@@ -196,10 +244,10 @@ function bp_activity_filter_kses( $content ) {
196
  /**
197
  * Find and link @-mentioned users in the contents of a given item.
198
  *
199
- * @since BuddyPress (1.2.0)
200
  *
201
- * @param string $content The contents of a given item.
202
- * @param int $activity_id The activity id. Deprecated.
203
  * @return string $content Content filtered for mentions.
204
  */
205
  function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
@@ -209,7 +257,7 @@ function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
209
  return $content;
210
  }
211
 
212
- // Try to find mentions
213
  $usernames = bp_activity_find_mentions( $content );
214
 
215
  // No mentions? Stop now!
@@ -217,11 +265,11 @@ function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
217
  return $content;
218
 
219
  // We don't want to link @mentions that are inside of links, so we
220
- // temporarily remove them
221
  $replace_count = 0;
222
  $replacements = array();
223
  foreach ( $usernames as $username ) {
224
- // prevent @ name linking inside <a> tags
225
  preg_match_all( '/(<a.*?(?!<\/a>)@' . $username . '.*?<\/a>)/', $content, $content_matches );
226
  if ( ! empty( $content_matches[1] ) ) {
227
  foreach ( $content_matches[1] as $replacement ) {
@@ -232,19 +280,19 @@ function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
232
  }
233
  }
234
 
235
- // Linkify the mentions with the username
236
  foreach ( (array) $usernames as $user_id => $username ) {
237
- $content = preg_replace( '/(@' . $username . '\b)/', "<a href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $content );
238
  }
239
 
240
- // put everything back
241
  if ( ! empty( $replacements ) ) {
242
  foreach ( $replacements as $placeholder => $original ) {
243
  $content = str_replace( $placeholder, $original, $content );
244
  }
245
  }
246
 
247
- // Return the content
248
  return $content;
249
  }
250
 
@@ -254,11 +302,9 @@ function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
254
  * If mentions are found, replace @mention text with user links and add our
255
  * hook to send mention notifications after the activity item is saved.
256
  *
257
- * @since BuddyPress (1.5)
258
- *
259
- * @uses bp_activity_find_mentions()
260
  *
261
- * @param BP_Activity_Activity $activity
262
  */
263
  function bp_activity_at_name_filter_updates( $activity ) {
264
  // Are mentions disabled?
@@ -270,20 +316,20 @@ function bp_activity_at_name_filter_updates( $activity ) {
270
  if ( ! empty( $activity->is_spam ) )
271
  return;
272
 
273
- // Try to find mentions
274
  $usernames = bp_activity_find_mentions( $activity->content );
275
 
276
  // We have mentions!
277
  if ( ! empty( $usernames ) ) {
278
- // Replace @mention text with userlinks
279
  foreach( (array) $usernames as $user_id => $username ) {
280
- $activity->content = preg_replace( '/(@' . $username . '\b)/', "<a href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $activity->content );
281
  }
282
 
283
- // Add our hook to send @mention emails after the activity item is saved
284
  add_action( 'bp_activity_after_save', 'bp_activity_at_name_send_emails' );
285
 
286
- // temporary variable to avoid having to run bp_activity_find_mentions() again
287
  buddypress()->activity->mentioned_users = $usernames;
288
  }
289
  }
@@ -291,12 +337,9 @@ function bp_activity_at_name_filter_updates( $activity ) {
291
  /**
292
  * Sends emails and BP notifications for users @-mentioned in an activity item.
293
  *
294
- * @since BuddyPress (1.7)
295
  *
296
- * @uses bp_activity_at_message_notification()
297
- * @uses bp_activity_update_mention_count_for_user()
298
- *
299
- * @param BP_Activity_Activity $activity The BP_Activity_Activity object
300
  */
301
  function bp_activity_at_name_send_emails( $activity ) {
302
  // Are mentions disabled?
@@ -308,20 +351,31 @@ function bp_activity_at_name_send_emails( $activity ) {
308
  if ( empty( buddypress()->activity->mentioned_users ) )
309
  return;
310
 
311
- // Grab our temporary variable from bp_activity_at_name_filter_updates()
312
  $usernames = buddypress()->activity->mentioned_users;
313
 
314
- // Get rid of temporary variable
315
  unset( buddypress()->activity->mentioned_users );
316
 
317
- // Send @mentions and setup BP notifications
318
  foreach( (array) $usernames as $user_id => $username ) {
319
- // If you want to disable notifications, you can use this filter to stop email sending
320
- if ( apply_filters( 'bp_activity_at_name_do_notifications', true, $usernames ) ) {
 
 
 
 
 
 
 
 
 
 
 
321
  bp_activity_at_message_notification( $activity->id, $user_id );
322
  }
323
 
324
- // Updates mention count for the user
325
  bp_activity_update_mention_count_for_user( $user_id, $activity->id );
326
  }
327
  }
@@ -329,7 +383,7 @@ function bp_activity_at_name_send_emails( $activity ) {
329
  /**
330
  * Catch links in activity text so rel=nofollow can be added.
331
  *
332
- * @since BuddyPress (1.2)
333
  *
334
  * @param string $text Activity text.
335
  * @return string $text Text with rel=nofollow added to any links.
@@ -341,12 +395,10 @@ function bp_activity_make_nofollow_filter( $text ) {
341
  /**
342
  * Add rel=nofollow to a link.
343
  *
344
- * @since BuddyPress (1.2)
345
- *
346
- * @param array $matches
347
  *
348
  * @param array $matches Items matched by preg_replace_callback() in bp_activity_make_nofollow_filter().
349
- * @return string $text Link with rel=nofollow added
350
  */
351
  function bp_activity_make_nofollow_filter_callback( $matches ) {
352
  $text = $matches[1];
@@ -357,51 +409,88 @@ function bp_activity_make_nofollow_filter( $text ) {
357
  /**
358
  * Truncate long activity entries when viewed in activity streams.
359
  *
360
- * @since BuddyPress (1.5)
361
  *
362
- * @uses bp_is_single_activity()
363
- * @uses apply_filters() To call the 'bp_activity_excerpt_append_text' hook.
364
- * @uses apply_filters() To call the 'bp_activity_excerpt_length' hook.
365
- * @uses bp_create_excerpt()
366
- * @uses bp_get_activity_id()
367
- * @uses bp_get_activity_thread_permalink()
368
- * @uses apply_filters() To call the 'bp_activity_truncate_entry' hook.
369
  *
370
  * @param string $text The original activity entry text.
 
 
 
 
371
  * @return string $excerpt The truncated text.
372
  */
373
- function bp_activity_truncate_entry( $text ) {
374
  global $activities_template;
375
 
376
- // The full text of the activity update should always show on the single activity screen
377
- if ( bp_is_single_activity() )
 
 
 
 
 
 
 
 
 
 
 
 
378
  return $text;
 
379
 
 
 
 
 
 
 
 
380
  $append_text = apply_filters( 'bp_activity_excerpt_append_text', __( '[Read more]', 'buddypress' ) );
 
 
 
 
 
 
 
 
381
  $excerpt_length = apply_filters( 'bp_activity_excerpt_length', 358 );
382
 
383
- // Run the text through the excerpt function. If it's too short, the original text will be
384
- // returned.
385
- $excerpt = bp_create_excerpt( $text, $excerpt_length, array( 'ending' => __( '&hellip;', 'buddypress' ) ) );
 
386
 
387
- // If the text returned by bp_create_excerpt() is different from the original text (ie it's
388
- // been truncated), add the "Read More" link. Note that bp_create_excerpt() is stripping
389
- // shortcodes, so we have strip them from the $text before the comparison
390
- if ( $excerpt != strip_shortcodes( $text ) ) {
 
 
391
  $id = !empty( $activities_template->activity->current_comment->id ) ? 'acomment-read-more-' . $activities_template->activity->current_comment->id : 'activity-read-more-' . bp_get_activity_id();
392
 
393
  $excerpt = sprintf( '%1$s<span class="activity-read-more" id="%2$s"><a href="%3$s" rel="nofollow">%4$s</a></span>', $excerpt, $id, bp_get_activity_thread_permalink(), $append_text );
394
  }
395
 
 
 
 
 
 
 
 
 
 
396
  return apply_filters( 'bp_activity_truncate_entry', $excerpt, $text, $append_text );
397
  }
398
 
399
  /**
400
- * Include extra javascript dependencies for activity component.
401
  *
402
- * @since BuddyPress (2.0.0)
403
- *
404
- * @uses bp_activity_do_heartbeat() to check if heartbeat is required.
405
  *
406
  * @param array $js_handles The original dependencies.
407
  * @return array $js_handles The new dependencies.
@@ -421,9 +510,9 @@ add_filter( 'bp_core_get_js_dependencies', 'bp_activity_get_js_dependencies', 10
421
  * We use these classes to avoid pagination issues when items are loaded
422
  * dynamically into the activity stream.
423
  *
424
- * @since BuddyPress (2.0.0)
425
  *
426
- * @param string $classes
427
  * @return string $classes
428
  */
429
  function bp_activity_newest_class( $classes = '' ) {
@@ -440,9 +529,9 @@ function bp_activity_newest_class( $classes = '' ) {
440
  /**
441
  * Check if Activity Heartbeat feature i on to add a timestamp class.
442
  *
443
- * @since BuddyPress (2.0.0)
444
  *
445
- * @param string $classes
446
  * @return string $classes
447
  */
448
  function bp_activity_timestamp_class( $classes = '' ) {
@@ -456,7 +545,7 @@ function bp_activity_timestamp_class( $classes = '' ) {
456
  if ( empty( $activity_date ) ) {
457
  return $classes;
458
  }
459
-
460
  $classes .= ' date-recorded-' . strtotime( $activity_date );
461
 
462
  return $classes;
@@ -466,33 +555,33 @@ add_filter( 'bp_get_activity_css_class', 'bp_activity_timestamp_class', 9, 1 );
466
  /**
467
  * Use WordPress Heartbeat API to check for latest activity update.
468
  *
469
- * @since BuddyPress (2.0.0)
470
  *
471
- * @uses bp_activity_get_last_updated() to get the recorded date of the last activity
472
- *
473
- * @param array $response
474
- * @param array $data
475
  * @return array $response
476
  */
477
  function bp_activity_heartbeat_last_recorded( $response = array(), $data = array() ) {
478
- $bp = buddypress();
479
-
480
  if ( empty( $data['bp_activity_last_recorded'] ) ) {
481
  return $response;
482
  }
483
 
484
  // Use the querystring argument stored in the cookie (to preserve
485
- // filters), but force the offset to get only new items
486
  $activity_latest_args = bp_parse_args(
487
  bp_ajax_querystring( 'activity' ),
488
  array( 'since' => date( 'Y-m-d H:i:s', $data['bp_activity_last_recorded'] ) ),
489
  'activity_latest_args'
490
  );
491
 
 
 
 
 
492
  $newest_activities = array();
493
  $last_activity_recorded = 0;
494
 
495
- // Temporarly add a just-posted class for new activity items
496
  add_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
497
 
498
  ob_start();
@@ -513,7 +602,7 @@ function bp_activity_heartbeat_last_recorded( $response = array(), $data = array
513
  $newest_activities['last_recorded'] = $last_activity_recorded;
514
  ob_end_clean();
515
 
516
- // Remove the temporary filter
517
  remove_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
518
 
519
  if ( ! empty( $newest_activities['last_recorded'] ) ) {
@@ -528,7 +617,7 @@ add_filter( 'heartbeat_nopriv_received', 'bp_activity_heartbeat_last_recorded',
528
  /**
529
  * Set the strings for WP HeartBeat API where needed.
530
  *
531
- * @since BuddyPress (2.0.0)
532
  *
533
  * @param array $strings Localized strings.
534
  * @return array $strings
@@ -541,14 +630,26 @@ function bp_activity_heartbeat_strings( $strings = array() ) {
541
 
542
  $global_pulse = 0;
543
 
544
- // Check whether the global heartbeat settings already exist.
 
 
 
 
 
 
545
  $heartbeat_settings = apply_filters( 'heartbeat_settings', array() );
546
  if ( ! empty( $heartbeat_settings['interval'] ) ) {
547
  // 'Fast' is 5
548
  $global_pulse = is_numeric( $heartbeat_settings['interval'] ) ? absint( $heartbeat_settings['interval'] ) : 5;
549
  }
550
 
551
- // Filter here to specify a BP-specific pulse frequency
 
 
 
 
 
 
552
  $bp_activity_pulse = apply_filters( 'bp_activity_heartbeat_pulse', 15 );
553
 
554
  /**
@@ -571,3 +672,168 @@ function bp_activity_heartbeat_strings( $strings = array() ) {
571
  return $strings;
572
  }
573
  add_filter( 'bp_core_get_js_strings', 'bp_activity_heartbeat_strings', 10, 1 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * Filters related to the Activity component.
4
  *
5
  * @package BuddyPress
6
  * @subpackage ActivityFilters
7
+ * @since 1.0.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
 
13
+ /* Filters *******************************************************************/
14
 
15
+ // Apply WordPress defined filters.
16
  add_filter( 'bp_get_activity_action', 'bp_activity_filter_kses', 1 );
17
  add_filter( 'bp_get_activity_content_body', 'bp_activity_filter_kses', 1 );
18
  add_filter( 'bp_get_activity_content', 'bp_activity_filter_kses', 1 );
22
  add_filter( 'bp_get_activity_feed_item_description', 'bp_activity_filter_kses', 1 );
23
  add_filter( 'bp_activity_content_before_save', 'bp_activity_filter_kses', 1 );
24
  add_filter( 'bp_activity_action_before_save', 'bp_activity_filter_kses', 1 );
25
+ add_filter( 'bp_activity_latest_update_content', 'bp_activity_filter_kses', 1 );
26
 
27
  add_filter( 'bp_get_activity_action', 'force_balance_tags' );
28
  add_filter( 'bp_get_activity_content_body', 'force_balance_tags' );
33
  add_filter( 'bp_activity_content_before_save', 'force_balance_tags' );
34
  add_filter( 'bp_activity_action_before_save', 'force_balance_tags' );
35
 
36
+ if ( function_exists( 'wp_encode_emoji' ) ) {
37
+ add_filter( 'bp_activity_content_before_save', 'wp_encode_emoji' );
38
+ }
39
+
40
  add_filter( 'bp_get_activity_action', 'wptexturize' );
41
  add_filter( 'bp_get_activity_content_body', 'wptexturize' );
42
  add_filter( 'bp_get_activity_content', 'wptexturize' );
43
  add_filter( 'bp_get_activity_parent_content', 'wptexturize' );
44
  add_filter( 'bp_get_activity_latest_update', 'wptexturize' );
45
  add_filter( 'bp_get_activity_latest_update_excerpt', 'wptexturize' );
46
+ add_filter( 'bp_activity_get_embed_excerpt', 'wptexturize' );
47
 
48
  add_filter( 'bp_get_activity_action', 'convert_smilies' );
49
  add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
51
  add_filter( 'bp_get_activity_parent_content', 'convert_smilies' );
52
  add_filter( 'bp_get_activity_latest_update', 'convert_smilies' );
53
  add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_smilies' );
54
+ add_filter( 'bp_activity_get_embed_excerpt', 'convert_smilies' );
55
 
56
  add_filter( 'bp_get_activity_action', 'convert_chars' );
57
  add_filter( 'bp_get_activity_content_body', 'convert_chars' );
59
  add_filter( 'bp_get_activity_parent_content', 'convert_chars' );
60
  add_filter( 'bp_get_activity_latest_update', 'convert_chars' );
61
  add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_chars' );
62
+ add_filter( 'bp_activity_get_embed_excerpt', 'convert_chars' );
63
 
64
  add_filter( 'bp_get_activity_action', 'wpautop' );
65
  add_filter( 'bp_get_activity_content_body', 'wpautop' );
66
  add_filter( 'bp_get_activity_content', 'wpautop' );
67
  add_filter( 'bp_get_activity_feed_item_description', 'wpautop' );
68
+ add_filter( 'bp_activity_get_embed_excerpt', 'wpautop' );
69
 
70
  add_filter( 'bp_get_activity_action', 'make_clickable', 9 );
71
  add_filter( 'bp_get_activity_content_body', 'make_clickable', 9 );
74
  add_filter( 'bp_get_activity_latest_update', 'make_clickable', 9 );
75
  add_filter( 'bp_get_activity_latest_update_excerpt', 'make_clickable', 9 );
76
  add_filter( 'bp_get_activity_feed_item_description', 'make_clickable', 9 );
77
+ add_filter( 'bp_activity_get_embed_excerpt', 'make_clickable', 9 );
78
 
79
  add_filter( 'bp_acomment_name', 'stripslashes_deep', 5 );
80
  add_filter( 'bp_get_activity_action', 'stripslashes_deep', 5 );
87
 
88
  add_filter( 'bp_activity_primary_link_before_save', 'esc_url_raw' );
89
 
90
+ // Apply BuddyPress-defined filters.
91
  add_filter( 'bp_get_activity_content', 'bp_activity_make_nofollow_filter' );
92
  add_filter( 'bp_get_activity_content_body', 'bp_activity_make_nofollow_filter' );
93
  add_filter( 'bp_get_activity_parent_content', 'bp_activity_make_nofollow_filter' );
99
  add_filter( 'group_forum_topic_text_before_save', 'bp_activity_at_name_filter' );
100
  add_filter( 'group_forum_post_text_before_save', 'bp_activity_at_name_filter' );
101
  add_filter( 'the_content', 'bp_activity_at_name_filter' );
102
+ add_filter( 'bp_activity_get_embed_excerpt', 'bp_activity_at_name_filter' );
103
 
104
  add_filter( 'bp_get_activity_parent_content', 'bp_create_excerpt' );
105
 
106
  add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
107
  add_filter( 'bp_get_activity_content', 'bp_activity_truncate_entry', 5 );
108
 
109
+ add_filter( 'bp_get_total_favorite_count_for_user', 'bp_core_number_format' );
110
+ add_filter( 'bp_get_total_mention_count_for_user', 'bp_core_number_format' );
111
+
112
+ add_filter( 'bp_activity_get_embed_excerpt', 'bp_activity_embed_excerpt_onclick_location_filter', 9 );
113
 
114
+ /* Actions *******************************************************************/
115
+
116
+ // At-name filter.
117
  add_action( 'bp_activity_before_save', 'bp_activity_at_name_filter_updates' );
118
 
119
+ // Activity stream moderation.
120
  add_action( 'bp_activity_before_save', 'bp_activity_check_moderation_keys', 2, 1 );
121
  add_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys', 2, 1 );
122
 
125
  /**
126
  * Types of activity stream items to moderate.
127
  *
128
+ * @since 1.6.0
129
  *
130
  * @return array $types List of the activity types to moderate.
131
  */
134
  'activity_comment',
135
  'activity_update'
136
  );
137
+
138
+ /**
139
+ * Filters the default activity types that BuddyPress should moderate.
140
+ *
141
+ * @since 1.6.0
142
+ *
143
+ * @param array $types Default activity types to moderate.
144
+ */
145
  return apply_filters( 'bp_activity_check_activity_types', $types );
146
  }
147
 
148
  /**
149
  * Moderate the posted activity item, if it contains moderate keywords.
150
  *
151
+ * @since 1.6.0
152
  *
153
  * @param BP_Activity_Activity $activity The activity object to check.
154
  */
155
  function bp_activity_check_moderation_keys( $activity ) {
156
 
157
+ // Only check specific types of activity updates.
158
+ if ( ! in_array( $activity->type, bp_activity_get_moderated_activity_types() ) ) {
159
  return;
160
+ }
161
+
162
+ // Send back the error so activity update fails.
163
+ // @todo This is temporary until some kind of moderation is built.
164
+ $moderate = bp_core_check_for_moderation( $activity->user_id, '', $activity->content, 'wp_error' );
165
+ if ( is_wp_error( $moderate ) ) {
166
+ $activity->errors = $moderate;
167
 
168
+ // Backpat.
 
 
169
  $activity->component = false;
170
+ }
171
  }
172
 
173
  /**
174
  * Mark the posted activity as spam, if it contains blacklist keywords.
175
  *
176
+ * @since 1.6.0
177
  *
178
  * @param BP_Activity_Activity $activity The activity object to check.
179
  */
180
  function bp_activity_check_blacklist_keys( $activity ) {
181
 
182
+ // Only check specific types of activity updates.
183
+ if ( ! in_array( $activity->type, bp_activity_get_moderated_activity_types() ) ) {
184
  return;
185
+ }
186
+
187
+ // Send back the error so activity update fails.
188
+ // @todo This is temporary until some kind of trash status is built.
189
+ $blacklist = bp_core_check_for_blacklist( $activity->user_id, '', $activity->content, 'wp_error' );
190
+ if ( is_wp_error( $blacklist ) ) {
191
+ $activity->errors = $blacklist;
192
 
193
+ // Backpat.
194
+ $activity->component = false;
195
+ }
196
  }
197
 
198
  /**
199
  * Custom kses filtering for activity content.
200
  *
201
+ * @since 1.1.0
 
 
 
202
  *
203
  * @param string $content The activity content.
204
  * @return string $content Filtered activity content.
207
  global $allowedtags;
208
 
209
  $activity_allowedtags = $allowedtags;
210
+ $activity_allowedtags['a']['class'] = array();
211
+ $activity_allowedtags['a']['id'] = array();
212
+ $activity_allowedtags['a']['rel'] = array();
213
+ $activity_allowedtags['a']['title'] = array();
214
+
215
+ $activity_allowedtags['b'] = array();
216
+ $activity_allowedtags['code'] = array();
217
+ $activity_allowedtags['i'] = array();
218
+
219
  $activity_allowedtags['img'] = array();
220
  $activity_allowedtags['img']['src'] = array();
221
  $activity_allowedtags['img']['alt'] = array();
224
  $activity_allowedtags['img']['class'] = array();
225
  $activity_allowedtags['img']['id'] = array();
226
  $activity_allowedtags['img']['title'] = array();
 
227
 
228
+ $activity_allowedtags['span'] = array();
229
+ $activity_allowedtags['span']['class'] = array();
230
+ $activity_allowedtags['span']['data-livestamp'] = array();
231
+
232
+
233
+ /**
234
+ * Filters the allowed HTML tags for BuddyPress Activity content.
235
+ *
236
+ * @since 1.2.0
237
+ *
238
+ * @param array $value Array of allowed HTML tags and attributes.
239
+ */
240
  $activity_allowedtags = apply_filters( 'bp_activity_allowed_tags', $activity_allowedtags );
241
  return wp_kses( $content, $activity_allowedtags );
242
  }
244
  /**
245
  * Find and link @-mentioned users in the contents of a given item.
246
  *
247
+ * @since 1.2.0
248
  *
249
+ * @param string $content The contents of a given item.
250
+ * @param int $activity_id The activity id. Deprecated.
251
  * @return string $content Content filtered for mentions.
252
  */
253
  function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
257
  return $content;
258
  }
259
 
260
+ // Try to find mentions.
261
  $usernames = bp_activity_find_mentions( $content );
262
 
263
  // No mentions? Stop now!
265
  return $content;
266
 
267
  // We don't want to link @mentions that are inside of links, so we
268
+ // temporarily remove them.
269
  $replace_count = 0;
270
  $replacements = array();
271
  foreach ( $usernames as $username ) {
272
+ // Prevent @ name linking inside <a> tags.
273
  preg_match_all( '/(<a.*?(?!<\/a>)@' . $username . '.*?<\/a>)/', $content, $content_matches );
274
  if ( ! empty( $content_matches[1] ) ) {
275
  foreach ( $content_matches[1] as $replacement ) {
280
  }
281
  }
282
 
283
+ // Linkify the mentions with the username.
284
  foreach ( (array) $usernames as $user_id => $username ) {
285
+ $content = preg_replace( '/(@' . $username . '\b)/', "<a class='bp-suggestions-mention' href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $content );
286
  }
287
 
288
+ // Put everything back.
289
  if ( ! empty( $replacements ) ) {
290
  foreach ( $replacements as $placeholder => $original ) {
291
  $content = str_replace( $placeholder, $original, $content );
292
  }
293
  }
294
 
295
+ // Return the content.
296
  return $content;
297
  }
298
 
302
  * If mentions are found, replace @mention text with user links and add our
303
  * hook to send mention notifications after the activity item is saved.
304
  *
305
+ * @since 1.5.0
 
 
306
  *
307
+ * @param BP_Activity_Activity $activity Activity Object.
308
  */
309
  function bp_activity_at_name_filter_updates( $activity ) {
310
  // Are mentions disabled?
316
  if ( ! empty( $activity->is_spam ) )
317
  return;
318
 
319
+ // Try to find mentions.
320
  $usernames = bp_activity_find_mentions( $activity->content );
321
 
322
  // We have mentions!
323
  if ( ! empty( $usernames ) ) {
324
+ // Replace @mention text with userlinks.
325
  foreach( (array) $usernames as $user_id => $username ) {
326
+ $activity->content = preg_replace( '/(@' . $username . '\b)/', "<a class='bp-suggestions-mention' href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $activity->content );
327
  }
328
 
329
+ // Add our hook to send @mention emails after the activity item is saved.
330
  add_action( 'bp_activity_after_save', 'bp_activity_at_name_send_emails' );
331
 
332
+ // Temporary variable to avoid having to run bp_activity_find_mentions() again.
333
  buddypress()->activity->mentioned_users = $usernames;
334
  }
335
  }
337
  /**
338
  * Sends emails and BP notifications for users @-mentioned in an activity item.
339
  *
340
+ * @since 1.7.0
341
  *
342
+ * @param BP_Activity_Activity $activity The BP_Activity_Activity object.
 
 
 
343
  */
344
  function bp_activity_at_name_send_emails( $activity ) {
345
  // Are mentions disabled?
351
  if ( empty( buddypress()->activity->mentioned_users ) )
352
  return;
353
 
354
+ // Grab our temporary variable from bp_activity_at_name_filter_updates().
355
  $usernames = buddypress()->activity->mentioned_users;
356
 
357
+ // Get rid of temporary variable.
358
  unset( buddypress()->activity->mentioned_users );
359
 
360
+ // Send @mentions and setup BP notifications.
361
  foreach( (array) $usernames as $user_id => $username ) {
362
+
363
+ /**
364
+ * Filters BuddyPress' ability to send email notifications for @mentions.
365
+ *
366
+ * @since 1.6.0
367
+ * @since 2.5.0 Introduced `$user_id` and `$activity` parameters.
368
+ *
369
+ * @param bool $value Whether or not BuddyPress should send a notification to the mentioned users.
370
+ * @param array $usernames Array of users potentially notified.
371
+ * @param int $user_id ID of the current user being notified.
372
+ * @param BP_Activity_Activity $activity Activity object.
373
+ */
374
+ if ( apply_filters( 'bp_activity_at_name_do_notifications', true, $usernames, $user_id, $activity ) ) {
375
  bp_activity_at_message_notification( $activity->id, $user_id );
376
  }
377
 
378
+ // Updates mention count for the user.
379
  bp_activity_update_mention_count_for_user( $user_id, $activity->id );
380
  }
381
  }
383
  /**
384
  * Catch links in activity text so rel=nofollow can be added.
385
  *
386
+ * @since 1.2.0
387
  *
388
  * @param string $text Activity text.
389
  * @return string $text Text with rel=nofollow added to any links.
395
  /**
396
  * Add rel=nofollow to a link.
397
  *
398
+ * @since 1.2.0
 
 
399
  *
400
  * @param array $matches Items matched by preg_replace_callback() in bp_activity_make_nofollow_filter().
401
+ * @return string $text Link with rel=nofollow added.
402
  */
403
  function bp_activity_make_nofollow_filter_callback( $matches ) {
404
  $text = $matches[1];
409
  /**
410
  * Truncate long activity entries when viewed in activity streams.
411
  *
412
+ * This method can only be used inside the Activity loop.
413
  *
414
+ * @since 1.5.0
415
+ * @since 2.6.0 Added $args parameter.
 
 
 
 
 
416
  *
417
  * @param string $text The original activity entry text.
418
+ * @param array $args {
419
+ * Optional parameters. See $options argument of {@link bp_create_excerpt()}
420
+ * for all available parameters.
421
+ * }
422
  * @return string $excerpt The truncated text.
423
  */
424
+ function bp_activity_truncate_entry( $text, $args = array() ) {
425
  global $activities_template;
426
 
427
+ /**
428
+ * Provides a filter that lets you choose whether to skip this filter on a per-activity basis.
429
+ *
430
+ * @since 2.3.0
431
+ *
432
+ * @param bool $value If true, text should be checked to see if it needs truncating.
433
+ */
434
+ $maybe_truncate_text = apply_filters(
435
+ 'bp_activity_maybe_truncate_entry',
436
+ isset( $activities_template->activity->type ) && ! in_array( $activities_template->activity->type, array( 'new_blog_post', ), true )
437
+ );
438
+
439
+ // The full text of the activity update should always show on the single activity screen.
440
+ if ( empty( $args['force_truncate'] ) && ( ! $maybe_truncate_text || bp_is_single_activity() ) ) {
441
  return $text;
442
+ }
443
 
444
+ /**
445
+ * Filters the appended text for the activity excerpt.
446
+ *
447
+ * @since 1.5.0
448
+ *
449
+ * @param string $value Internationalized "Read more" text.
450
+ */
451
  $append_text = apply_filters( 'bp_activity_excerpt_append_text', __( '[Read more]', 'buddypress' ) );
452
+
453
+ /**
454
+ * Filters the excerpt length for the activity excerpt.
455
+ *
456
+ * @since 1.5.0
457
+ *
458
+ * @param int $value Number indicating how many words to trim the excerpt down to.
459
+ */
460
  $excerpt_length = apply_filters( 'bp_activity_excerpt_length', 358 );
461
 
462
+ $args = wp_parse_args( $args, array( 'ending' => __( '&hellip;', 'buddypress' ) ) );
463
+
464
+ // Run the text through the excerpt function. If it's too short, the original text will be returned.
465
+ $excerpt = bp_create_excerpt( $text, $excerpt_length, $args );
466
 
467
+ /*
468
+ * If the text returned by bp_create_excerpt() is different from the original text (ie it's
469
+ * been truncated), add the "Read More" link. Note that bp_create_excerpt() is stripping
470
+ * shortcodes, so we have strip them from the $text before the comparison.
471
+ */
472
+ if ( strlen( $excerpt ) < strlen( strip_shortcodes( $text ) ) ) {
473
  $id = !empty( $activities_template->activity->current_comment->id ) ? 'acomment-read-more-' . $activities_template->activity->current_comment->id : 'activity-read-more-' . bp_get_activity_id();
474
 
475
  $excerpt = sprintf( '%1$s<span class="activity-read-more" id="%2$s"><a href="%3$s" rel="nofollow">%4$s</a></span>', $excerpt, $id, bp_get_activity_thread_permalink(), $append_text );
476
  }
477
 
478
+ /**
479
+ * Filters the composite activity excerpt entry.
480
+ *
481
+ * @since 1.5.0
482
+ *
483
+ * @param string $excerpt Excerpt text and markup to be displayed.
484
+ * @param string $text The original activity entry text.
485
+ * @param string $append_text The final append text applied.
486
+ */
487
  return apply_filters( 'bp_activity_truncate_entry', $excerpt, $text, $append_text );
488
  }
489
 
490
  /**
491
+ * Include extra JavaScript dependencies for activity component.
492
  *
493
+ * @since 2.0.0
 
 
494
  *
495
  * @param array $js_handles The original dependencies.
496
  * @return array $js_handles The new dependencies.
510
  * We use these classes to avoid pagination issues when items are loaded
511
  * dynamically into the activity stream.
512
  *
513
+ * @since 2.0.0
514
  *
515
+ * @param string $classes Array of classes for most recent activity item.
516
  * @return string $classes
517
  */
518
  function bp_activity_newest_class( $classes = '' ) {
529
  /**
530
  * Check if Activity Heartbeat feature i on to add a timestamp class.
531
  *
532
+ * @since 2.0.0
533
  *
534
+ * @param string $classes Array of classes for timestamp.
535
  * @return string $classes
536
  */
537
  function bp_activity_timestamp_class( $classes = '' ) {
545
  if ( empty( $activity_date ) ) {
546
  return $classes;
547
  }
548
+
549
  $classes .= ' date-recorded-' . strtotime( $activity_date );
550
 
551
  return $classes;
555
  /**
556
  * Use WordPress Heartbeat API to check for latest activity update.
557
  *
558
+ * @since 2.0.0
559
  *
560
+ * @param array $response Array containing Heartbeat API response.
561
+ * @param array $data Array containing data for Heartbeat API response.
 
 
562
  * @return array $response
563
  */
564
  function bp_activity_heartbeat_last_recorded( $response = array(), $data = array() ) {
 
 
565
  if ( empty( $data['bp_activity_last_recorded'] ) ) {
566
  return $response;
567
  }
568
 
569
  // Use the querystring argument stored in the cookie (to preserve
570
+ // filters), but force the offset to get only new items.
571
  $activity_latest_args = bp_parse_args(
572
  bp_ajax_querystring( 'activity' ),
573
  array( 'since' => date( 'Y-m-d H:i:s', $data['bp_activity_last_recorded'] ) ),
574
  'activity_latest_args'
575
  );
576
 
577
+ if ( ! empty( $data['bp_activity_last_recorded_search_terms'] ) && empty( $activity_latest_args['search_terms'] ) ) {
578
+ $activity_latest_args['search_terms'] = addslashes( $data['bp_activity_last_recorded_search_terms'] );
579
+ }
580
+
581
  $newest_activities = array();
582
  $last_activity_recorded = 0;
583
 
584
+ // Temporarily add a just-posted class for new activity items.
585
  add_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
586
 
587
  ob_start();
602
  $newest_activities['last_recorded'] = $last_activity_recorded;
603
  ob_end_clean();
604
 
605
+ // Remove the temporary filter.
606
  remove_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
607
 
608
  if ( ! empty( $newest_activities['last_recorded'] ) ) {
617
  /**
618
  * Set the strings for WP HeartBeat API where needed.
619
  *
620
+ * @since 2.0.0
621
  *
622
  * @param array $strings Localized strings.
623
  * @return array $strings
630
 
631
  $global_pulse = 0;
632
 
633
+ /**
634
+ * Filter that checks whether the global heartbeat settings already exist.
635
+ *
636
+ * @since 2.0.0
637
+ *
638
+ * @param array $value Heartbeat settings array.
639
+ */
640
  $heartbeat_settings = apply_filters( 'heartbeat_settings', array() );
641
  if ( ! empty( $heartbeat_settings['interval'] ) ) {
642
  // 'Fast' is 5
643
  $global_pulse = is_numeric( $heartbeat_settings['interval'] ) ? absint( $heartbeat_settings['interval'] ) : 5;
644
  }
645
 
646
+ /**
647
+ * Filters the pulse frequency to be used for the BuddyPress Activity heartbeat.
648
+ *
649
+ * @since 2.0.0
650
+ *
651
+ * @param int $value The frequency in seconds between pulses.
652
+ */
653
  $bp_activity_pulse = apply_filters( 'bp_activity_heartbeat_pulse', 15 );
654
 
655
  /**
672
  return $strings;
673
  }
674
  add_filter( 'bp_core_get_js_strings', 'bp_activity_heartbeat_strings', 10, 1 );
675
+
676
+ /** Scopes ********************************************************************/
677
+
678
+ /**
679
+ * Set up activity arguments for use with the 'just-me' scope.
680
+ *
681
+ * @since 2.2.0
682
+ *
683
+ * @param array $retval Empty array by default.
684
+ * @param array $filter Current activity arguments.
685
+ * @return array $retval
686
+ */
687
+ function bp_activity_filter_just_me_scope( $retval = array(), $filter = array() ) {
688
+
689
+ // Determine the user_id.
690
+ if ( ! empty( $filter['user_id'] ) ) {
691
+ $user_id = $filter['user_id'];
692
+ } else {
693
+ $user_id = bp_displayed_user_id()
694
+ ? bp_displayed_user_id()
695
+ : bp_loggedin_user_id();
696
+ }
697
+
698
+ // Should we show all items regardless of sitewide visibility?
699
+ $show_hidden = array();
700
+ if ( ! empty( $user_id ) && $user_id !== bp_loggedin_user_id() ) {
701
+ $show_hidden = array(
702
+ 'column' => 'hide_sitewide',
703
+ 'value' => 0
704
+ );
705
+ }
706
+
707
+ $retval = array(
708
+ 'relation' => 'AND',
709
+ array(
710
+ 'column' => 'user_id',
711
+ 'value' => $user_id
712
+ ),
713
+ $show_hidden,
714
+
715
+ // Overrides.
716
+ 'override' => array(
717
+ 'display_comments' => 'stream',
718
+ 'filter' => array( 'user_id' => 0 ),
719
+ 'show_hidden' => true
720
+ ),
721
+ );
722
+
723
+ return $retval;
724
+ }
725
+ add_filter( 'bp_activity_set_just-me_scope_args', 'bp_activity_filter_just_me_scope', 10, 2 );
726
+
727
+ /**
728
+ * Set up activity arguments for use with the 'favorites' scope.
729
+ *
730
+ * @since 2.2.0
731
+ *
732
+ * @param array $retval Empty array by default.
733
+ * @param array $filter Current activity arguments.
734
+ * @return array $retval
735
+ */
736
+ function bp_activity_filter_favorites_scope( $retval = array(), $filter = array() ) {
737
+
738
+ // Determine the user_id.
739
+ if ( ! empty( $filter['user_id'] ) ) {
740
+ $user_id = $filter['user_id'];
741
+ } else {
742
+ $user_id = bp_displayed_user_id()
743
+ ? bp_displayed_user_id()
744
+ : bp_loggedin_user_id();
745
+ }
746
+
747
+ // Determine the favorites.
748
+ $favs = bp_activity_get_user_favorites( $user_id );
749
+ if ( empty( $favs ) ) {
750
+ $favs = array( 0 );
751
+ }
752
+
753
+ // Should we show all items regardless of sitewide visibility?
754
+ $show_hidden = array();
755
+ if ( ! empty( $user_id ) && ( $user_id !== bp_loggedin_user_id() ) ) {
756
+ $show_hidden = array(
757
+ 'column' => 'hide_sitewide',
758
+ 'value' => 0
759
+ );
760
+ }
761
+
762
+ $retval = array(
763
+ 'relation' => 'AND',
764
+ array(
765
+ 'column' => 'id',
766
+ 'compare' => 'IN',
767
+ 'value' => (array) $favs
768
+ ),
769
+ $show_hidden,
770
+
771
+ // Overrides.
772
+ 'override' => array(
773
+ 'display_comments' => true,
774
+ 'filter' => array( 'user_id' => 0 ),
775
+ 'show_hidden' => true
776
+ ),
777
+ );
778
+
779
+ return $retval;
780
+ }
781
+ add_filter( 'bp_activity_set_favorites_scope_args', 'bp_activity_filter_favorites_scope', 10, 2 );
782
+
783
+
784
+ /**
785
+ * Set up activity arguments for use with the 'favorites' scope.
786
+ *
787
+ * @since 2.2.0
788
+ *
789
+ * @param array $retval Empty array by default.
790
+ * @param array $filter Current activity arguments.
791
+ * @return array $retval
792
+ */
793
+ function bp_activity_filter_mentions_scope( $retval = array(), $filter = array() ) {
794
+
795
+ // Are mentions disabled?
796
+ if ( ! bp_activity_do_mentions() ) {
797
+ return $retval;
798
+ }
799
+
800
+ // Determine the user_id.
801
+ if ( ! empty( $filter['user_id'] ) ) {
802
+ $user_id = $filter['user_id'];
803
+ } else {
804
+ $user_id = bp_displayed_user_id()
805
+ ? bp_displayed_user_id()
806
+ : bp_loggedin_user_id();
807
+ }
808
+
809
+ // Should we show all items regardless of sitewide visibility?
810
+ $show_hidden = array();
811
+ if ( ! empty( $user_id ) && $user_id !== bp_loggedin_user_id() ) {
812
+ $show_hidden = array(
813
+ 'column' => 'hide_sitewide',
814
+ 'value' => 0
815
+ );
816
+ }
817
+
818
+ $retval = array(
819
+ 'relation' => 'AND',
820
+ array(
821
+ 'column' => 'content',
822
+ 'compare' => 'LIKE',
823
+
824
+ // Start search at @ symbol and stop search at closing tag delimiter.
825
+ 'value' => '@' . bp_activity_get_user_mentionname( $user_id ) . '<'
826
+ ),
827
+ $show_hidden,
828
+
829
+ // Overrides.
830
+ 'override' => array(
831
+ 'display_comments' => 'stream',
832
+ 'filter' => array( 'user_id' => 0 ),
833
+ 'show_hidden' => true
834
+ ),
835
+ );
836
+
837
+ return $retval;
838
+ }
839
+ add_filter( 'bp_activity_set_mentions_scope_args', 'bp_activity_filter_mentions_scope', 10, 2 );
bp-activity/bp-activity-functions.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Activity Functions.
5
  *
@@ -7,24 +6,21 @@
7
  *
8
  * @package BuddyPress
9
  * @subpackage ActivityFunctions
 
10
  */
11
 
12
- // Exit if accessed directly
13
- if ( !defined( 'ABSPATH' ) ) exit;
14
 
15
  /**
16
  * Check whether the $bp global lists an activity directory page.
17
  *
18
- * @since BuddyPress (1.5)
19
- *
20
- * @global object $bp BuddyPress global settings
21
  *
22
  * @return bool True if activity directory page is found, otherwise false.
23
  */
24
  function bp_activity_has_directory() {
25
- global $bp;
26
-
27
- return (bool) !empty( $bp->pages->activity->id );
28
  }
29
 
30
  /**
@@ -32,72 +28,123 @@ function bp_activity_has_directory() {
32
  *
33
  * The Mentions feature does a number of things, all of which will be turned
34
  * off if you disable mentions:
35
- * - Detecting and auto-linking @username in all BP/WP content
36
  * - Sending BP notifications and emails to users when they are mentioned
37
- * using the @username syntax
38
- * - The Public Message button on user profiles
39
  *
40
  * Mentions are enabled by default. To disable, put the following line in
41
  * bp-custom.php or your theme's functions.php file:
42
  *
43
  * add_filter( 'bp_activity_do_mentions', '__return_false' );
44
  *
45
- * @since BuddyPress (1.8)
46
- *
47
- * @uses apply_filters() To call 'bp_activity_do_mentions' hook.
48
  *
49
  * @return bool $retval True to enable mentions, false to disable.
50
  */
51
  function bp_activity_do_mentions() {
 
 
 
 
 
 
 
 
52
  return (bool) apply_filters( 'bp_activity_do_mentions', true );
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  /**
56
  * Locate usernames in an activity content string, as designated by an @ sign.
57
  *
58
- * @since BuddyPress (1.5)
59
  *
60
- * @param string $content The content of the activity, usually found in $activity->content.
61
- * @return array|bool Associative array with user ID as key and username as value. Boolean false if no mentions found.
 
 
62
  */
63
  function bp_activity_find_mentions( $content ) {
 
64
  $pattern = '/[@]+([A-Za-z0-9-_\.@]+)\b/';
65
  preg_match_all( $pattern, $content, $usernames );
66
 
67
- // Make sure there's only one instance of each username
68
- if ( !$usernames = array_unique( $usernames[1] ) )
 
 
 
69
  return false;
 
70
 
71
  $mentioned_users = array();
72
 
73
- // We've found some mentions! Check to see if users exist
74
- foreach( (array) $usernames as $key => $username ) {
75
  $user_id = bp_activity_get_userid_from_mentionname( $username );
76
 
77
- // user ID exists, so let's add it to our array
78
  if ( ! empty( $user_id ) ) {
79
- $mentioned_users[$user_id] = $username;
80
  }
81
  }
82
 
83
- if ( empty( $mentioned_users ) )
84
  return false;
 
85
 
86
- return $mentioned_users;
 
 
 
 
 
 
 
87
  }
88
 
89
  /**
90
  * Reset a user's unread mentions list and count.
91
  *
92
- * @since BuddyPress (1.5)
93
- *
94
- * @uses bp_delete_user_meta()
95
  *
96
  * @param int $user_id The id of the user whose unread mentions are being reset.
97
  */
98
  function bp_activity_clear_new_mentions( $user_id ) {
99
  bp_delete_user_meta( $user_id, 'bp_new_mention_count' );
100
- bp_delete_user_meta( $user_id, 'bp_new_mentions' );
 
 
 
 
 
 
 
 
 
101
  }
102
 
103
  /**
@@ -108,30 +155,32 @@ function bp_activity_clear_new_mentions( $user_id ) {
108
  *
109
  * Currently, only used in {@link bp_activity_delete()}.
110
  *
111
- * @since BuddyPress (1.5)
112
  *
113
- * @uses bp_activity_find_mentions()
114
- * @uses bp_activity_update_mention_count_for_user()
115
- *
116
- * @param int $activity_id The unique id for the activity item.
117
- * @param string $action Can be 'delete' or 'add'. Defaults to 'add'.
118
  */
119
  function bp_activity_adjust_mention_count( $activity_id = 0, $action = 'add' ) {
120
- if ( empty( $activity_id ) )
 
 
121
  return false;
 
122
 
123
- // Get activity object
124
- $activity = new BP_Activity_Activity( (int) $activity_id );
125
 
126
- // Try to find mentions
127
  $usernames = bp_activity_find_mentions( strip_tags( $activity->content ) );
128
 
129
- // Still empty? Stop now
130
- if ( empty( $usernames ) )
131
  return false;
 
132
 
133
- // Increment mention count foreach mentioned user
134
- foreach( (array) $usernames as $user_id => $username ) {
135
  bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action );
136
  }
137
  }
@@ -142,24 +191,27 @@ function bp_activity_adjust_mention_count( $activity_id = 0, $action = 'add' ) {
142
  * This function should be used when you've already parsed your activity item
143
  * for @mentions.
144
  *
145
- * @since BuddyPress (1.7)
146
  *
147
- * @uses bp_get_user_meta()
148
- * @uses bp_update_user_meta()
149
- *
150
- * @param int $user_id The user ID.
151
- * @param int $activity_id The unique ID for the activity item.
152
- * @param string $action 'delete' or 'add'. Default: 'add'.
153
  * @return bool
154
  */
155
  function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action = 'add' ) {
156
- if ( empty( $user_id ) || empty( $activity_id ) )
 
157
  return false;
 
158
 
159
- // Adjust the mention list and count for the member
160
  $new_mention_count = (int) bp_get_user_meta( $user_id, 'bp_new_mention_count', true );
161
- if ( !$new_mentions = bp_get_user_meta( $user_id, 'bp_new_mentions', true ) )
 
 
 
162
  $new_mentions = array();
 
163
 
164
  switch ( $action ) {
165
  case 'delete' :
@@ -180,10 +232,10 @@ function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $act
180
  break;
181
  }
182
 
183
- // Get an updated mention count
184
  $new_mention_count = count( $new_mentions );
185
 
186
- // Resave the user_meta
187
  bp_update_user_meta( $user_id, 'bp_new_mention_count', $new_mention_count );
188
  bp_update_user_meta( $user_id, 'bp_new_mentions', $new_mentions );
189
 
@@ -193,9 +245,10 @@ function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $act
193
  /**
194
  * Determine a user's "mentionname", the name used for that user in @-mentions.
195
  *
196
- * @since BuddyPress (1.9.0)
197
  *
198
- * @return string User name appropriate for @-mentions.
 
199
  */
200
  function bp_activity_get_user_mentionname( $user_id ) {
201
  $mentionname = '';
@@ -216,21 +269,24 @@ function bp_activity_get_user_mentionname( $user_id ) {
216
  /**
217
  * Get a user ID from a "mentionname", the name used for a user in @-mentions.
218
  *
219
- * @since BuddyPress (1.9.0)
220
  *
 
221
  * @return int|bool ID of the user, if one is found. Otherwise false.
222
  */
223
  function bp_activity_get_userid_from_mentionname( $mentionname ) {
224
  $user_id = false;
225
 
226
- // In username compatibility mode, hyphens are ambiguous between
227
- // actual hyphens and converted spaces.
228
- //
229
- // @todo There is the potential for username clashes between 'foo bar'
230
- // and 'foo-bar' in compatibility mode. Come up with a system for
231
- // unique mentionnames.
 
 
232
  if ( bp_is_username_compatibility_mode() ) {
233
- // First, try the raw username
234
  $userdata = get_user_by( 'login', $mentionname );
235
 
236
  // Doing a direct query to use proper regex. Necessary to
@@ -244,7 +300,7 @@ function bp_activity_get_userid_from_mentionname( $mentionname ) {
244
  }
245
 
246
  // When username compatibility mode is disabled, the mentionname is
247
- // the same as the nicename
248
  } else {
249
  $user_id = bp_core_get_userid_from_nicename( $mentionname );
250
  }
@@ -269,28 +325,32 @@ function bp_activity_get_userid_from_mentionname( $mentionname ) {
269
  * panel, and dynamic action generation (which is essential for multilingual
270
  * sites, etc) will not work.
271
  *
272
- * @since BuddyPress (1.1.0)
273
  *
274
- * @param string $component_id The unique string ID of the component.
275
- * @param string $type The action type.
276
- * @param string $description The action description.
277
- * @param callable $format_callback Callback for formatting the action string.
 
 
 
 
278
  * @return bool False if any param is empty, otherwise true.
279
  */
280
- function bp_activity_set_action( $component_id, $type, $description, $format_callback = false ) {
281
  $bp = buddypress();
282
 
283
- // Return false if any of the above values are not set
284
  if ( empty( $component_id ) || empty( $type ) || empty( $description ) ) {
285
  return false;
286
  }
287
 
288
- // Set activity action
289
  if ( ! isset( $bp->activity->actions ) || ! is_object( $bp->activity->actions ) ) {
290
  $bp->activity->actions = new stdClass;
291
  }
292
 
293
- // Verify callback
294
  if ( ! is_callable( $format_callback ) ) {
295
  $format_callback = '';
296
  }
@@ -299,41 +359,458 @@ function bp_activity_set_action( $component_id, $type, $description, $format_cal
299
  $bp->activity->actions->{$component_id} = new stdClass;
300
  }
301
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  $bp->activity->actions->{$component_id}->{$type} = apply_filters( 'bp_activity_set_action', array(
303
  'key' => $type,
304
  'value' => $description,
305
  'format_callback' => $format_callback,
306
- ), $component_id, $type, $description, $format_callback );
 
 
 
 
 
 
 
 
 
 
 
 
 
307
 
308
  return true;
309
  }
310
 
311
  /**
312
- * Retreive the current action from a component and key.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  *
314
- * @since BuddyPress (1.1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  *
316
- * @global object $bp BuddyPress global settings.
317
- * @uses apply_filters() To call the 'bp_activity_get_action' hook.
318
  *
319
  * @param string $component_id The unique string ID of the component.
320
- * @param string $key The action key.
321
  * @return string|bool Action value if found, otherwise false.
322
  */
323
  function bp_activity_get_action( $component_id, $key ) {
324
- global $bp;
325
 
326
- // Return false if any of the above values are not set
327
- if ( empty( $component_id ) || empty( $key ) )
328
  return false;
 
329
 
330
- return apply_filters( 'bp_activity_get_action', $bp->activity->actions->{$component_id}->{$key}, $component_id, $key );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  }
332
 
333
  /**
334
  * Fetch details of all registered activity types.
335
  *
336
- * @since BuddyPress (1.7)
337
  *
338
  * @return array array( type => description ), ...
339
  */
@@ -341,16 +818,24 @@ function bp_activity_get_types() {
341
  $actions = array();
342
 
343
  // Walk through the registered actions, and build an array of actions/values.
344
- foreach ( buddypress()->activity->actions as $action ) {
345
  $action = array_values( (array) $action );
346
 
347
- for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
348
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
 
349
  }
350
 
351
- // This was a mis-named activity type from before BP 1.6
352
  unset( $actions['friends_register_activity_action'] );
353
 
 
 
 
 
 
 
 
354
  return apply_filters( 'bp_activity_get_types', $actions );
355
  }
356
 
@@ -359,85 +844,99 @@ function bp_activity_get_types() {
359
  /**
360
  * Get a users favorite activity stream items.
361
  *
362
- * @since BuddyPress (1.2)
363
- *
364
- * @uses bp_get_user_meta()
365
- * @uses apply_filters() To call the 'bp_activity_get_user_favorites' hook.
366
  *
367
  * @param int $user_id ID of the user whose favorites are being queried.
368
  * @return array IDs of the user's favorite activity items.
369
  */
370
  function bp_activity_get_user_favorites( $user_id = 0 ) {
371
 
372
- // Fallback to logged in user if no user_id is passed
373
- if ( empty( $user_id ) )
374
  $user_id = bp_displayed_user_id();
 
375
 
376
- // Get favorites for user
377
  $favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
378
 
 
 
 
 
 
 
 
379
  return apply_filters( 'bp_activity_get_user_favorites', $favs );
380
  }
381
 
382
  /**
383
  * Add an activity stream item as a favorite for a user.
384
  *
385
- * @since BuddyPress (1.2)
386
- *
387
- * @uses is_user_logged_in()
388
- * @uses bp_get_user_meta()
389
- * @uses bp_activity_get_meta()
390
- * @uses bp_update_user_meta()
391
- * @uses bp_activity_update_meta()
392
- * @uses do_action() To call the 'bp_activity_add_user_favorite' hook.
393
- * @uses do_action() To call the 'bp_activity_add_user_favorite_fail' hook.
394
  *
395
  * @param int $activity_id ID of the activity item being favorited.
396
- * @param int $user_id ID of the user favoriting the activity item.
397
  * @return bool True on success, false on failure.
398
  */
399
  function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) {
400
 
401
- // Favorite activity stream items are for logged in users only
402
- if ( !is_user_logged_in() )
403
  return false;
 
404
 
405
- // Fallback to logged in user if no user_id is passed
406
- if ( empty( $user_id ) )
407
  $user_id = bp_loggedin_user_id();
 
408
 
409
  $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
410
  if ( empty( $my_favs ) || ! is_array( $my_favs ) ) {
411
  $my_favs = array();
412
  }
413
 
414
- // Bail if the user has already favorited this activity item
415
  if ( in_array( $activity_id, $my_favs ) ) {
416
  return false;
417
  }
418
 
419
- // Add to user's favorites
420
  $my_favs[] = $activity_id;
421
 
422
- // Update the total number of users who have favorited this activity
423
  $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' );
424
  $fav_count = !empty( $fav_count ) ? (int) $fav_count + 1 : 1;
425
 
426
- // Update user meta
427
  bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs );
428
 
429
- // Update activity meta counts
430
  if ( bp_activity_update_meta( $activity_id, 'favorite_count', $fav_count ) ) {
431
 
432
- // Execute additional code
 
 
 
 
 
 
 
433
  do_action( 'bp_activity_add_user_favorite', $activity_id, $user_id );
434
 
435
- // Success
436
  return true;
437
 
438
- // Saving meta was unsuccessful for an unknown reason
439
  } else {
440
- // Execute additional code
 
 
 
 
 
 
 
 
441
  do_action( 'bp_activity_add_user_favorite_fail', $activity_id, $user_id );
442
 
443
  return false;
@@ -447,67 +946,70 @@ function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) {
447
  /**
448
  * Remove an activity stream item as a favorite for a user.
449
  *
450
- * @since BuddyPress (1.2)
451
- *
452
- * @uses is_user_logged_in()
453
- * @uses bp_get_user_meta()
454
- * @uses bp_activity_get_meta()
455
- * @uses bp_activity_update_meta()
456
- * @uses bp_update_user_meta()
457
- * @uses do_action() To call the 'bp_activity_remove_user_favorite' hook.
458
  *
459
  * @param int $activity_id ID of the activity item being unfavorited.
460
- * @param int $user_id ID of the user unfavoriting the activity item.
461
  * @return bool True on success, false on failure.
462
  */
463
  function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) {
464
 
465
- // Favorite activity stream items are for logged in users only
466
- if ( !is_user_logged_in() )
467
  return false;
 
468
 
469
- // Fallback to logged in user if no user_id is passed
470
- if ( empty( $user_id ) )
471
  $user_id = bp_loggedin_user_id();
 
472
 
473
  $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
474
  $my_favs = array_flip( (array) $my_favs );
475
 
476
- // Bail if the user has not previously favorited the item
477
  if ( ! isset( $my_favs[ $activity_id ] ) ) {
478
  return false;
479
  }
480
 
481
- // Remove the fav from the user's favs
482
  unset( $my_favs[$activity_id] );
483
  $my_favs = array_unique( array_flip( $my_favs ) );
484
 
485
- // Update the total number of users who have favorited this activity
486
- if ( $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' ) ) {
 
487
 
488
- // Deduct from total favorites
489
  if ( bp_activity_update_meta( $activity_id, 'favorite_count', (int) $fav_count - 1 ) ) {
490
 
491
- // Update users favorites
492
  if ( bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ) ) {
493
 
494
- // Execute additional code
 
 
 
 
 
 
 
495
  do_action( 'bp_activity_remove_user_favorite', $activity_id, $user_id );
496
 
497
- // Success
498
  return true;
499
 
500
- // Error updating
501
  } else {
502
  return false;
503
  }
504
 
505
- // Error updating favorite count
506
  } else {
507
  return false;
508
  }
509
 
510
- // Error getting favorite count
511
  } else {
512
  return false;
513
  }
@@ -516,47 +1018,56 @@ function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) {
516
  /**
517
  * Check whether an activity item exists with a given content string.
518
  *
519
- * @since BuddyPress (1.1)
520
- *
521
- * @uses BP_Activity_Activity::check_exists_by_content() {@link BP_Activity_Activity}
522
- * @uses apply_filters() To call the 'bp_activity_check_exists_by_content' hook.
523
  *
524
  * @param string $content The content to filter by.
525
  * @return int|null The ID of the located activity item. Null if none is found.
526
  */
527
  function bp_activity_check_exists_by_content( $content ) {
 
 
 
 
 
 
 
 
528
  return apply_filters( 'bp_activity_check_exists_by_content', BP_Activity_Activity::check_exists_by_content( $content ) );
529
  }
530
 
531
  /**
532
  * Retrieve the last time activity was updated.
533
  *
534
- * @since BuddyPress (1.0)
535
- *
536
- * @uses BP_Activity_Activity::get_last_updated() {@link BP_Activity_Activity}
537
- * @uses apply_filters() To call the 'bp_activity_get_last_updated' hook.
538
  *
539
  * @return string Date last updated.
540
  */
541
  function bp_activity_get_last_updated() {
 
 
 
 
 
 
 
 
542
  return apply_filters( 'bp_activity_get_last_updated', BP_Activity_Activity::get_last_updated() );
543
  }
544
 
545
  /**
546
  * Retrieve the number of favorite activity stream items a user has.
547
  *
548
- * @since BuddyPress (1.2)
549
- *
550
- * @uses BP_Activity_Activity::total_favorite_count() {@link BP_Activity_Activity}
551
  *
552
  * @param int $user_id ID of the user whose favorite count is being requested.
553
  * @return int Total favorite count for the user.
554
  */
555
  function bp_activity_total_favorites_for_user( $user_id = 0 ) {
556
 
557
- // Fallback on displayed user, and then logged in user
558
- if ( empty( $user_id ) )
559
  $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
 
560
 
561
  return BP_Activity_Activity::total_favorite_count( $user_id );
562
  }
@@ -566,32 +1077,30 @@ function bp_activity_total_favorites_for_user( $user_id = 0 ) {
566
  /**
567
  * Delete a meta entry from the DB for an activity stream item.
568
  *
569
- * @since BuddyPress (1.2.0)
570
  *
571
  * @global object $wpdb WordPress database access object.
572
- * @global object $bp BuddyPress global settings.
573
- *
574
- * @param int $activity_id ID of the activity item whose metadata is being deleted.
575
- * @param string $meta_key Optional. The key of the metadata being deleted. If
576
- * omitted, all metadata associated with the activity
577
- * item will be deleted.
578
- * @param string $meta_value Optional. If present, the metadata will only be
579
- * deleted if the meta_value matches this parameter.
580
- * @param bool $delete_all Optional. If true, delete matching metadata entries
581
- * for all objects, ignoring the specified object_id. Otherwise,
582
- * only delete matching metadata entries for the specified
583
- * activity item. Default: false.
584
  * @return bool True on success, false on failure.
585
  */
586
  function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = '', $delete_all = false ) {
587
- global $wpdb, $bp;
588
 
589
- // Legacy - if no meta_key is passed, delete all for the item
590
  if ( empty( $meta_key ) ) {
591
  $all_meta = bp_activity_get_meta( $activity_id );
592
  $keys = ! empty( $all_meta ) ? array_keys( $all_meta ) : array();
593
 
594
- // With no meta_key, ignore $delete_all
595
  $delete_all = false;
596
  } else {
597
  $keys = array( $meta_key );
@@ -611,17 +1120,15 @@ function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = ''
611
  /**
612
  * Get metadata for a given activity item.
613
  *
614
- * @since BuddyPress (1.2)
615
- *
616
- * @uses apply_filters() To call the 'bp_activity_get_meta' hook.
617
  *
618
- * @param int $activity_id ID of the activity item whose metadata is being requested.
619
- * @param string $meta_key Optional. If present, only the metadata matching
620
- * that meta key will be returned. Otherwise, all metadata for the
621
- * activity item will be fetched.
622
- * @param bool $single Optional. If true, return only the first value of the
623
- * specified meta_key. This parameter has no effect if meta_key is not
624
- * specified. Default: true.
625
  * @return mixed The meta value(s) being requested.
626
  */
627
  function bp_activity_get_meta( $activity_id = 0, $meta_key = '', $single = true ) {
@@ -629,25 +1136,32 @@ function bp_activity_get_meta( $activity_id = 0, $meta_key = '', $single = true
629
  $retval = get_metadata( 'activity', $activity_id, $meta_key, $single );
630
  remove_filter( 'query', 'bp_filter_metaid_column_name' );
631
 
632
- // Filter result before returning
 
 
 
 
 
 
 
 
 
633
  return apply_filters( 'bp_activity_get_meta', $retval, $activity_id, $meta_key, $single );
634
  }
635
 
636
  /**
637
  * Update a piece of activity meta.
638
  *
639
- * @since BuddyPress (1.2)
640
  *
641
- * @param int $activity_id ID of the activity item whose metadata is being
642
- * updated.
643
- * @param string $meta_key Key of the metadata being updated.
644
- * @param mixed $meta_value Value to be set.
645
- * @param mixed $prev_value Optional. If specified, only update existing
646
- * metadata entries with the specified value. Otherwise, update all
647
- * entries.
648
  * @return bool|int Returns false on failure. On successful update of existing
649
- * metadata, returns true. On successful creation of new metadata,
650
- * returns the integer ID of the new metadata row.
651
  */
652
  function bp_activity_update_meta( $activity_id, $meta_key, $meta_value, $prev_value = '' ) {
653
  add_filter( 'query', 'bp_filter_metaid_column_name' );
@@ -660,14 +1174,14 @@ function bp_activity_update_meta( $activity_id, $meta_key, $meta_value, $prev_va
660
  /**
661
  * Add a piece of activity metadata.
662
  *
663
- * @since BuddyPress (2.0.0)
664
  *
665
- * @param int $activity_id ID of the activity item.
666
- * @param string $meta_key Metadata key.
667
- * @param mixed $meta_value Metadata value.
668
- * @param bool $unique. Optional. Whether to enforce a single metadata value
669
- * for the given key. If true, and the object already has a value for
670
- * the key, no change will be made. Default: false.
671
  * @return int|bool The meta ID on successful update, false on failure.
672
  */
673
  function bp_activity_add_meta( $activity_id, $meta_key, $meta_value, $unique = false ) {
@@ -683,33 +1197,35 @@ function bp_activity_add_meta( $activity_id, $meta_key, $meta_value, $unique = f
683
  /**
684
  * Completely remove a user's activity data.
685
  *
686
- * @since BuddyPress (1.5)
687
- *
688
- * @uses is_user_logged_in()
689
- * @uses bp_activity_delete()
690
- * @uses bp_delete_user_meta()
691
- * @uses do_action() To call the 'bp_activity_remove_data' hook.
692
- * @uses do_action() To call the 'bp_activity_remove_all_user_data' hook.
693
  *
694
  * @param int $user_id ID of the user whose activity is being deleted.
 
695
  */
696
  function bp_activity_remove_all_user_data( $user_id = 0 ) {
697
 
698
- // Do not delete user data unless a logged in user says so
699
- if ( empty( $user_id ) || !is_user_logged_in() )
700
  return false;
 
701
 
702
- // Clear the user's activity from the sitewide stream and clear their activity tables
703
  bp_activity_delete( array( 'user_id' => $user_id ) );
704
 
705
- // Remove any usermeta
706
- bp_delete_user_meta( $user_id, 'bp_latest_update' );
707
  bp_delete_user_meta( $user_id, 'bp_favorite_activities' );
708
 
709
  // Execute additional code
710
  do_action( 'bp_activity_remove_data', $user_id ); // Deprecated! Do not use!
711
 
712
- // Use this going forward
 
 
 
 
 
 
713
  do_action( 'bp_activity_remove_all_user_data', $user_id );
714
  }
715
  add_action( 'wpmu_delete_user', 'bp_activity_remove_all_user_data' );
@@ -718,52 +1234,68 @@ add_action( 'delete_user', 'bp_activity_remove_all_user_data' );
718
  /**
719
  * Mark all of the user's activity as spam.
720
  *
721
- * @since BuddyPress (1.6)
722
  *
723
  * @global object $wpdb WordPress database access object.
724
- * @global object $bp BuddyPress global settings.
725
  *
726
  * @param int $user_id ID of the user whose activity is being spammed.
 
727
  */
728
  function bp_activity_spam_all_user_data( $user_id = 0 ) {
729
- global $bp, $wpdb;
730
 
731
- // Do not delete user data unless a logged in user says so
732
- if ( empty( $user_id ) || ! is_user_logged_in() )
733
  return false;
 
734
 
735
  // Get all the user's activities.
736
- $activities = bp_activity_get( array( 'display_comments' => 'stream', 'filter' => array( 'user_id' => $user_id ), 'show_hidden' => true, ) );
 
 
 
 
 
 
737
 
738
- // Mark each as spam
739
  foreach ( (array) $activities['activities'] as $activity ) {
740
 
741
- // Create an activity object
742
  $activity_obj = new BP_Activity_Activity;
743
- foreach ( $activity as $k => $v )
744
  $activity_obj->$k = $v;
 
745
 
746
- // Mark as spam
747
  bp_activity_mark_as_spam( $activity_obj );
748
 
749
  /*
750
  * If Akismet is present, update the activity history meta.
751
  *
752
  * This is usually taken care of when BP_Activity_Activity::save() happens, but
753
- * as we're going to be updating all the activity statuses directly, for efficency,
754
  * we need to update manually.
755
  */
756
- if ( ! empty( $bp->activity->akismet ) )
757
  $bp->activity->akismet->update_activity_spam_meta( $activity_obj );
 
758
 
759
- // Tidy up
760
  unset( $activity_obj );
761
  }
762
 
763
- // Mark all of this user's activities as spam
764
  $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id ) );
765
 
766
- // Call an action for plugins to use
 
 
 
 
 
 
 
767
  do_action( 'bp_activity_spam_all_user_data', $user_id, $activities['activities'] );
768
  }
769
  add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' );
@@ -771,80 +1303,105 @@ add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' );
771
  /**
772
  * Mark all of the user's activity as ham (not spam).
773
  *
774
- * @since BuddyPress (1.6)
775
  *
776
  * @global object $wpdb WordPress database access object.
777
- * @global object $bp BuddyPress global settings.
778
  *
779
  * @param int $user_id ID of the user whose activity is being hammed.
 
780
  */
781
  function bp_activity_ham_all_user_data( $user_id = 0 ) {
782
- global $bp, $wpdb;
783
 
784
- // Do not delete user data unless a logged in user says so
785
- if ( empty( $user_id ) || ! is_user_logged_in() )
786
  return false;
 
787
 
788
  // Get all the user's activities.
789
- $activities = bp_activity_get( array( 'display_comments' => 'stream', 'filter' => array( 'user_id' => $user_id ), 'show_hidden' => true, 'spam' => 'all', ) );
 
 
 
 
 
790
 
791
- // Mark each as not spam
 
 
792
  foreach ( (array) $activities['activities'] as $activity ) {
793
 
794
- // Create an activity object
795
  $activity_obj = new BP_Activity_Activity;
796
- foreach ( $activity as $k => $v )
797
  $activity_obj->$k = $v;
 
798
 
799
- // Mark as not spam
800
  bp_activity_mark_as_ham( $activity_obj );
801
 
802
  /*
803
  * If Akismet is present, update the activity history meta.
804
  *
805
  * This is usually taken care of when BP_Activity_Activity::save() happens, but
806
- * as we're going to be updating all the activity statuses directly, for efficency,
807
  * we need to update manually.
808
  */
809
- if ( ! empty( $bp->activity->akismet ) )
810
  $bp->activity->akismet->update_activity_ham_meta( $activity_obj );
 
811
 
812
- // Tidy up
813
  unset( $activity_obj );
814
  }
815
 
816
- // Mark all of this user's activities as spam
817
  $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 0 WHERE user_id = %d", $user_id ) );
818
 
819
- // Call an action for plugins to use
 
 
 
 
 
 
 
820
  do_action( 'bp_activity_ham_all_user_data', $user_id, $activities['activities'] );
821
  }
822
  add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' );
823
 
824
  /**
825
- * Register the activity stream actions for updates
826
- *
827
- * @since BuddyPress (1.6)
828
  *
829
- * @global object $bp BuddyPress global settings.
830
  */
831
  function bp_activity_register_activity_actions() {
832
- global $bp;
833
 
834
  bp_activity_set_action(
835
  $bp->activity->id,
836
  'activity_update',
837
  __( 'Posted a status update', 'buddypress' ),
838
- 'bp_activity_format_activity_action_activity_update'
 
 
839
  );
840
 
841
  bp_activity_set_action(
842
  $bp->activity->id,
843
  'activity_comment',
844
  __( 'Replied to a status update', 'buddypress' ),
845
- 'bp_activity_format_activity_action_activity_comment'
 
846
  );
847
 
 
 
 
 
 
 
 
848
  do_action( 'bp_activity_register_activity_actions' );
849
 
850
  // Backpat. Don't use this.
@@ -855,29 +1412,40 @@ add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actio
855
  /**
856
  * Generate an activity action string for an activity item.
857
  *
 
 
858
  * @param object $activity Activity data object.
859
  * @return string|bool Returns false if no callback is found, otherwise returns
860
- * the formatted action string.
861
  */
862
  function bp_activity_generate_action_string( $activity ) {
863
- // Check for valid input
 
864
  if ( empty( $activity->component ) || empty( $activity->type ) ) {
865
  return false;
866
  }
867
 
868
- // Check for registered format callback
869
- if ( empty( buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'] ) ) {
 
870
  return false;
871
  }
872
 
873
- // We apply the format_callback as a filter
874
- add_filter( 'bp_activity_generate_action_string', buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 );
875
 
876
- // Generate the action string (run through the filter defined above)
 
 
 
 
 
 
 
877
  $action = apply_filters( 'bp_activity_generate_action_string', $activity->action, $activity );
878
 
879
- // Remove the filter for future activity items
880
- remove_filter( 'bp_activity_generate_action_string', buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 );
881
 
882
  return $action;
883
  }
@@ -885,32 +1453,158 @@ function bp_activity_generate_action_string( $activity ) {
885
  /**
886
  * Format 'activity_update' activity actions.
887
  *
888
- * @since BuddyPress (2.0.0)
889
  *
890
- * @param string $action Static activity action.
891
  * @param object $activity Activity data object.
892
- * @return string
893
  */
894
  function bp_activity_format_activity_action_activity_update( $action, $activity ) {
895
  $action = sprintf( __( '%s posted an update', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
 
 
 
 
 
 
 
 
 
896
  return apply_filters( 'bp_activity_new_update_action', $action, $activity );
897
  }
898
 
899
  /**
900
  * Format 'activity_comment' activity actions.
901
  *
902
- * @since BuddyPress (2.0.0)
903
  *
904
- * @param string $action Static activity action.
905
  * @param object $activity Activity data object.
906
- * @return string
907
  */
908
  function bp_activity_format_activity_action_activity_comment( $action, $activity ) {
909
  $action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
 
 
 
 
 
 
 
 
 
910
  return apply_filters( 'bp_activity_comment_action', $action, $activity );
911
  }
912
 
913
- /******************************************************************************
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
914
  * Business functions are where all the magic happens in BuddyPress. They will
915
  * handle the actual saving or manipulation of information. Usually they will
916
  * hand off to a database class for data access, then return
@@ -920,240 +1614,252 @@ function bp_activity_format_activity_action_activity_comment( $action, $activity
920
  /**
921
  * Retrieve an activity or activities.
922
  *
923
- * bp_activity_get() shares all arguments with BP_Activity_Activity::get(). The
924
- * following is a list of bp_activity_get() parameters that have different
925
  * default values from BP_Activity_Activity::get() (value in parentheses is
926
  * the default for the bp_activity_get()).
927
  * - 'per_page' (false)
928
  *
929
- * @since BuddyPress (1.2)
 
930
  *
931
  * @see BP_Activity_Activity::get() For more information on accepted arguments
932
  * and the format of the returned value.
933
- * @uses wp_parse_args()
934
- * @uses wp_cache_get()
935
- * @uses wp_cache_set()
936
- * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
937
- * @uses apply_filters_ref_array() To call the 'bp_activity_get' hook.
938
  *
939
- * @param array $args See BP_Activity_Activity::get() for description.
940
  * @return array $activity See BP_Activity_Activity::get() for description.
941
  */
942
  function bp_activity_get( $args = '' ) {
943
- $defaults = array(
944
- 'max' => false, // Maximum number of results to return
945
- 'page' => 1, // page 1 without a per_page will result in no pagination.
 
 
946
  'per_page' => false, // results per page
947
  'sort' => 'DESC', // sort ASC or DESC
948
- 'display_comments' => false, // false for no comments. 'stream' for within stream display, 'threaded' for below each activity item
949
 
950
  'search_terms' => false, // Pass search terms as a string
951
  'meta_query' => false, // Filter by activity meta. See WP_Meta_Query for format
 
 
952
  'show_hidden' => false, // Show activity items that are hidden site-wide?
953
- 'exclude' => false, // Comma-separated list of activity IDs to exclude
954
- 'in' => false, // Comma-separated list or array of activity IDs to which you want to limit the query
 
955
  'spam' => 'ham_only', // 'ham_only' (default), 'spam_only' or 'all'.
956
  'update_meta_cache' => true,
 
 
957
 
958
  /**
959
  * Pass filters as an array -- all filter items can be multiple values comma separated:
960
  * array(
961
- * 'user_id' => false, // user_id to filter on
962
- * 'object' => false, // object to filter on e.g. groups, profile, status, friends
963
- * 'action' => false, // action to filter on e.g. activity_update, profile_updated
964
- * 'primary_id' => false, // object ID to filter on e.g. a group_id or forum_id or blog_id etc.
965
- * 'secondary_id' => false, // secondary object ID to filter on e.g. a post_id
966
  * );
967
  */
968
  'filter' => array()
969
- );
970
- $r = wp_parse_args( $args, $defaults );
971
- extract( $r, EXTR_SKIP );
972
-
973
- // Attempt to return a cached copy of the first page of sitewide activity.
974
- if ( 1 == (int) $page && empty( $max ) && empty( $search_terms ) && empty( $meta_query ) && empty( $filter ) && empty( $exclude ) && empty( $in ) && 'DESC' == $sort && empty( $exclude ) && 'ham_only' == $spam ) {
975
- if ( !$activity = wp_cache_get( 'bp_activity_sitewide_front', 'bp' ) ) {
976
- $args = array(
977
- 'page' => $page,
978
- 'per_page' => $per_page,
979
- 'max' => $max,
980
- 'sort' => $sort,
981
- 'search_terms' => $search_terms,
982
- 'meta_query' => $meta_query,
983
- 'filter' => $filter,
984
- 'display_comments' => $display_comments,
985
- 'show_hidden' => $show_hidden,
986
- 'spam' => $spam,
987
- 'update_meta_cache' => $update_meta_cache,
988
- );
989
- $activity = BP_Activity_Activity::get( $args );
990
- wp_cache_set( 'bp_activity_sitewide_front', $activity, 'bp' );
991
- }
992
-
993
- } else {
994
- $args = array(
995
- 'page' => $page,
996
- 'per_page' => $per_page,
997
- 'max' => $max,
998
- 'sort' => $sort,
999
- 'search_terms' => $search_terms,
1000
- 'meta_query' => $meta_query,
1001
- 'filter' => $filter,
1002
- 'display_comments' => $display_comments,
1003
- 'show_hidden' => $show_hidden,
1004
- 'exclude' => $exclude,
1005
- 'in' => $in,
1006
- 'spam' => $spam
1007
- );
1008
- $activity = BP_Activity_Activity::get( $args );
1009
- }
1010
 
 
 
 
 
 
 
 
 
1011
  return apply_filters_ref_array( 'bp_activity_get', array( &$activity, &$r ) );
1012
  }
1013
 
1014
  /**
1015
  * Fetch specific activity items.
1016
  *
1017
- * @since BuddyPress (1.2)
1018
  *
1019
- * @see BP_Activity_Activity::get() For more information on accepted arguments
1020
- * @uses wp_parse_args()
1021
- * @uses apply_filters() To call the 'bp_activity_get_specific' hook
1022
- * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
1023
  *
1024
- * @param array $args {
1025
  * All arguments and defaults are shared with BP_Activity_Activity::get(),
1026
  * except for the following:
1027
  * @type string|int|array Single activity ID, comma-separated list of IDs,
1028
- * or array of IDs.
1029
  * }
1030
  * @return array $activity See BP_Activity_Activity::get() for description.
1031
  */
1032
  function bp_activity_get_specific( $args = '' ) {
1033
- $defaults = array(
1034
- 'activity_ids' => false, // A single activity_id or array of IDs.
1035
- 'display_comments' => false, // true or false to display threaded comments for these specific activity items
1036
- 'max' => false, // Maximum number of results to return
1037
- 'page' => 1, // page 1 without a per_page will result in no pagination.
1038
- 'per_page' => false, // results per page
1039
- 'show_hidden' => true, // When fetching specific items, show all
1040
- 'sort' => 'DESC', // sort ASC or DESC
1041
- 'spam' => 'ham_only', // Retrieve items marked as spam
 
1042
  'update_meta_cache' => true,
1043
- );
1044
- $r = wp_parse_args( $args, $defaults );
1045
- extract( $r, EXTR_SKIP );
1046
 
1047
  $get_args = array(
1048
- 'page' => $page,
1049
- 'per_page' => $per_page,
1050
- 'max' => $max,
1051
- 'sort' => $sort,
1052
- 'display_comments' => $display_comments,
1053
- 'show_hidden' => $show_hidden,
1054
- 'in' => $activity_ids,
1055
- 'spam' => $spam,
1056
- 'update_meta_cache' => $update_meta_cache,
1057
  );
 
 
 
 
 
 
 
 
 
 
1058
  return apply_filters( 'bp_activity_get_specific', BP_Activity_Activity::get( $get_args ), $args, $get_args );
1059
  }
1060
 
1061
  /**
1062
  * Add an activity item.
1063
  *
1064
- * @since BuddyPress (1.1)
 
1065
  *
1066
- * @uses wp_parse_args()
1067
- * @uses BP_Activity_Activity::save() {@link BP_Activity_Activity}
1068
- * @uses BP_Activity_Activity::rebuild_activity_comment_tree() {@link BP_Activity_Activity}
1069
- * @uses wp_cache_delete()
1070
- * @uses do_action() To call the 'bp_activity_add' hook
1071
- *
1072
- * @param array $args {
1073
  * An array of arguments.
1074
- * @type int|bool $id Pass an activity ID to update an existing item, or
1075
- * false to create a new item. Default: false.
1076
- * @type string $action Optional. The activity action/description, typically
1077
- * something like "Joe posted an update". Values passed to this param
1078
- * will be stored in the database and used as a fallback for when the
1079
- * activity item's format_callback cannot be found (eg, when the
1080
- * component is disabled). As long as you have registered a
1081
- * format_callback for your $type, it is unnecessary to include this
1082
- * argument - BP will generate it automatically.
1083
- * See {@link bp_activity_set_action()}.
1084
- * @type string $content Optional. The content of the activity item.
1085
- * @type string $component The unique name of the component associated with
1086
- * the activity item - 'groups', 'profile', etc.
1087
- * @type string $type The specific activity type, used for directory
1088
- * filtering. 'new_blog_post', 'activity_update', etc.
1089
- * @type string $primary_link Optional. The URL for this item, as used in
1090
- * RSS feeds. Defaults to the URL for this activity item's permalink page.
1091
- * @type int|bool $user_id Optional. The ID of the user associated with the
1092
- * activity item. May be set to false or 0 if the item is not related
1093
- * to any user. Default: the ID of the currently logged-in user.
1094
- * @type int $item_id Optional. The ID of the associated item.
1095
- * @type int $secondary_item_id Optional. The ID of a secondary associated
1096
- * item.
1097
- * @type string $date_recorded Optional. The GMT time, in Y-m-d h:i:s format,
1098
- * when the item was recorded. Defaults to the current time.
1099
- * @type bool $hide_sitewide Should the item be hidden on sitewide streams?
1100
- * Default: false.
1101
- * @type bool $is_spam Should the item be marked as spam? Default: false.
 
1102
  * }
1103
  * @return int|bool The ID of the activity on success. False on error.
1104
  */
1105
  function bp_activity_add( $args = '' ) {
1106
 
1107
- $defaults = array(
1108
- 'id' => false, // Pass an existing activity ID to update an existing entry.
1109
-
1110
- 'action' => '', // The activity action - e.g. "Jon Doe posted an update"
1111
- 'content' => '', // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1112
 
1113
- 'component' => false, // The name/ID of the component e.g. groups, profile, mycomponent
1114
- 'type' => false, // The activity type e.g. activity_update, profile_updated
1115
- 'primary_link' => '', // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink)
1116
 
1117
- 'user_id' => bp_loggedin_user_id(), // Optional: The user to record the activity for, can be false if this activity is not for a user.
1118
- 'item_id' => false, // Optional: The ID of the specific item being recorded, e.g. a blog_id
1119
- 'secondary_item_id' => false, // Optional: A second ID used to further filter e.g. a comment_id
1120
- 'recorded_time' => bp_core_current_time(), // The GMT time that this activity was recorded
1121
- 'hide_sitewide' => false, // Should this be hidden on the sitewide activity stream?
1122
- 'is_spam' => false, // Is this activity item to be marked as spam?
1123
- );
1124
- $params = wp_parse_args( $args, $defaults );
1125
- extract( $params, EXTR_SKIP );
1126
-
1127
- // Make sure we are backwards compatible
1128
- if ( empty( $component ) && !empty( $component_name ) )
1129
- $component = $component_name;
1130
-
1131
- if ( empty( $type ) && !empty( $component_action ) )
1132
- $type = $component_action;
1133
-
1134
- // Setup activity to be added
1135
- $activity = new BP_Activity_Activity( $id );
1136
- $activity->user_id = $user_id;
1137
- $activity->component = $component;
1138
- $activity->type = $type;
1139
- $activity->content = $content;
1140
- $activity->primary_link = $primary_link;
1141
- $activity->item_id = $item_id;
1142
- $activity->secondary_item_id = $secondary_item_id;
1143
- $activity->date_recorded = $recorded_time;
1144
- $activity->hide_sitewide = $hide_sitewide;
1145
- $activity->is_spam = $is_spam;
1146
- $activity->action = ! empty( $action ) ? $action : bp_activity_generate_action_string( $activity );
1147
-
1148
- if ( !$activity->save() )
1149
  return false;
 
 
 
 
 
 
1150
 
1151
- // If this is an activity comment, rebuild the tree
1152
- if ( 'activity_comment' == $activity->type )
1153
  BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id );
 
1154
 
1155
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1156
- do_action( 'bp_activity_add', $params );
 
 
 
 
 
 
 
 
1157
 
1158
  return $activity->id;
1159
  }
@@ -1161,136 +1867,740 @@ function bp_activity_add( $args = '' ) {
1161
  /**
1162
  * Post an activity update.
1163
  *
1164
- * @since BuddyPress (1.2)
1165
- *
1166
- * @global object $bp BuddyPress global settings.
1167
- * @uses wp_parse_args()
1168
- * @uses bp_is_user_inactive()
1169
- * @uses bp_core_get_userlink()
1170
- * @uses bp_activity_add()
1171
- * @uses apply_filters() To call the 'bp_activity_new_update_action' hook.
1172
- * @uses apply_filters() To call the 'bp_activity_new_update_content' hook.
1173
- * @uses apply_filters() To call the 'bp_activity_new_update_primary_link' hook.
1174
- * @uses bp_update_user_meta()
1175
- * @uses wp_filter_kses()
1176
- * @uses do_action() To call the 'bp_activity_posted_update' hook.
1177
- *
1178
- * @param array $args {
1179
- * @type string $content The content of the activity update.
1180
- * @type int $user_id Optional. Defaults to the logged-in user.
1181
  * }
1182
- * @return int $activity_id The activity id
 
1183
  */
1184
  function bp_activity_post_update( $args = '' ) {
1185
- global $bp;
1186
 
1187
- $defaults = array(
1188
- 'content' => false,
1189
- 'user_id' => bp_loggedin_user_id()
1190
- );
1191
- $r = wp_parse_args( $args, $defaults );
1192
- extract( $r, EXTR_SKIP );
1193
 
1194
- if ( empty( $content ) || !strlen( trim( $content ) ) )
1195
  return false;
 
1196
 
1197
- if ( bp_is_user_inactive( $user_id ) )
1198
  return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1199
 
1200
- // Record this on the user's profile
1201
- $from_user_link = bp_core_get_userlink( $user_id );
1202
- $activity_content = $content;
1203
- $primary_link = bp_core_get_userlink( $user_id, false, true );
 
 
 
 
1204
 
1205
- // Now write the values
1206
  $activity_id = bp_activity_add( array(
1207
- 'user_id' => $user_id,
1208
- 'content' => apply_filters( 'bp_activity_new_update_content', $activity_content ),
1209
- 'primary_link' => apply_filters( 'bp_activity_new_update_primary_link', $primary_link ),
1210
- 'component' => $bp->activity->id,
1211
  'type' => 'activity_update',
 
1212
  ) );
1213
 
1214
- $activity_content = apply_filters( 'bp_activity_latest_update_content', $content, $activity_content );
 
 
 
 
 
 
 
 
 
 
 
 
 
1215
 
1216
  // Add this update to the "latest update" usermeta so it can be fetched anywhere.
1217
- bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array( 'id' => $activity_id, 'content' => $activity_content ) );
 
 
 
1218
 
1219
- do_action( 'bp_activity_posted_update', $content, $user_id, $activity_id );
 
 
 
 
 
 
 
 
 
1220
 
1221
  return $activity_id;
1222
  }
1223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1224
  /**
1225
  * Add an activity comment.
1226
  *
1227
- * @since BuddyPress (1.2)
1228
- *
1229
- * @global object $bp BuddyPress global settings.
1230
- * @uses wp_parse_args()
1231
- * @uses bp_activity_add()
1232
- * @uses apply_filters() To call the 'bp_activity_comment_action' hook.
1233
- * @uses apply_filters() To call the 'bp_activity_comment_content' hook.
1234
- * @uses bp_activity_new_comment_notification()
1235
- * @uses wp_cache_delete()
1236
- * @uses do_action() To call the 'bp_activity_comment_posted' hook.
1237
- *
1238
- * @param array $args {
1239
- * @type int $id Optional. Pass an ID to update an existing comment.
1240
- * @type string $content The content of the comment.
1241
- * @type int $user_id Optional. The ID of the user making the comment.
1242
- * Defaults to the ID of the logged-in user.
1243
- * @type int $activity_id The ID of the "root" activity item, ie the oldest
1244
- * ancestor of the comment.
1245
- * @type int $parent_id Optional. The ID of the parent activity item, ie the
1246
- * item to which the comment is an immediate reply. If
1247
- * not provided, this value defaults to the $activity_id.
1248
  * }
1249
  * @return int|bool The ID of the comment on success, otherwise false.
1250
  */
1251
  function bp_activity_new_comment( $args = '' ) {
 
1252
 
1253
- $params = wp_parse_args( $args, array(
1254
- 'id' => false,
1255
- 'content' => false,
1256
- 'user_id' => bp_loggedin_user_id(),
1257
- 'activity_id' => false, // ID of the root activity item
1258
- 'parent_id' => false // ID of a parent comment (optional)
 
 
 
1259
  ) );
1260
 
1261
- extract( $params, EXTR_SKIP );
 
 
 
 
 
1262
 
1263
- // Bail if missing necessary data
1264
- if ( empty( $content ) || empty( $user_id ) || empty( $activity_id ) ) {
1265
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
1266
  }
1267
 
1268
- // Maybe set current activity ID as the parent
1269
- if ( empty( $parent_id ) ) {
1270
- $parent_id = $activity_id;
1271
  }
1272
 
1273
- // Check to see if the parent activity is hidden, and if so, hide this comment publically.
 
 
1274
  $activity = new BP_Activity_Activity( $activity_id );
1275
- $is_hidden = ( (int) $activity->hide_sitewide ) ? 1 : 0;
1276
 
1277
- // Insert the activity comment
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1278
  $comment_id = bp_activity_add( array(
1279
- 'id' => $id,
1280
- 'content' => apply_filters( 'bp_activity_comment_content', $content ),
1281
  'component' => buddypress()->activity->id,
1282
  'type' => 'activity_comment',
1283
- 'user_id' => $user_id,
 
1284
  'item_id' => $activity_id,
1285
- 'secondary_item_id' => $parent_id,
1286
- 'hide_sitewide' => $is_hidden
 
1287
  ) );
1288
 
1289
- // Comment caches are stored only with the top-level item
 
 
 
 
 
1290
  wp_cache_delete( $activity_id, 'bp_activity_comments' );
1291
 
1292
- // Walk the tree to clear caches for all parent items
1293
- $clear_id = $parent_id;
1294
  while ( $clear_id != $activity_id ) {
1295
  $clear_object = new BP_Activity_Activity( $clear_id );
1296
  wp_cache_delete( $clear_id, 'bp_activity' );
@@ -1298,7 +2608,43 @@ function bp_activity_new_comment( $args = '' ) {
1298
  }
1299
  wp_cache_delete( $activity_id, 'bp_activity' );
1300
 
1301
- do_action( 'bp_activity_comment_posted', $comment_id, $params, $activity );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1302
 
1303
  return $comment_id;
1304
  }
@@ -1306,18 +2652,16 @@ function bp_activity_new_comment( $args = '' ) {
1306
  /**
1307
  * Fetch the activity_id for an existing activity entry in the DB.
1308
  *
1309
- * @since BuddyPress (1.2)
1310
  *
1311
  * @see BP_Activity_Activity::get() For more information on accepted arguments.
1312
- * @uses wp_parse_args()
1313
- * @uses apply_filters() To call the 'bp_activity_get_activity_id' hook.
1314
- * @uses BP_Activity_Activity::save() {@link BP_Activity_Activity}
1315
  *
1316
- * @param array $args See BP_Activity_Activity::get() for description.
1317
  * @return int $activity_id The ID of the activity item found.
1318
  */
1319
  function bp_activity_get_activity_id( $args = '' ) {
1320
- $defaults = array(
 
1321
  'user_id' => false,
1322
  'component' => false,
1323
  'type' => false,
@@ -1326,12 +2670,28 @@ function bp_activity_get_activity_id( $args = '' ) {
1326
  'action' => false,
1327
  'content' => false,
1328
  'date_recorded' => false,
1329
- );
1330
-
1331
- $r = wp_parse_args( $args, $defaults );
1332
- extract( $r, EXTR_SKIP );
1333
 
1334
- return apply_filters( 'bp_activity_get_activity_id', BP_Activity_Activity::get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1335
  }
1336
 
1337
  /**
@@ -1347,29 +2707,21 @@ function bp_activity_get_activity_id( $args = '' ) {
1347
  *
1348
  * If you are deleting an activity comment please use bp_activity_delete_comment();
1349
  *
1350
- * @since BuddyPress (1.0)
1351
  *
1352
  * @see BP_Activity_Activity::get() For more information on accepted arguments.
1353
- * @uses wp_parse_args()
1354
- * @uses bp_activity_adjust_mention_count()
1355
- * @uses BP_Activity_Activity::delete() {@link BP_Activity_Activity}
1356
- * @uses do_action() To call the 'bp_before_activity_delete' hook.
1357
- * @uses bp_get_user_meta()
1358
- * @uses bp_delete_user_meta()
1359
- * @uses do_action() To call the 'bp_activity_delete' hook.
1360
- * @uses do_action() To call the 'bp_activity_deleted_activities' hook.
1361
- * @uses wp_cache_delete()
1362
- *
1363
- * @param array $args To delete specific activity items, use
1364
- * $args = array( 'id' => $ids );
1365
- * Otherwise, to use filters for item deletion, the argument format is
1366
- * the same as BP_Activity_Activity::get(). See that method for a description.
1367
  * @return bool True on success, false on failure.
1368
  */
1369
  function bp_activity_delete( $args = '' ) {
1370
 
1371
- // Pass one or more the of following variables to delete by those variables
1372
- $defaults = array(
1373
  'id' => false,
1374
  'action' => false,
1375
  'content' => false,
@@ -1381,23 +2733,29 @@ function bp_activity_delete( $args = '' ) {
1381
  'secondary_item_id' => false,
1382
  'date_recorded' => false,
1383
  'hide_sitewide' => false
1384
- );
1385
-
1386
- $args = wp_parse_args( $args, $defaults );
1387
 
 
 
 
 
 
 
 
1388
  do_action( 'bp_before_activity_delete', $args );
1389
 
1390
- // Adjust the new mention count of any mentioned member
1391
  bp_activity_adjust_mention_count( $args['id'], 'delete' );
1392
 
1393
- if ( !$activity_ids_deleted = BP_Activity_Activity::delete( $args ) )
 
1394
  return false;
 
1395
 
1396
- // Check if the user's latest update has been deleted
1397
- if ( empty( $args['user_id'] ) )
1398
- $user_id = bp_loggedin_user_id();
1399
- else
1400
- $user_id = $args['user_id'];
1401
 
1402
  $latest_update = bp_get_user_meta( $user_id, 'bp_latest_update', true );
1403
  if ( !empty( $latest_update ) ) {
@@ -1406,7 +2764,22 @@ function bp_activity_delete( $args = '' ) {
1406
  }
1407
  }
1408
 
 
 
 
 
 
 
 
1409
  do_action( 'bp_activity_delete', $args );
 
 
 
 
 
 
 
 
1410
  do_action( 'bp_activity_deleted_activities', $activity_ids_deleted );
1411
 
1412
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
@@ -1419,40 +2792,34 @@ function bp_activity_delete( $args = '' ) {
1419
  *
1420
  * You should use bp_activity_delete() instead.
1421
  *
1422
- * @since BuddyPress (1.1)
1423
- * @deprecated BuddyPress (1.2)
1424
- *
1425
- * @uses wp_parse_args()
1426
- * @uses bp_activity_delete()
1427
  *
1428
- * @param array $args See BP_Activity_Activity::get for a description
1429
- * of accepted arguments.
1430
  *
 
 
1431
  * @return bool True on success, false on failure.
1432
  */
1433
  function bp_activity_delete_by_item_id( $args = '' ) {
1434
 
1435
- $defaults = array(
1436
  'item_id' => false,
1437
  'component' => false,
1438
  'type' => false,
1439
  'user_id' => false,
1440
  'secondary_item_id' => false
1441
- );
1442
- $r = wp_parse_args( $args, $defaults );
1443
- extract( $r, EXTR_SKIP );
1444
 
1445
- return bp_activity_delete( array( 'item_id' => $item_id, 'component' => $component, 'type' => $type, 'user_id' => $user_id, 'secondary_item_id' => $secondary_item_id ) );
1446
  }
1447
 
1448
  /**
1449
  * Delete an activity item by activity id.
1450
  *
1451
- * @since BuddyPress (1.1)
1452
  *
1453
- * @uses bp_activity_delete()
1454
  *
1455
- * @param int ID of the activity item to be deleted.
1456
  * @return bool True on success, false on failure.
1457
  */
1458
  function bp_activity_delete_by_activity_id( $activity_id ) {
@@ -1464,19 +2831,23 @@ function bp_activity_delete( $args = '' ) {
1464
  *
1465
  * You should use bp_activity_delete() instead.
1466
  *
1467
- * @since BuddyPress (1.1)
1468
- * @deprecated BuddyPress (1.2)
1469
  *
1470
- * @uses bp_activity_delete()
1471
  *
1472
- * @param int $user_id The user id.
1473
- * @param string $content The activity id.
1474
  * @param string $component The activity component.
1475
- * @param string $type The activity type.
1476
  * @return bool True on success, false on failure.
1477
  */
1478
  function bp_activity_delete_by_content( $user_id, $content, $component, $type ) {
1479
- return bp_activity_delete( array( 'user_id' => $user_id, 'content' => $content, 'component' => $component, 'type' => $type ) );
 
 
 
 
 
1480
  }
1481
 
1482
  /**
@@ -1484,29 +2855,26 @@ function bp_activity_delete( $args = '' ) {
1484
  *
1485
  * You should use bp_activity_delete() instead.
1486
  *
1487
- * @since BuddyPress (1.1)
1488
- * @deprecated BuddyPress (1.2)
1489
  *
1490
- * @uses bp_activity_delete()
1491
  *
1492
- * @param int $user_id The user id.
1493
  * @param string $component The activity component.
1494
  * @return bool True on success, false on failure.
1495
  */
1496
  function bp_activity_delete_for_user_by_component( $user_id, $component ) {
1497
- return bp_activity_delete( array( 'user_id' => $user_id, 'component' => $component ) );
 
 
 
1498
  }
1499
 
1500
  /**
1501
  * Delete an activity comment.
1502
  *
1503
- * @since BuddyPress (1.2)
1504
  *
1505
- * @uses apply_filters() To call the 'bp_activity_delete_comment_pre' hook.
1506
- * @uses bp_activity_delete_children()
1507
- * @uses bp_activity_delete()
1508
- * @uses BP_Activity_Activity::rebuild_activity_comment_tree() {@link BP_Activity_Activity}
1509
- * @uses do_action() To call the 'bp_activity_delete_comment' hook.
1510
  * @todo Why is an activity id required? We could look this up.
1511
  * @todo Why do we encourage users to call this function directly? We could just
1512
  * as easily examine the activity type in bp_activity_delete() and then
@@ -1514,53 +2882,87 @@ function bp_activity_delete( $args = '' ) {
1514
  *
1515
  * @param int $activity_id The ID of the "root" activity, ie the comment's
1516
  * oldest ancestor.
1517
- * @param int $comment_id The ID of the comment to be deleted.
1518
- * @return bool True on success, false on failure
1519
  */
1520
  function bp_activity_delete_comment( $activity_id, $comment_id ) {
1521
- /***
 
 
 
 
1522
  * You may want to hook into this filter if you want to override this function and
1523
  * handle the deletion of child comments differently. Make sure you return false.
 
 
 
 
 
 
 
 
1524
  */
1525
- if ( !apply_filters( 'bp_activity_delete_comment_pre', true, $activity_id, $comment_id ) )
1526
- return false;
 
1527
 
1528
  // Delete any children of this comment.
1529
  bp_activity_delete_children( $activity_id, $comment_id );
1530
 
1531
- // Delete the actual comment
1532
- if ( !bp_activity_delete( array( 'id' => $comment_id, 'type' => 'activity_comment' ) ) )
1533
  return false;
 
 
 
 
 
 
1534
 
1535
- // Recalculate the comment tree
1536
  BP_Activity_Activity::rebuild_activity_comment_tree( $activity_id );
1537
 
 
 
 
 
 
 
 
 
1538
  do_action( 'bp_activity_delete_comment', $activity_id, $comment_id );
1539
 
1540
- return true;
1541
  }
1542
 
1543
  /**
1544
  * Delete an activity comment's children.
1545
  *
1546
- * @since BuddyPress (1.2)
1547
  *
1548
- * @uses BP_Activity_Activity::get_child_comments() {@link BP_Activity_Activity}
1549
- * @uses bp_activity_delete_children()
1550
- * @uses bp_activity_delete()
1551
  *
1552
  * @param int $activity_id The ID of the "root" activity, ie the
1553
  * comment's oldest ancestor.
1554
- * @param int $comment_id The ID of the comment to be deleted.
1555
  */
1556
- function bp_activity_delete_children( $activity_id, $comment_id) {
 
 
 
 
1557
  // Recursively delete all children of this comment.
1558
- if ( $children = BP_Activity_Activity::get_child_comments( $comment_id ) ) {
1559
  foreach( (array) $children as $child ) {
1560
  bp_activity_delete_children( $activity_id, $child->id );
1561
  }
1562
  }
1563
- bp_activity_delete( array( 'secondary_item_id' => $comment_id, 'type' => 'activity_comment', 'item_id' => $activity_id ) );
 
 
 
 
 
 
1564
  }
1565
 
1566
  /**
@@ -1571,44 +2973,58 @@ function bp_activity_delete_comment( $activity_id, $comment_id ) {
1571
  * be sure to pass the full $activity_obj parameter as well, if you already
1572
  * have it available.
1573
  *
1574
- * @since BuddyPress (1.2)
1575
- *
1576
- * @uses bp_get_root_domain()
1577
- * @uses bp_get_activity_root_slug()
1578
- * @uses apply_filters_ref_array() To call the 'bp_activity_get_permalink' hook.
1579
  *
1580
- * @param int $activity_id The unique id of the activity object.
1581
- * @param object $activity_obj Optional. The activity object.
1582
  * @return string $link Permalink for the activity item.
1583
  */
1584
  function bp_activity_get_permalink( $activity_id, $activity_obj = false ) {
 
1585
 
1586
- if ( empty( $activity_obj ) )
1587
  $activity_obj = new BP_Activity_Activity( $activity_id );
 
1588
 
1589
  if ( isset( $activity_obj->current_comment ) ) {
1590
  $activity_obj = $activity_obj->current_comment;
1591
  }
1592
 
1593
- if ( 'new_blog_post' == $activity_obj->type || 'new_blog_comment' == $activity_obj->type || 'new_forum_topic' == $activity_obj->type || 'new_forum_post' == $activity_obj->type ) {
 
 
 
 
 
 
 
 
 
 
 
1594
  $link = $activity_obj->primary_link;
1595
  } else {
1596
  if ( 'activity_comment' == $activity_obj->type ) {
1597
- $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->item_id . '/';
1598
  } else {
1599
  $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->id . '/';
1600
  }
1601
  }
1602
 
 
 
 
 
 
 
 
1603
  return apply_filters_ref_array( 'bp_activity_get_permalink', array( $link, &$activity_obj ) );
1604
  }
1605
 
1606
  /**
1607
  * Hide a user's activity.
1608
  *
1609
- * @since BuddyPress (1.2)
1610
- *
1611
- * @uses BP_Activity_Activity::hide_all_for_user() {@link BP_Activity_Activity}
1612
  *
1613
  * @param int $user_id The ID of the user whose activity is being hidden.
1614
  * @return bool True on success, false on failure.
@@ -1627,15 +3043,14 @@ function bp_activity_hide_user_activity( $user_id ) {
1627
  * through the content, grabs the first image and converts it to a thumbnail,
1628
  * and removes the rest of the images from the string.
1629
  *
1630
- * @since BuddyPress (1.2)
1631
  *
1632
- * @uses esc_attr()
1633
- * @uses apply_filters() To call the 'bp_activity_thumbnail_content_images' hook
1634
  *
1635
- * @param string $content The content of the activity item.
1636
- * @param string $link Optional. The unescaped URL that the image should link
1637
- * to. If absent, the image will not be a link.
1638
- * @param array $activity_args Optional. The args passed to the activity
1639
  * creation function (eg bp_blogs_record_activity()).
1640
  * @return string $content The content with images stripped and replaced with a
1641
  * single thumb.
@@ -1644,21 +3059,28 @@ function bp_activity_thumbnail_content_images( $content, $link = false, $args =
1644
 
1645
  preg_match_all( '/<img[^>]*>/Ui', $content, $matches );
1646
 
1647
- // Remove <img> tags. Also remove caption shortcodes and caption text if present
1648
  $content = preg_replace('|(\[caption(.*?)\])?<img[^>]*>([^\[\[]*\[\/caption\])?|', '', $content );
1649
 
1650
  if ( !empty( $matches ) && !empty( $matches[0] ) ) {
1651
- // Get the SRC value
1652
- preg_match( '/<img.*?(src\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $src );
1653
 
1654
- // Get the width and height
 
 
 
1655
  preg_match( '/<img.*?(height\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $height );
1656
  preg_match( '/<img.*?(width\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $width );
1657
 
1658
- if ( !empty( $src ) ) {
1659
- $src = substr( substr( str_replace( 'src=', '', $src[1] ), 0, -1 ), 1 );
1660
- $height = substr( substr( str_replace( 'height=', '', $height[1] ), 0, -1 ), 1 );
1661
- $width = substr( substr( str_replace( 'width=', '', $width[1] ), 0, -1 ), 1 );
 
 
 
 
 
 
1662
 
1663
  if ( empty( $width ) || empty( $height ) ) {
1664
  $width = 100;
@@ -1678,100 +3100,503 @@ function bp_activity_thumbnail_content_images( $content, $link = false, $args =
1678
  }
1679
  }
1680
 
 
 
 
 
 
 
 
 
 
1681
  return apply_filters( 'bp_activity_thumbnail_content_images', $content, $matches, $args );
1682
  }
1683
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1684
  /**
1685
  * Fetch whether the current user is allowed to mark items as spam.
1686
  *
1687
- * @since BuddyPress (1.6)
1688
  *
1689
  * @return bool True if user is allowed to mark activity items as spam.
1690
  */
1691
  function bp_activity_user_can_mark_spam() {
 
 
 
 
 
 
 
 
1692
  return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) );
1693
  }
1694
 
1695
  /**
1696
  * Mark an activity item as spam.
1697
  *
1698
- * @since BuddyPress (1.6)
1699
  *
1700
- * @global object $bp BuddyPress global settings.
1701
  *
1702
  * @param BP_Activity_Activity $activity The activity item to be spammed.
1703
- * @param string $source Optional. Default is "by_a_person" (ie, a person has
1704
- * manually marked the activity as spam). BP core also
1705
- * accepts 'by_akismet'.
1706
  */
1707
  function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) {
1708
- global $bp;
1709
 
1710
  $activity->is_spam = 1;
1711
 
1712
- // Clear the activity stream first page cache
1713
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1714
 
1715
- // Clear the activity comment cache for this activity item
1716
  wp_cache_delete( $activity->id, 'bp_activity_comments' );
1717
 
1718
- // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity
1719
  if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
1720
  remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
1721
 
1722
- // Build data package for Akismet
1723
  $activity_data = BP_Akismet::build_akismet_data_package( $activity );
1724
 
1725
- // Tell Akismet this is spam
1726
  $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' );
1727
 
1728
- // Update meta
1729
  add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 );
1730
  }
1731
 
 
 
 
 
 
 
 
 
 
1732
  do_action( 'bp_activity_mark_as_spam', $activity, $source );
1733
  }
1734
 
1735
  /**
1736
  * Mark an activity item as ham.
1737
  *
1738
- * @since BuddyPress (1.6)
1739
  *
1740
- * @global object $bp BuddyPress global settings.
1741
- *
1742
- * @param BP_Activity_Activity $activity The activity item to be hammed.
1743
- * @param string $source Optional. Default is "by_a_person" (ie, a person has
1744
- * manually marked the activity as spam). BP core also
1745
- * accepts 'by_akismet'.
1746
  */
1747
  function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
1748
- global $bp;
1749
 
1750
  $activity->is_spam = 0;
1751
 
1752
- // Clear the activity stream first page cache
1753
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1754
 
1755
- // Clear the activity comment cache for this activity item
1756
  wp_cache_delete( $activity->id, 'bp_activity_comments' );
1757
 
1758
- // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity
1759
  if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
1760
  remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
1761
 
1762
- // Build data package for Akismet
1763
  $activity_data = BP_Akismet::build_akismet_data_package( $activity );
1764
 
1765
- // Tell Akismet this is spam
1766
  $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' );
1767
 
1768
- // Update meta
1769
  add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 );
1770
  }
1771
 
 
 
 
 
 
 
 
 
 
1772
  do_action( 'bp_activity_mark_as_ham', $activity, $source );
1773
  }
1774
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1775
 
1776
  /** Embeds *******************************************************************/
1777
 
@@ -1785,22 +3610,37 @@ function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
1785
  * This does not cover recursive activity comments, as they do not use a real loop.
1786
  * For that, see {@link bp_activity_comment_embed()}.
1787
  *
1788
- * @since BuddyPress (1.5)
1789
  *
1790
  * @see BP_Embed
1791
  * @see bp_embed_activity_cache()
1792
  * @see bp_embed_activity_save_cache()
1793
- * @uses add_filter() To attach 'bp_get_activity_id' to 'embed_post_id'.
1794
- * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
1795
- * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
1796
  */
1797
  function bp_activity_embed() {
1798
  add_filter( 'embed_post_id', 'bp_get_activity_id' );
 
1799
  add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
1800
  add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
1801
  }
1802
  add_action( 'activity_loop_start', 'bp_activity_embed' );
1803
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1804
  /**
1805
  * Set up activity oEmbed cache while recursing through activity comments.
1806
  *
@@ -1809,14 +3649,12 @@ add_action( 'activity_loop_start', 'bp_activity_embed' );
1809
  * necessary to grab each comment's embeds from the cache, or put them in
1810
  * the cache if they are not there yet.
1811
  *
1812
- * @since BuddyPress (1.5)
1813
  *
1814
  * @see BP_Embed
1815
  * @see bp_embed_activity_cache()
1816
  * @see bp_embed_activity_save_cache()
1817
- * @uses add_filter() To attach 'bp_get_activity_comment_id' to 'embed_post_id'.
1818
- * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
1819
- * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
1820
  */
1821
  function bp_activity_comment_embed() {
1822
  add_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
@@ -1828,26 +3666,21 @@ add_action( 'bp_before_activity_comment', 'bp_activity_comment_embed' );
1828
  /**
1829
  * When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content.
1830
  *
1831
- * @since BuddyPress (1.5)
1832
  *
1833
  * @see BP_Embed
1834
- * @global object $bp BuddyPress global settings
1835
- * @uses add_filter() To attach create_function() to 'embed_post_id'.
1836
- * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
1837
- * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
1838
  *
1839
  * @param object $activity The activity that is being expanded.
1840
  */
1841
  function bp_dtheme_embed_read_more( $activity ) {
1842
- global $bp;
1843
 
1844
- $bp->activity->read_more_id = $activity->id;
1845
-
1846
- add_filter( 'embed_post_id', create_function( '', 'global $bp; return $bp->activity->read_more_id;' ) );
1847
- add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
1848
- add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
1849
  }
1850
- add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
 
1851
 
1852
  /**
1853
  * Clean up 'embed_post_id' filter after comment recursion.
@@ -1855,10 +3688,9 @@ add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more'
1855
  * This filter must be removed so that the non-comment filters take over again
1856
  * once the comments are done being processed.
1857
  *
1858
- * @since BuddyPress (1.5)
1859
  *
1860
  * @see bp_activity_comment_embed()
1861
- * @uses remove_filter() To remove 'bp_get_activity_comment_id' from 'embed_post_id'.
1862
  */
1863
  function bp_activity_comment_embed_after_recurse() {
1864
  remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
@@ -1870,14 +3702,13 @@ add_action( 'bp_after_activity_comment', 'bp_activity_comment_embed_after_recurs
1870
  *
1871
  * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
1872
  *
1873
- * @since BuddyPress (1.5)
1874
  *
1875
  * @see BP_Embed::parse_oembed()
1876
- * @uses bp_activity_get_meta()
1877
  *
1878
- * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
1879
- * functions like this one to filter.
1880
- * @param int $id The ID of the activity item.
1881
  * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
1882
  * @return mixed The cached embeds for this activity item.
1883
  */
@@ -1890,34 +3721,32 @@ function bp_embed_activity_cache( $cache, $id, $cachekey ) {
1890
  *
1891
  * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
1892
  *
1893
- * @since BuddyPress (1.5)
1894
  *
1895
  * @see BP_Embed::parse_oembed()
1896
- * @uses bp_activity_update_meta()
1897
  *
1898
- * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
1899
- * functions like this one to filter.
1900
- * @param int $id The ID of the activity item.
1901
  * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
1902
- * @return bool True on success, false on failure.
1903
  */
1904
  function bp_embed_activity_save_cache( $cache, $cachekey, $id ) {
1905
  bp_activity_update_meta( $id, $cachekey, $cache );
 
 
 
 
 
 
1906
  }
1907
 
1908
  /**
1909
  * Should we use Heartbeat to refresh activities?
1910
  *
1911
- * @since BuddyPress (2.0.0)
1912
  *
1913
- * @uses bp_is_activity_heartbeat_active() to check if heatbeat setting is on.
1914
- * @uses bp_is_activity_directory() to check if the current page is the activity
1915
  * directory.
1916
- * @uses bp_is_active() to check if the group component is active.
1917
- * @uses bp_is_group_activity() to check if on a single group, the current page
1918
  * is the group activities.
1919
- * @uses bp_is_group_home() to check if the current page is a single group home
1920
- * page.
1921
  *
1922
  * @return bool True if activity heartbeat is enabled, otherwise false.
1923
  */
@@ -1928,18 +3757,9 @@ function bp_activity_do_heartbeat() {
1928
  return $retval;
1929
  }
1930
 
1931
- if ( bp_is_activity_directory() ) {
1932
  $retval = true;
1933
  }
1934
 
1935
- if ( bp_is_active( 'groups') ) {
1936
- // If no custom front, then activities are loaded in group's home
1937
- $has_custom_front = bp_locate_template( array( 'groups/single/front.php' ), false, true );
1938
-
1939
- if ( bp_is_group_activity() || ( ! $has_custom_front && bp_is_group_home() ) ) {
1940
- $retval = true;
1941
- }
1942
- }
1943
-
1944
  return $retval;
1945
  }
1
  <?php
 
2
  /**
3
  * BuddyPress Activity Functions.
4
  *
6
  *
7
  * @package BuddyPress
8
  * @subpackage ActivityFunctions
9
+ * @since 1.5.0
10
  */
11
 
12
+ // Exit if accessed directly.
13
+ defined( 'ABSPATH' ) || exit;
14
 
15
  /**
16
  * Check whether the $bp global lists an activity directory page.
17
  *
18
+ * @since 1.5.0
 
 
19
  *
20
  * @return bool True if activity directory page is found, otherwise false.
21
  */
22
  function bp_activity_has_directory() {
23
+ return (bool) !empty( buddypress()->pages->activity->id );
 
 
24
  }
25
 
26
  /**
28
  *
29
  * The Mentions feature does a number of things, all of which will be turned
30
  * off if you disable mentions:
31
+ * - Detecting and auto-linking @username in all BP/WP content.
32
  * - Sending BP notifications and emails to users when they are mentioned
33
+ * using the @username syntax.
34
+ * - The Public Message button on user profiles.
35
  *
36
  * Mentions are enabled by default. To disable, put the following line in
37
  * bp-custom.php or your theme's functions.php file:
38
  *
39
  * add_filter( 'bp_activity_do_mentions', '__return_false' );
40
  *
41
+ * @since 1.8.0
 
 
42
  *
43
  * @return bool $retval True to enable mentions, false to disable.
44
  */
45
  function bp_activity_do_mentions() {
46
+
47
+ /**
48
+ * Filters whether or not mentions are enabled.
49
+ *
50
+ * @since 1.8.0
51
+ *
52
+ * @param bool $enabled True to enable mentions, false to disable.
53
+ */
54
  return (bool) apply_filters( 'bp_activity_do_mentions', true );
55
  }
56
 
57
+ /**
58
+ * Should BuddyPress load the mentions scripts and related assets, including results to prime the
59
+ * mentions suggestions?
60
+ *
61
+ * @since 2.1.0
62
+ *
63
+ * @return bool True if mentions scripts should be loaded.
64
+ */
65
+ function bp_activity_maybe_load_mentions_scripts() {
66
+ $mentions_enabled = bp_activity_do_mentions() && bp_is_user_active();
67
+ $load_mentions = $mentions_enabled && ( bp_is_activity_component() || is_admin() );
68
+
69
+ /**
70
+ * Filters whether or not BuddyPress should load mentions scripts and assets.
71
+ *
72
+ * @since 2.1.0
73
+ *
74
+ * @param bool $load_mentions True to load mentions assets, false otherwise.
75
+ * @param bool $mentions_enabled True if mentions are enabled.
76
+ */
77
+ return (bool) apply_filters( 'bp_activity_maybe_load_mentions_scripts', $load_mentions, $mentions_enabled );
78
+ }
79
+
80
  /**
81
  * Locate usernames in an activity content string, as designated by an @ sign.
82
  *
83
+ * @since 1.5.0
84
  *
85
+ * @param string $content The content of the activity, usually found in
86
+ * $activity->content.
87
+ * @return array|bool Associative array with user ID as key and username as
88
+ * value. Boolean false if no mentions found.
89
  */
90
  function bp_activity_find_mentions( $content ) {
91
+
92
  $pattern = '/[@]+([A-Za-z0-9-_\.@]+)\b/';
93
  preg_match_all( $pattern, $content, $usernames );
94
 
95
+ // Make sure there's only one instance of each username.
96
+ $usernames = array_unique( $usernames[1] );
97
+
98
+ // Bail if no usernames.
99
+ if ( empty( $usernames ) ) {
100
  return false;
101
+ }
102
 
103
  $mentioned_users = array();
104
 
105
+ // We've found some mentions! Check to see if users exist.
106
+ foreach( (array) array_values( $usernames ) as $username ) {
107
  $user_id = bp_activity_get_userid_from_mentionname( $username );
108
 
109
+ // The user ID exists, so let's add it to our array.
110
  if ( ! empty( $user_id ) ) {
111
+ $mentioned_users[ $user_id ] = $username;
112
  }
113
  }
114
 
115
+ if ( empty( $mentioned_users ) ) {
116
  return false;
117
+ }
118
 
119
+ /**
120
+ * Filters the mentioned users.
121
+ *
122
+ * @since 2.5.0
123
+ *
124
+ * @param array $mentioned_users Associative array with user IDs as keys and usernames as values.
125
+ */
126
+ return apply_filters( 'bp_activity_mentioned_users', $mentioned_users );
127
  }
128
 
129
  /**
130
  * Reset a user's unread mentions list and count.
131
  *
132
+ * @since 1.5.0
 
 
133
  *
134
  * @param int $user_id The id of the user whose unread mentions are being reset.
135
  */
136
  function bp_activity_clear_new_mentions( $user_id ) {
137
  bp_delete_user_meta( $user_id, 'bp_new_mention_count' );
138
+ bp_delete_user_meta( $user_id, 'bp_new_mentions' );
139
+
140
+ /**
141
+ * Fires once mentions has been reset for a given user.
142
+ *
143
+ * @since 2.5.0
144
+ *
145
+ * @param int $user_id The id of the user whose unread mentions are being reset.
146
+ */
147
+ do_action( 'bp_activity_clear_new_mentions', $user_id );
148
  }
149
 
150
  /**
155
  *
156
  * Currently, only used in {@link bp_activity_delete()}.
157
  *
158
+ * @since 1.5.0
159
  *
160
+ * @param int $activity_id The unique id for the activity item.
161
+ * @param string $action Can be 'delete' or 'add'. Defaults to 'add'.
162
+ * @return bool
 
 
163
  */
164
  function bp_activity_adjust_mention_count( $activity_id = 0, $action = 'add' ) {
165
+
166
+ // Bail if no activity ID passed.
167
+ if ( empty( $activity_id ) ) {
168
  return false;
169
+ }
170
 
171
+ // Get activity object.
172
+ $activity = new BP_Activity_Activity( $activity_id );
173
 
174
+ // Try to find mentions.
175
  $usernames = bp_activity_find_mentions( strip_tags( $activity->content ) );
176
 
177
+ // Still empty? Stop now.
178
+ if ( empty( $usernames ) ) {
179
  return false;
180
+ }
181
 
182
+ // Increment mention count foreach mentioned user.
183
+ foreach( (array) array_keys( $usernames ) as $user_id ) {
184
  bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action );
185
  }
186
  }
191
  * This function should be used when you've already parsed your activity item
192
  * for @mentions.
193
  *
194
+ * @since 1.7.0
195
  *
196
+ * @param int $user_id The user ID.
197
+ * @param int $activity_id The unique ID for the activity item.
198
+ * @param string $action 'delete' or 'add'. Default: 'add'.
 
 
 
199
  * @return bool
200
  */
201
  function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action = 'add' ) {
202
+
203
+ if ( empty( $user_id ) || empty( $activity_id ) ) {
204
  return false;
205
+ }
206
 
207
+ // Adjust the mention list and count for the member.
208
  $new_mention_count = (int) bp_get_user_meta( $user_id, 'bp_new_mention_count', true );
209
+ $new_mentions = bp_get_user_meta( $user_id, 'bp_new_mentions', true );
210
+
211
+ // Make sure new mentions is an array.
212
+ if ( empty( $new_mentions ) ) {
213
  $new_mentions = array();
214
+ }
215
 
216
  switch ( $action ) {
217
  case 'delete' :
232
  break;
233
  }
234
 
235
+ // Get an updated mention count.
236
  $new_mention_count = count( $new_mentions );
237
 
238
+ // Resave the user_meta.
239
  bp_update_user_meta( $user_id, 'bp_new_mention_count', $new_mention_count );
240
  bp_update_user_meta( $user_id, 'bp_new_mentions', $new_mentions );
241
 
245
  /**
246
  * Determine a user's "mentionname", the name used for that user in @-mentions.
247
  *
248
+ * @since 1.9.0
249
  *
250
+ * @param int|string $user_id ID of the user to get @-mention name for.
251
+ * @return string $mentionname User name appropriate for @-mentions.
252
  */
253
  function bp_activity_get_user_mentionname( $user_id ) {
254
  $mentionname = '';
269
  /**
270
  * Get a user ID from a "mentionname", the name used for a user in @-mentions.
271
  *
272
+ * @since 1.9.0
273
  *
274
+ * @param string $mentionname Username of user in @-mentions.
275
  * @return int|bool ID of the user, if one is found. Otherwise false.
276
  */
277
  function bp_activity_get_userid_from_mentionname( $mentionname ) {
278
  $user_id = false;
279
 
280
+ /*
281
+ * In username compatibility mode, hyphens are ambiguous between
282
+ * actual hyphens and converted spaces.
283
+ *
284
+ * @todo There is the potential for username clashes between 'foo bar'
285
+ * and 'foo-bar' in compatibility mode. Come up with a system for
286
+ * unique mentionnames.
287
+ */
288
  if ( bp_is_username_compatibility_mode() ) {
289
+ // First, try the raw username.
290
  $userdata = get_user_by( 'login', $mentionname );
291
 
292
  // Doing a direct query to use proper regex. Necessary to
300
  }
301
 
302
  // When username compatibility mode is disabled, the mentionname is
303
+ // the same as the nicename.
304
  } else {
305
  $user_id = bp_core_get_userid_from_nicename( $mentionname );
306
  }
325
  * panel, and dynamic action generation (which is essential for multilingual
326
  * sites, etc) will not work.
327
  *
328
+ * @since 1.1.0
329
  *
330
+ * @param string $component_id The unique string ID of the component.
331
+ * @param string $type The action type.
332
+ * @param string $description The action description.
333
+ * @param callable|bool $format_callback Callback for formatting the action string.
334
+ * @param string|bool $label String to describe this action in the activity stream filter dropdown.
335
+ * @param array $context Optional. Activity stream contexts where the filter should appear.
336
+ * Values: 'activity', 'member', 'member_groups', 'group'.
337
+ * @param int $position Optional. The position of the action when listed in dropdowns.
338
  * @return bool False if any param is empty, otherwise true.
339
  */
340
+ function bp_activity_set_action( $component_id, $type, $description, $format_callback = false, $label = false, $context = array(), $position = 0 ) {
341
  $bp = buddypress();
342
 
343
+ // Return false if any of the above values are not set.
344
  if ( empty( $component_id ) || empty( $type ) || empty( $description ) ) {
345
  return false;
346
  }
347
 
348
+ // Set activity action.
349
  if ( ! isset( $bp->activity->actions ) || ! is_object( $bp->activity->actions ) ) {
350
  $bp->activity->actions = new stdClass;
351
  }
352
 
353
+ // Verify callback.
354
  if ( ! is_callable( $format_callback ) ) {
355
  $format_callback = '';
356
  }
359
  $bp->activity->actions->{$component_id} = new stdClass;
360
  }
361
 
362
+ /**
363
+ * Filters the action type being set for the current activity item.
364
+ *
365
+ * @since 1.1.0
366
+ *
367
+ * @param array $array Array of arguments for action type being set.
368
+ * @param string $component_id ID of the current component being set.
369
+ * @param string $type Action type being set.
370
+ * @param string $description Action description for action being set.
371
+ * @param callable $format_callback Callback for formatting the action string.
372
+ * @param string $label String to describe this action in the activity stream filter dropdown.
373
+ * @param array $context Activity stream contexts where the filter should appear. 'activity', 'member',
374
+ * 'member_groups', 'group'.
375
+ */
376
  $bp->activity->actions->{$component_id}->{$type} = apply_filters( 'bp_activity_set_action', array(
377
  'key' => $type,
378
  'value' => $description,
379
  'format_callback' => $format_callback,
380
+ 'label' => $label,
381
+ 'context' => $context,
382
+ 'position' => $position,
383
+ ), $component_id, $type, $description, $format_callback, $label, $context );
384
+
385
+ // Sort the actions of the affected component.
386
+ $action_array = (array) $bp->activity->actions->{$component_id};
387
+ $action_array = bp_sort_by_key( $action_array, 'position', 'num' );
388
+
389
+ // Restore keys.
390
+ $bp->activity->actions->{$component_id} = new stdClass;
391
+ foreach ( $action_array as $key_ordered ) {
392
+ $bp->activity->actions->{$component_id}->{$key_ordered['key']} = $key_ordered;
393
+ }
394
 
395
  return true;
396
  }
397
 
398
  /**
399
+ * Set tracking arguments for a given post type.
400
+ *
401
+ * @since 2.2.0
402
+ *
403
+ * @global $wp_post_types
404
+ *
405
+ * @param string $post_type The name of the post type, as registered with WordPress. Eg 'post' or 'page'.
406
+ * @param array $args {
407
+ * An associative array of tracking parameters. All items are optional.
408
+ * @type string $bp_activity_admin_filter String to use in the Dashboard > Activity dropdown.
409
+ * @type string $bp_activity_front_filter String to use in frontend dropdown.
410
+ * @type string $bp_activity_new_post String format to use for generating the activity action. Should be a
411
+ * translatable string where %1$s is replaced by a user link and %2$s is
412
+ * the URL of the newly created post.
413
+ * @type string $bp_activity_new_post_ms String format to use for generating the activity action on Multisite.
414
+ * Should be a translatable string where %1$s is replaced by a user link,
415
+ * %2$s is the URL of the newly created post, and %3$s is a link to
416
+ * the site.
417
+ * @type string $component_id ID of the BuddyPress component to associate the activity item.
418
+ * @type string $action_id Value for the 'type' param of the new activity item.
419
+ * @type callable $format_callback Callback for formatting the activity action string.
420
+ * Default: 'bp_activity_format_activity_action_custom_post_type_post'.
421
+ * @type array $contexts The directory contexts in which the filter will show.
422
+ * Default: array( 'activity' ).
423
+ * @type array $position Position of the item in filter dropdowns.
424
+ * @type string $singular Singular, translatable name of the post type item. If no value is
425
+ * provided, it's pulled from the 'singular_name' of the post type.
426
+ * @type bool $activity_comment Whether to allow comments on the activity items. Defaults to true if
427
+ * the post type does not natively support comments, otherwise false.
428
+ * }
429
+ * @return bool
430
+ */
431
+ function bp_activity_set_post_type_tracking_args( $post_type = '', $args = array() ) {
432
+ global $wp_post_types;
433
+
434
+ if ( empty( $wp_post_types[ $post_type ] ) || ! post_type_supports( $post_type, 'buddypress-activity' ) || ! is_array( $args ) ) {
435
+ return false;
436
+ }
437
+
438
+ $activity_labels = array(
439
+ /* Post labels */
440
+ 'bp_activity_admin_filter',
441
+ 'bp_activity_front_filter',
442
+ 'bp_activity_new_post',
443
+ 'bp_activity_new_post_ms',
444
+ /* Comment labels */
445
+ 'bp_activity_comments_admin_filter',
446
+ 'bp_activity_comments_front_filter',
447
+ 'bp_activity_new_comment',
448
+ 'bp_activity_new_comment_ms'
449
+ );
450
+
451
+ // Labels are loaded into the post type object.
452
+ foreach ( $activity_labels as $label_type ) {
453
+ if ( ! empty( $args[ $label_type ] ) ) {
454
+ $wp_post_types[ $post_type ]->labels->{$label_type} = $args[ $label_type ];
455
+ unset( $args[ $label_type ] );
456
+ }
457
+ }
458
+
459
+ // If there are any additional args, put them in the bp_activity attribute of the post type.
460
+ if ( ! empty( $args ) ) {
461
+ $wp_post_types[ $post_type ]->bp_activity = $args;
462
+ }
463
+ }
464
+
465
+ /**
466
+ * Get tracking arguments for a specific post type.
467
+ *
468
+ * @since 2.2.0
469
+ * @since 2.5.0 Add post type comments tracking args
470
+ *
471
+ * @param string $post_type Name of the post type.
472
+ * @return object The tracking arguments of the post type.
473
+ */
474
+ function bp_activity_get_post_type_tracking_args( $post_type ) {
475
+ if ( ! post_type_supports( $post_type, 'buddypress-activity' ) ) {
476
+ return false;
477
+ }
478
+
479
+ $post_type_object = get_post_type_object( $post_type );
480
+ $post_type_support_comments = post_type_supports( $post_type, 'comments' );
481
+
482
+ $post_type_activity = array(
483
+ 'component_id' => buddypress()->activity->id,
484
+ 'action_id' => 'new_' . $post_type,
485
+ 'format_callback' => 'bp_activity_format_activity_action_custom_post_type_post',
486
+ 'front_filter' => $post_type_object->labels->name,
487
+ 'contexts' => array( 'activity' ),
488
+ 'position' => 0,
489
+ 'singular' => strtolower( $post_type_object->labels->singular_name ),
490
+ 'activity_comment' => ! $post_type_support_comments,
491
+ 'comment_action_id' => false,
492
+ 'comment_format_callback' => 'bp_activity_format_activity_action_custom_post_type_comment',
493
+ );
494
+
495
+ if ( ! empty( $post_type_object->bp_activity ) ) {
496
+ $post_type_activity = bp_parse_args( (array) $post_type_object->bp_activity, $post_type_activity, $post_type . '_tracking_args' );
497
+ }
498
+
499
+ $post_type_activity = (object) $post_type_activity;
500
+
501
+ // Try to get the admin filter from the post type labels.
502
+ if ( ! empty( $post_type_object->labels->bp_activity_admin_filter ) ) {
503
+ $post_type_activity->admin_filter = $post_type_object->labels->bp_activity_admin_filter;
504
+
505
+ // Fall back to a generic name.
506
+ } else {
507
+ $post_type_activity->admin_filter = _x( 'New item published', 'Post Type generic activity post admin filter', 'buddypress' );
508
+ }
509
+
510
+ // Check for the front filter in the post type labels.
511
+ if ( ! empty( $post_type_object->labels->bp_activity_front_filter ) ) {
512
+ $post_type_activity->front_filter = $post_type_object->labels->bp_activity_front_filter;
513
+ }
514
+
515
+ // Try to get the action for new post type action on non-multisite installations.
516
+ if ( ! empty( $post_type_object->labels->bp_activity_new_post ) ) {
517
+ $post_type_activity->new_post_type_action = $post_type_object->labels->bp_activity_new_post;
518
+ }
519
+
520
+ // Try to get the action for new post type action on multisite installations.
521
+ if ( ! empty( $post_type_object->labels->bp_activity_new_post_ms ) ) {
522
+ $post_type_activity->new_post_type_action_ms = $post_type_object->labels->bp_activity_new_post_ms;
523
+ }
524
+
525
+ // If the post type supports comments and has a comment action id, build the comments tracking args
526
+ if ( $post_type_support_comments && ! empty( $post_type_activity->comment_action_id ) ) {
527
+ // Init a new container for the activity type for comments
528
+ $post_type_activity->comments_tracking = new stdClass();
529
+
530
+ // Build the activity type for comments
531
+ $post_type_activity->comments_tracking->component_id = $post_type_activity->component_id;
532
+ $post_type_activity->comments_tracking->action_id = $post_type_activity->comment_action_id;
533
+
534
+ // Try to get the comments admin filter from the post type labels.
535
+ if ( ! empty( $post_type_object->labels->bp_activity_comments_admin_filter ) ) {
536
+ $post_type_activity->comments_tracking->admin_filter = $post_type_object->labels->bp_activity_comments_admin_filter;
537
+
538
+ // Fall back to a generic name.
539
+ } else {
540
+ $post_type_activity->comments_tracking->admin_filter = _x( 'New item comment posted', 'Post Type generic comments activity admin filter', 'buddypress' );
541
+ }
542
+
543
+ $post_type_activity->comments_tracking->format_callback = $post_type_activity->comment_format_callback;
544
+
545
+ // Check for the comments front filter in the post type labels.
546
+ if ( ! empty( $post_type_object->labels->bp_activity_comments_front_filter ) ) {
547
+ $post_type_activity->comments_tracking->front_filter = $post_type_object->labels->bp_activity_comments_front_filter;
548
+
549
+ // Fall back to a generic name.
550
+ } else {
551
+ $post_type_activity->comments_tracking->front_filter = _x( 'Item comments', 'Post Type generic comments activity front filter', 'buddypress' );
552
+ }
553
+
554
+ $post_type_activity->comments_tracking->contexts = $post_type_activity->contexts;
555
+ $post_type_activity->comments_tracking->position = (int) $post_type_activity->position + 1;
556
+
557
+ // Try to get the action for new post type comment action on non-multisite installations.
558
+ if ( ! empty( $post_type_object->labels->bp_activity_new_comment ) ) {
559
+ $post_type_activity->comments_tracking->new_post_type_comment_action = $post_type_object->labels->bp_activity_new_comment;
560
+ }
561
+
562
+ // Try to get the action for new post type comment action on multisite installations.
563
+ if ( ! empty( $post_type_object->labels->bp_activity_new_comment_ms ) ) {
564
+ $post_type_activity->comments_tracking->new_post_type_comment_action_ms = $post_type_object->labels->bp_activity_new_comment_ms;
565
+ }
566
+ }
567
+
568
+ // Finally make sure we'll be able to find the post type this activity type is associated to.
569
+ $post_type_activity->post_type = $post_type;
570
+
571
+ /**
572
+ * Filters tracking arguments for a specific post type.
573
+ *
574
+ * @since 2.2.0
575
+ *
576
+ * @param object $post_type_activity The tracking arguments of the post type.
577
+ * @param string $post_type Name of the post type.
578
+ */
579
+ return apply_filters( 'bp_activity_get_post_type_tracking_args', $post_type_activity, $post_type );
580
+ }
581
+
582
+ /**
583
+ * Get tracking arguments for all post types.
584
+ *
585
+ * @since 2.2.0
586
+ * @since 2.5.0 Include post type comments tracking args if needed
587
+ *
588
+ * @return array List of post types with their tracking arguments.
589
+ */
590
+ function bp_activity_get_post_types_tracking_args() {
591
+ // Fetch all public post types.
592
+ $post_types = get_post_types( array( 'public' => true ), 'names' );
593
+
594
+ $post_types_tracking_args = array();
595
+
596
+ foreach ( $post_types as $post_type ) {
597
+ $track_post_type = bp_activity_get_post_type_tracking_args( $post_type );
598
+
599
+ if ( ! empty( $track_post_type ) ) {
600
+ // Set the post type comments tracking args
601
+ if ( ! empty( $track_post_type->comments_tracking->action_id ) ) {
602
+ // Used to check support for comment tracking by activity type (new_post_type_comment)
603
+ $track_post_type->comments_tracking->comments_tracking = true;
604
+
605
+ // Used to be able to find the post type this activity type is associated to.
606
+ $track_post_type->comments_tracking->post_type = $post_type;
607
+
608
+ $post_types_tracking_args[ $track_post_type->comments_tracking->action_id ] = $track_post_type->comments_tracking;
609
+
610
+ // Used to check support for comment tracking by activity type (new_post_type)
611
+ $track_post_type->comments_tracking = true;
612
+ }
613
+
614
+ $post_types_tracking_args[ $track_post_type->action_id ] = $track_post_type;
615
+ }
616
+
617
+ }
618
+
619
+ /**
620
+ * Filters tracking arguments for all post types.
621
+ *
622
+ * @since 2.2.0
623
+ *
624
+ * @param array $post_types_tracking_args Array of post types with
625
+ * their tracking arguments.
626
+ */
627
+ return apply_filters( 'bp_activity_get_post_types_tracking_args', $post_types_tracking_args );
628
+ }
629
+
630
+ /**
631
+ * Check if the *Post Type* activity supports a specific feature.
632
+ *
633
+ * @since 2.5.0
634
+ *
635
+ * @param string $activity_type The activity type to check.
636
+ * @param string $feature The feature to check. Currently supports:
637
+ * 'post-type-comment-tracking', 'post-type-comment-reply' & 'comment-reply'.
638
+ * See inline doc for more info.
639
+ * @return bool
640
+ */
641
+ function bp_activity_type_supports( $activity_type = '', $feature = '' ) {
642
+ $retval = false;
643
+
644
+ $bp = buddypress();
645
+
646
+ switch ( $feature ) {
647
+ /**
648
+ * Does this activity type support comment tracking?
649
+ *
650
+ * eg. 'new_blog_post' and 'new_blog_comment' will both return true.
651
+ */
652
+ case 'post-type-comment-tracking' :
653
+ // Set the activity track global if not set yet
654
+ if ( empty( $bp->activity->track ) ) {
655
+ $bp->activity->track = bp_activity_get_post_types_tracking_args();
656
+ }
657
+
658
+ if ( ! empty( $bp->activity->track[ $activity_type ]->comments_tracking ) ) {
659
+ $retval = true;
660
+ }
661
+ break;
662
+
663
+ /**
664
+ * Is this a parent activity type that support post comments?
665
+ *
666
+ * eg. 'new_blog_post' will return true; 'new_blog_comment' will return false.
667
+ */
668
+ case 'post-type-comment-reply' :
669
+ // Set the activity track global if not set yet.
670
+ if ( empty( $bp->activity->track ) ) {
671
+ $bp->activity->track = bp_activity_get_post_types_tracking_args();
672
+ }
673
+
674
+ if ( ! empty( $bp->activity->track[ $activity_type ]->comments_tracking ) && ! empty( $bp->activity->track[ $activity_type ]->comment_action_id ) ) {
675
+ $retval = true;
676
+ }
677
+ break;
678
+
679
+ /**
680
+ * Does this activity type support comment & reply?
681
+ */
682
+ case 'comment-reply' :
683
+ // Set the activity track global if not set yet.
684
+ if ( empty( $bp->activity->track ) ) {
685
+ $bp->activity->track = bp_activity_get_post_types_tracking_args();
686
+ }
687
+
688
+ // Post Type activities
689
+ if ( ! empty( $bp->activity->track[ $activity_type ] ) ) {
690
+ if ( isset( $bp->activity->track[ $activity_type ]->activity_comment ) ) {
691
+ $retval = $bp->activity->track[ $activity_type ]->activity_comment;
692
+ }
693
+
694
+ // Eventually override with comment synchronization feature.
695
+ if ( isset( $bp->activity->track[ $activity_type ]->comments_tracking ) ) {
696
+ $retval = $bp->activity->track[ $activity_type ]->comments_tracking && ! bp_disable_blogforum_comments();
697
+ }
698
+
699
+ // Retired Forums component
700
+ } elseif ( 'new_forum_topic' === $activity_type || 'new_forum_post' === $activity_type ) {
701
+ $retval = ! bp_disable_blogforum_comments();
702
+
703
+ // By Default, all other activity types are supporting comments.
704
+ } else {
705
+ $retval = true;
706
+ }
707
+ break;
708
+ }
709
+
710
+ return $retval;
711
+ }
712
+
713
+ /**
714
+ * Get a specific tracking argument for a given activity type
715
+ *
716
+ * @since 2.5.0
717
+ *
718
+ * @param string $activity_type the activity type.
719
+ * @param string $arg the key of the tracking argument.
720
+ * @return mixed the value of the tracking arg, false if not found.
721
+ */
722
+ function bp_activity_post_type_get_tracking_arg( $activity_type, $arg = '' ) {
723
+ if ( empty( $activity_type ) || empty( $arg ) ) {
724
+ return false;
725
+ }
726
+
727
+ $bp = buddypress();
728
+
729
+ // Set the activity track global if not set yet
730
+ if ( empty( $bp->activity->track ) ) {
731
+ $bp->activity->track = bp_activity_get_post_types_tracking_args();
732
+ }
733
+
734
+ if ( isset( $bp->activity->track[ $activity_type ]->{$arg} ) ) {
735
+ return $bp->activity->track[ $activity_type ]->{$arg};
736
+ } else {
737
+ return false;
738
+ }
739
+ }
740
+
741
+ /**
742
+ * Get all components' activity actions, sorted by their position attribute.
743
+ *
744
+ * @since 2.2.0
745
  *
746
+ * @return object Actions ordered by their position.
747
+ */
748
+ function bp_activity_get_actions() {
749
+ $bp = buddypress();
750
+
751
+ $post_types = bp_activity_get_post_types_tracking_args();
752
+
753
+ // Create the actions for the post types, if they haven't already been created.
754
+ if ( ! empty( $post_types ) ) {
755
+ foreach ( $post_types as $post_type ) {
756
+ if ( isset( $bp->activity->actions->{$post_type->component_id}->{$post_type->action_id} ) ) {
757
+ continue;
758
+ }
759
+
760
+ bp_activity_set_action(
761
+ $post_type->component_id,
762
+ $post_type->action_id,
763
+ $post_type->admin_filter,
764
+ $post_type->format_callback,
765
+ $post_type->front_filter,
766
+ $post_type->contexts,
767
+ $post_type->position
768
+ );
769
+ }
770
+ }
771
+
772
+ return $bp->activity->actions;
773
+ }
774
+
775
+ /**
776
+ * Retrieve the current action from a component and key.
777
  *
778
+ * @since 1.1.0
 
779
  *
780
  * @param string $component_id The unique string ID of the component.
781
+ * @param string $key The action key.
782
  * @return string|bool Action value if found, otherwise false.
783
  */
784
  function bp_activity_get_action( $component_id, $key ) {
 
785
 
786
+ // Return false if any of the above values are not set.
787
+ if ( empty( $component_id ) || empty( $key ) ) {
788
  return false;
789
+ }
790
 
791
+ $actions = bp_activity_get_actions();
792
+ $retval = false;
793
+
794
+ if ( isset( $actions->{$component_id}->{$key} ) ) {
795
+ $retval = $actions->{$component_id}->{$key};
796
+ }
797
+
798
+ /**
799
+ * Filters the current action by component and key.
800
+ *
801
+ * @since 1.1.0
802
+ *
803
+ * @param string|bool $retval The action key.
804
+ * @param string $component_id The unique string ID of the component.
805
+ * @param string $key The action key.
806
+ */
807
+ return apply_filters( 'bp_activity_get_action', $retval, $component_id, $key );
808
  }
809
 
810
  /**
811
  * Fetch details of all registered activity types.
812
  *
813
+ * @since 1.7.0
814
  *
815
  * @return array array( type => description ), ...
816
  */
818
  $actions = array();
819
 
820
  // Walk through the registered actions, and build an array of actions/values.
821
+ foreach ( bp_activity_get_actions() as $action ) {
822
  $action = array_values( (array) $action );
823
 
824
+ for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
825
  $actions[ $action[$i]['key'] ] = $action[$i]['value'];
826
+ }
827
  }
828
 
829
+ // This was a mis-named activity type from before BP 1.6.
830
  unset( $actions['friends_register_activity_action'] );
831
 
832
+ /**
833
+ * Filters the available activity types.
834
+ *
835
+ * @since 1.7.0
836
+ *
837
+ * @param array $actions Array of registered activity types.
838
+ */
839
  return apply_filters( 'bp_activity_get_types', $actions );
840
  }
841
 
844
  /**
845
  * Get a users favorite activity stream items.
846
  *
847
+ * @since 1.2.0
 
 
 
848
  *
849
  * @param int $user_id ID of the user whose favorites are being queried.
850
  * @return array IDs of the user's favorite activity items.
851
  */
852
  function bp_activity_get_user_favorites( $user_id = 0 ) {
853
 
854
+ // Fallback to logged in user if no user_id is passed.
855
+ if ( empty( $user_id ) ) {
856
  $user_id = bp_displayed_user_id();
857
+ }
858
 
859
+ // Get favorites for user.
860
  $favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
861
 
862
+ /**
863
+ * Filters the favorited activity items for a specified user.
864
+ *
865
+ * @since 1.2.0
866
+ *
867
+ * @param array $favs Array of user's favorited activity items.
868
+ */
869
  return apply_filters( 'bp_activity_get_user_favorites', $favs );
870
  }
871
 
872
  /**
873
  * Add an activity stream item as a favorite for a user.
874
  *
875
+ * @since 1.2.0
 
 
 
 
 
 
 
 
876
  *
877
  * @param int $activity_id ID of the activity item being favorited.
878
+ * @param int $user_id ID of the user favoriting the activity item.
879
  * @return bool True on success, false on failure.
880
  */
881
  function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) {
882
 
883
+ // Favorite activity stream items are for logged in users only.
884
+ if ( ! is_user_logged_in() ) {
885
  return false;
886
+ }
887
 
888
+ // Fallback to logged in user if no user_id is passed.
889
+ if ( empty( $user_id ) ) {
890
  $user_id = bp_loggedin_user_id();
891
+ }
892
 
893
  $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
894
  if ( empty( $my_favs ) || ! is_array( $my_favs ) ) {
895
  $my_favs = array();
896
  }
897
 
898
+ // Bail if the user has already favorited this activity item.
899
  if ( in_array( $activity_id, $my_favs ) ) {
900
  return false;
901
  }
902
 
903
+ // Add to user's favorites.
904
  $my_favs[] = $activity_id;
905
 
906
+ // Update the total number of users who have favorited this activity.
907
  $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' );
908
  $fav_count = !empty( $fav_count ) ? (int) $fav_count + 1 : 1;
909
 
910
+ // Update user meta.
911
  bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs );
912
 
913
+ // Update activity meta counts.
914
  if ( bp_activity_update_meta( $activity_id, 'favorite_count', $fav_count ) ) {
915
 
916
+ /**
917
+ * Fires if bp_activity_update_meta() for favorite_count is successful and before returning a true value for success.
918
+ *
919
+ * @since 1.2.1
920
+ *
921
+ * @param int $activity_id ID of the activity item being favorited.
922
+ * @param int $user_id ID of the user doing the favoriting.
923
+ */
924
  do_action( 'bp_activity_add_user_favorite', $activity_id, $user_id );
925
 
926
+ // Success.
927
  return true;
928
 
929
+ // Saving meta was unsuccessful for an unknown reason.
930
  } else {
931
+
932
+ /**
933
+ * Fires if bp_activity_update_meta() for favorite_count is unsuccessful and before returning a false value for failure.
934
+ *
935
+ * @since 1.5.0
936
+ *
937
+ * @param int $activity_id ID of the activity item being favorited.
938
+ * @param int $user_id ID of the user doing the favoriting.
939
+ */
940
  do_action( 'bp_activity_add_user_favorite_fail', $activity_id, $user_id );
941
 
942
  return false;
946
  /**
947
  * Remove an activity stream item as a favorite for a user.
948
  *
949
+ * @since 1.2.0
 
 
 
 
 
 
 
950
  *
951
  * @param int $activity_id ID of the activity item being unfavorited.
952
+ * @param int $user_id ID of the user unfavoriting the activity item.
953
  * @return bool True on success, false on failure.
954
  */
955
  function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) {
956
 
957
+ // Favorite activity stream items are for logged in users only.
958
+ if ( ! is_user_logged_in() ) {
959
  return false;
960
+ }
961
 
962
+ // Fallback to logged in user if no user_id is passed.
963
+ if ( empty( $user_id ) ) {
964
  $user_id = bp_loggedin_user_id();
965
+ }
966
 
967
  $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
968
  $my_favs = array_flip( (array) $my_favs );
969
 
970
+ // Bail if the user has not previously favorited the item.
971
  if ( ! isset( $my_favs[ $activity_id ] ) ) {
972
  return false;
973
  }
974
 
975
+ // Remove the fav from the user's favs.
976
  unset( $my_favs[$activity_id] );
977
  $my_favs = array_unique( array_flip( $my_favs ) );
978
 
979
+ // Update the total number of users who have favorited this activity.
980
+ $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' );
981
+ if ( ! empty( $fav_count ) ) {
982
 
983
+ // Deduct from total favorites.
984
  if ( bp_activity_update_meta( $activity_id, 'favorite_count', (int) $fav_count - 1 ) ) {
985
 
986
+ // Update users favorites.
987
  if ( bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ) ) {
988
 
989
+ /**
990
+ * Fires if bp_update_user_meta() is successful and before returning a true value for success.
991
+ *
992
+ * @since 1.2.1
993
+ *
994
+ * @param int $activity_id ID of the activity item being unfavorited.
995
+ * @param int $user_id ID of the user doing the unfavoriting.
996
+ */
997
  do_action( 'bp_activity_remove_user_favorite', $activity_id, $user_id );
998
 
999
+ // Success.
1000
  return true;
1001
 
1002
+ // Error updating.
1003
  } else {
1004
  return false;
1005
  }
1006
 
1007
+ // Error updating favorite count.
1008
  } else {
1009
  return false;
1010
  }
1011
 
1012
+ // Error getting favorite count.
1013
  } else {
1014
  return false;
1015
  }
1018
  /**
1019
  * Check whether an activity item exists with a given content string.
1020
  *
1021
+ * @since 1.1.0
 
 
 
1022
  *
1023
  * @param string $content The content to filter by.
1024
  * @return int|null The ID of the located activity item. Null if none is found.
1025
  */
1026
  function bp_activity_check_exists_by_content( $content ) {
1027
+
1028
+ /**
1029
+ * Filters the results of the check for whether an activity item exists by specified content.
1030
+ *
1031
+ * @since 1.1.0
1032
+ *
1033
+ * @param BP_Activity_Activity $value ID of the activity if found, else null.
1034
+ */
1035
  return apply_filters( 'bp_activity_check_exists_by_content', BP_Activity_Activity::check_exists_by_content( $content ) );
1036
  }
1037
 
1038
  /**
1039
  * Retrieve the last time activity was updated.
1040
  *
1041
+ * @since 1.0.0
 
 
 
1042
  *
1043
  * @return string Date last updated.
1044
  */
1045
  function bp_activity_get_last_updated() {
1046
+
1047
+ /**
1048
+ * Filters the value for the last updated time for an activity item.
1049
+ *
1050
+ * @since 1.1.0
1051
+ *
1052
+ * @param BP_Activity_Activity $last_updated Date last updated.
1053
+ */
1054
  return apply_filters( 'bp_activity_get_last_updated', BP_Activity_Activity::get_last_updated() );
1055
  }
1056
 
1057
  /**
1058
  * Retrieve the number of favorite activity stream items a user has.
1059
  *
1060
+ * @since 1.2.0
 
 
1061
  *
1062
  * @param int $user_id ID of the user whose favorite count is being requested.
1063
  * @return int Total favorite count for the user.
1064
  */
1065
  function bp_activity_total_favorites_for_user( $user_id = 0 ) {
1066
 
1067
+ // Fallback on displayed user, and then logged in user.
1068
+ if ( empty( $user_id ) ) {
1069
  $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
1070
+ }
1071
 
1072
  return BP_Activity_Activity::total_favorite_count( $user_id );
1073
  }
1077
  /**
1078
  * Delete a meta entry from the DB for an activity stream item.
1079
  *
1080
+ * @since 1.2.0
1081
  *
1082
  * @global object $wpdb WordPress database access object.
1083
+ *
1084
+ * @param int $activity_id ID of the activity item whose metadata is being deleted.
1085
+ * @param string $meta_key Optional. The key of the metadata being deleted. If
1086
+ * omitted, all metadata associated with the activity
1087
+ * item will be deleted.
1088
+ * @param string $meta_value Optional. If present, the metadata will only be
1089
+ * deleted if the meta_value matches this parameter.
1090
+ * @param bool $delete_all Optional. If true, delete matching metadata entries
1091
+ * for all objects, ignoring the specified object_id. Otherwise,
1092
+ * only delete matching metadata entries for the specified
1093
+ * activity item. Default: false.
 
1094
  * @return bool True on success, false on failure.
1095
  */
1096
  function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = '', $delete_all = false ) {
 
1097
 
1098
+ // Legacy - if no meta_key is passed, delete all for the item.
1099
  if ( empty( $meta_key ) ) {
1100
  $all_meta = bp_activity_get_meta( $activity_id );
1101
  $keys = ! empty( $all_meta ) ? array_keys( $all_meta ) : array();
1102
 
1103
+ // With no meta_key, ignore $delete_all.
1104
  $delete_all = false;
1105
  } else {
1106
  $keys = array( $meta_key );
1120
  /**
1121
  * Get metadata for a given activity item.
1122
  *
1123
+ * @since 1.2.0
 
 
1124
  *
1125
+ * @param int $activity_id ID of the activity item whose metadata is being requested.
1126
+ * @param string $meta_key Optional. If present, only the metadata matching
1127
+ * that meta key will be returned. Otherwise, all metadata for the
1128
+ * activity item will be fetched.
1129
+ * @param bool $single Optional. If true, return only the first value of the
1130
+ * specified meta_key. This parameter has no effect if meta_key is not
1131
+ * specified. Default: true.
1132
  * @return mixed The meta value(s) being requested.
1133
  */
1134
  function bp_activity_get_meta( $activity_id = 0, $meta_key = '', $single = true ) {
1136
  $retval = get_metadata( 'activity', $activity_id, $meta_key, $single );
1137
  remove_filter( 'query', 'bp_filter_metaid_column_name' );
1138
 
1139
+ /**
1140
+ * Filters the metadata for a specified activity item.
1141
+ *
1142
+ * @since 1.5.0
1143
+ *
1144
+ * @param mixed $retval The meta values for the activity item.
1145
+ * @param int $activity_id ID of the activity item.
1146
+ * @param string $meta_key Meta key for the value being requested.
1147
+ * @param bool $single Whether to return one matched meta key row or all.
1148
+ */
1149
  return apply_filters( 'bp_activity_get_meta', $retval, $activity_id, $meta_key, $single );
1150
  }
1151
 
1152
  /**
1153
  * Update a piece of activity meta.
1154
  *
1155
+ * @since 1.2.0
1156
  *
1157
+ * @param int $activity_id ID of the activity item whose metadata is being updated.
1158
+ * @param string $meta_key Key of the metadata being updated.
1159
+ * @param mixed $meta_value Value to be set.
1160
+ * @param mixed $prev_value Optional. If specified, only update existing metadata entries
1161
+ * with the specified value. Otherwise, update all entries.
 
 
1162
  * @return bool|int Returns false on failure. On successful update of existing
1163
+ * metadata, returns true. On successful creation of new metadata,
1164
+ * returns the integer ID of the new metadata row.
1165
  */
1166
  function bp_activity_update_meta( $activity_id, $meta_key, $meta_value, $prev_value = '' ) {
1167
  add_filter( 'query', 'bp_filter_metaid_column_name' );
1174
  /**
1175
  * Add a piece of activity metadata.
1176
  *
1177
+ * @since 2.0.0
1178
  *
1179
+ * @param int $activity_id ID of the activity item.
1180
+ * @param string $meta_key Metadata key.
1181
+ * @param mixed $meta_value Metadata value.
1182
+ * @param bool $unique Optional. Whether to enforce a single metadata value for the
1183
+ * given key. If true, and the object already has a value for
1184
+ * the key, no change will be made. Default: false.
1185
  * @return int|bool The meta ID on successful update, false on failure.
1186
  */
1187
  function bp_activity_add_meta( $activity_id, $meta_key, $meta_value, $unique = false ) {
1197
  /**
1198
  * Completely remove a user's activity data.
1199
  *
1200
+ * @since 1.5.0
 
 
 
 
 
 
1201
  *
1202
  * @param int $user_id ID of the user whose activity is being deleted.
1203
+ * @return bool
1204
  */
1205
  function bp_activity_remove_all_user_data( $user_id = 0 ) {
1206
 
1207
+ // Do not delete user data unless a logged in user says so.
1208
+ if ( empty( $user_id ) || ! is_user_logged_in() ) {
1209
  return false;
1210
+ }
1211
 
1212
+ // Clear the user's activity from the sitewide stream and clear their activity tables.
1213
  bp_activity_delete( array( 'user_id' => $user_id ) );
1214
 
1215
+ // Remove any usermeta.
1216
+ bp_delete_user_meta( $user_id, 'bp_latest_update' );
1217
  bp_delete_user_meta( $user_id, 'bp_favorite_activities' );
1218
 
1219
  // Execute additional code
1220
  do_action( 'bp_activity_remove_data', $user_id ); // Deprecated! Do not use!
1221
 
1222
+ /**
1223
+ * Fires after the removal of all of a user's activity data.
1224
+ *
1225
+ * @since 1.5.0
1226
+ *
1227
+ * @param int $user_id ID of the user being deleted.
1228
+ */
1229
  do_action( 'bp_activity_remove_all_user_data', $user_id );
1230
  }
1231
  add_action( 'wpmu_delete_user', 'bp_activity_remove_all_user_data' );
1234
  /**
1235
  * Mark all of the user's activity as spam.
1236
  *
1237
+ * @since 1.6.0
1238
  *
1239
  * @global object $wpdb WordPress database access object.
 
1240
  *
1241
  * @param int $user_id ID of the user whose activity is being spammed.
1242
+ * @return bool
1243
  */
1244
  function bp_activity_spam_all_user_data( $user_id = 0 ) {
1245
+ global $wpdb;
1246
 
1247
+ // Do not delete user data unless a logged in user says so.
1248
+ if ( empty( $user_id ) || ! is_user_logged_in() ) {
1249
  return false;
1250
+ }
1251
 
1252
  // Get all the user's activities.
1253
+ $activities = bp_activity_get( array(
1254
+ 'display_comments' => 'stream',
1255
+ 'filter' => array( 'user_id' => $user_id ),
1256
+ 'show_hidden' => true
1257
+ ) );
1258
+
1259
+ $bp = buddypress();
1260
 
1261
+ // Mark each as spam.
1262
  foreach ( (array) $activities['activities'] as $activity ) {
1263
 
1264
+ // Create an activity object.
1265
  $activity_obj = new BP_Activity_Activity;
1266
+ foreach ( $activity as $k => $v ) {
1267
  $activity_obj->$k = $v;
1268
+ }
1269
 
1270
+ // Mark as spam.
1271
  bp_activity_mark_as_spam( $activity_obj );
1272
 
1273
  /*
1274
  * If Akismet is present, update the activity history meta.
1275
  *
1276
  * This is usually taken care of when BP_Activity_Activity::save() happens, but
1277
+ * as we're going to be updating all the activity statuses directly, for efficiency,
1278
  * we need to update manually.
1279
  */
1280
+ if ( ! empty( $bp->activity->akismet ) ) {
1281
  $bp->activity->akismet->update_activity_spam_meta( $activity_obj );
1282
+ }
1283
 
1284
+ // Tidy up.
1285
  unset( $activity_obj );
1286
  }
1287
 
1288
+ // Mark all of this user's activities as spam.
1289
  $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id ) );
1290
 
1291
+ /**
1292
+ * Fires after all activity data from a user has been marked as spam.
1293
+ *
1294
+ * @since 1.6.0
1295
+ *
1296
+ * @param int $user_id ID of the user whose activity is being marked as spam.
1297
+ * @param array $activities Array of activity items being marked as spam.
1298
+ */
1299
  do_action( 'bp_activity_spam_all_user_data', $user_id, $activities['activities'] );
1300
  }
1301
  add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' );
1303
  /**
1304
  * Mark all of the user's activity as ham (not spam).
1305
  *
1306
+ * @since 1.6.0
1307
  *
1308
  * @global object $wpdb WordPress database access object.
 
1309
  *
1310
  * @param int $user_id ID of the user whose activity is being hammed.
1311
+ * @return bool
1312
  */
1313
  function bp_activity_ham_all_user_data( $user_id = 0 ) {
1314
+ global $wpdb;
1315
 
1316
+ // Do not delete user data unless a logged in user says so.
1317
+ if ( empty( $user_id ) || ! is_user_logged_in() ) {
1318
  return false;
1319
+ }
1320
 
1321
  // Get all the user's activities.
1322
+ $activities = bp_activity_get( array(
1323
+ 'display_comments' => 'stream',
1324
+ 'filter' => array( 'user_id' => $user_id ),
1325
+ 'show_hidden' => true,
1326
+ 'spam' => 'all'
1327
+ ) );
1328
 
1329
+ $bp = buddypress();
1330
+
1331
+ // Mark each as not spam.
1332
  foreach ( (array) $activities['activities'] as $activity ) {
1333
 
1334
+ // Create an activity object.
1335
  $activity_obj = new BP_Activity_Activity;
1336
+ foreach ( $activity as $k => $v ) {
1337
  $activity_obj->$k = $v;
1338
+ }
1339
 
1340
+ // Mark as not spam.
1341
  bp_activity_mark_as_ham( $activity_obj );
1342
 
1343
  /*
1344
  * If Akismet is present, update the activity history meta.
1345
  *
1346
  * This is usually taken care of when BP_Activity_Activity::save() happens, but
1347
+ * as we're going to be updating all the activity statuses directly, for efficiency,
1348
  * we need to update manually.
1349
  */
1350
+ if ( ! empty( $bp->activity->akismet ) ) {
1351
  $bp->activity->akismet->update_activity_ham_meta( $activity_obj );
1352
+ }
1353
 
1354
+ // Tidy up.
1355
  unset( $activity_obj );
1356
  }
1357
 
1358
+ // Mark all of this user's activities as not spam.
1359
  $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 0 WHERE user_id = %d", $user_id ) );
1360
 
1361
+ /**
1362
+ * Fires after all activity data from a user has been marked as ham.
1363
+ *
1364
+ * @since 1.6.0
1365
+ *
1366
+ * @param int $user_id ID of the user whose activity is being marked as ham.
1367
+ * @param array $activities Array of activity items being marked as ham.
1368
+ */
1369
  do_action( 'bp_activity_ham_all_user_data', $user_id, $activities['activities'] );
1370
  }
1371
  add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' );
1372
 
1373
  /**
1374
+ * Register the activity stream actions for updates.
 
 
1375
  *
1376
+ * @since 1.6.0
1377
  */
1378
  function bp_activity_register_activity_actions() {
1379
+ $bp = buddypress();
1380
 
1381
  bp_activity_set_action(
1382
  $bp->activity->id,
1383
  'activity_update',
1384
  __( 'Posted a status update', 'buddypress' ),
1385
+ 'bp_activity_format_activity_action_activity_update',
1386
+ __( 'Updates', 'buddypress' ),
1387
+ array( 'activity', 'group', 'member', 'member_groups' )
1388
  );
1389
 
1390
  bp_activity_set_action(
1391
  $bp->activity->id,
1392
  'activity_comment',
1393
  __( 'Replied to a status update', 'buddypress' ),
1394
+ 'bp_activity_format_activity_action_activity_comment',
1395
+ __( 'Activity Comments', 'buddypress' )
1396
  );
1397
 
1398
+ /**
1399
+ * Fires at the end of the activity actions registration.
1400
+ *
1401
+ * Allows plugin authors to add their own activity actions alongside the core actions.
1402
+ *
1403
+ * @since 1.6.0
1404
+ */
1405
  do_action( 'bp_activity_register_activity_actions' );
1406
 
1407
  // Backpat. Don't use this.
1412
  /**
1413
  * Generate an activity action string for an activity item.
1414
  *
1415
+ * @since 2.0.0
1416
+ *
1417
  * @param object $activity Activity data object.
1418
  * @return string|bool Returns false if no callback is found, otherwise returns
1419
+ * the formatted action string.
1420
  */
1421
  function bp_activity_generate_action_string( $activity ) {
1422
+
1423
+ // Check for valid input.
1424
  if ( empty( $activity->component ) || empty( $activity->type ) ) {
1425
  return false;
1426
  }
1427
 
1428
+ // Check for registered format callback.
1429
+ $actions = bp_activity_get_actions();
1430
+ if ( empty( $actions->{$activity->component}->{$activity->type}['format_callback'] ) ) {
1431
  return false;
1432
  }
1433
 
1434
+ // We apply the format_callback as a filter.
1435
+ add_filter( 'bp_activity_generate_action_string', $actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 );
1436
 
1437
+ /**
1438
+ * Filters the string for the activity action being returned.
1439
+ *
1440
+ * @since 2.0.0
1441
+ *
1442
+ * @param BP_Activity_Activity $action Action string being requested.
1443
+ * @param BP_Activity_Activity $activity Activity item object.
1444
+ */
1445
  $action = apply_filters( 'bp_activity_generate_action_string', $activity->action, $activity );
1446
 
1447
+ // Remove the filter for future activity items.
1448
+ remove_filter( 'bp_activity_generate_action_string', $actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 );
1449
 
1450
  return $action;
1451
  }
1453
  /**
1454
  * Format 'activity_update' activity actions.
1455
  *
1456
+ * @since 2.0.0
1457
  *
1458
+ * @param string $action Static activity action.
1459
  * @param object $activity Activity data object.
1460
+ * @return string $action
1461
  */
1462
  function bp_activity_format_activity_action_activity_update( $action, $activity ) {
1463
  $action = sprintf( __( '%s posted an update', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
1464
+
1465
+ /**
1466
+ * Filters the formatted activity action update string.
1467
+ *
1468
+ * @since 1.2.0
1469
+ *
1470
+ * @param string $action Activity action string value.
1471
+ * @param BP_Activity_Activity $activity Activity item object.
1472
+ */
1473
  return apply_filters( 'bp_activity_new_update_action', $action, $activity );
1474
  }
1475
 
1476
  /**
1477
  * Format 'activity_comment' activity actions.
1478
  *
1479
+ * @since 2.0.0
1480
  *
1481
+ * @param string $action Static activity action.
1482
  * @param object $activity Activity data object.
1483
+ * @return string $action
1484
  */
1485
  function bp_activity_format_activity_action_activity_comment( $action, $activity ) {
1486
  $action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
1487
+
1488
+ /**
1489
+ * Filters the formatted activity action comment string.
1490
+ *
1491
+ * @since 1.2.0
1492
+ *
1493
+ * @param string $action Activity action string value.
1494
+ * @param BP_Activity_Activity $activity Activity item object.
1495
+ */
1496
  return apply_filters( 'bp_activity_comment_action', $action, $activity );
1497
  }
1498
 
1499
+ /**
1500
+ * Format activity action strings for custom post types.
1501
+ *
1502
+ * @since 2.2.0
1503
+ *
1504
+ * @param string $action Static activity action.
1505
+ * @param object $activity Activity data object.
1506
+ * @return string $action
1507
+ */
1508
+ function bp_activity_format_activity_action_custom_post_type_post( $action, $activity ) {
1509
+ $bp = buddypress();
1510
+
1511
+ // Fetch all the tracked post types once.
1512
+ if ( empty( $bp->activity->track ) ) {
1513
+ $bp->activity->track = bp_activity_get_post_types_tracking_args();
1514
+ }
1515
+
1516
+ if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) {
1517
+ return $action;
1518
+ }
1519
+
1520
+ $user_link = bp_core_get_userlink( $activity->user_id );
1521
+ $blog_url = get_home_url( $activity->item_id );
1522
+
1523
+ if ( empty( $activity->post_url ) ) {
1524
+ $post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
1525
+ } else {
1526
+ $post_url = $activity->post_url;
1527
+ }
1528
+
1529
+ if ( is_multisite() ) {
1530
+ $blog_link = '<a href="' . esc_url( $blog_url ) . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>';
1531
+
1532
+ if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action_ms ) ) {
1533
+ $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action_ms, $user_link, $post_url, $blog_link );
1534
+ } else {
1535
+ $action = sprintf( _x( '%1$s wrote a new <a href="%2$s">item</a>, on the site %3$s', 'Activity Custom Post Type post action', 'buddypress' ), $user_link, esc_url( $post_url ), $blog_link );
1536
+ }
1537
+ } else {
1538
+ if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action ) ) {
1539
+ $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action, $user_link, $post_url );
1540
+ } else {
1541
+ $action = sprintf( _x( '%1$s wrote a new <a href="%2$s">item</a>', 'Activity Custom Post Type post action', 'buddypress' ), $user_link, esc_url( $post_url ) );
1542
+ }
1543
+ }
1544
+
1545
+ /**
1546
+ * Filters the formatted custom post type activity post action string.
1547
+ *
1548
+ * @since 2.2.0
1549
+ *
1550
+ * @param string $action Activity action string value.
1551
+ * @param BP_Activity_Activity $activity Activity item object.
1552
+ */
1553
+ return apply_filters( 'bp_activity_custom_post_type_post_action', $action, $activity );
1554
+ }
1555
+
1556
+ /**
1557
+ * Format activity action strings for custom post types comments.
1558
+ *
1559
+ * @since 2.5.0
1560
+ *
1561
+ * @param string $action Static activity action.
1562
+ * @param object $activity Activity data object.
1563
+ *
1564
+ * @return string
1565
+ */
1566
+ function bp_activity_format_activity_action_custom_post_type_comment( $action, $activity ) {
1567
+ $bp = buddypress();
1568
+
1569
+ // Fetch all the tracked post types once.
1570
+ if ( empty( $bp->activity->track ) ) {
1571
+ $bp->activity->track = bp_activity_get_post_types_tracking_args();
1572
+ }
1573
+
1574
+ if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) {
1575
+ return $action;
1576
+ }
1577
+
1578
+ $user_link = bp_core_get_userlink( $activity->user_id );
1579
+
1580
+ if ( is_multisite() ) {
1581
+ $blog_link = '<a href="' . esc_url( get_home_url( $activity->item_id ) ) . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>';
1582
+
1583
+ if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_comment_action_ms ) ) {
1584
+ $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_comment_action_ms, $user_link, $activity->primary_link, $blog_link );
1585
+ } else {
1586
+ $action = sprintf( _x( '%1$s commented on the <a href="%2$s">item</a>, on the site %3$s', 'Activity Custom Post Type comment action', 'buddypress' ), $user_link, $activity->primary_link, $blog_link );
1587
+ }
1588
+ } else {
1589
+ if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_comment_action ) ) {
1590
+ $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_comment_action, $user_link, $activity->primary_link );
1591
+ } else {
1592
+ $action = sprintf( _x( '%1$s commented on the <a href="%2$s">item</a>', 'Activity Custom Post Type post comment action', 'buddypress' ), $user_link, $activity->primary_link );
1593
+ }
1594
+ }
1595
+
1596
+ /**
1597
+ * Filters the formatted custom post type activity comment action string.
1598
+ *
1599
+ * @since 2.5.0
1600
+ *
1601
+ * @param string $action Activity action string value.
1602
+ * @param BP_Activity_Activity $activity Activity item object.
1603
+ */
1604
+ return apply_filters( 'bp_activity_custom_post_type_comment_action', $action, $activity );
1605
+ }
1606
+
1607
+ /*
1608
  * Business functions are where all the magic happens in BuddyPress. They will
1609
  * handle the actual saving or manipulation of information. Usually they will
1610
  * hand off to a database class for data access, then return
1614
  /**
1615
  * Retrieve an activity or activities.
1616
  *
1617
+ * The bp_activity_get() function shares all arguments with BP_Activity_Activity::get().
1618
+ * The following is a list of bp_activity_get() parameters that have different
1619
  * default values from BP_Activity_Activity::get() (value in parentheses is
1620
  * the default for the bp_activity_get()).
1621
  * - 'per_page' (false)
1622
  *
1623
+ * @since 1.2.0
1624
+ * @since 2.4.0 Introduced the `$fields` parameter.
1625
  *
1626
  * @see BP_Activity_Activity::get() For more information on accepted arguments
1627
  * and the format of the returned value.
 
 
 
 
 
1628
  *
1629
+ * @param array|string $args See BP_Activity_Activity::get() for description.
1630
  * @return array $activity See BP_Activity_Activity::get() for description.
1631
  */
1632
  function bp_activity_get( $args = '' ) {
1633
+
1634
+ $r = bp_parse_args( $args, array(
1635
+ 'max' => false, // Maximum number of results to return.
1636
+ 'fields' => 'all',
1637
+ 'page' => 1, // Page 1 without a per_page will result in no pagination.
1638
  'per_page' => false, // results per page
1639
  'sort' => 'DESC', // sort ASC or DESC
1640
+ 'display_comments' => false, // False for no comments. 'stream' for within stream display, 'threaded' for below each activity item.
1641
 
1642
  'search_terms' => false, // Pass search terms as a string
1643
  'meta_query' => false, // Filter by activity meta. See WP_Meta_Query for format
1644
+ 'date_query' => false, // Filter by date. See first parameter of WP_Date_Query for format.
1645
+ 'filter_query' => false,
1646
  'show_hidden' => false, // Show activity items that are hidden site-wide?
1647
+ 'exclude' => false, // Comma-separated list of activity IDs to exclude.
1648
+ 'in' => false, // Comma-separated list or array of activity IDs to which you
1649
+ // want to limit the query.
1650
  'spam' => 'ham_only', // 'ham_only' (default), 'spam_only' or 'all'.
1651
  'update_meta_cache' => true,
1652
+ 'count_total' => false,
1653
+ 'scope' => false,
1654
 
1655
  /**
1656
  * Pass filters as an array -- all filter items can be multiple values comma separated:
1657
  * array(
1658
+ * 'user_id' => false, // User ID to filter on.
1659
+ * 'object' => false, // Object to filter on e.g. groups, profile, status, friends.
1660
+ * 'action' => false, // Action to filter on e.g. activity_update, profile_updated.
1661
+ * 'primary_id' => false, // Object ID to filter on e.g. a group_id or forum_id or blog_id etc.
1662
+ * 'secondary_id' => false, // Secondary object ID to filter on e.g. a post_id.
1663
  * );
1664
  */
1665
  'filter' => array()
1666
+ ), 'activity_get' );
1667
+
1668
+ $activity = BP_Activity_Activity::get( array(
1669
+ 'page' => $r['page'],
1670
+ 'per_page' => $r['per_page'],
1671
+ 'max' => $r['max'],
1672
+ 'sort' => $r['sort'],
1673
+ 'search_terms' => $r['search_terms'],
1674
+ 'meta_query' => $r['meta_query'],
1675
+ 'date_query' => $r['date_query'],
1676
+ 'filter_query' => $r['filter_query'],
1677
+ 'filter' => $r['filter'],
1678
+ 'scope' => $r['scope'],
1679
+ 'display_comments' => $r['display_comments'],
1680
+ 'show_hidden' => $r['show_hidden'],
1681
+ 'exclude' => $r['exclude'],
1682
+ 'in' => $r['in'],
1683
+ 'spam' => $r['spam'],
1684
+ 'update_meta_cache' => $r['update_meta_cache'],
1685
+ 'count_total' => $r['count_total'],
1686
+ 'fields' => $r['fields'],
1687
+ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1688
 
1689
+ /**
1690
+ * Filters the requested activity item(s).
1691
+ *
1692
+ * @since 1.2.0
1693
+ *
1694
+ * @param BP_Activity_Activity $activity Requested activity object.
1695
+ * @param array $r Arguments used for the activity query.
1696
+ */
1697
  return apply_filters_ref_array( 'bp_activity_get', array( &$activity, &$r ) );
1698
  }
1699
 
1700
  /**
1701
  * Fetch specific activity items.
1702
  *
1703
+ * @since 1.2.0
1704
  *
1705
+ * @see BP_Activity_Activity::get() For more information on accepted arguments.
 
 
 
1706
  *
1707
+ * @param array|string $args {
1708
  * All arguments and defaults are shared with BP_Activity_Activity::get(),
1709
  * except for the following:
1710
  * @type string|int|array Single activity ID, comma-separated list of IDs,
1711
+ * or array of IDs.
1712
  * }
1713
  * @return array $activity See BP_Activity_Activity::get() for description.
1714
  */
1715
  function bp_activity_get_specific( $args = '' ) {
1716
+
1717
+ $r = bp_parse_args( $args, array(
1718
+ 'activity_ids' => false, // A single activity_id or array of IDs.
1719
+ 'display_comments' => false, // True or false to display threaded comments for these specific activity items.
1720
+ 'max' => false, // Maximum number of results to return.
1721
+ 'page' => 1, // Page 1 without a per_page will result in no pagination.
1722
+ 'per_page' => false, // Results per page.
1723
+ 'show_hidden' => true, // When fetching specific items, show all.
1724
+ 'sort' => 'DESC', // Sort ASC or DESC
1725
+ 'spam' => 'ham_only', // Retrieve items marked as spam.
1726
  'update_meta_cache' => true,
1727
+ ) );
 
 
1728
 
1729
  $get_args = array(
1730
+ 'display_comments' => $r['display_comments'],
1731
+ 'in' => $r['activity_ids'],
1732
+ 'max' => $r['max'],
1733
+ 'page' => $r['page'],
1734
+ 'per_page' => $r['per_page'],
1735
+ 'show_hidden' => $r['show_hidden'],
1736
+ 'sort' => $r['sort'],
1737
+ 'spam' => $r['spam'],
1738
+ 'update_meta_cache' => $r['update_meta_cache'],
1739
  );
1740
+
1741
+ /**
1742
+ * Filters the requested specific activity item.
1743
+ *
1744
+ * @since 1.2.0
1745
+ *
1746
+ * @param BP_Activity_Activity $activity Requested activity object.
1747
+ * @param array $args Original passed in arguments.
1748
+ * @param array $get_args Constructed arguments used with request.
1749
+ */
1750
  return apply_filters( 'bp_activity_get_specific', BP_Activity_Activity::get( $get_args ), $args, $get_args );
1751
  }
1752
 
1753
  /**
1754
  * Add an activity item.
1755
  *
1756
+ * @since 1.1.0
1757
+ * @since 2.6.0 Added 'error_type' parameter to $args.
1758
  *
1759
+ * @param array|string $args {
 
 
 
 
 
 
1760
  * An array of arguments.
1761
+ * @type int|bool $id Pass an activity ID to update an existing item, or
1762
+ * false to create a new item. Default: false.
1763
+ * @type string $action Optional. The activity action/description, typically
1764
+ * something like "Joe posted an update". Values passed to this param
1765
+ * will be stored in the database and used as a fallback for when the
1766
+ * activity item's format_callback cannot be found (eg, when the
1767
+ * component is disabled). As long as you have registered a
1768
+ * format_callback for your $type, it is unnecessary to include this
1769
+ * argument - BP will generate it automatically.
1770
+ * See {@link bp_activity_set_action()}.
1771
+ * @type string $content Optional. The content of the activity item.
1772
+ * @type string $component The unique name of the component associated with
1773
+ * the activity item - 'groups', 'profile', etc.
1774
+ * @type string $type The specific activity type, used for directory
1775
+ * filtering. 'new_blog_post', 'activity_update', etc.
1776
+ * @type string $primary_link Optional. The URL for this item, as used in
1777
+ * RSS feeds. Defaults to the URL for this activity
1778
+ * item's permalink page.
1779
+ * @type int|bool $user_id Optional. The ID of the user associated with the activity
1780
+ * item. May be set to false or 0 if the item is not related
1781
+ * to any user. Default: the ID of the currently logged-in user.
1782
+ * @type int $item_id Optional. The ID of the associated item.
1783
+ * @type int $secondary_item_id Optional. The ID of a secondary associated item.
1784
+ * @type string $date_recorded Optional. The GMT time, in Y-m-d h:i:s format, when
1785
+ * the item was recorded. Defaults to the current time.
1786
+ * @type bool $hide_sitewide Should the item be hidden on sitewide streams?
1787
+ * Default: false.
1788
+ * @type bool $is_spam Should the item be marked as spam? Default: false.
1789
+ * @type string $error_type Optional. Error type. Either 'bool' or 'wp_error'. Default: 'bool'.
1790
  * }
1791
  * @return int|bool The ID of the activity on success. False on error.
1792
  */
1793
  function bp_activity_add( $args = '' ) {
1794
 
1795
+ $r = bp_parse_args( $args, array(
1796
+ 'id' => false, // Pass an existing activity ID to update an existing entry.
1797
+ 'action' => '', // The activity action - e.g. "Jon Doe posted an update"
1798
+ 'content' => '', // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!"
1799
+ 'component' => false, // The name/ID of the component e.g. groups, profile, mycomponent.
1800
+ 'type' => false, // The activity type e.g. activity_update, profile_updated.
1801
+ 'primary_link' => '', // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink).
1802
+ 'user_id' => bp_loggedin_user_id(), // Optional: The user to record the activity for, can be false if this activity is not for a user.
1803
+ 'item_id' => false, // Optional: The ID of the specific item being recorded, e.g. a blog_id.
1804
+ 'secondary_item_id' => false, // Optional: A second ID used to further filter e.g. a comment_id.
1805
+ 'recorded_time' => bp_core_current_time(), // The GMT time that this activity was recorded.
1806
+ 'hide_sitewide' => false, // Should this be hidden on the sitewide activity stream?
1807
+ 'is_spam' => false, // Is this activity item to be marked as spam?
1808
+ 'error_type' => 'bool'
1809
+ ), 'activity_add' );
1810
+
1811
+ // Make sure we are backwards compatible.
1812
+ if ( empty( $r['component'] ) && !empty( $r['component_name'] ) ) {
1813
+ $r['component'] = $r['component_name'];
1814
+ }
1815
 
1816
+ if ( empty( $r['type'] ) && !empty( $r['component_action'] ) ) {
1817
+ $r['type'] = $r['component_action'];
1818
+ }
1819
 
1820
+ // Setup activity to be added.
1821
+ $activity = new BP_Activity_Activity( $r['id'] );
1822
+ $activity->user_id = $r['user_id'];
1823
+ $activity->component = $r['component'];
1824
+ $activity->type = $r['type'];
1825
+ $activity->content = $r['content'];
1826
+ $activity->primary_link = $r['primary_link'];
1827
+ $activity->item_id = $r['item_id'];
1828
+ $activity->secondary_item_id = $r['secondary_item_id'];
1829
+ $activity->date_recorded = $r['recorded_time'];
1830
+ $activity->hide_sitewide = $r['hide_sitewide'];
1831
+ $activity->is_spam = $r['is_spam'];
1832
+ $activity->error_type = $r['error_type'];
1833
+ $activity->action = ! empty( $r['action'] )
1834
+ ? $r['action']
1835
+ : bp_activity_generate_action_string( $activity );
1836
+
1837
+ $save = $activity->save();
1838
+
1839
+ if ( 'wp_error' === $r['error_type'] && is_wp_error( $save ) ) {
1840
+ return $save;
1841
+ } elseif ('bool' === $r['error_type'] && false === $save ) {
 
 
 
 
 
 
 
 
 
 
1842
  return false;
1843
+ }
1844
+
1845
+ // If this is an activity comment, rebuild the tree.
1846
+ if ( 'activity_comment' === $activity->type ) {
1847
+ // Also clear the comment cache for the parent activity ID.
1848
+ wp_cache_delete( $activity->item_id, 'bp_activity_comments' );
1849
 
 
 
1850
  BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id );
1851
+ }
1852
 
1853
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1854
+
1855
+ /**
1856
+ * Fires at the end of the execution of adding a new activity item, before returning the new activity item ID.
1857
+ *
1858
+ * @since 1.1.0
1859
+ *
1860
+ * @param array $r Array of parsed arguments for the activity item being added.
1861
+ */
1862
+ do_action( 'bp_activity_add', $r );
1863
 
1864
  return $activity->id;
1865
  }
1867
  /**
1868
  * Post an activity update.
1869
  *
1870
+ * @since 1.2.0
1871
+ *
1872
+ * @param array|string $args {
1873
+ * @type string $content The content of the activity update.
1874
+ * @type int $user_id Optional. Defaults to the logged-in user.
1875
+ * @type string $error_type Optional. Error type to return. Either 'bool' or 'wp_error'. Defaults to
1876
+ * 'bool' for boolean. 'wp_error' will return a WP_Error object.
 
 
 
 
 
 
 
 
 
 
1877
  * }
1878
+ * @return int|bool|WP_Error $activity_id The activity id on success. On failure, either boolean false or WP_Error
1879
+ * object depending on the 'error_type' $args parameter.
1880
  */
1881
  function bp_activity_post_update( $args = '' ) {
 
1882
 
1883
+ $r = wp_parse_args( $args, array(
1884
+ 'content' => false,
1885
+ 'user_id' => bp_loggedin_user_id(),
1886
+ 'error_type' => 'bool',
1887
+ ) );
 
1888
 
1889
+ if ( empty( $r['content'] ) || !strlen( trim( $r['content'] ) ) ) {
1890
  return false;
1891
+ }
1892
 
1893
+ if ( bp_is_user_inactive( $r['user_id'] ) ) {
1894
  return false;
1895
+ }
1896
+
1897
+ // Record this on the user's profile.
1898
+ $activity_content = $r['content'];
1899
+ $primary_link = bp_core_get_userlink( $r['user_id'], false, true );
1900
+
1901
+ /**
1902
+ * Filters the new activity content for current activity item.
1903
+ *
1904
+ * @since 1.2.0
1905
+ *
1906
+ * @param string $activity_content Activity content posted by user.
1907
+ */
1908
+ $add_content = apply_filters( 'bp_activity_new_update_content', $activity_content );
1909
 
1910
+ /**
1911
+ * Filters the activity primary link for current activity item.
1912
+ *
1913
+ * @since 1.2.0
1914
+ *
1915
+ * @param string $primary_link Link to the profile for the user who posted the activity.
1916
+ */
1917
+ $add_primary_link = apply_filters( 'bp_activity_new_update_primary_link', $primary_link );
1918
 
1919
+ // Now write the values.
1920
  $activity_id = bp_activity_add( array(
1921
+ 'user_id' => $r['user_id'],
1922
+ 'content' => $add_content,
1923
+ 'primary_link' => $add_primary_link,
1924
+ 'component' => buddypress()->activity->id,
1925
  'type' => 'activity_update',
1926
+ 'error_type' => $r['error_type']
1927
  ) );
1928
 
1929
+ // Bail on failure.
1930
+ if ( false === $activity_id || is_wp_error( $activity_id ) ) {
1931
+ return $activity_id;
1932
+ }
1933
+
1934
+ /**
1935
+ * Filters the latest update content for the activity item.
1936
+ *
1937
+ * @since 1.6.0
1938
+ *
1939
+ * @param string $r Content of the activity update.
1940
+ * @param string $activity_content Content of the activity update.
1941
+ */
1942
+ $activity_content = apply_filters( 'bp_activity_latest_update_content', $r['content'], $activity_content );
1943
 
1944
  // Add this update to the "latest update" usermeta so it can be fetched anywhere.
1945
+ bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array(
1946
+ 'id' => $activity_id,
1947
+ 'content' => $activity_content
1948
+ ) );
1949
 
1950
+ /**
1951
+ * Fires at the end of an activity post update, before returning the updated activity item ID.
1952
+ *
1953
+ * @since 1.2.0
1954
+ *
1955
+ * @param string $content Content of the activity post update.
1956
+ * @param int $user_id ID of the user posting the activity update.
1957
+ * @param int $activity_id ID of the activity item being updated.
1958
+ */
1959
+ do_action( 'bp_activity_posted_update', $r['content'], $r['user_id'], $activity_id );
1960
 
1961
  return $activity_id;
1962
  }
1963
 
1964
+ /**
1965
+ * Create an activity item for a newly published post type post.
1966
+ *
1967
+ * @since 2.2.0
1968
+ *
1969
+ * @param int $post_id ID of the new post.
1970
+ * @param WP_Post|null $post Post object.
1971
+ * @param int $user_id ID of the post author.
1972
+ * @return int|bool The ID of the activity on success. False on error.
1973
+ */
1974
+ function bp_activity_post_type_publish( $post_id = 0, $post = null, $user_id = 0 ) {
1975
+
1976
+ if ( ! is_a( $post, 'WP_Post' ) ) {
1977
+ return;
1978
+ }
1979
+
1980
+ // Get the post type tracking args.
1981
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type );
1982
+
1983
+ if ( 'publish' != $post->post_status || ! empty( $post->post_password ) || empty( $activity_post_object->action_id ) ) {
1984
+ return;
1985
+ }
1986
+
1987
+ if ( empty( $post_id ) ) {
1988
+ $post_id = $post->ID;
1989
+ }
1990
+
1991
+ $blog_id = get_current_blog_id();
1992
+
1993
+ if ( empty( $user_id ) ) {
1994
+ $user_id = (int) $post->post_author;
1995
+ }
1996
+
1997
+ // Bail if an activity item already exists for this post.
1998
+ $existing = bp_activity_get( array(
1999
+ 'filter' => array(
2000
+ 'action' => $activity_post_object->action_id,
2001
+ 'primary_id' => $blog_id,
2002
+ 'secondary_id' => $post_id,
2003
+ )
2004
+ ) );
2005
+
2006
+ if ( ! empty( $existing['activities'] ) ) {
2007
+ return;
2008
+ }
2009
+
2010
+ /**
2011
+ * Filters whether or not to post the activity.
2012
+ *
2013
+ * This is a variable filter, dependent on the post type,
2014
+ * that lets components or plugins bail early if needed.
2015
+ *
2016
+ * @since 2.2.0
2017
+ *
2018
+ * @param bool $value Whether or not to continue.
2019
+ * @param int $blog_id ID of the current site.
2020
+ * @param int $post_id ID of the current post being published.
2021
+ * @param int $user_id ID of the current user or post author.
2022
+ */
2023
+ if ( false === apply_filters( "bp_activity_{$post->post_type}_pre_publish", true, $blog_id, $post_id, $user_id ) ) {
2024
+ return;
2025
+ }
2026
+
2027
+ // Record this in activity streams.
2028
+ $blog_url = get_home_url( $blog_id );
2029
+ $post_url = add_query_arg(
2030
+ 'p',
2031
+ $post_id,
2032
+ trailingslashit( $blog_url )
2033
+ );
2034
+
2035
+ // Backward compatibility filters for the 'blogs' component.
2036
+ if ( 'blogs' == $activity_post_object->component_id ) {
2037
+ $activity_content = apply_filters( 'bp_blogs_activity_new_post_content', $post->post_content, $post, $post_url, $post->post_type );
2038
+ $activity_primary_link = apply_filters( 'bp_blogs_activity_new_post_primary_link', $post_url, $post_id, $post->post_type );
2039
+ } else {
2040
+ $activity_content = $post->post_content;
2041
+ $activity_primary_link = $post_url;
2042
+ }
2043
+
2044
+ $activity_args = array(
2045
+ 'user_id' => $user_id,
2046
+ 'content' => $activity_content,
2047
+ 'primary_link' => $activity_primary_link,
2048
+ 'component' => $activity_post_object->component_id,
2049
+ 'type' => $activity_post_object->action_id,
2050
+ 'item_id' => $blog_id,
2051
+ 'secondary_item_id' => $post_id,
2052
+ 'recorded_time' => $post->post_date_gmt,
2053
+ );
2054
+
2055
+ if ( ! empty( $activity_args['content'] ) ) {
2056
+ // Create the excerpt.
2057
+ $activity_summary = bp_activity_create_summary( $activity_args['content'], $activity_args );
2058
+
2059
+ // Backward compatibility filter for blog posts.
2060
+ if ( 'blogs' == $activity_post_object->component_id ) {
2061
+ $activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post->post_type );
2062
+ } else {
2063
+ $activity_args['content'] = $activity_summary;
2064
+ }
2065
+ }
2066
+
2067
+ // Set up the action by using the format functions.
2068
+ $action_args = array_merge( $activity_args, array(
2069
+ 'post_title' => $post->post_title,
2070
+ 'post_url' => $post_url,
2071
+ ) );
2072
+
2073
+ $activity_args['action'] = call_user_func_array( $activity_post_object->format_callback, array( '', (object) $action_args ) );
2074
+
2075
+ // Make sure the action is set.
2076
+ if ( empty( $activity_args['action'] ) ) {
2077
+ return;
2078
+ } else {
2079
+ // Backward compatibility filter for the blogs component.
2080
+ if ( 'blogs' == $activity_post_object->component_id ) {
2081
+ $activity_args['action'] = apply_filters( 'bp_blogs_record_activity_action', $activity_args['action'] );
2082
+ }
2083
+ }
2084
+
2085
+ $activity_id = bp_activity_add( $activity_args );
2086
+
2087
+ /**
2088
+ * Fires after the publishing of an activity item for a newly published post type post.
2089
+ *
2090
+ * @since 2.2.0
2091
+ *
2092
+ * @param int $activity_id ID of the newly published activity item.
2093
+ * @param WP_Post $post Post object.
2094
+ * @param array $activity_args Array of activity arguments.
2095
+ */
2096
+ do_action( 'bp_activity_post_type_published', $activity_id, $post, $activity_args );
2097
+
2098
+ return $activity_id;
2099
+ }
2100
+
2101
+ /**
2102
+ * Update the activity item for a custom post type entry.
2103
+ *
2104
+ * @since 2.2.0
2105
+ *
2106
+ * @param WP_Post|null $post Post item.
2107
+ * @return bool True on success, false on failure.
2108
+ */
2109
+ function bp_activity_post_type_update( $post = null ) {
2110
+
2111
+ if ( ! is_a( $post, 'WP_Post' ) ) {
2112
+ return;
2113
+ }
2114
+
2115
+ // Get the post type tracking args.
2116
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type );
2117
+
2118
+ if ( empty( $activity_post_object->action_id ) ) {
2119
+ return;
2120
+ }
2121
+
2122
+ $activity_id = bp_activity_get_activity_id( array(
2123
+ 'component' => $activity_post_object->component_id,
2124
+ 'item_id' => get_current_blog_id(),
2125
+ 'secondary_item_id' => $post->ID,
2126
+ 'type' => $activity_post_object->action_id,
2127
+ ) );
2128
+
2129
+ // Activity ID doesn't exist, so stop!
2130
+ if ( empty( $activity_id ) ) {
2131
+ return;
2132
+ }
2133
+
2134
+ // Delete the activity if the post was updated with a password.
2135
+ if ( ! empty( $post->post_password ) ) {
2136
+ bp_activity_delete( array( 'id' => $activity_id ) );
2137
+ }
2138
+
2139
+ // Update the activity entry.
2140
+ $activity = new BP_Activity_Activity( $activity_id );
2141
+
2142
+ if ( ! empty( $post->post_content ) ) {
2143
+ $activity_summary = bp_activity_create_summary( $post->post_content, (array) $activity );
2144
+
2145
+ // Backward compatibility filter for the blogs component.
2146
+ if ( 'blogs' == $activity_post_object->component_id ) {
2147
+ $activity->content = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $post->post_content, (array) $activity, $post->post_type );
2148
+ } else {
2149
+ $activity->content = $activity_summary;
2150
+ }
2151
+ }
2152
+
2153
+ // Save the updated activity.
2154
+ $updated = $activity->save();
2155
+
2156
+ /**
2157
+ * Fires after the updating of an activity item for a custom post type entry.
2158
+ *
2159
+ * @since 2.2.0
2160
+ * @since 2.5.0 Add the post type tracking args parameter
2161
+ *
2162
+ * @param WP_Post $post Post object.
2163
+ * @param BP_Activity_Activity $activity Activity object.
2164
+ * @param object $activity_post_object The post type tracking args object.
2165
+ */
2166
+ do_action( 'bp_activity_post_type_updated', $post, $activity, $activity_post_object );
2167
+
2168
+ return $updated;
2169
+ }
2170
+
2171
+ /**
2172
+ * Unpublish an activity for the custom post type.
2173
+ *
2174
+ * @since 2.2.0
2175
+ *
2176
+ * @param int $post_id ID of the post being unpublished.
2177
+ * @param WP_Post|null $post Post object.
2178
+ * @return bool True on success, false on failure.
2179
+ */
2180
+ function bp_activity_post_type_unpublish( $post_id = 0, $post = null ) {
2181
+
2182
+ if ( ! is_a( $post, 'WP_Post' ) ) {
2183
+ return;
2184
+ }
2185
+
2186
+ // Get the post type tracking args.
2187
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type );
2188
+
2189
+ if ( empty( $activity_post_object->action_id ) ) {
2190
+ return;
2191
+ }
2192
+
2193
+ if ( empty( $post_id ) ) {
2194
+ $post_id = $post->ID;
2195
+ }
2196
+
2197
+ $delete_activity_args = array(
2198
+ 'item_id' => get_current_blog_id(),
2199
+ 'secondary_item_id' => $post_id,
2200
+ 'component' => $activity_post_object->component_id,
2201
+ 'type' => $activity_post_object->action_id,
2202
+ 'user_id' => false,
2203
+ );
2204
+
2205
+ $deleted = bp_activity_delete_by_item_id( $delete_activity_args );
2206
+
2207
+ /**
2208
+ * Fires after the unpublishing for the custom post type.
2209
+ *
2210
+ * @since 2.2.0
2211
+ *
2212
+ * @param array $delete_activity_args Array of arguments for activity deletion.
2213
+ * @param WP_Post $post Post object.
2214
+ * @param bool $activity Whether or not the activity was successfully deleted.
2215
+ */
2216
+ do_action( 'bp_activity_post_type_unpublished', $delete_activity_args, $post, $deleted );
2217
+
2218
+ return $deleted;
2219
+ }
2220
+
2221
+ /**
2222
+ * Create an activity item for a newly posted post type comment.
2223
+ *
2224
+ * @since 2.5.0
2225
+ *
2226
+ * @param int $comment_id ID of the comment.
2227
+ * @param bool $is_approved Whether the comment is approved or not.
2228
+ * @param object|null $activity_post_object The post type tracking args object.
2229
+ * @return int|bool The ID of the activity on success. False on error.
2230
+ */
2231
+ function bp_activity_post_type_comment( $comment_id = 0, $is_approved = true, $activity_post_object = null ) {
2232
+ // Get the users comment
2233
+ $post_type_comment = get_comment( $comment_id );
2234
+
2235
+ // Don't record activity if the comment hasn't been approved
2236
+ if ( empty( $is_approved ) ) {
2237
+ return false;
2238
+ }
2239
+
2240
+ // Don't record activity if no email address has been included
2241
+ if ( empty( $post_type_comment->comment_author_email ) ) {
2242
+ return false;
2243
+ }
2244
+
2245
+ // Don't record activity if the comment has already been marked as spam
2246
+ if ( 'spam' === $is_approved ) {
2247
+ return false;
2248
+ }
2249
+
2250
+ // Get the user by the comment author email.
2251
+ $user = get_user_by( 'email', $post_type_comment->comment_author_email );
2252
+
2253
+ // If user isn't registered, don't record activity
2254
+ if ( empty( $user ) ) {
2255
+ return false;
2256
+ }
2257
+
2258
+ // Get the user_id
2259
+ $user_id = (int) $user->ID;
2260
+
2261
+ // Get blog and post data
2262
+ $blog_id = get_current_blog_id();
2263
+
2264
+ // Get the post
2265
+ $post_type_comment->post = get_post( $post_type_comment->comment_post_ID );
2266
+
2267
+ if ( ! is_a( $post_type_comment->post, 'WP_Post' ) ) {
2268
+ return false;
2269
+ }
2270
+
2271
+ /**
2272
+ * Filters whether to publish activities about the comment regarding the post status
2273
+ *
2274
+ * @since 2.5.0
2275
+ *
2276
+ * @param bool true to bail, false otherwise.
2277
+ */
2278
+ $is_post_status_not_allowed = (bool) apply_filters( 'bp_activity_post_type_is_post_status_allowed', 'publish' !== $post_type_comment->post->post_status || ! empty( $post_type_comment->post->post_password ) );
2279
+
2280
+ // If this is a password protected post, or not a public post don't record the comment
2281
+ if ( $is_post_status_not_allowed ) {
2282
+ return false;
2283
+ }
2284
+
2285
+ // Set post type
2286
+ $post_type = $post_type_comment->post->post_type;
2287
+
2288
+ if ( empty( $activity_post_object ) ) {
2289
+ // Get the post type tracking args.
2290
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type );
2291
+
2292
+ // Bail if the activity type does not exist
2293
+ if ( empty( $activity_post_object->comments_tracking->action_id ) ) {
2294
+ return false;
2295
+ }
2296
+ }
2297
+
2298
+ // Set the $activity_comment_object
2299
+ $activity_comment_object = $activity_post_object->comments_tracking;
2300
+
2301
+ /**
2302
+ * Filters whether or not to post the activity about the comment.
2303
+ *
2304
+ * This is a variable filter, dependent on the post type,
2305
+ * that lets components or plugins bail early if needed.
2306
+ *
2307
+ * @since 2.5.0
2308
+ *
2309
+ * @param bool $value Whether or not to continue.
2310
+ * @param int $blog_id ID of the current site.
2311
+ * @param int $post_id ID of the current post being commented.
2312
+ * @param int $user_id ID of the current user.
2313
+ * @param int $comment_id ID of the current comment being posted.
2314
+ */
2315
+ if ( false === apply_filters( "bp_activity_{$post_type}_pre_comment", true, $blog_id, $post_type_comment->post->ID, $user_id, $comment_id ) ) {
2316
+ return false;
2317
+ }
2318
+
2319
+ // Is this an update ?
2320
+ $activity_id = bp_activity_get_activity_id( array(
2321
+ 'user_id' => $user_id,
2322
+ 'component' => $activity_comment_object->component_id,
2323
+ 'type' => $activity_comment_object->action_id,
2324
+ 'item_id' => $blog_id,
2325
+ 'secondary_item_id' => $comment_id,
2326
+ ) );
2327
+
2328
+ // Record this in activity streams.
2329
+ $comment_link = get_comment_link( $post_type_comment->comment_ID );
2330
+
2331
+ // Backward compatibility filters for the 'blogs' component.
2332
+ if ( 'blogs' == $activity_comment_object->component_id ) {
2333
+ $activity_content = apply_filters_ref_array( 'bp_blogs_activity_new_comment_content', array( $post_type_comment->comment_content, &$post_type_comment, $comment_link ) );
2334
+ $activity_primary_link = apply_filters_ref_array( 'bp_blogs_activity_new_comment_primary_link', array( $comment_link, &$post_type_comment ) );
2335
+ } else {
2336
+ $activity_content = $post_type_comment->comment_content;
2337
+ $activity_primary_link = $comment_link;
2338
+ }
2339
+
2340
+ $activity_args = array(
2341
+ 'id' => $activity_id,
2342
+ 'user_id' => $user_id,
2343
+ 'content' => $activity_content,
2344
+ 'primary_link' => $activity_primary_link,
2345
+ 'component' => $activity_comment_object->component_id,
2346
+ 'recorded_time' => $post_type_comment->comment_date_gmt,
2347
+ );
2348
+
2349
+ if ( bp_disable_blogforum_comments() ) {
2350
+ $blog_url = get_home_url( $blog_id );
2351
+ $post_url = add_query_arg(
2352
+ 'p',
2353
+ $post_type_comment->post->ID,
2354
+ trailingslashit( $blog_url )
2355
+ );
2356
+
2357
+ $activity_args['type'] = $activity_comment_object->action_id;
2358
+ $activity_args['item_id'] = $blog_id;
2359
+ $activity_args['secondary_item_id'] = $post_type_comment->comment_ID;
2360
+
2361
+ if ( ! empty( $activity_args['content'] ) ) {
2362
+ // Create the excerpt.
2363
+ $activity_summary = bp_activity_create_summary( $activity_args['content'], $activity_args );
2364
+
2365
+ // Backward compatibility filter for blog comments.
2366
+ if ( 'blogs' == $activity_post_object->component_id ) {
2367
+ $activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post_type );
2368
+ } else {
2369
+ $activity_args['content'] = $activity_summary;
2370
+ }
2371
+ }
2372
+
2373
+ // Set up the action by using the format functions.
2374
+ $action_args = array_merge( $activity_args, array(
2375
+ 'post_title' => $post_type_comment->post->post_title,
2376
+ 'post_url' => $post_url,
2377
+ 'blog_url' => $blog_url,
2378
+ 'blog_name' => get_blog_option( $blog_id, 'blogname' ),
2379
+ ) );
2380
+
2381
+ $activity_args['action'] = call_user_func_array( $activity_comment_object->format_callback, array( '', (object) $action_args ) );
2382
+
2383
+ // Make sure the action is set.
2384
+ if ( empty( $activity_args['action'] ) ) {
2385
+ return;
2386
+ } else {
2387
+ // Backward compatibility filter for the blogs component.
2388
+ if ( 'blogs' === $activity_post_object->component_id ) {
2389
+ $activity_args['action'] = apply_filters( 'bp_blogs_record_activity_action', $activity_args['action'] );
2390
+ }
2391
+ }
2392
+
2393
+ $activity_id = bp_activity_add( $activity_args );
2394
+ }
2395
+
2396
+ /**
2397
+ * Fires after the publishing of an activity item for a newly published post type post.
2398
+ *
2399
+ * @since 2.5.0
2400
+ *
2401
+ * @param int $activity_id ID of the newly published activity item.
2402
+ * @param WP_Comment $post_type_comment Comment object.
2403
+ * @param array $activity_args Array of activity arguments.
2404
+ * @param object $activity_post_object the post type tracking args object.
2405
+ */
2406
+ do_action_ref_array( 'bp_activity_post_type_comment', array( &$activity_id, $post_type_comment, $activity_args, $activity_post_object ) );
2407
+
2408
+ return $activity_id;
2409
+ }
2410
+ add_action( 'comment_post', 'bp_activity_post_type_comment', 10, 2 );
2411
+ add_action( 'edit_comment', 'bp_activity_post_type_comment', 10 );
2412
+
2413
+ /**
2414
+ * Remove an activity item when a comment about a post type is deleted.
2415
+ *
2416
+ * @since 2.5.0
2417
+ *
2418
+ * @param int $comment_id ID of the comment.
2419
+ * @param object|null $activity_post_object The post type tracking args object.
2420
+ * @return bool True on success. False on error.
2421
+ */
2422
+ function bp_activity_post_type_remove_comment( $comment_id = 0, $activity_post_object = null ) {
2423
+ if ( empty( $activity_post_object ) ) {
2424
+ $comment = get_comment( $comment_id );
2425
+ if ( ! $comment ) {
2426
+ return;
2427
+ }
2428
+
2429
+ $post_type = get_post_type( $comment->comment_post_ID );
2430
+ if ( ! $post_type ) {
2431
+ return;
2432
+ }
2433
+
2434
+ // Get the post type tracking args.
2435
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type );
2436
+
2437
+ // Bail if the activity type does not exist
2438
+ if ( empty( $activity_post_object->comments_tracking->action_id ) ) {
2439
+ return false;
2440
+ }
2441
+ }
2442
+
2443
+ // Set the $activity_comment_object
2444
+ $activity_comment_object = $activity_post_object->comments_tracking;
2445
+
2446
+ if ( empty( $activity_comment_object->action_id ) ) {
2447
+ return false;
2448
+ }
2449
+
2450
+ $deleted = false;
2451
+
2452
+ if ( bp_disable_blogforum_comments() ) {
2453
+ $deleted = bp_activity_delete_by_item_id( array(
2454
+ 'item_id' => get_current_blog_id(),
2455
+ 'secondary_item_id' => $comment_id,
2456
+ 'component' => $activity_comment_object->component_id,
2457
+ 'type' => $activity_comment_object->action_id,
2458
+ 'user_id' => false,
2459
+ ) );
2460
+ }
2461
+
2462
+ /**
2463
+ * Fires after the custom post type comment activity was removed.
2464
+ *
2465
+ * @since 2.5.0
2466
+ *
2467
+ * @param bool $deleted True if the activity was deleted false otherwise
2468
+ * @param WP_Comment $comment Comment object.
2469
+ * @param object $activity_post_object The post type tracking args object.
2470
+ * @param string $value The post type comment activity type.
2471
+ */
2472
+ do_action( 'bp_activity_post_type_remove_comment', $deleted, $comment_id, $activity_post_object, $activity_comment_object->action_id );
2473
+
2474
+ return $deleted;
2475
+ }
2476
+ add_action( 'delete_comment', 'bp_activity_post_type_remove_comment', 10, 1 );
2477
+
2478
  /**
2479
  * Add an activity comment.
2480
  *
2481
+ * @since 1.2.0
2482
+ * @since 2.5.0 Add a new possible parameter $skip_notification for the array of arguments.
2483
+ * Add the $primary_link parameter for the array of arguments.
2484
+ * @since 2.6.0 Added 'error_type' parameter to $args.
2485
+ *
2486
+ * @param array|string $args {
2487
+ * An array of arguments.
2488
+ * @type int $id Optional. Pass an ID to update an existing comment.
2489
+ * @type string $content The content of the comment.
2490
+ * @type int $user_id Optional. The ID of the user making the comment.
2491
+ * Defaults to the ID of the logged-in user.
2492
+ * @type int $activity_id The ID of the "root" activity item, ie the oldest
2493
+ * ancestor of the comment.
2494
+ * @type int $parent_id Optional. The ID of the parent activity item, ie the item to
2495
+ * which the comment is an immediate reply. If not provided,
2496
+ * this value defaults to the $activity_id.
2497
+ * @type string $primary_link Optional. the primary link for the comment.
2498
+ * Defaults to an empty string.
2499
+ * @type bool $skip_notification Optional. false to send a comment notification, false otherwise.
2500
+ * Defaults to false.
2501
+ * @type string $error_type Optional. Error type. Either 'bool' or 'wp_error'. Default: 'bool'.
2502
  * }
2503
  * @return int|bool The ID of the comment on success, otherwise false.
2504
  */
2505
  function bp_activity_new_comment( $args = '' ) {
2506
+ $bp = buddypress();
2507
 
2508
+ $r = wp_parse_args( $args, array(
2509
+ 'id' => false,
2510
+ 'content' => false,
2511
+ 'user_id' => bp_loggedin_user_id(),
2512
+ 'activity_id' => false, // ID of the root activity item.
2513
+ 'parent_id' => false, // ID of a parent comment (optional).
2514
+ 'primary_link' => '',
2515
+ 'skip_notification' => false,
2516
+ 'error_type' => 'bool'
2517
  ) );
2518
 
2519
+ // Error type is boolean; need to initialize some variables for backpat.
2520
+ if ( 'bool' === $r['error_type'] ) {
2521
+ if ( empty( $bp->activity->errors ) ) {
2522
+ $bp->activity->errors = array();
2523
+ }
2524
+ }
2525
 
2526
+ // Default error message.
2527
+ $feedback = __( 'There was an error posting your reply. Please try again.', 'buddypress' );
2528
+
2529
+ // Bail if missing necessary data.
2530
+ if ( empty( $r['content'] ) || empty( $r['user_id'] ) || empty( $r['activity_id'] ) ) {
2531
+ $error = new WP_Error( 'missing_data', $feedback );
2532
+
2533
+ if ( 'wp_error' === $r['error_type'] ) {
2534
+ return $error;
2535
+
2536
+ // Backpat.
2537
+ } else {
2538
+ $bp->activity->errors['new_comment'] = $error;
2539
+ return false;
2540
+ }
2541
  }
2542
 
2543
+ // Maybe set current activity ID as the parent.
2544
+ if ( empty( $r['parent_id'] ) ) {
2545
+ $r['parent_id'] = $r['activity_id'];
2546
  }
2547
 
2548
+ $activity_id = $r['activity_id'];
2549
+
2550
+ // Get the parent activity.
2551
  $activity = new BP_Activity_Activity( $activity_id );
 
2552
 
2553
+ // Bail if the parent activity does not exist.
2554
+ if ( empty( $activity->date_recorded ) ) {
2555
+ $error = new WP_Error( 'missing_activity', __( 'The item you were replying to no longer exists.', 'buddypress' ) );
2556
+
2557
+ if ( 'wp_error' === $r['error_type'] ) {
2558
+ return $error;
2559
+
2560
+ // Backpat.
2561
+ } else {
2562
+ $bp->activity->errors['new_comment'] = $error;
2563
+ return false;
2564
+ }
2565
+
2566
+ }
2567
+
2568
+ // Check to see if the parent activity is hidden, and if so, hide this comment publicly.
2569
+ $is_hidden = $activity->hide_sitewide ? 1 : 0;
2570
+
2571
+ /**
2572
+ * Filters the content of a new comment.
2573
+ *
2574
+ * @since 1.2.0
2575
+ *
2576
+ * @param string $r Content for the newly posted comment.
2577
+ */
2578
+ $comment_content = apply_filters( 'bp_activity_comment_content', $r['content'] );
2579
+
2580
+ // Insert the activity comment.
2581
  $comment_id = bp_activity_add( array(
2582
+ 'id' => $r['id'],
2583
+ 'content' => $comment_content,
2584
  'component' => buddypress()->activity->id,
2585
  'type' => 'activity_comment',
2586
+ 'primary_link' => $r['primary_link'],
2587
+ 'user_id' => $r['user_id'],
2588
  'item_id' => $activity_id,
2589
+ 'secondary_item_id' => $r['parent_id'],
2590
+ 'hide_sitewide' => $is_hidden,
2591
+ 'error_type' => $r['error_type']
2592
  ) );
2593
 
2594
+ // Bail on failure.
2595
+ if ( false === $comment_id || is_wp_error( $comment_id ) ) {
2596
+ return $comment_id;
2597
+ }
2598
+
2599
+ // Comment caches are stored only with the top-level item.
2600
  wp_cache_delete( $activity_id, 'bp_activity_comments' );
2601
 
2602
+ // Walk the tree to clear caches for all parent items.
2603
+ $clear_id = $r['parent_id'];
2604
  while ( $clear_id != $activity_id ) {
2605
  $clear_object = new BP_Activity_Activity( $clear_id );
2606
  wp_cache_delete( $clear_id, 'bp_activity' );
2608
  }
2609
  wp_cache_delete( $activity_id, 'bp_activity' );
2610
 
2611
+ if ( empty( $r[ 'skip_notification' ] ) ) {
2612
+ /**
2613
+ * Fires near the end of an activity comment posting, before the returning of the comment ID.
2614
+ * Sends a notification to the user @see bp_activity_new_comment_notification_helper().
2615
+ *
2616
+ * @since 1.2.0
2617
+ *
2618
+ * @param int $comment_id ID of the newly posted activity comment.
2619
+ * @param array $r Array of parsed comment arguments.
2620
+ * @param int $activity ID of the activity item being commented on.
2621
+ */
2622
+ do_action( 'bp_activity_comment_posted', $comment_id, $r, $activity );
2623
+ } else {
2624
+ /**
2625
+ * Fires near the end of an activity comment posting, before the returning of the comment ID.
2626
+ * without sending a notification to the user
2627
+ *
2628
+ * @since 2.5.0
2629
+ *
2630
+ * @param int $comment_id ID of the newly posted activity comment.
2631
+ * @param array $r Array of parsed comment arguments.
2632
+ * @param int $activity ID of the activity item being commented on.
2633
+ */
2634
+ do_action( 'bp_activity_comment_posted_notification_skipped', $comment_id, $r, $activity );
2635
+ }
2636
+
2637
+ if ( empty( $comment_id ) ) {
2638
+ $error = new WP_Error( 'comment_failed', $feedback );
2639
+
2640
+ if ( 'wp_error' === $r['error_type'] ) {
2641
+ return $error;
2642
+
2643
+ // Backpat.
2644
+ } else {
2645
+ $bp->activity->errors['new_comment'] = $error;
2646
+ }
2647
+ }
2648
 
2649
  return $comment_id;
2650
  }
2652
  /**
2653
  * Fetch the activity_id for an existing activity entry in the DB.
2654
  *
2655
+ * @since 1.2.0
2656
  *
2657
  * @see BP_Activity_Activity::get() For more information on accepted arguments.
 
 
 
2658
  *
2659
+ * @param array|string $args See BP_Activity_Activity::get() for description.
2660
  * @return int $activity_id The ID of the activity item found.
2661
  */
2662
  function bp_activity_get_activity_id( $args = '' ) {
2663
+
2664
+ $r = bp_parse_args( $args, array(
2665
  'user_id' => false,
2666
  'component' => false,
2667
  'type' => false,
2670
  'action' => false,
2671
  'content' => false,
2672
  'date_recorded' => false,
2673
+ ) );
 
 
 
2674
 
2675
+ /**
2676
+ * Filters the activity ID being requested.
2677
+ *
2678
+ * @since 1.2.0
2679
+ * @since 2.5.0 Added the `$r` and `$args` parameters.
2680
+ *
2681
+ * @param BP_Activity_Activity $value ID returned by BP_Activity_Activity get_id() method with provided arguments.
2682
+ * @param array $r Parsed function arguments.
2683
+ * @param array $args Arguments passed to the function.
2684
+ */
2685
+ return apply_filters( 'bp_activity_get_activity_id', BP_Activity_Activity::get_id(
2686
+ $r['user_id'],
2687
+ $r['component'],
2688
+ $r['type'],
2689
+ $r['item_id'],
2690
+ $r['secondary_item_id'],
2691
+ $r['action'],
2692
+ $r['content'],
2693
+ $r['date_recorded']
2694
+ ), $r, $args );
2695
  }
2696
 
2697
  /**
2707
  *
2708
  * If you are deleting an activity comment please use bp_activity_delete_comment();
2709
  *
2710
+ * @since 1.0.0
2711
  *
2712
  * @see BP_Activity_Activity::get() For more information on accepted arguments.
2713
+ *
2714
+ * @param array|string $args To delete specific activity items, use
2715
+ * $args = array( 'id' => $ids ); Otherwise, to use
2716
+ * filters for item deletion, the argument format is
2717
+ * the same as BP_Activity_Activity::get().
2718
+ * See that method for a description.
 
 
 
 
 
 
 
 
2719
  * @return bool True on success, false on failure.
2720
  */
2721
  function bp_activity_delete( $args = '' ) {
2722
 
2723
+ // Pass one or more the of following variables to delete by those variables.
2724
+ $args = bp_parse_args( $args, array(
2725
  'id' => false,
2726
  'action' => false,
2727
  'content' => false,
2733
  'secondary_item_id' => false,
2734
  'date_recorded' => false,
2735
  'hide_sitewide' => false
2736
+ ) );
 
 
2737
 
2738
+ /**
2739
+ * Fires before an activity item proceeds to be deleted.
2740
+ *
2741
+ * @since 1.5.0
2742
+ *
2743
+ * @param array $args Array of arguments to be used with the activity deletion.
2744
+ */
2745
  do_action( 'bp_before_activity_delete', $args );
2746
 
2747
+ // Adjust the new mention count of any mentioned member.
2748
  bp_activity_adjust_mention_count( $args['id'], 'delete' );
2749
 
2750
+ $activity_ids_deleted = BP_Activity_Activity::delete( $args );
2751
+ if ( empty( $activity_ids_deleted ) ) {
2752
  return false;
2753
+ }
2754
 
2755
+ // Check if the user's latest update has been deleted.
2756
+ $user_id = empty( $args['user_id'] )
2757
+ ? bp_loggedin_user_id()
2758
+ : $args['user_id'];
 
2759
 
2760
  $latest_update = bp_get_user_meta( $user_id, 'bp_latest_update', true );
2761
  if ( !empty( $latest_update ) ) {
2764
  }
2765
  }
2766
 
2767
+ /**
2768
+ * Fires after the activity item has been deleted.
2769
+ *
2770
+ * @since 1.0.0
2771
+ *
2772
+ * @param array $args Array of arguments used with the activity deletion.
2773
+ */
2774
  do_action( 'bp_activity_delete', $args );
2775
+
2776
+ /**
2777
+ * Fires after the activity item has been deleted.
2778
+ *
2779
+ * @since 1.2.0
2780
+ *
2781
+ * @param array $activity_ids_deleted Array of affected activity item IDs.
2782
+ */
2783
  do_action( 'bp_activity_deleted_activities', $activity_ids_deleted );
2784
 
2785
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
2792
  *
2793
  * You should use bp_activity_delete() instead.
2794
  *
2795
+ * @since 1.1.0
2796
+ * @deprecated 1.2.0
 
 
 
2797
  *
 
 
2798
  *
2799
+ * @param array|string $args See BP_Activity_Activity::get for a
2800
+ * description of accepted arguments.
2801
  * @return bool True on success, false on failure.
2802
  */
2803
  function bp_activity_delete_by_item_id( $args = '' ) {
2804
 
2805
+ $r = bp_parse_args( $args, array(
2806
  'item_id' => false,
2807
  'component' => false,
2808
  'type' => false,
2809
  'user_id' => false,
2810
  'secondary_item_id' => false
2811
+ ) );
 
 
2812
 
2813
+ return bp_activity_delete( $r );
2814
  }
2815
 
2816
  /**
2817
  * Delete an activity item by activity id.
2818
  *
2819
+ * @since 1.1.0
2820
  *
 
2821
  *
2822
+ * @param int $activity_id ID of the activity item to be deleted.
2823
  * @return bool True on success, false on failure.
2824
  */
2825
  function bp_activity_delete_by_activity_id( $activity_id ) {
2831
  *
2832
  * You should use bp_activity_delete() instead.
2833
  *
2834
+ * @since 1.1.0
2835
+ * @deprecated 1.2.0
2836
  *
 
2837
  *
2838
+ * @param int $user_id The user id.
2839
+ * @param string $content The activity id.
2840
  * @param string $component The activity component.
2841
+ * @param string $type The activity type.
2842
  * @return bool True on success, false on failure.
2843
  */
2844
  function bp_activity_delete_by_content( $user_id, $content, $component, $type ) {
2845
+ return bp_activity_delete( array(
2846
+ 'user_id' => $user_id,
2847
+ 'content' => $content,
2848
+ 'component' => $component,
2849
+ 'type' => $type
2850
+ ) );
2851
  }
2852
 
2853
  /**
2855
  *
2856
  * You should use bp_activity_delete() instead.
2857
  *
2858
+ * @since 1.1.0
2859
+ * @deprecated 1.2.0
2860
  *
 
2861
  *
2862
+ * @param int $user_id The user id.
2863
  * @param string $component The activity component.
2864
  * @return bool True on success, false on failure.
2865
  */
2866
  function bp_activity_delete_for_user_by_component( $user_id, $component ) {
2867
+ return bp_activity_delete( array(
2868
+ 'user_id' => $user_id,
2869
+ 'component' => $component
2870
+ ) );
2871
  }
2872
 
2873
  /**
2874
  * Delete an activity comment.
2875
  *
2876
+ * @since 1.2.0
2877
  *
 
 
 
 
 
2878
  * @todo Why is an activity id required? We could look this up.
2879
  * @todo Why do we encourage users to call this function directly? We could just
2880
  * as easily examine the activity type in bp_activity_delete() and then
2882
  *
2883
  * @param int $activity_id The ID of the "root" activity, ie the comment's
2884
  * oldest ancestor.
2885
+ * @param int $comment_id The ID of the comment to be deleted.
2886
+ * @return bool True on success, false on failure.
2887
  */
2888
  function bp_activity_delete_comment( $activity_id, $comment_id ) {
2889
+ $deleted = false;
2890
+
2891
+ /**
2892
+ * Filters whether BuddyPress should delete an activity comment or not.
2893
+ *
2894
  * You may want to hook into this filter if you want to override this function and
2895
  * handle the deletion of child comments differently. Make sure you return false.
2896
+ *
2897
+ * @since 1.2.0
2898
+ * @since 2.5.0 Add the deleted parameter (passed by reference)
2899
+ *
2900
+ * @param bool $value Whether BuddyPress should continue or not.
2901
+ * @param int $activity_id ID of the root activity item being deleted.
2902
+ * @param int $comment_id ID of the comment being deleted.
2903
+ * @param bool $deleted Whether the activity comment has been deleted or not.
2904
  */
2905
+ if ( ! apply_filters_ref_array( 'bp_activity_delete_comment_pre', array( true, $activity_id, $comment_id, &$deleted ) ) ) {
2906
+ return $deleted;
2907
+ }
2908
 
2909
  // Delete any children of this comment.
2910
  bp_activity_delete_children( $activity_id, $comment_id );
2911
 
2912
+ // Delete the actual comment.
2913
+ if ( ! bp_activity_delete( array( 'id' => $comment_id, 'type' => 'activity_comment' ) ) ) {
2914
  return false;
2915
+ } else {
2916
+ $deleted = true;
2917
+ }
2918
+
2919
+ // Purge comment cache for the root activity update.
2920
+ wp_cache_delete( $activity_id, 'bp_activity_comments' );
2921
 
2922
+ // Recalculate the comment tree.
2923
  BP_Activity_Activity::rebuild_activity_comment_tree( $activity_id );
2924
 
2925
+ /**
2926
+ * Fires at the end of the deletion of an activity comment, before returning success.
2927
+ *
2928
+ * @since 1.2.0
2929
+ *
2930
+ * @param int $activity_id ID of the activity that has had a comment deleted from.
2931
+ * @param int $comment_id ID of the comment that was deleted.
2932
+ */
2933
  do_action( 'bp_activity_delete_comment', $activity_id, $comment_id );
2934
 
2935
+ return $deleted;
2936
  }
2937
 
2938
  /**
2939
  * Delete an activity comment's children.
2940
  *
2941
+ * @since 1.2.0
2942
  *
 
 
 
2943
  *
2944
  * @param int $activity_id The ID of the "root" activity, ie the
2945
  * comment's oldest ancestor.
2946
+ * @param int $comment_id The ID of the comment to be deleted.
2947
  */
2948
+ function bp_activity_delete_children( $activity_id, $comment_id ) {
2949
+
2950
+ // Get activity children to delete.
2951
+ $children = BP_Activity_Activity::get_child_comments( $comment_id );
2952
+
2953
  // Recursively delete all children of this comment.
2954
+ if ( ! empty( $children ) ) {
2955
  foreach( (array) $children as $child ) {
2956
  bp_activity_delete_children( $activity_id, $child->id );
2957
  }
2958
  }
2959
+
2960
+ // Delete the comment itself.
2961
+ bp_activity_delete( array(
2962
+ 'secondary_item_id' => $comment_id,
2963
+ 'type' => 'activity_comment',
2964
+ 'item_id' => $activity_id
2965
+ ) );
2966
  }
2967
 
2968
  /**
2973
  * be sure to pass the full $activity_obj parameter as well, if you already
2974
  * have it available.
2975
  *
2976
+ * @since 1.2.0
 
 
 
 
2977
  *
2978
+ * @param int $activity_id The unique id of the activity object.
2979
+ * @param object|bool $activity_obj Optional. The activity object.
2980
  * @return string $link Permalink for the activity item.
2981
  */
2982
  function bp_activity_get_permalink( $activity_id, $activity_obj = false ) {
2983
+ $bp = buddypress();
2984
 
2985
+ if ( empty( $activity_obj ) ) {
2986
  $activity_obj = new BP_Activity_Activity( $activity_id );
2987
+ }
2988
 
2989
  if ( isset( $activity_obj->current_comment ) ) {
2990
  $activity_obj = $activity_obj->current_comment;
2991
  }
2992
 
2993
+ $use_primary_links = array(
2994
+ 'new_blog_post',
2995
+ 'new_blog_comment',
2996
+ 'new_forum_topic',
2997
+ 'new_forum_post',
2998
+ );
2999
+
3000
+ if ( ! empty( $bp->activity->track ) ) {
3001
+ $use_primary_links = array_merge( $use_primary_links, array_keys( $bp->activity->track ) );
3002
+ }
3003
+
3004
+ if ( false !== array_search( $activity_obj->type, $use_primary_links ) ) {
3005
  $link = $activity_obj->primary_link;
3006
  } else {
3007
  if ( 'activity_comment' == $activity_obj->type ) {
3008
+ $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->item_id . '/#acomment-' . $activity_obj->id;
3009
  } else {
3010
  $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->id . '/';
3011
  }
3012
  }
3013
 
3014
+ /**
3015
+ * Filters the activity permalink for the specified activity item.
3016
+ *
3017
+ * @since 1.2.0
3018
+ *
3019
+ * @param array $array Array holding activity permalink and activity item object.
3020
+ */
3021
  return apply_filters_ref_array( 'bp_activity_get_permalink', array( $link, &$activity_obj ) );
3022
  }
3023
 
3024
  /**
3025
  * Hide a user's activity.
3026
  *
3027
+ * @since 1.2.0
 
 
3028
  *
3029
  * @param int $user_id The ID of the user whose activity is being hidden.
3030
  * @return bool True on success, false on failure.
3043
  * through the content, grabs the first image and converts it to a thumbnail,
3044
  * and removes the rest of the images from the string.
3045
  *
3046
+ * As of BuddyPress 2.3, this function is no longer in use.
3047
  *
3048
+ * @since 1.2.0
 
3049
  *
3050
+ * @param string $content The content of the activity item.
3051
+ * @param string|bool $link Optional. The unescaped URL that the image should link
3052
+ * to. If absent, the image will not be a link.
3053
+ * @param array|bool $args Optional. The args passed to the activity
3054
  * creation function (eg bp_blogs_record_activity()).
3055
  * @return string $content The content with images stripped and replaced with a
3056
  * single thumb.
3059
 
3060
  preg_match_all( '/<img[^>]*>/Ui', $content, $matches );
3061
 
3062
+ // Remove <img> tags. Also remove caption shortcodes and caption text if present.
3063
  $content = preg_replace('|(\[caption(.*?)\])?<img[^>]*>([^\[\[]*\[\/caption\])?|', '', $content );
3064
 
3065
  if ( !empty( $matches ) && !empty( $matches[0] ) ) {
 
 
3066
 
3067
+ // Get the SRC value.
3068
+ preg_match( '/<img.*?(src\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $src );
3069
+
3070
+ // Get the width and height.
3071
  preg_match( '/<img.*?(height\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $height );
3072
  preg_match( '/<img.*?(width\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $width );
3073
 
3074
+ if ( ! empty( $src ) ) {
3075
+ $src = substr( substr( str_replace( 'src=', '', $src[1] ), 0, -1 ), 1 );
3076
+
3077
+ if ( isset( $width[1] ) ) {
3078
+ $width = substr( substr( str_replace( 'width=', '', $width[1] ), 0, -1 ), 1 );
3079
+ }
3080
+
3081
+ if ( isset( $height[1] ) ) {
3082
+ $height = substr( substr( str_replace( 'height=', '', $height[1] ), 0, -1 ), 1 );
3083
+ }
3084
 
3085
  if ( empty( $width ) || empty( $height ) ) {
3086
  $width = 100;
3100
  }
3101
  }
3102
 
3103
+ /**
3104
+ * Filters the activity content that had a thumbnail replace images.
3105
+ *
3106
+ * @since 1.2.0
3107
+ *
3108
+ * @param string $content Activity content that had images replaced in.
3109
+ * @param array $matches Array of all image tags found in the posted content.
3110
+ * @param array $args Arguments passed into function creating the activity update.
3111
+ */
3112
  return apply_filters( 'bp_activity_thumbnail_content_images', $content, $matches, $args );
3113
  }
3114
 
3115
+ /**
3116
+ * Create a rich summary of an activity item for the activity stream.
3117
+ *
3118
+ * More than just a simple excerpt, the summary could contain oEmbeds and other types of media.
3119
+ * Currently, it's only used for blog post items, but it will probably be used for all types of
3120
+ * activity in the future.
3121
+ *
3122
+ * @since 2.3.0
3123
+ *
3124
+ * @param string $content The content of the activity item.
3125
+ * @param array $activity The data passed to bp_activity_add() or the values
3126
+ * from an Activity obj.
3127
+ * @return string $summary
3128
+ */
3129
+ function bp_activity_create_summary( $content, $activity ) {
3130
+ $args = array(
3131
+ 'width' => isset( $GLOBALS['content_width'] ) ? (int) $GLOBALS['content_width'] : 'medium',
3132
+ );
3133
+
3134
+ // Get the WP_Post object if this activity type is a blog post.
3135
+ if ( $activity['type'] === 'new_blog_post' ) {
3136
+ $content = get_post( $activity['secondary_item_id'] );
3137
+ }
3138
+
3139
+ /**
3140
+ * Filter the class name of the media extractor when creating an Activity summary.
3141
+ *
3142
+ * Use this filter to change the media extractor used to extract media info for the activity item.
3143
+ *
3144
+ * @since 2.3.0
3145
+ *
3146
+ * @param string $extractor Class name.
3147
+ * @param string $content The content of the activity item.
3148
+ * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj.
3149
+ */
3150
+ $extractor = apply_filters( 'bp_activity_create_summary_extractor_class', 'BP_Media_Extractor', $content, $activity );
3151
+ $extractor = new $extractor;
3152
+
3153
+ /**
3154
+ * Filter the arguments passed to the media extractor when creating an Activity summary.
3155
+ *
3156
+ * @since 2.3.0
3157
+ *
3158
+ * @param array $args Array of bespoke data for the media extractor.
3159
+ * @param string $content The content of the activity item.
3160
+ * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj.
3161
+ * @param BP_Media_Extractor $extractor The media extractor object.
3162
+ */
3163
+ $args = apply_filters( 'bp_activity_create_summary_extractor_args', $args, $content, $activity, $extractor );
3164
+
3165
+
3166
+ // Extract media information from the $content.
3167
+ $media = $extractor->extract( $content, BP_Media_Extractor::ALL, $args );
3168
+
3169
+ // If we converted $content to an object earlier, flip it back to a string.
3170
+ if ( is_a( $content, 'WP_Post' ) ) {
3171
+ $content = $content->post_content;
3172
+ }
3173
+
3174
+ $para_count = substr_count( strtolower( wpautop( $content ) ), '<p>' );
3175
+ $has_audio = ! empty( $media['has']['audio'] ) && $media['has']['audio'];
3176
+ $has_videos = ! empty( $media['has']['videos'] ) && $media['has']['videos'];
3177
+ $has_feat_image = ! empty( $media['has']['featured_images'] ) && $media['has']['featured_images'];
3178
+ $has_galleries = ! empty( $media['has']['galleries'] ) && $media['has']['galleries'];
3179
+ $has_images = ! empty( $media['has']['images'] ) && $media['has']['images'];
3180
+ $has_embeds = false;
3181
+
3182
+ // Embeds must be subtracted from the paragraph count.
3183
+ if ( ! empty( $media['has']['embeds'] ) ) {
3184
+ $has_embeds = $media['has']['embeds'] > 0;
3185
+ $para_count -= count( $media['has']['embeds'] );
3186
+ }
3187
+
3188
+ $extracted_media = array();
3189
+ $use_media_type = '';
3190
+ $image_source = '';
3191
+
3192
+ // If it's a short article and there's an embed/audio/video, use it.
3193
+ if ( $para_count <= 3 ) {
3194
+ if ( $has_embeds ) {
3195
+ $use_media_type = 'embeds';
3196
+ } elseif ( $has_audio ) {
3197
+ $use_media_type = 'audio';
3198
+ } elseif ( $has_videos ) {
3199
+ $use_media_type = 'videos';
3200
+ }
3201
+ }
3202
+
3203
+ // If not, or in any other situation, try to use an image.
3204
+ if ( ! $use_media_type && $has_images ) {
3205
+ $use_media_type = 'images';
3206
+ $image_source = 'html';
3207
+
3208
+ // Featured Image > Galleries > inline <img>.
3209
+ if ( $has_feat_image ) {
3210
+ $image_source = 'featured_images';
3211
+
3212
+ } elseif ( $has_galleries ) {
3213
+ $image_source = 'galleries';
3214
+ }
3215
+ }
3216
+
3217
+ // Extract an item from the $media results.
3218
+ if ( $use_media_type ) {
3219
+ if ( $use_media_type === 'images' ) {
3220
+ $extracted_media = wp_list_filter( $media[ $use_media_type ], array( 'source' => $image_source ) );
3221
+ $extracted_media = array_shift( $extracted_media );
3222
+ } else {
3223
+ $extracted_media = array_shift( $media[ $use_media_type ] );
3224
+ }
3225
+
3226
+ /**
3227
+ * Filter the results of the media extractor when creating an Activity summary.
3228
+ *
3229
+ * @since 2.3.0
3230
+ *
3231
+ * @param array $extracted_media Extracted media item. See {@link BP_Media_Extractor::extract()} for format.
3232
+ * @param string $content Content of the activity item.
3233
+ * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj.
3234
+ * @param array $media All results from the media extraction.
3235
+ * See {@link BP_Media_Extractor::extract()} for format.
3236
+ * @param string $use_media_type The kind of media item that was preferentially extracted.
3237
+ * @param string $image_source If $use_media_type was "images", the preferential source of the image.
3238
+ * Otherwise empty.
3239
+ */
3240
+ $extracted_media = apply_filters(
3241
+ 'bp_activity_create_summary_extractor_result',
3242
+ $extracted_media,
3243
+ $content,
3244
+ $activity,
3245
+ $media,
3246
+ $use_media_type,
3247
+ $image_source
3248
+ );
3249
+ }
3250
+
3251
+ // Generate a text excerpt for this activity item (and remove any oEmbeds URLs).
3252
+ $summary = bp_create_excerpt( html_entity_decode( $content ), 225, array(
3253
+ 'html' => false,
3254
+ 'filter_shortcodes' => true,
3255
+ 'strip_tags' => true,
3256
+ 'remove_links' => true
3257
+ ) );
3258
+
3259
+ if ( $use_media_type === 'embeds' ) {
3260
+ $summary .= PHP_EOL . PHP_EOL . $extracted_media['url'];
3261
+ } elseif ( $use_media_type === 'images' ) {
3262
+ $summary .= sprintf( ' <img src="%s">', esc_url( $extracted_media['url'] ) );
3263
+ } elseif ( in_array( $use_media_type, array( 'audio', 'videos' ), true ) ) {
3264
+ $summary .= PHP_EOL . PHP_EOL . $extracted_media['original']; // Full shortcode.
3265
+ }
3266
+
3267
+ /**
3268
+ * Filters the newly-generated summary for the activity item.
3269
+ *
3270
+ * @since 2.3.0
3271
+ *
3272
+ * @param string $summary Activity summary HTML.
3273
+ * @param string $content Content of the activity item.
3274
+ * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj.
3275
+ * @param array $extracted_media Media item extracted. See {@link BP_Media_Extractor::extract()} for format.
3276
+ */
3277
+ return apply_filters( 'bp_activity_create_summary', $summary, $content, $activity, $extracted_media );
3278
+ }
3279
+
3280
  /**
3281
  * Fetch whether the current user is allowed to mark items as spam.
3282
  *
3283
+ * @since 1.6.0
3284
  *
3285
  * @return bool True if user is allowed to mark activity items as spam.
3286
  */
3287
  function bp_activity_user_can_mark_spam() {
3288
+
3289
+ /**
3290
+ * Filters whether the current user should be able to mark items as spam.
3291
+ *
3292
+ * @since 1.6.0
3293
+ *
3294
+ * @param bool $moderate Whether or not the current user has bp_moderate capability.
3295
+ */
3296
  return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) );
3297
  }
3298
 
3299
  /**
3300
  * Mark an activity item as spam.
3301
  *
3302
+ * @since 1.6.0
3303
  *
3304
+ * @todo We should probably save $source to activity meta.
3305
  *
3306
  * @param BP_Activity_Activity $activity The activity item to be spammed.
3307
+ * @param string $source Optional. Default is "by_a_person" (ie, a person has
3308
+ * manually marked the activity as spam). BP core also
3309
+ * accepts 'by_akismet'.
3310
  */
3311
  function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) {
3312
+ $bp = buddypress();
3313
 
3314
  $activity->is_spam = 1;
3315
 
3316
+ // Clear the activity stream first page cache.
3317
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
3318
 
3319
+ // Clear the activity comment cache for this activity item.
3320
  wp_cache_delete( $activity->id, 'bp_activity_comments' );
3321
 
3322
+ // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity.
3323
  if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
3324
  remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
3325
 
3326
+ // Build data package for Akismet.
3327
  $activity_data = BP_Akismet::build_akismet_data_package( $activity );
3328
 
3329
+ // Tell Akismet this is spam.
3330
  $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' );
3331
 
3332
+ // Update meta.
3333
  add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 );
3334
  }
3335
 
3336
+ /**
3337
+ * Fires at the end of the process to mark an activity item as spam.
3338
+ *
3339
+ * @since 1.6.0
3340
+ *
3341
+ * @param BP_Activity_Activity $activity Activity item being marked as spam.
3342
+ * @param string $source Source of determination of spam status. For example
3343
+ * "by_a_person" or "by_akismet".
3344
+ */
3345
  do_action( 'bp_activity_mark_as_spam', $activity, $source );
3346
  }
3347
 
3348
  /**
3349
  * Mark an activity item as ham.
3350
  *
3351
+ * @since 1.6.0
3352
  *
3353
+ * @param BP_Activity_Activity $activity The activity item to be hammed. Passed by reference.
3354
+ * @param string $source Optional. Default is "by_a_person" (ie, a person has
3355
+ * manually marked the activity as spam). BP core also accepts
3356
+ * 'by_akismet'.
 
 
3357
  */
3358
  function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
3359
+ $bp = buddypress();
3360
 
3361
  $activity->is_spam = 0;
3362
 
3363
+ // Clear the activity stream first page cache.
3364
  wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
3365
 
3366
+ // Clear the activity comment cache for this activity item.
3367
  wp_cache_delete( $activity->id, 'bp_activity_comments' );
3368
 
3369
+ // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity.
3370
  if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
3371
  remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
3372
 
3373
+ // Build data package for Akismet.
3374
  $activity_data = BP_Akismet::build_akismet_data_package( $activity );
3375
 
3376
+ // Tell Akismet this is spam.
3377
  $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' );
3378
 
3379
+ // Update meta.
3380
  add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 );
3381
  }
3382
 
3383
+ /**
3384
+ * Fires at the end of the process to mark an activity item as ham.
3385
+ *
3386
+ * @since 1.6.0
3387
+ *
3388
+ * @param BP_Activity_Activity $activity Activity item being marked as ham.
3389
+ * @param string $source Source of determination of ham status. For example
3390
+ * "by_a_person" or "by_akismet".
3391
+ */
3392
  do_action( 'bp_activity_mark_as_ham', $activity, $source );
3393
  }
3394
 
3395
+ /* Emails *********************************************************************/
3396
+
3397
+ /**
3398
+ * Send email and BP notifications when a user is mentioned in an update.
3399
+ *
3400
+ * @since 1.2.0
3401
+ *
3402
+ * @param int $activity_id The ID of the activity update.
3403
+ * @param int $receiver_user_id The ID of the user who is receiving the update.
3404
+ */
3405
+ function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) {
3406
+ $notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' );
3407
+
3408
+ // Don't leave multiple notifications for the same activity item.
3409
+ foreach( $notifications as $notification ) {
3410
+ if ( $activity_id == $notification->item_id ) {
3411
+ return;
3412
+ }
3413
+ }
3414
+
3415
+ $activity = new BP_Activity_Activity( $activity_id );
3416
+ $email_type = 'activity-at-message';
3417
+ $group_name = '';
3418
+ $message_link = bp_activity_get_permalink( $activity_id );
3419
+ $poster_name = bp_core_get_user_displayname( $activity->user_id );
3420
+
3421
+ remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3422
+ remove_filter( 'bp_get_activity_content_body', 'wpautop' );
3423
+ remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3424
+
3425
+ /** This filter is documented in bp-activity/bp-activity-template.php */
3426
+ $content = apply_filters( 'bp_get_activity_content_body', $activity->content );
3427
+
3428
+ add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3429
+ add_filter( 'bp_get_activity_content_body', 'wpautop' );
3430
+ add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3431
+
3432
+ // Now email the user with the contents of the message (if they have enabled email notifications).
3433
+ if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
3434
+ if ( bp_is_active( 'groups' ) && bp_is_group() ) {
3435
+ $email_type = 'groups-at-message';
3436
+ $group_name = bp_get_current_group_name();
3437
+ }
3438
+
3439
+ $unsubscribe_args = array(
3440
+ 'user_id' => $receiver_user_id,
3441
+ 'notification_type' => $email_type,
3442
+ );
3443
+
3444
+ $args = array(
3445
+ 'tokens' => array(
3446
+ 'activity' => $activity,
3447
+ 'usermessage' => wp_strip_all_tags( $content ),
3448
+ 'group.name' => $group_name,
3449
+ 'mentioned.url' => $message_link,
3450
+ 'poster.name' => $poster_name,
3451
+ 'receiver-user.id' => $receiver_user_id,
3452
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
3453
+ ),
3454
+ );
3455
+
3456
+ bp_send_email( $email_type, $receiver_user_id, $args );
3457
+ }
3458
+
3459
+ /**
3460
+ * Fires after the sending of an @mention email notification.
3461
+ *
3462
+ * @since 1.5.0
3463
+ * @since 2.5.0 $subject, $message, $content arguments unset and deprecated.
3464
+ *
3465
+ * @param BP_Activity_Activity $activity Activity Item object.
3466
+ * @param string $deprecated Removed in 2.5; now an empty string.
3467
+ * @param string $deprecated Removed in 2.5; now an empty string.
3468
+ * @param string $deprecated Removed in 2.5; now an empty string.
3469
+ * @param int $receiver_user_id The ID of the user who is receiving the update.
3470
+ */
3471
+ do_action( 'bp_activity_sent_mention_email', $activity, '', '', '', $receiver_user_id );
3472
+ }
3473
+
3474
+ /**
3475
+ * Send email and BP notifications when an activity item receives a comment.
3476
+ *
3477
+ * @since 1.2.0
3478
+ * @since 2.5.0 Updated to use new email APIs.
3479
+ *
3480
+ * @param int $comment_id The comment id.
3481
+ * @param int $commenter_id The ID of the user who posted the comment.
3482
+ * @param array $params {@link bp_activity_new_comment()}.
3483
+ */
3484
+ function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) {
3485
+ $original_activity = new BP_Activity_Activity( $params['activity_id'] );
3486
+ $poster_name = bp_core_get_user_displayname( $commenter_id );
3487
+ $thread_link = bp_activity_get_permalink( $params['activity_id'] );
3488
+
3489
+ remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3490
+ remove_filter( 'bp_get_activity_content_body', 'wpautop' );
3491
+ remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3492
+
3493
+ /** This filter is documented in bp-activity/bp-activity-template.php */
3494
+ $content = apply_filters( 'bp_get_activity_content_body', $params['content'] );
3495
+
3496
+ add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
3497
+ add_filter( 'bp_get_activity_content_body', 'wpautop' );
3498
+ add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
3499
+
3500
+ if ( $original_activity->user_id != $commenter_id ) {
3501
+
3502
+ // Send an email if the user hasn't opted-out.
3503
+ if ( 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) {
3504
+
3505
+ $unsubscribe_args = array(
3506
+ 'user_id' => $original_activity->user_id,
3507
+ 'notification_type' => 'activity-comment',
3508
+ );
3509
+
3510
+ $args = array(
3511
+ 'tokens' => array(
3512
+ 'comment.id' => $comment_id,
3513
+ 'commenter.id' => $commenter_id,
3514
+ 'usermessage' => wp_strip_all_tags( $content ),
3515
+ 'original_activity.user_id' => $original_activity->user_id,
3516
+ 'poster.name' => $poster_name,
3517
+ 'thread.url' => esc_url( $thread_link ),
3518
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
3519
+ ),
3520
+ );
3521
+
3522
+ bp_send_email( 'activity-comment', $original_activity->user_id, $args );
3523
+ }
3524
+
3525
+ /**
3526
+ * Fires at the point that notifications should be sent for activity comments.
3527
+ *
3528
+ * @since 2.6.0
3529
+ *
3530
+ * @param BP_Activity_Activity $original_activity The original activity.
3531
+ * @param int $comment_id ID for the newly received comment.
3532
+ * @param int $commenter_id ID of the user who made the comment.
3533
+ * @param array $params Arguments used with the original activity comment.
3534
+ */
3535
+ do_action( 'bp_activity_sent_reply_to_update_notification', $original_activity, $comment_id, $commenter_id, $params );
3536
+ }
3537
+
3538
+
3539
+ /*
3540
+ * If this is a reply to another comment, send an email notification to the
3541
+ * author of the immediate parent comment.
3542
+ */
3543
+ if ( empty( $params['parent_id'] ) || ( $params['activity_id'] == $params['parent_id'] ) ) {
3544
+ return;
3545
+ }
3546
+
3547
+ $parent_comment = new BP_Activity_Activity( $params['parent_id'] );
3548
+
3549
+ if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id ) {
3550
+
3551
+ // Send an email if the user hasn't opted-out.
3552
+ if ( 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) {
3553
+
3554
+ $unsubscribe_args = array(
3555
+ 'user_id' => $parent_comment->user_id,
3556
+ 'notification_type' => 'activity-comment-author',
3557
+ );
3558
+
3559
+ $args = array(
3560
+ 'tokens' => array(
3561
+ 'comment.id' => $comment_id,
3562
+ 'commenter.id' => $commenter_id,
3563
+ 'usermessage' => wp_strip_all_tags( $content ),
3564
+ 'parent-comment-user.id' => $parent_comment->user_id,
3565
+ 'poster.name' => $poster_name,
3566
+ 'thread.url' => esc_url( $thread_link ),
3567
+ 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
3568
+ ),
3569
+ );
3570
+
3571
+ bp_send_email( 'activity-comment-author', $parent_comment->user_id, $args );
3572
+ }
3573
+
3574
+ /**
3575
+ * Fires at the point that notifications should be sent for comments on activity replies.
3576
+ *
3577
+ * @since 2.6.0
3578
+ *
3579
+ * @param BP_Activity_Activity $parent_comment The parent activity.
3580
+ * @param int $comment_id ID for the newly received comment.
3581
+ * @param int $commenter_id ID of the user who made the comment.
3582
+ * @param array $params Arguments used with the original activity comment.
3583
+ */
3584
+ do_action( 'bp_activity_sent_reply_to_reply_notification', $parent_comment, $comment_id, $commenter_id, $params );
3585
+ }
3586
+ }
3587
+
3588
+ /**
3589
+ * Helper method to map action arguments to function parameters.
3590
+ *
3591
+ * @since 1.9.0
3592
+ *
3593
+ * @param int $comment_id ID of the comment being notified about.
3594
+ * @param array $params Parameters to use with notification.
3595
+ */
3596
+ function bp_activity_new_comment_notification_helper( $comment_id, $params ) {
3597
+ bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params );
3598
+ }
3599
+ add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 );
3600
 
3601
  /** Embeds *******************************************************************/
3602
 
3610
  * This does not cover recursive activity comments, as they do not use a real loop.
3611
  * For that, see {@link bp_activity_comment_embed()}.
3612
  *
3613
+ * @since 1.5.0
3614
  *
3615
  * @see BP_Embed
3616
  * @see bp_embed_activity_cache()
3617
  * @see bp_embed_activity_save_cache()
3618
+ *
 
 
3619
  */
3620
  function bp_activity_embed() {
3621
  add_filter( 'embed_post_id', 'bp_get_activity_id' );
3622
+ add_filter( 'oembed_dataparse', 'bp_activity_oembed_dataparse', 10, 2 );
3623
  add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
3624
  add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
3625
  }
3626
  add_action( 'activity_loop_start', 'bp_activity_embed' );
3627
 
3628
+ /**
3629
+ * Cache full oEmbed response from oEmbed.
3630
+ *
3631
+ * @since 2.6.0
3632
+ *
3633
+ * @param string $retval Current oEmbed result.
3634
+ * @param object $data Full oEmbed response.
3635
+ * @param string $url URL used for the oEmbed request.
3636
+ * @return string
3637
+ */
3638
+ function bp_activity_oembed_dataparse( $retval, $data ) {
3639
+ buddypress()->activity->oembed_response = $data;
3640
+
3641
+ return $retval;
3642
+ }
3643
+
3644
  /**
3645
  * Set up activity oEmbed cache while recursing through activity comments.
3646
  *
3649
  * necessary to grab each comment's embeds from the cache, or put them in
3650
  * the cache if they are not there yet.
3651
  *
3652
+ * @since 1.5.0
3653
  *
3654
  * @see BP_Embed
3655
  * @see bp_embed_activity_cache()
3656
  * @see bp_embed_activity_save_cache()
3657
+ *
 
 
3658
  */
3659
  function bp_activity_comment_embed() {
3660
  add_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
3666
  /**
3667
  * When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content.
3668
  *
3669
+ * @since 1.5.0
3670
  *
3671
  * @see BP_Embed
 
 
 
 
3672
  *
3673
  * @param object $activity The activity that is being expanded.
3674
  */
3675
  function bp_dtheme_embed_read_more( $activity ) {
3676
+ buddypress()->activity->read_more_id = $activity->id;
3677
 
3678
+ add_filter( 'embed_post_id', create_function( '', 'return buddypress()->activity->read_more_id;' ) );
3679
+ add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
3680
+ add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
 
 
3681
  }
3682
+ add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
3683
+ add_action( 'bp_legacy_theme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
3684
 
3685
  /**
3686
  * Clean up 'embed_post_id' filter after comment recursion.
3688
  * This filter must be removed so that the non-comment filters take over again
3689
  * once the comments are done being processed.
3690
  *
3691
+ * @since 1.5.0
3692
  *
3693
  * @see bp_activity_comment_embed()
 
3694
  */
3695
  function bp_activity_comment_embed_after_recurse() {
3696
  remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
3702
  *
3703
  * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
3704
  *
3705
+ * @since 1.5.0
3706
  *
3707
  * @see BP_Embed::parse_oembed()
 
3708
  *
3709
+ * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
3710
+ * functions like this one to filter.
3711
+ * @param int $id The ID of the activity item.
3712
  * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
3713
  * @return mixed The cached embeds for this activity item.
3714
  */
3721
  *
3722
  * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
3723
  *
3724
+ * @since 1.5.0
3725
  *
3726
  * @see BP_Embed::parse_oembed()
 
3727
  *
3728
+ * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
3729
+ * functions like this one to filter.
 
3730
  * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
3731
+ * @param int $id The ID of the activity item.
3732
  */
3733
  function bp_embed_activity_save_cache( $cache, $cachekey, $id ) {
3734
  bp_activity_update_meta( $id, $cachekey, $cache );
3735
+
3736
+ // Cache full oEmbed response.
3737
+ if ( true === isset( buddypress()->activity->oembed_response ) ) {
3738
+ $cachekey = str_replace( '_oembed', '_oembed_response', $cachekey );
3739
+ bp_activity_update_meta( $id, $cachekey, buddypress()->activity->oembed_response );
3740
+ }
3741
  }
3742
 
3743
  /**
3744
  * Should we use Heartbeat to refresh activities?
3745
  *
3746
+ * @since 2.0.0
3747
  *
 
 
3748
  * directory.
 
 
3749
  * is the group activities.
 
 
3750
  *
3751
  * @return bool True if activity heartbeat is enabled, otherwise false.
3752
  */
3757
  return $retval;
3758
  }
3759
 
3760
+ if ( bp_is_activity_directory() || bp_is_group_activity() ) {
3761
  $retval = true;
3762
  }
3763
 
 
 
 
 
 
 
 
 
 
3764
  return $retval;
3765
  }
bp-activity/bp-activity-loader.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Activity Streams Loader.
5
  *
@@ -7,362 +6,20 @@
7
  *
8
  * @package BuddyPress
9
  * @subpackage ActivityCore
 
10
  */
11
 
12
- // Exit if accessed directly
13
- if ( !defined( 'ABSPATH' ) ) exit;
14
-
15
- /**
16
- * Main Activity Class.
17
- *
18
- * @since BuddyPress (1.5)
19
- */
20
- class BP_Activity_Component extends BP_Component {
21
-
22
- /**
23
- * Start the activity component setup process.
24
- *
25
- * @since BuddyPress (1.5)
26
- */
27
- public function __construct() {
28
- parent::start(
29
- 'activity',
30
- __( 'Activity Streams', 'buddypress' ),
31
- buddypress()->plugin_dir,
32
- array(
33
- 'adminbar_myaccount_order' => 10
34
- )
35
- );
36
- }
37
-
38
- /**
39
- * Include component files.
40
- *
41
- * @since BuddyPress (1.5)
42
- *
43
- * @see BP_Component::includes() for a description of arguments.
44
- *
45
- * @param array $includes See BP_Component::includes() for a description.
46
- */
47
- public function includes( $includes = array() ) {
48
- // Files to include
49
- $includes = array(
50
- 'actions',
51
- 'screens',
52
- 'filters',
53
- 'classes',
54
- 'template',
55
- 'functions',
56
- 'notifications',
57
- 'cache'
58
- );
59
-
60
- // Load Akismet support if Akismet is configured
61
- $akismet_key = bp_get_option( 'wordpress_api_key' );
62
- if ( defined( 'AKISMET_VERSION' ) && ( !empty( $akismet_key ) || defined( 'WPCOM_API_KEY' ) ) && apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
63
- $includes[] = 'akismet';
64
- }
65
-
66
- if ( is_admin() ) {
67
- $includes[] = 'admin';
68
- }
69
-
70
- parent::includes( $includes );
71
- }
72
-
73
- /**
74
- * Set up component global variables.
75
- *
76
- * The BP_ACTIVITY_SLUG constant is deprecated, and only used here for
77
- * backwards compatibility.
78
- *
79
- * @since BuddyPress (1.5)
80
- *
81
- * @see BP_Component::setup_globals() for a description of arguments.
82
- *
83
- * @param array $args See BP_Component::setup_globals() for a description.
84
- */
85
- public function setup_globals( $args = array() ) {
86
- $bp = buddypress();
87
-
88
- // Define a slug, if necessary
89
- if ( !defined( 'BP_ACTIVITY_SLUG' ) )
90
- define( 'BP_ACTIVITY_SLUG', $this->id );
91
-
92
- // Global tables for activity component
93
- $global_tables = array(
94
- 'table_name' => $bp->table_prefix . 'bp_activity',
95
- 'table_name_meta' => $bp->table_prefix . 'bp_activity_meta',
96
- );
97
-
98
- // Metadata tables for groups component
99
- $meta_tables = array(
100
- 'activity' => $bp->table_prefix . 'bp_activity_meta',
101
- );
102
-
103
- // All globals for activity component.
104
- // Note that global_tables is included in this array.
105
- $args = array(
106
- 'slug' => BP_ACTIVITY_SLUG,
107
- 'root_slug' => isset( $bp->pages->activity->slug ) ? $bp->pages->activity->slug : BP_ACTIVITY_SLUG,
108
- 'has_directory' => true,
109
- 'directory_title' => _x( 'Sitewide Activity', 'component directory title', 'buddypress' ),
110
- 'notification_callback' => 'bp_activity_format_notifications',
111
- 'search_string' => __( 'Search Activity...', 'buddypress' ),
112
- 'global_tables' => $global_tables,
113
- 'meta_tables' => $meta_tables,
114
- );
115
-
116
- parent::setup_globals( $args );
117
- }
118
-
119
- /**
120
- * Set up component navigation.
121
- *
122
- * @since BuddyPress (1.5)
123
- *
124
- * @see BP_Component::setup_nav() for a description of arguments.
125
- * @uses bp_is_active()
126
- * @uses is_user_logged_in()
127
- * @uses bp_get_friends_slug()
128
- * @uses bp_get_groups_slug()
129
- *
130
- * @param array $main_nav Optional. See BP_Component::setup_nav() for
131
- * description.
132
- * @param array $sub_nav Optional. See BP_Component::setup_nav() for
133
- * description.
134
- */
135
- public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
136
-
137
- // Add 'Activity' to the main navigation
138
- $main_nav = array(
139
- 'name' => __( 'Activity', 'buddypress' ),
140
- 'slug' => $this->slug,
141
- 'position' => 10,
142
- 'screen_function' => 'bp_activity_screen_my_activity',
143
- 'default_subnav_slug' => 'just-me',
144
- 'item_css_id' => $this->id
145
- );
146
-
147
- // Stop if there is no user displayed or logged in
148
- if ( !is_user_logged_in() && !bp_displayed_user_id() )
149
- return;
150
-
151
- // Determine user to use
152
- if ( bp_displayed_user_domain() ) {
153
- $user_domain = bp_displayed_user_domain();
154
- } elseif ( bp_loggedin_user_domain() ) {
155
- $user_domain = bp_loggedin_user_domain();
156
- } else {
157
- return;
158
- }
159
-
160
- // User link
161
- $activity_link = trailingslashit( $user_domain . $this->slug );
162
-
163
- // Add the subnav items to the activity nav item if we are using a theme that supports this
164
- $sub_nav[] = array(
165
- 'name' => __( 'Personal', 'buddypress' ),
166
- 'slug' => 'just-me',
167
- 'parent_url' => $activity_link,
168
- 'parent_slug' => $this->slug,
169
- 'screen_function' => 'bp_activity_screen_my_activity',
170
- 'position' => 10
171
- );
172
 
173
- // @ mentions
174
- if ( bp_activity_do_mentions() ) {
175
- $sub_nav[] = array(
176
- 'name' => __( 'Mentions', 'buddypress' ),
177
- 'slug' => 'mentions',
178
- 'parent_url' => $activity_link,
179
- 'parent_slug' => $this->slug,
180
- 'screen_function' => 'bp_activity_screen_mentions',
181
- 'position' => 20,
182
- 'item_css_id' => 'activity-mentions'
183
- );
184
- }
185
-
186
- // Favorite activity items
187
- $sub_nav[] = array(
188
- 'name' => __( 'Favorites', 'buddypress' ),
189
- 'slug' => 'favorites',
190
- 'parent_url' => $activity_link,
191
- 'parent_slug' => $this->slug,
192
- 'screen_function' => 'bp_activity_screen_favorites',
193
- 'position' => 30,
194
- 'item_css_id' => 'activity-favs'
195
- );
196
-
197
- // Additional menu if friends is active
198
- if ( bp_is_active( 'friends' ) ) {
199
- $sub_nav[] = array(
200
- 'name' => __( 'Friends', 'buddypress' ),
201
- 'slug' => bp_get_friends_slug(),
202
- 'parent_url' => $activity_link,
203
- 'parent_slug' => $this->slug,
204
- 'screen_function' => 'bp_activity_screen_friends',
205
- 'position' => 40,
206
- 'item_css_id' => 'activity-friends'
207
- ) ;
208
- }
209
-
210
- // Additional menu if groups is active
211
- if ( bp_is_active( 'groups' ) ) {
212
- $sub_nav[] = array(
213
- 'name' => __( 'Groups', 'buddypress' ),
214
- 'slug' => bp_get_groups_slug(),
215
- 'parent_url' => $activity_link,
216
- 'parent_slug' => $this->slug,
217
- 'screen_function' => 'bp_activity_screen_groups',
218
- 'position' => 50,
219
- 'item_css_id' => 'activity-groups'
220
- );
221
- }
222
-
223
- parent::setup_nav( $main_nav, $sub_nav );
224
- }
225
-
226
- /**
227
- * Set up the component entries in the WordPress Admin Bar.
228
- *
229
- * @since BuddyPress (1.5)
230
- *
231
- * @see BP_Component::setup_nav() for a description of the $wp_admin_nav
232
- * parameter array.
233
- * @uses is_user_logged_in()
234
- * @uses trailingslashit()
235
- * @uses bp_get_total_mention_count_for_user()
236
- * @uses bp_loggedin_user_id()
237
- * @uses bp_is_active()
238
- * @uses bp_get_friends_slug()
239
- * @uses bp_get_groups_slug()
240
- *
241
- * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a
242
- * description.
243
- */
244
- public function setup_admin_bar( $wp_admin_nav = array() ) {
245
- $bp = buddypress();
246
-
247
- // Menus for logged in user
248
- if ( is_user_logged_in() ) {
249
-
250
- // Setup the logged in user variables
251
- $user_domain = bp_loggedin_user_domain();
252
- $activity_link = trailingslashit( $user_domain . $this->slug );
253
-
254
- // Unread message count
255
- if ( bp_activity_do_mentions() ) {
256
- $count = bp_get_total_mention_count_for_user( bp_loggedin_user_id() );
257
- if ( !empty( $count ) ) {
258
- $title = sprintf( __( 'Mentions <span class="count">%s</span>', 'buddypress' ), number_format_i18n( $count ) );
259
- } else {
260
- $title = __( 'Mentions', 'buddypress' );
261
- }
262
- }
263
-
264
- // Add the "Activity" sub menu
265
- $wp_admin_nav[] = array(
266
- 'parent' => $bp->my_account_menu_id,
267
- 'id' => 'my-account-' . $this->id,
268
- 'title' => __( 'Activity', 'buddypress' ),
269
- 'href' => trailingslashit( $activity_link )
270
- );
271
-
272
- // Personal
273
- $wp_admin_nav[] = array(
274
- 'parent' => 'my-account-' . $this->id,
275
- 'id' => 'my-account-' . $this->id . '-personal',
276
- 'title' => __( 'Personal', 'buddypress' ),
277
- 'href' => trailingslashit( $activity_link )
278
- );
279
-
280
- // Mentions
281
- if ( bp_activity_do_mentions() ) {
282
- $wp_admin_nav[] = array(
283
- 'parent' => 'my-account-' . $this->id,
284
- 'id' => 'my-account-' . $this->id . '-mentions',
285
- 'title' => $title,
286
- 'href' => trailingslashit( $activity_link . 'mentions' )
287
- );
288
- }
289
-
290
- // Favorites
291
- $wp_admin_nav[] = array(
292
- 'parent' => 'my-account-' . $this->id,
293
- 'id' => 'my-account-' . $this->id . '-favorites',
294
- 'title' => __( 'Favorites', 'buddypress' ),
295
- 'href' => trailingslashit( $activity_link . 'favorites' )
296
- );
297
-
298
- // Friends?
299
- if ( bp_is_active( 'friends' ) ) {
300
- $wp_admin_nav[] = array(
301
- 'parent' => 'my-account-' . $this->id,
302
- 'id' => 'my-account-' . $this->id . '-friends',
303
- 'title' => __( 'Friends', 'buddypress' ),
304
- 'href' => trailingslashit( $activity_link . bp_get_friends_slug() )
305
- );
306
- }
307
-
308
- // Groups?
309
- if ( bp_is_active( 'groups' ) ) {
310
- $wp_admin_nav[] = array(
311
- 'parent' => 'my-account-' . $this->id,
312
- 'id' => 'my-account-' . $this->id . '-groups',
313
- 'title' => __( 'Groups', 'buddypress' ),
314
- 'href' => trailingslashit( $activity_link . bp_get_groups_slug() )
315
- );
316
- }
317
- }
318
-
319
- parent::setup_admin_bar( $wp_admin_nav );
320
- }
321
-
322
- /**
323
- * Set up the title for pages and <title>.
324
- *
325
- * @since BuddyPress (1.5)
326
- *
327
- * @uses bp_is_activity_component()
328
- * @uses bp_is_my_profile()
329
- * @uses bp_core_fetch_avatar()
330
- */
331
- public function setup_title() {
332
- $bp = buddypress();
333
-
334
- // Adjust title based on view
335
- if ( bp_is_activity_component() ) {
336
- if ( bp_is_my_profile() ) {
337
- $bp->bp_options_title = __( 'My Activity', 'buddypress' );
338
- } else {
339
- $bp->bp_options_avatar = bp_core_fetch_avatar( array(
340
- 'item_id' => bp_displayed_user_id(),
341
- 'type' => 'thumb',
342
- 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
343
- ) );
344
- $bp->bp_options_title = bp_get_displayed_user_fullname();
345
- }
346
- }
347
-
348
- parent::setup_title();
349
- }
350
-
351
- /**
352
- * Set up actions necessary for the component.
353
- *
354
- * @since BuddyPress (1.6)
355
- */
356
- public function setup_actions() {
357
- // Spam prevention
358
- add_action( 'bp_include', 'bp_activity_setup_akismet' );
359
-
360
- parent::setup_actions();
361
- }
362
  }
363
 
364
  /**
365
- * Bootstrap the Activity component.
 
 
366
  */
367
  function bp_setup_activity() {
368
  buddypress()->activity = new BP_Activity_Component();
1
  <?php
 
2
  /**
3
  * BuddyPress Activity Streams Loader.
4
  *
6
  *
7
  * @package BuddyPress
8
  * @subpackage ActivityCore
9
+ * @since 1.5.0
10
  */
11
 
12
+ // Exit if accessed directly.
13
+ defined( 'ABSPATH' ) || exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ if ( ! buddypress()->do_autoload ) {
16
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-component.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
 
19
  /**
20
+ * Set up the bp-activity component.
21
+ *
22
+ * @since 1.6.0
23
  */
24
  function bp_setup_activity() {
25
  buddypress()->activity = new BP_Activity_Component();
bp-activity/bp-activity-notifications.php CHANGED
@@ -1,304 +1,134 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Activity Notifications.
5
  *
6
  * @package BuddyPress
7
  * @subpackage ActivityNotifications
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
12
-
13
- /* Emails *********************************************************************/
14
-
15
- /**
16
- * Send email and BP notifications when a user is mentioned in an update.
17
- *
18
- * @since BuddyPress (1.2)
19
- *
20
- * @uses bp_notifications_add_notification()
21
- * @uses bp_get_user_meta()
22
- * @uses bp_core_get_user_displayname()
23
- * @uses bp_activity_get_permalink()
24
- * @uses bp_core_get_user_domain()
25
- * @uses bp_get_settings_slug()
26
- * @uses bp_activity_filter_kses()
27
- * @uses bp_core_get_core_userdata()
28
- * @uses wp_specialchars_decode()
29
- * @uses get_blog_option()
30
- * @uses bp_is_active()
31
- * @uses bp_is_group()
32
- * @uses bp_get_current_group_name()
33
- * @uses apply_filters() To call the 'bp_activity_at_message_notification_to' hook.
34
- * @uses apply_filters() To call the 'bp_activity_at_message_notification_subject' hook.
35
- * @uses apply_filters() To call the 'bp_activity_at_message_notification_message' hook.
36
- * @uses wp_mail()
37
- * @uses do_action() To call the 'bp_activity_sent_mention_email' hook
38
- *
39
- * @param int $activity_id The ID of the activity update.
40
- * @param int $receiver_user_id The ID of the user who is receiving the update.
41
- */
42
- function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) {
43
-
44
- // Don't leave multiple notifications for the same activity item
45
- $notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' );
46
-
47
- foreach( $notifications as $notification ) {
48
- if ( $activity_id == $notification->item_id ) {
49
- return;
50
- }
51
- }
52
-
53
- $activity = new BP_Activity_Activity( $activity_id );
54
-
55
- $subject = '';
56
- $message = '';
57
- $content = '';
58
-
59
- // Now email the user with the contents of the message (if they have enabled email notifications)
60
- if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
61
- $poster_name = bp_core_get_user_displayname( $activity->user_id );
62
-
63
- $message_link = bp_activity_get_permalink( $activity_id );
64
- $settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
65
- $settings_link = bp_core_get_user_domain( $receiver_user_id ) . $settings_slug . '/notifications/';
66
-
67
- $poster_name = stripslashes( $poster_name );
68
- $content = bp_activity_filter_kses( strip_tags( stripslashes( $activity->content ) ) );
69
-
70
- // Set up and send the message
71
- $ud = bp_core_get_core_userdata( $receiver_user_id );
72
- $to = $ud->user_email;
73
- $subject = bp_get_email_subject( array( 'text' => sprintf( __( '%s mentioned you in an update', 'buddypress' ), $poster_name ) ) );
74
-
75
- if ( bp_is_active( 'groups' ) && bp_is_group() ) {
76
- $message = sprintf( __(
77
- '%1$s mentioned you in the group "%2$s":
78
-
79
- "%3$s"
80
-
81
- To view and respond to the message, log in and visit: %4$s
82
-
83
- ---------------------
84
- ', 'buddypress' ), $poster_name, bp_get_current_group_name(), $content, $message_link );
85
- } else {
86
- $message = sprintf( __(
87
- '%1$s mentioned you in an update:
88
-
89
- "%2$s"
90
-
91
- To view and respond to the message, log in and visit: %3$s
92
-
93
- ---------------------
94
- ', 'buddypress' ), $poster_name, $content, $message_link );
95
- }
96
-
97
- // Only show the disable notifications line if the settings component is enabled
98
- if ( bp_is_active( 'settings' ) ) {
99
- $message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
100
- }
101
-
102
- // Send the message
103
- $to = apply_filters( 'bp_activity_at_message_notification_to', $to );
104
- $subject = apply_filters( 'bp_activity_at_message_notification_subject', $subject, $poster_name );
105
- $message = apply_filters( 'bp_activity_at_message_notification_message', $message, $poster_name, $content, $message_link, $settings_link );
106
-
107
- wp_mail( $to, $subject, $message );
108
- }
109
-
110
- do_action( 'bp_activity_sent_mention_email', $activity, $subject, $message, $content, $receiver_user_id );
111
- }
112
-
113
- /**
114
- * Send email and BP notifications when an activity item receives a comment.
115
- *
116
- * @since BuddyPress (1.2)
117
- *
118
- * @uses bp_get_user_meta()
119
- * @uses bp_core_get_user_displayname()
120
- * @uses bp_activity_get_permalink()
121
- * @uses bp_core_get_user_domain()
122
- * @uses bp_get_settings_slug()
123
- * @uses bp_activity_filter_kses()
124
- * @uses bp_core_get_core_userdata()
125
- * @uses wp_specialchars_decode()
126
- * @uses get_blog_option()
127
- * @uses bp_get_root_blog_id()
128
- * @uses apply_filters() To call the 'bp_activity_new_comment_notification_to' hook
129
- * @uses apply_filters() To call the 'bp_activity_new_comment_notification_subject' hook
130
- * @uses apply_filters() To call the 'bp_activity_new_comment_notification_message' hook
131
- * @uses wp_mail()
132
- * @uses do_action() To call the 'bp_activity_sent_reply_to_update_email' hook
133
- * @uses apply_filters() To call the 'bp_activity_new_comment_notification_comment_author_to' hook
134
- * @uses apply_filters() To call the 'bp_activity_new_comment_notification_comment_author_subject' hook
135
- * @uses apply_filters() To call the 'bp_activity_new_comment_notification_comment_author_message' hook
136
- * @uses do_action() To call the 'bp_activity_sent_reply_to_reply_email' hook
137
- *
138
- * @param int $comment_id The comment id.
139
- * @param int $commenter_id The ID of the user who posted the comment.
140
- * @param array $params {@link bp_activity_new_comment()}
141
- */
142
- function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) {
143
-
144
- // Set some default parameters
145
- $activity_id = 0;
146
- $parent_id = 0;
147
-
148
- extract( $params );
149
-
150
- $original_activity = new BP_Activity_Activity( $activity_id );
151
-
152
- if ( $original_activity->user_id != $commenter_id && 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) {
153
- $poster_name = bp_core_get_user_displayname( $commenter_id );
154
- $thread_link = bp_activity_get_permalink( $activity_id );
155
- $settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
156
- $settings_link = bp_core_get_user_domain( $original_activity->user_id ) . $settings_slug . '/notifications/';
157
-
158
- $poster_name = stripslashes( $poster_name );
159
- $content = bp_activity_filter_kses( stripslashes($content) );
160
-
161
- // Set up and send the message
162
- $ud = bp_core_get_core_userdata( $original_activity->user_id );
163
- $to = $ud->user_email;
164
- $subject = bp_get_email_subject( array( 'text' => sprintf( __( '%s replied to one of your updates', 'buddypress' ), $poster_name ) ) );
165
- $message = sprintf( __(
166
- '%1$s replied to one of your updates:
167
-
168
- "%2$s"
169
-
170
- To view your original update and all comments, log in and visit: %3$s
171
-
172
- ---------------------
173
- ', 'buddypress' ), $poster_name, $content, $thread_link );
174
-
175
- // Only show the disable notifications line if the settings component is enabled
176
- if ( bp_is_active( 'settings' ) ) {
177
- $message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
178
- }
179
-
180
- /* Send the message */
181
- $to = apply_filters( 'bp_activity_new_comment_notification_to', $to );
182
- $subject = apply_filters( 'bp_activity_new_comment_notification_subject', $subject, $poster_name );
183
- $message = apply_filters( 'bp_activity_new_comment_notification_message', $message, $poster_name, $content, $thread_link, $settings_link );
184
-
185
- wp_mail( $to, $subject, $message );
186
-
187
- do_action( 'bp_activity_sent_reply_to_update_email', $original_activity->user_id, $subject, $message, $comment_id, $commenter_id, $params );
188
- }
189
-
190
- /***
191
- * If this is a reply to another comment, send an email notification to the
192
- * author of the immediate parent comment.
193
- */
194
- if ( empty( $parent_id ) || ( $activity_id == $parent_id ) ) {
195
- return false;
196
- }
197
-
198
- $parent_comment = new BP_Activity_Activity( $parent_id );
199
-
200
- if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id && 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) {
201
- $poster_name = bp_core_get_user_displayname( $commenter_id );
202
- $thread_link = bp_activity_get_permalink( $activity_id );
203
- $settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
204
- $settings_link = bp_core_get_user_domain( $parent_comment->user_id ) . $settings_slug . '/notifications/';
205
-
206
- // Set up and send the message
207
- $ud = bp_core_get_core_userdata( $parent_comment->user_id );
208
- $to = $ud->user_email;
209
- $subject = bp_get_email_subject( array( 'text' => sprintf( __( '%s replied to one of your comments', 'buddypress' ), $poster_name ) ) );
210
-
211
- $poster_name = stripslashes( $poster_name );
212
- $content = bp_activity_filter_kses( stripslashes( $content ) );
213
-
214
- $message = sprintf( __(
215
- '%1$s replied to one of your comments:
216
-
217
- "%2$s"
218
-
219
- To view the original activity, your comment and all replies, log in and visit: %3$s
220
-
221
- ---------------------
222
- ', 'buddypress' ), $poster_name, $content, $thread_link );
223
-
224
- // Only show the disable notifications line if the settings component is enabled
225
- if ( bp_is_active( 'settings' ) ) {
226
- $message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
227
- }
228
-
229
- /* Send the message */
230
- $to = apply_filters( 'bp_activity_new_comment_notification_comment_author_to', $to );
231
- $subject = apply_filters( 'bp_activity_new_comment_notification_comment_author_subject', $subject, $poster_name );
232
- $message = apply_filters( 'bp_activity_new_comment_notification_comment_author_message', $message, $poster_name, $content, $settings_link, $thread_link );
233
-
234
- wp_mail( $to, $subject, $message );
235
-
236
- do_action( 'bp_activity_sent_reply_to_reply_email', $original_activity->user_id, $subject, $message, $comment_id, $commenter_id, $params );
237
- }
238
- }
239
-
240
- /**
241
- * Helper method to map action arguments to function parameters
242
- *
243
- * @since BuddyPress (1.9.0)
244
- * @param int $comment_id
245
- * @param array $params
246
- */
247
- function bp_activity_new_comment_notification_helper( $comment_id, $params ) {
248
- bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params );
249
- }
250
- add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 );
251
-
252
- /** Notifications *************************************************************/
253
 
254
  /**
255
  * Format notifications related to activity.
256
  *
257
- * @since BuddyPress (1.5)
258
  *
259
- * @uses bp_loggedin_user_domain()
260
- * @uses bp_get_activity_slug()
261
- * @uses bp_core_get_user_displayname()
262
- * @uses apply_filters() To call the 'bp_activity_multiple_at_mentions_notification' hook.
263
- * @uses apply_filters() To call the 'bp_activity_single_at_mentions_notification' hook.
264
- * @uses do_action() To call 'activity_format_notifications' hook.
265
- *
266
- * @param string $action The type of activity item. Just 'new_at_mention' for now.
267
- * @param int $item_id The activity ID.
268
- * @param int $secondary_item_id In the case of at-mentions, this is the mentioner's ID.
269
- * @param int $total_items The total number of notifications to format.
270
- * @param string $format 'string' to get a BuddyBar-compatible notification, 'array' otherwise.
271
  * @return string $return Formatted @mention notification.
272
  */
273
- function bp_activity_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
 
 
 
 
 
274
 
275
  switch ( $action ) {
276
  case 'new_at_mention':
277
- $activity_id = $item_id;
278
- $poster_user_id = $secondary_item_id;
279
- $at_mention_link = bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/';
280
- $at_mention_title = sprintf( __( '@%s Mentions', 'buddypress' ), bp_get_loggedin_user_username() );
281
 
282
  if ( (int) $total_items > 1 ) {
283
- $text = sprintf( __( 'You have %1$d new mentions', 'buddypress' ), (int) $total_items );
284
- $filter = 'bp_activity_multiple_at_mentions_notification';
285
  } else {
286
- $user_fullname = bp_core_get_user_displayname( $poster_user_id );
287
- $text = sprintf( __( '%1$s mentioned you', 'buddypress' ), $user_fullname );
288
- $filter = 'bp_activity_single_at_mentions_notification';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  }
290
  break;
291
  }
292
 
293
  if ( 'string' == $format ) {
294
- $return = apply_filters( $filter, '<a href="' . esc_url( $at_mention_link ) . '" title="' . esc_attr( $at_mention_title ) . '">' . esc_html( $text ) . '</a>', $at_mention_link, (int) $total_items, $activity_id, $poster_user_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  } else {
296
- $return = apply_filters( $filter, array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  'text' => $text,
298
- 'link' => $at_mention_link
299
- ), $at_mention_link, (int) $total_items, $activity_id, $poster_user_id );
300
  }
301
 
 
 
 
 
 
 
 
 
 
 
302
  do_action( 'activity_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
303
 
304
  return $return;
@@ -312,17 +142,16 @@ function bp_activity_format_notifications( $action, $item_id, $secondary_item_id
312
  * future when we separate emails from Notifications, this will need its own
313
  * 'bp_activity_at_name_send_emails' equivalent helper function.
314
  *
315
- * @since BuddyPress (1.9.0)
316
  *
317
- * @param obj $activity
318
- * @param string $subject (not used)
319
- * @param string $message (not used)
320
- * @param string $content (not used)
321
- * @param int $receiver_user_id
322
  */
323
  function bp_activity_at_mention_add_notification( $activity, $subject, $message, $content, $receiver_user_id ) {
324
- if ( bp_is_active( 'notifications' ) ) {
325
- bp_notifications_add_notification( array(
326
  'user_id' => $receiver_user_id,
327
  'item_id' => $activity->id,
328
  'secondary_item_id' => $activity->user_id,
@@ -330,66 +159,183 @@ function bp_activity_at_mention_add_notification( $activity, $subject, $message,
330
  'component_action' => 'new_at_mention',
331
  'date_notified' => bp_core_current_time(),
332
  'is_new' => 1,
333
- ) );
334
- }
335
  }
336
  add_action( 'bp_activity_sent_mention_email', 'bp_activity_at_mention_add_notification', 10, 5 );
337
 
338
  /**
339
- * Mark at-mention notifications as read when users visit their Mentions page.
340
  *
341
- * @since BuddyPress (1.5)
342
  *
343
- * @uses bp_notifications_mark_all_notifications_by_type()
 
 
344
  */
345
- function bp_activity_remove_screen_notifications() {
346
- if ( ! bp_is_active( 'notifications' ) ) {
347
- return;
348
- }
 
 
 
 
 
 
 
 
349
 
350
- // Only mark read if you're looking at your own mentions
351
- if ( ! bp_is_my_profile() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  return;
353
  }
354
 
355
- bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->activity->id, 'new_at_mention' );
356
  }
357
- add_action( 'bp_activity_screen_mentions', 'bp_activity_remove_screen_notifications' );
358
 
359
  /**
360
  * Mark at-mention notification as read when user visits the activity with the mention.
361
  *
362
- * @since BuddyPress (2.0.0)
 
 
363
  */
364
  function bp_activity_remove_screen_notifications_single_activity_permalink( $activity ) {
365
- if ( ! bp_is_active( 'notifications' ) ) {
366
- return;
367
- }
368
-
369
  if ( ! is_user_logged_in() ) {
370
  return;
371
  }
372
 
373
- // Mark as read any notifications for the current user related to this
374
- // activity item
375
  bp_notifications_mark_notifications_by_item_id( bp_loggedin_user_id(), $activity->id, buddypress()->activity->id, 'new_at_mention' );
376
  }
377
  add_action( 'bp_activity_screen_single_activity_permalink', 'bp_activity_remove_screen_notifications_single_activity_permalink' );
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  /**
380
  * Delete at-mention notifications when the corresponding activity item is deleted.
381
  *
382
- * @since BuddyPress (2.0.0)
383
  *
384
  * @param array $activity_ids_deleted IDs of deleted activity items.
385
  */
386
  function bp_activity_at_mention_delete_notification( $activity_ids_deleted = array() ) {
387
  // Let's delete all without checking if content contains any mentions
388
- // to avoid a query to get the activity
389
- if ( bp_is_active( 'notifications' ) && ! empty( $activity_ids_deleted ) ) {
390
  foreach ( $activity_ids_deleted as $activity_id ) {
391
  bp_notifications_delete_all_notifications_by_type( $activity_id, buddypress()->activity->id );
392
  }
393
  }
394
  }
395
  add_action( 'bp_activity_deleted_activities', 'bp_activity_at_mention_delete_notification', 10 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * BuddyPress Activity Notifications.
4
  *
5
  * @package BuddyPress
6
  * @subpackage ActivityNotifications
7
+ * @since 1.2.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  /**
14
  * Format notifications related to activity.
15
  *
16
+ * @since 1.5.0
17
  *
18
+ * @param string $action The type of activity item. Just 'new_at_mention' for now.
19
+ * @param int $item_id The activity ID.
20
+ * @param int $secondary_item_id In the case of at-mentions, this is the mentioner's ID.
21
+ * @param int $total_items The total number of notifications to format.
22
+ * @param string $format 'string' to get a BuddyBar-compatible notification, 'array' otherwise.
23
+ * @param int $id Optional. The notification ID.
 
 
 
 
 
 
24
  * @return string $return Formatted @mention notification.
25
  */
26
+ function bp_activity_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string', $id = 0 ) {
27
+ $action_filter = $action;
28
+ $return = false;
29
+ $activity_id = $item_id;
30
+ $user_id = $secondary_item_id;
31
+ $user_fullname = bp_core_get_user_displayname( $user_id );
32
 
33
  switch ( $action ) {
34
  case 'new_at_mention':
35
+ $action_filter = 'at_mentions';
36
+ $link = bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/';
37
+ $title = sprintf( __( '@%s Mentions', 'buddypress' ), bp_get_loggedin_user_username() );
38
+ $amount = 'single';
39
 
40
  if ( (int) $total_items > 1 ) {
41
+ $text = sprintf( __( 'You have %1$d new mentions', 'buddypress' ), (int) $total_items );
42
+ $amount = 'multiple';
43
  } else {
44
+ $text = sprintf( __( '%1$s mentioned you', 'buddypress' ), $user_fullname );
45
+ }
46
+ break;
47
+
48
+ case 'update_reply':
49
+ $link = bp_get_notifications_permalink();
50
+ $title = __( 'New Activity reply', 'buddypress' );
51
+ $amount = 'single';
52
+
53
+ if ( (int) $total_items > 1 ) {
54
+ $link = add_query_arg( 'type', $action, $link );
55
+ $text = sprintf( __( 'You have %1$d new replies', 'buddypress' ), (int) $total_items );
56
+ $amount = 'multiple';
57
+ } else {
58
+ $link = add_query_arg( 'nid', (int) $id, bp_activity_get_permalink( $activity_id ) );
59
+ $text = sprintf( __( '%1$s commented on one of your updates', 'buddypress' ), $user_fullname );
60
+ }
61
+ break;
62
+
63
+ case 'comment_reply':
64
+ $link = bp_get_notifications_permalink();
65
+ $title = __( 'New Activity comment reply', 'buddypress' );
66
+ $amount = 'single';
67
+
68
+ if ( (int) $total_items > 1 ) {
69
+ $link = add_query_arg( 'type', $action, $link );
70
+ $text = sprintf( __( 'You have %1$d new comment replies', 'buddypress' ), (int) $total_items );
71
+ $amount = 'multiple';
72
+ } else {
73
+ $link = add_query_arg( 'nid', (int) $id, bp_activity_get_permalink( $activity_id ) );
74
+ $text = sprintf( __( '%1$s replied to one your activity comments', 'buddypress' ), $user_fullname );
75
  }
76
  break;
77
  }
78
 
79
  if ( 'string' == $format ) {
80
+
81
+ /**
82
+ * Filters the activity notification for the string format.
83
+ *
84
+ * This is a variable filter that is dependent on how many items
85
+ * need notified about. The two possible hooks are bp_activity_single_at_mentions_notification
86
+ * or bp_activity_multiple_at_mentions_notification.
87
+ *
88
+ * @since 1.5.0
89
+ * @since 2.6.0 use the $action_filter as a new dynamic portion of the filter name.
90
+ *
91
+ * @param string $string HTML anchor tag for the interaction.
92
+ * @param string $link The permalink for the interaction.
93
+ * @param int $total_items How many items being notified about.
94
+ * @param int $activity_id ID of the activity item being formatted.
95
+ * @param int $user_id ID of the user who inited the interaction.
96
+ */
97
+ $return = apply_filters( 'bp_activity_' . $amount . '_' . $action_filter . '_notification', '<a href="' . esc_url( $link ) . '" title="' . esc_attr( $title ) . '">' . esc_html( $text ) . '</a>', $link, (int) $total_items, $activity_id, $user_id );
98
  } else {
99
+
100
+ /**
101
+ * Filters the activity notification for any non-string format.
102
+ *
103
+ * This is a variable filter that is dependent on how many items need notified about.
104
+ * The two possible hooks are bp_activity_single_at_mentions_notification
105
+ * or bp_activity_multiple_at_mentions_notification.
106
+ *
107
+ * @since 1.5.0
108
+ * @since 2.6.0 use the $action_filter as a new dynamic portion of the filter name.
109
+ *
110
+ * @param array $array Array holding the content and permalink for the interaction notification.
111
+ * @param string $link The permalink for the interaction.
112
+ * @param int $total_items How many items being notified about.
113
+ * @param int $activity_id ID of the activity item being formatted.
114
+ * @param int $user_id ID of the user who inited the interaction.
115
+ */
116
+ $return = apply_filters( 'bp_activity_' . $amount . '_' . $action_filter . '_notification', array(
117
  'text' => $text,
118
+ 'link' => $link
119
+ ), $link, (int) $total_items, $activity_id, $user_id );
120
  }
121
 
122
+ /**
123
+ * Fires right before returning the formatted activity notifications.
124
+ *
125
+ * @since 1.2.0
126
+ *
127
+ * @param string $action The type of activity item.
128
+ * @param int $item_id The activity ID.
129
+ * @param int $secondary_item_id The user ID who inited the interaction.
130
+ * @param int $total_items Total amount of items to format.
131
+ */
132
  do_action( 'activity_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
133
 
134
  return $return;
142
  * future when we separate emails from Notifications, this will need its own
143
  * 'bp_activity_at_name_send_emails' equivalent helper function.
144
  *
145
+ * @since 1.9.0
146
  *
147
+ * @param object $activity Activity object.
148
+ * @param string $subject (not used) Notification subject.
149
+ * @param string $message (not used) Notification message.
150
+ * @param string $content (not used) Notification content.
151
+ * @param int $receiver_user_id ID of user receiving notification.
152
  */
153
  function bp_activity_at_mention_add_notification( $activity, $subject, $message, $content, $receiver_user_id ) {
154
+ bp_notifications_add_notification( array(
 
155
  'user_id' => $receiver_user_id,
156
  'item_id' => $activity->id,
157
  'secondary_item_id' => $activity->user_id,
159
  'component_action' => 'new_at_mention',
160
  'date_notified' => bp_core_current_time(),
161
  'is_new' => 1,
162
+ ) );
 
163
  }
164
  add_action( 'bp_activity_sent_mention_email', 'bp_activity_at_mention_add_notification', 10, 5 );
165
 
166
  /**
167
+ * Notify a member one of their activity received a reply.
168
  *
169
+ * @since 2.6.0
170
  *
171
+ * @param BP_Activity_Activity $activity The original activity.
172
+ * @param int $comment_id ID for the newly received comment.
173
+ * @param int $commenter_id ID of the user who made the comment.
174
  */
175
+ function bp_activity_update_reply_add_notification( $activity, $comment_id, $commenter_id ) {
176
+ bp_notifications_add_notification( array(
177
+ 'user_id' => $activity->user_id,
178
+ 'item_id' => $comment_id,
179
+ 'secondary_item_id' => $commenter_id,
180
+ 'component_name' => buddypress()->activity->id,
181
+ 'component_action' => 'update_reply',
182
+ 'date_notified' => bp_core_current_time(),
183
+ 'is_new' => 1,
184
+ ) );
185
+ }
186
+ add_action( 'bp_activity_sent_reply_to_update_notification', 'bp_activity_update_reply_add_notification', 10, 3 );
187
 
188
+ /**
189
+ * Notify a member one of their activity comment received a reply.
190
+ *
191
+ * @since 2.6.0
192
+ *
193
+ * @param BP_Activity_Activity $activity_comment The parent activity.
194
+ * @param int $comment_id ID for the newly received comment.
195
+ * @param int $commenter_id ID of the user who made the comment.
196
+ */
197
+ function bp_activity_comment_reply_add_notification( $activity_comment, $comment_id, $commenter_id ) {
198
+ bp_notifications_add_notification( array(
199
+ 'user_id' => $activity_comment->user_id,
200
+ 'item_id' => $comment_id,
201
+ 'secondary_item_id' => $commenter_id,
202
+ 'component_name' => buddypress()->activity->id,
203
+ 'component_action' => 'comment_reply',
204
+ 'date_notified' => bp_core_current_time(),
205
+ 'is_new' => 1,
206
+ ) );
207
+ }
208
+ add_action( 'bp_activity_sent_reply_to_reply_notification', 'bp_activity_comment_reply_add_notification', 10, 3 );
209
+
210
+ /**
211
+ * Mark at-mention notifications as read when users visit their Mentions page.
212
+ *
213
+ * @since 1.5.0
214
+ * @since 2.5.0 Add the $user_id parameter
215
+ *
216
+ * @param int $user_id The id of the user whose notifications are marked as read.
217
+ */
218
+ function bp_activity_remove_screen_notifications( $user_id = 0 ) {
219
+ // Only mark read if the current user is looking at his own mentions.
220
+ if ( empty( $user_id ) || (int) $user_id !== (int) bp_loggedin_user_id() ) {
221
  return;
222
  }
223
 
224
+ bp_notifications_mark_notifications_by_type( $user_id, buddypress()->activity->id, 'new_at_mention' );
225
  }
226
+ add_action( 'bp_activity_clear_new_mentions', 'bp_activity_remove_screen_notifications', 10, 1 );
227
 
228
  /**
229
  * Mark at-mention notification as read when user visits the activity with the mention.
230
  *
231
+ * @since 2.0.0
232
+ *
233
+ * @param BP_Activity_Activity $activity Activity object.
234
  */
235
  function bp_activity_remove_screen_notifications_single_activity_permalink( $activity ) {
 
 
 
 
236
  if ( ! is_user_logged_in() ) {
237
  return;
238
  }
239
 
240
+ // Mark as read any notifications for the current user related to this activity item.
 
241
  bp_notifications_mark_notifications_by_item_id( bp_loggedin_user_id(), $activity->id, buddypress()->activity->id, 'new_at_mention' );
242
  }
243
  add_action( 'bp_activity_screen_single_activity_permalink', 'bp_activity_remove_screen_notifications_single_activity_permalink' );
244
 
245
+ /**
246
+ * Mark non-mention notifications as read when user visits our read permalink.
247
+ *
248
+ * In particular, 'update_reply' and 'comment_reply' notifications are handled
249
+ * here. See {@link bp_activity_format_notifications()} for more info.
250
+ *
251
+ * @since 2.6.0
252
+ */
253
+ function bp_activity_remove_screen_notifications_for_non_mentions() {
254
+ if ( false === is_singular() || false === is_user_logged_in() || empty( $_GET['nid'] ) ) {
255
+ return;
256
+ }
257
+
258
+ // Mark notification as read.
259
+ BP_Notifications_Notification::update(
260
+ array(
261
+ 'is_new' => false
262
+ ),
263
+ array(
264
+ 'user_id' => bp_loggedin_user_id(),
265
+ 'id' => (int) $_GET['nid']
266
+ )
267
+ );
268
+ }
269
+ add_action( 'bp_screens', 'bp_activity_remove_screen_notifications_for_non_mentions' );
270
+
271
  /**
272
  * Delete at-mention notifications when the corresponding activity item is deleted.
273
  *
274
+ * @since 2.0.0
275
  *
276
  * @param array $activity_ids_deleted IDs of deleted activity items.
277
  */
278
  function bp_activity_at_mention_delete_notification( $activity_ids_deleted = array() ) {
279
  // Let's delete all without checking if content contains any mentions
280
+ // to avoid a query to get the activity.
281
+ if ( ! empty( $activity_ids_deleted ) ) {
282
  foreach ( $activity_ids_deleted as $activity_id ) {
283
  bp_notifications_delete_all_notifications_by_type( $activity_id, buddypress()->activity->id );
284
  }
285
  }
286
  }
287
  add_action( 'bp_activity_deleted_activities', 'bp_activity_at_mention_delete_notification', 10 );
288
+
289
+ /**
290
+ * Add a notification for post comments to the post author or post commenter.
291
+ *
292
+ * Requires "activity stream commenting on blog and forum posts" to be enabled.
293
+ *
294
+ * @since 2.6.0
295
+ *
296
+ * @param int $activity_id The activity comment ID.
297
+ * @param WP_Comment $post_type_comment WP Comment object.
298
+ * @param array $activity_args Activity comment arguments.
299
+ * @param object $activity_post_object The post type tracking args object.
300
+ */
301
+ function bp_activity_add_notification_for_synced_blog_comment( $activity_id, $post_type_comment, $activity_args, $activity_post_object ) {
302
+ // If activity comments are disabled for WP posts, stop now!
303
+ if ( bp_disable_blogforum_comments() || empty( $activity_id ) ) {
304
+ return;
305
+ }
306
+
307
+ // Send a notification to the blog post author.
308
+ if ( (int) $post_type_comment->post->post_author !== (int) $activity_args['user_id'] ) {
309
+ // Only add a notification if comment author is a registered user.
310
+ // @todo Should we remove this restriction?
311
+ if ( ! empty( $post_type_comment->user_id ) ) {
312
+ bp_notifications_add_notification( array(
313
+ 'user_id' => $post_type_comment->post->post_author,
314
+ 'item_id' => $activity_id,
315
+ 'secondary_item_id' => $post_type_comment->user_id,
316
+ 'component_name' => buddypress()->activity->id,
317
+ 'component_action' => 'update_reply',
318
+ 'date_notified' => $post_type_comment->comment_date_gmt,
319
+ 'is_new' => 1,
320
+ ) );
321
+ }
322
+ }
323
+
324
+ // Send a notification to the parent comment author for follow-up comments.
325
+ if ( ! empty( $post_type_comment->comment_parent ) ) {
326
+ $parent_comment = get_comment( $post_type_comment->comment_parent );
327
+
328
+ if ( ! empty( $parent_comment->user_id ) && (int) $parent_comment->user_id !== (int) $activity_args['user_id'] ) {
329
+ bp_notifications_add_notification( array(
330
+ 'user_id' => $parent_comment->user_id,
331
+ 'item_id' => $activity_id,
332
+ 'secondary_item_id' => $post_type_comment->user_id,
333
+ 'component_name' => buddypress()->activity->id,
334
+ 'component_action' => 'comment_reply',
335
+ 'date_notified' => $post_type_comment->comment_date_gmt,
336
+ 'is_new' => 1,
337
+ ) );
338
+ }
339
+ }
340
+ }
341
+ add_action( 'bp_blogs_comment_sync_activity_comment', 'bp_activity_add_notification_for_synced_blog_comment', 10, 4 );
bp-activity/bp-activity-screens.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Activity Screens.
5
  *
@@ -9,30 +8,40 @@
9
  *
10
  * @package BuddyPress
11
  * @subpackage ActivityScreens
 
12
  */
13
 
14
- // Exit if accessed directly
15
- if ( !defined( 'ABSPATH' ) ) exit;
 
 
 
 
16
 
17
  /**
18
  * Load the Activity directory.
19
  *
20
- * @since BuddyPress (1.5)
21
  *
22
- * @uses bp_displayed_user_id()
23
- * @uses bp_is_activity_component()
24
- * @uses bp_current_action()
25
- * @uses bp_update_is_directory()
26
- * @uses do_action() To call the 'bp_activity_screen_index' hook.
27
- * @uses bp_core_load_template()
28
- * @uses apply_filters() To call the 'bp_activity_screen_index' hook.
29
  */
30
  function bp_activity_screen_index() {
31
  if ( bp_is_activity_directory() ) {
32
  bp_update_is_directory( true, 'activity' );
33
 
 
 
 
 
 
34
  do_action( 'bp_activity_screen_index' );
35
 
 
 
 
 
 
 
 
36
  bp_core_load_template( apply_filters( 'bp_activity_screen_index', 'activity/index' ) );
37
  }
38
  }
@@ -41,101 +50,143 @@ add_action( 'bp_screens', 'bp_activity_screen_index' );
41
  /**
42
  * Load the 'My Activity' page.
43
  *
44
- * @since BuddyPress (1.0)
45
  *
46
- * @uses do_action() To call the 'bp_activity_screen_my_activity' hook.
47
- * @uses bp_core_load_template()
48
- * @uses apply_filters() To call the 'bp_activity_template_my_activity' hook.
49
  */
50
  function bp_activity_screen_my_activity() {
 
 
 
 
 
 
51
  do_action( 'bp_activity_screen_my_activity' );
 
 
 
 
 
 
 
 
52
  bp_core_load_template( apply_filters( 'bp_activity_template_my_activity', 'members/single/home' ) );
53
  }
54
 
55
  /**
56
  * Load the 'My Friends' activity page.
57
  *
58
- * @since BuddyPress (1.0)
59
  *
60
- * @uses bp_is_active()
61
- * @uses bp_update_is_item_admin()
62
- * @uses bp_current_user_can()
63
- * @uses do_action() To call the 'bp_activity_screen_friends' hook.
64
- * @uses bp_core_load_template()
65
- * @uses apply_filters() To call the 'bp_activity_template_friends_activity' hook.
66
  */
67
  function bp_activity_screen_friends() {
68
  if ( !bp_is_active( 'friends' ) )
69
  return false;
70
 
71
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
 
 
 
 
 
 
72
  do_action( 'bp_activity_screen_friends' );
 
 
 
 
 
 
 
 
73
  bp_core_load_template( apply_filters( 'bp_activity_template_friends_activity', 'members/single/home' ) );
74
  }
75
 
76
  /**
77
  * Load the 'My Groups' activity page.
78
  *
79
- * @since BuddyPress (1.2)
80
  *
81
- * @uses bp_is_active()
82
- * @uses bp_update_is_item_admin()
83
- * @uses bp_current_user_can()
84
- * @uses do_action() To call the 'bp_activity_screen_groups' hook
85
- * @uses bp_core_load_template()
86
- * @uses apply_filters() To call the 'bp_activity_template_groups_activity' hook
87
  */
88
  function bp_activity_screen_groups() {
89
  if ( !bp_is_active( 'groups' ) )
90
  return false;
91
 
92
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
 
 
 
 
 
 
93
  do_action( 'bp_activity_screen_groups' );
 
 
 
 
 
 
 
 
94
  bp_core_load_template( apply_filters( 'bp_activity_template_groups_activity', 'members/single/home' ) );
95
  }
96
 
97
  /**
98
  * Load the 'Favorites' activity page.
99
  *
100
- * @since BuddyPress (1.2)
101
  *
102
- * @uses bp_update_is_item_admin()
103
- * @uses bp_current_user_can()
104
- * @uses do_action() To call the 'bp_activity_screen_favorites' hook
105
- * @uses bp_core_load_template()
106
- * @uses apply_filters() To call the 'bp_activity_template_favorite_activity' hook
107
  */
108
  function bp_activity_screen_favorites() {
109
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
 
 
 
 
 
 
110
  do_action( 'bp_activity_screen_favorites' );
 
 
 
 
 
 
 
 
111
  bp_core_load_template( apply_filters( 'bp_activity_template_favorite_activity', 'members/single/home' ) );
112
  }
113
 
114
  /**
115
  * Load the 'Mentions' activity page.
116
  *
117
- * @since BuddyPress (1.2)
118
  *
119
- * @uses bp_update_is_item_admin()
120
- * @uses bp_current_user_can()
121
- * @uses do_action() To call the 'bp_activity_screen_mentions' hook
122
- * @uses bp_core_load_template()
123
- * @uses apply_filters() To call the 'bp_activity_template_mention_activity' hook
124
  */
125
  function bp_activity_screen_mentions() {
126
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
 
 
 
 
 
 
127
  do_action( 'bp_activity_screen_mentions' );
 
 
 
 
 
 
 
 
128
  bp_core_load_template( apply_filters( 'bp_activity_template_mention_activity', 'members/single/home' ) );
129
  }
130
 
131
  /**
132
  * Reset the logged-in user's new mentions data when he visits his mentions screen.
133
  *
134
- * @since BuddyPress (1.5)
135
  *
136
- * @uses bp_is_my_profile()
137
- * @uses bp_activity_clear_new_mentions()
138
- * @uses bp_loggedin_user_id()
139
  */
140
  function bp_activity_reset_my_new_mentions() {
141
  if ( bp_is_my_profile() )
@@ -146,40 +197,20 @@ add_action( 'bp_activity_screen_mentions', 'bp_activity_reset_my_new_mentions' )
146
  /**
147
  * Load the page for a single activity item.
148
  *
149
- * @since BuddyPress (1.2)
150
  *
151
- * @global object $bp BuddyPress global settings
152
- * @uses bp_is_activity_component()
153
- * @uses bp_activity_get_specific()
154
- * @uses bp_current_action()
155
- * @uses bp_action_variables()
156
- * @uses bp_do_404()
157
- * @uses bp_is_active()
158
- * @uses groups_get_group()
159
- * @uses groups_is_user_member()
160
- * @uses apply_filters_ref_array() To call the 'bp_activity_permalink_access' hook
161
- * @uses do_action() To call the 'bp_activity_screen_single_activity_permalink' hook
162
- * @uses bp_core_add_message()
163
- * @uses is_user_logged_in()
164
- * @uses bp_core_redirect()
165
- * @uses site_url()
166
- * @uses esc_url()
167
- * @uses bp_get_root_domain()
168
- * @uses bp_get_activity_root_slug()
169
- * @uses bp_core_load_template()
170
- * @uses apply_filters() To call the 'bp_activity_template_profile_activity_permalink' hook
171
  */
172
  function bp_activity_screen_single_activity_permalink() {
173
- global $bp;
174
 
175
- // No displayed user or not viewing activity component
176
  if ( !bp_is_activity_component() )
177
  return false;
178
 
179
  if ( ! bp_current_action() || !is_numeric( bp_current_action() ) )
180
  return false;
181
 
182
- // Get the activity details
183
  $activity = bp_activity_get_specific( array( 'activity_ids' => bp_current_action(), 'show_hidden' => true, 'spam' => 'ham_only', ) );
184
 
185
  // 404 if activity does not exist
@@ -191,26 +222,26 @@ function bp_activity_screen_single_activity_permalink() {
191
  $activity = $activity['activities'][0];
192
  }
193
 
194
- // Default access is true
195
  $has_access = true;
196
 
197
- // If activity is from a group, do an extra cap check
198
  if ( isset( $bp->groups->id ) && $activity->component == $bp->groups->id ) {
199
 
200
- // Activity is from a group, but groups is currently disabled
201
  if ( !bp_is_active( 'groups') ) {
202
  bp_do_404();
203
  return;
204
  }
205
 
206
  // Check to see if the group is not public, if so, check the
207
- // user has access to see this activity
208
- if ( $group = groups_get_group( array( 'group_id' => $activity->item_id ) ) ) {
209
 
210
- // Group is not public
211
  if ( 'public' != $group->status ) {
212
 
213
- // User is not a member of group
214
  if ( !groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
215
  $has_access = false;
216
  }
@@ -218,24 +249,57 @@ function bp_activity_screen_single_activity_permalink() {
218
  }
219
  }
220
 
221
- // Allow access to be filtered
 
 
 
 
 
 
 
 
 
 
 
222
  $has_access = apply_filters_ref_array( 'bp_activity_permalink_access', array( $has_access, &$activity ) );
223
 
224
- // Allow additional code execution
 
 
 
 
 
 
 
225
  do_action( 'bp_activity_screen_single_activity_permalink', $activity, $has_access );
226
 
227
- // Access is specifically disallowed
228
  if ( false === $has_access ) {
229
 
230
- // User feedback
231
  bp_core_add_message( __( 'You do not have access to this activity.', 'buddypress' ), 'error' );
232
 
233
- // Redirect based on logged in status
234
- is_user_logged_in() ?
235
- bp_core_redirect( bp_loggedin_user_domain() ) :
236
- bp_core_redirect( site_url( 'wp-login.php?redirect_to=' . esc_url( bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . bp_current_action() . '/' ) ) );
 
 
 
 
 
 
 
 
237
  }
238
 
 
 
 
 
 
 
 
239
  bp_core_load_template( apply_filters( 'bp_activity_template_profile_activity_permalink', 'members/single/activity/permalink' ) );
240
  }
241
  add_action( 'bp_screens', 'bp_activity_screen_single_activity_permalink' );
@@ -243,11 +307,8 @@ add_action( 'bp_screens', 'bp_activity_screen_single_activity_permalink' );
243
  /**
244
  * Add activity notifications settings to the notifications settings page.
245
  *
246
- * @since BuddyPress (1.2)
247
  *
248
- * @uses bp_get_user_meta()
249
- * @uses bp_core_get_username()
250
- * @uses do_action() To call the 'bp_activity_screen_notification_settings' hook.
251
  */
252
  function bp_activity_screen_notification_settings() {
253
 
@@ -278,19 +339,38 @@ function bp_activity_screen_notification_settings() {
278
  <tr id="activity-notification-settings-mentions">
279
  <td>&nbsp;</td>
280
  <td><?php printf( __( 'A member mentions you in an update using "@%s"', 'buddypress' ), bp_core_get_username( bp_displayed_user_id() ) ) ?></td>
281
- <td class="yes"><input type="radio" name="notifications[notification_activity_new_mention]" value="yes" <?php checked( $mention, 'yes', true ) ?>/></td>
282
- <td class="no"><input type="radio" name="notifications[notification_activity_new_mention]" value="no" <?php checked( $mention, 'no', true ) ?>/></td>
 
 
 
 
 
 
283
  </tr>
284
  <?php endif; ?>
285
 
286
  <tr id="activity-notification-settings-replies">
287
  <td>&nbsp;</td>
288
  <td><?php _e( "A member replies to an update or comment you've posted", 'buddypress' ) ?></td>
289
- <td class="yes"><input type="radio" name="notifications[notification_activity_new_reply]" value="yes" <?php checked( $reply, 'yes', true ) ?>/></td>
290
- <td class="no"><input type="radio" name="notifications[notification_activity_new_reply]" value="no" <?php checked( $reply, 'no', true ) ?>/></td>
 
 
 
 
 
 
291
  </tr>
292
 
293
- <?php do_action( 'bp_activity_screen_notification_settings' ) ?>
 
 
 
 
 
 
 
294
  </tbody>
295
  </table>
296
 
@@ -298,160 +378,6 @@ function bp_activity_screen_notification_settings() {
298
  }
299
  add_action( 'bp_notification_settings', 'bp_activity_screen_notification_settings', 1 );
300
 
301
- /** Theme Compatability *******************************************************/
302
-
303
- /**
304
- * The main theme compat class for BuddyPress Activity.
305
- *
306
- * This class sets up the necessary theme compatability actions to safely output
307
- * activity template parts to the_title and the_content areas of a theme.
308
- *
309
- * @since BuddyPress (1.7)
310
- */
311
- class BP_Activity_Theme_Compat {
312
-
313
- /**
314
- * Set up the activity component theme compatibility.
315
- *
316
- * @since BuddyPress (1.7)
317
- */
318
- public function __construct() {
319
- add_action( 'bp_setup_theme_compat', array( $this, 'is_activity' ) );
320
- }
321
-
322
- /**
323
- * Set up the theme compatibility hooks, if we're looking at an activity page.
324
- *
325
- * @since BuddyPress (1.7)
326
- */
327
- public function is_activity() {
328
-
329
- // Bail if not looking at a group
330
- if ( ! bp_is_activity_component() )
331
- return;
332
-
333
- // Activity Directory
334
- if ( ! bp_displayed_user_id() && ! bp_current_action() ) {
335
- bp_update_is_directory( true, 'activity' );
336
-
337
- do_action( 'bp_activity_screen_index' );
338
-
339
- add_filter( 'bp_get_buddypress_template', array( $this, 'directory_template_hierarchy' ) );
340
- add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
341
- add_filter( 'bp_replace_the_content', array( $this, 'directory_content' ) );
342
-
343
- // Single activity
344
- } elseif ( bp_is_single_activity() ) {
345
- add_filter( 'bp_get_buddypress_template', array( $this, 'single_template_hierarchy' ) );
346
- add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'single_dummy_post' ) );
347
- add_filter( 'bp_replace_the_content', array( $this, 'single_dummy_content' ) );
348
- }
349
- }
350
-
351
- /** Directory *************************************************************/
352
-
353
- /**
354
- * Add template hierarchy to theme compat for the activity directory page.
355
- *
356
- * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
357
- *
358
- * @since BuddyPress (1.8)
359
- *
360
- * @param string $templates The templates from bp_get_theme_compat_templates().
361
- * @return array $templates Array of custom templates to look for.
362
- */
363
- public function directory_template_hierarchy( $templates ) {
364
- // Setup our templates based on priority
365
- $new_templates = apply_filters( 'bp_template_hierarchy_activity_directory', array(
366
- 'activity/index-directory.php'
367
- ) );
368
-
369
- // Merge new templates with existing stack
370
- // @see bp_get_theme_compat_templates()
371
- $templates = array_merge( (array) $new_templates, $templates );
372
 
373
- return $templates;
374
- }
375
-
376
- /**
377
- * Update the global $post with directory data.
378
- *
379
- * @since BuddyPress (1.7)
380
- */
381
- public function directory_dummy_post() {
382
- bp_theme_compat_reset_post( array(
383
- 'ID' => 0,
384
- 'post_title' => bp_get_directory_title( 'activity' ),
385
- 'post_author' => 0,
386
- 'post_date' => 0,
387
- 'post_content' => '',
388
- 'post_type' => 'bp_activity',
389
- 'post_status' => 'publish',
390
- 'is_page' => true,
391
- 'comment_status' => 'closed'
392
- ) );
393
- }
394
-
395
- /**
396
- * Filter the_content with the groups index template part.
397
- *
398
- * @since BuddyPress (1.7)
399
- */
400
- public function directory_content() {
401
- return bp_buffer_template_part( 'activity/index', null, false );
402
- }
403
-
404
- /** Single ****************************************************************/
405
-
406
- /**
407
- * Add custom template hierarchy to theme compat for activity permalink pages.
408
- *
409
- * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
410
- *
411
- * @since BuddyPress (1.8)
412
- *
413
- * @param string $templates The templates from bp_get_theme_compat_templates().
414
- * @return array $templates Array of custom templates to look for.
415
- */
416
- public function single_template_hierarchy( $templates ) {
417
- // Setup our templates based on priority
418
- $new_templates = apply_filters( 'bp_template_hierarchy_activity_single_item', array(
419
- 'activity/single/index.php'
420
- ) );
421
-
422
- // Merge new templates with existing stack
423
- // @see bp_get_theme_compat_templates()
424
- $templates = array_merge( (array) $new_templates, $templates );
425
-
426
- return $templates;
427
- }
428
-
429
- /**
430
- * Update the global $post with the displayed user's data.
431
- *
432
- * @since BuddyPress (1.7)
433
- */
434
- public function single_dummy_post() {
435
- bp_theme_compat_reset_post( array(
436
- 'ID' => 0,
437
- 'post_title' => __( 'Activity', 'buddypress' ),
438
- 'post_author' => 0,
439
- 'post_date' => 0,
440
- 'post_content' => '',
441
- 'post_type' => 'bp_activity',
442
- 'post_status' => 'publish',
443
- 'is_page' => true,
444
- 'comment_status' => 'closed'
445
- ) );
446
- }
447
-
448
- /**
449
- * Filter the_content with the members' activity permalink template part.
450
- *
451
- * @since BuddyPress (1.7)
452
- */
453
- public function single_dummy_content() {
454
- return bp_buffer_template_part( 'activity/single/home', null, false );
455
- }
456
- }
457
  new BP_Activity_Theme_Compat();
1
  <?php
 
2
  /**
3
  * BuddyPress Activity Screens.
4
  *
8
  *
9
  * @package BuddyPress
10
  * @subpackage ActivityScreens
11
+ * @since 1.5.0
12
  */
13
 
14
+ // Exit if accessed directly.
15
+ defined( 'ABSPATH' ) || exit;
16
+
17
+ if ( ! buddypress()->do_autoload ) {
18
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-theme-compat.php';
19
+ }
20
 
21
  /**
22
  * Load the Activity directory.
23
  *
24
+ * @since 1.5.0
25
  *
 
 
 
 
 
 
 
26
  */
27
  function bp_activity_screen_index() {
28
  if ( bp_is_activity_directory() ) {
29
  bp_update_is_directory( true, 'activity' );
30
 
31
+ /**
32
+ * Fires right before the loading of the Activity directory screen template file.
33
+ *
34
+ * @since 1.5.0
35
+ */
36
  do_action( 'bp_activity_screen_index' );
37
 
38
+ /**
39
+ * Filters the template to load for the Activity directory screen.
40
+ *
41
+ * @since 1.5.0
42
+ *
43
+ * @param string $template Path to the activity template to load.
44
+ */
45
  bp_core_load_template( apply_filters( 'bp_activity_screen_index', 'activity/index' ) );
46
  }
47
  }
50
  /**
51
  * Load the 'My Activity' page.
52
  *
53
+ * @since 1.0.0
54
  *
 
 
 
55
  */
56
  function bp_activity_screen_my_activity() {
57
+
58
+ /**
59
+ * Fires right before the loading of the "My Activity" screen template file.
60
+ *
61
+ * @since 1.0.0
62
+ */
63
  do_action( 'bp_activity_screen_my_activity' );
64
+
65
+ /**
66
+ * Filters the template to load for the "My Activity" screen.
67
+ *
68
+ * @since 1.0.0
69
+ *
70
+ * @param string $template Path to the activity template to load.
71
+ */
72
  bp_core_load_template( apply_filters( 'bp_activity_template_my_activity', 'members/single/home' ) );
73
  }
74
 
75
  /**
76
  * Load the 'My Friends' activity page.
77
  *
78
+ * @since 1.0.0
79
  *
 
 
 
 
 
 
80
  */
81
  function bp_activity_screen_friends() {
82
  if ( !bp_is_active( 'friends' ) )
83
  return false;
84
 
85
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
86
+
87
+ /**
88
+ * Fires right before the loading of the "My Friends" screen template file.
89
+ *
90
+ * @since 1.2.0
91
+ */
92
  do_action( 'bp_activity_screen_friends' );
93
+
94
+ /**
95
+ * Filters the template to load for the "My Friends" screen.
96
+ *
97
+ * @since 1.0.0
98
+ *
99
+ * @param string $template Path to the activity template to load.
100
+ */
101
  bp_core_load_template( apply_filters( 'bp_activity_template_friends_activity', 'members/single/home' ) );
102
  }
103
 
104
  /**
105
  * Load the 'My Groups' activity page.
106
  *
107
+ * @since 1.2.0
108
  *
 
 
 
 
 
 
109
  */
110
  function bp_activity_screen_groups() {
111
  if ( !bp_is_active( 'groups' ) )
112
  return false;
113
 
114
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
115
+
116
+ /**
117
+ * Fires right before the loading of the "My Groups" screen template file.
118
+ *
119
+ * @since 1.2.0
120
+ */
121
  do_action( 'bp_activity_screen_groups' );
122
+
123
+ /**
124
+ * Filters the template to load for the "My Groups" screen.
125
+ *
126
+ * @since 1.2.0
127
+ *
128
+ * @param string $template Path to the activity template to load.
129
+ */
130
  bp_core_load_template( apply_filters( 'bp_activity_template_groups_activity', 'members/single/home' ) );
131
  }
132
 
133
  /**
134
  * Load the 'Favorites' activity page.
135
  *
136
+ * @since 1.2.0
137
  *
 
 
 
 
 
138
  */
139
  function bp_activity_screen_favorites() {
140
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
141
+
142
+ /**
143
+ * Fires right before the loading of the "Favorites" screen template file.
144
+ *
145
+ * @since 1.2.0
146
+ */
147
  do_action( 'bp_activity_screen_favorites' );
148
+
149
+ /**
150
+ * Filters the template to load for the "Favorites" screen.
151
+ *
152
+ * @since 1.2.0
153
+ *
154
+ * @param string $template Path to the activity template to load.
155
+ */
156
  bp_core_load_template( apply_filters( 'bp_activity_template_favorite_activity', 'members/single/home' ) );
157
  }
158
 
159
  /**
160
  * Load the 'Mentions' activity page.
161
  *
162
+ * @since 1.2.0
163
  *
 
 
 
 
 
164
  */
165
  function bp_activity_screen_mentions() {
166
  bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
167
+
168
+ /**
169
+ * Fires right before the loading of the "Mentions" screen template file.
170
+ *
171
+ * @since 1.2.0
172
+ */
173
  do_action( 'bp_activity_screen_mentions' );
174
+
175
+ /**
176
+ * Filters the template to load for the "Mentions" screen.
177
+ *
178
+ * @since 1.2.0
179
+ *
180
+ * @param string $template Path to the activity template to load.
181
+ */
182
  bp_core_load_template( apply_filters( 'bp_activity_template_mention_activity', 'members/single/home' ) );
183
  }
184
 
185
  /**
186
  * Reset the logged-in user's new mentions data when he visits his mentions screen.
187
  *
188
+ * @since 1.5.0
189
  *
 
 
 
190
  */
191
  function bp_activity_reset_my_new_mentions() {
192
  if ( bp_is_my_profile() )
197
  /**
198
  * Load the page for a single activity item.
199
  *
200
+ * @since 1.2.0
201
  *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  */
203
  function bp_activity_screen_single_activity_permalink() {
204
+ $bp = buddypress();
205
 
206
+ // No displayed user or not viewing activity component.
207
  if ( !bp_is_activity_component() )
208
  return false;
209
 
210
  if ( ! bp_current_action() || !is_numeric( bp_current_action() ) )
211
  return false;
212
 
213
+ // Get the activity details.
214
  $activity = bp_activity_get_specific( array( 'activity_ids' => bp_current_action(), 'show_hidden' => true, 'spam' => 'ham_only', ) );
215
 
216
  // 404 if activity does not exist
222
  $activity = $activity['activities'][0];
223
  }
224
 
225
+ // Default access is true.
226
  $has_access = true;
227
 
228
+ // If activity is from a group, do an extra cap check.
229
  if ( isset( $bp->groups->id ) && $activity->component == $bp->groups->id ) {
230
 
231
+ // Activity is from a group, but groups is currently disabled.
232
  if ( !bp_is_active( 'groups') ) {
233
  bp_do_404();
234
  return;
235
  }
236
 
237
  // Check to see if the group is not public, if so, check the
238
+ // user has access to see this activity.
239
+ if ( $group = groups_get_group( $activity->item_id ) ) {
240
 
241
+ // Group is not public.
242
  if ( 'public' != $group->status ) {
243
 
244
+ // User is not a member of group.
245
  if ( !groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
246
  $has_access = false;
247
  }
249
  }
250
  }
251
 
252
+ // If activity author does not match displayed user, block access.
253
+ if ( true === $has_access && bp_displayed_user_id() !== $activity->user_id ) {
254
+ $has_access = false;
255
+ }
256
+
257
+ /**
258
+ * Filters the access permission for a single activity view.
259
+ *
260
+ * @since 1.2.0
261
+ *
262
+ * @param array $access Array holding the current $has_access value and current activity item instance.
263
+ */
264
  $has_access = apply_filters_ref_array( 'bp_activity_permalink_access', array( $has_access, &$activity ) );
265
 
266
+ /**
267
+ * Fires before the loading of a single activity template file.
268
+ *
269
+ * @since 1.2.0
270
+ *
271
+ * @param BP_Activity_Activity $activity Object representing the current activity item being displayed.
272
+ * @param bool $has_access Whether or not the current user has access to view activity.
273
+ */
274
  do_action( 'bp_activity_screen_single_activity_permalink', $activity, $has_access );
275
 
276
+ // Access is specifically disallowed.
277
  if ( false === $has_access ) {
278
 
279
+ // User feedback.
280
  bp_core_add_message( __( 'You do not have access to this activity.', 'buddypress' ), 'error' );
281
 
282
+ // Redirect based on logged in status.
283
+ if ( is_user_logged_in() ) {
284
+ $url = bp_loggedin_user_domain();
285
+
286
+ } else {
287
+ $url = sprintf(
288
+ site_url( 'wp-login.php?redirect_to=%s' ),
289
+ urlencode( esc_url_raw( bp_activity_get_permalink( bp_current_action() ) ) )
290
+ );
291
+ }
292
+
293
+ bp_core_redirect( $url );
294
  }
295
 
296
+ /**
297
+ * Filters the template to load for a single activity screen.
298
+ *
299
+ * @since 1.0.0
300
+ *
301
+ * @param string $template Path to the activity template to load.
302
+ */
303
  bp_core_load_template( apply_filters( 'bp_activity_template_profile_activity_permalink', 'members/single/activity/permalink' ) );
304
  }
305
  add_action( 'bp_screens', 'bp_activity_screen_single_activity_permalink' );
307
  /**
308
  * Add activity notifications settings to the notifications settings page.
309
  *
310
+ * @since 1.2.0
311
  *
 
 
 
312
  */
313
  function bp_activity_screen_notification_settings() {
314
 
339
  <tr id="activity-notification-settings-mentions">
340
  <td>&nbsp;</td>
341
  <td><?php printf( __( 'A member mentions you in an update using "@%s"', 'buddypress' ), bp_core_get_username( bp_displayed_user_id() ) ) ?></td>
342
+ <td class="yes"><input type="radio" name="notifications[notification_activity_new_mention]" id="notification-activity-new-mention-yes" value="yes" <?php checked( $mention, 'yes', true ) ?>/><label for="notification-activity-new-mention-yes" class="bp-screen-reader-text"><?php
343
+ /* translators: accessibility text */
344
+ _e( 'Yes, send email', 'buddypress' );
345
+ ?></label></td>
346
+ <td class="no"><input type="radio" name="notifications[notification_activity_new_mention]" id="notification-activity-new-mention-no" value="no" <?php checked( $mention, 'no', true ) ?>/><label for="notification-activity-new-mention-no" class="bp-screen-reader-text"><?php
347
+ /* translators: accessibility text */
348
+ _e( 'No, do not send email', 'buddypress' );
349
+ ?></label></td>
350
  </tr>
351
  <?php endif; ?>
352
 
353
  <tr id="activity-notification-settings-replies">
354
  <td>&nbsp;</td>
355
  <td><?php _e( "A member replies to an update or comment you've posted", 'buddypress' ) ?></td>
356
+ <td class="yes"><input type="radio" name="notifications[notification_activity_new_reply]" id="notification-activity-new-reply-yes" value="yes" <?php checked( $reply, 'yes', true ) ?>/><label for="notification-activity-new-reply-yes" class="bp-screen-reader-text"><?php
357
+ /* translators: accessibility text */
358
+ _e( 'Yes, send email', 'buddypress' );
359
+ ?></label></td>
360
+ <td class="no"><input type="radio" name="notifications[notification_activity_new_reply]" id="notification-activity-new-reply-no" value="no" <?php checked( $reply, 'no', true ) ?>/><label for="notification-activity-new-reply-no" class="bp-screen-reader-text"><?php
361
+ /* translators: accessibility text */
362
+ _e( 'No, do not send email', 'buddypress' );
363
+ ?></label></td>
364
  </tr>
365
 
366
+ <?php
367
+
368
+ /**
369
+ * Fires inside the closing </tbody> tag for activity screen notification settings.
370
+ *
371
+ * @since 1.2.0
372
+ */
373
+ do_action( 'bp_activity_screen_notification_settings' ) ?>
374
  </tbody>
375
  </table>
376
 
378
  }
379
  add_action( 'bp_notification_settings', 'bp_activity_screen_notification_settings', 1 );
380
 
381
+ /** Theme Compatibility *******************************************************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  new BP_Activity_Theme_Compat();
bp-activity/bp-activity-template.php CHANGED
@@ -1,21 +1,24 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Activity Template Functions.
5
  *
6
  * @package BuddyPress
7
  * @subpackage ActivityTemplate
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
 
 
 
 
12
 
13
  /**
14
  * Output the activity component slug.
15
  *
16
- * @since BuddyPress (1.5)
17
  *
18
- * @uses bp_get_activity_slug()
19
  */
20
  function bp_activity_slug() {
21
  echo bp_get_activity_slug();
@@ -23,22 +26,28 @@ function bp_activity_slug() {
23
  /**
24
  * Return the activity component slug.
25
  *
26
- * @since BuddyPress (1.5)
27
  *
28
- * @uses apply_filters() To call the 'bp_get_activity_slug' hook.
29
  *
30
  * @return string The activity component slug.
31
  */
32
  function bp_get_activity_slug() {
 
 
 
 
 
 
 
 
33
  return apply_filters( 'bp_get_activity_slug', buddypress()->activity->slug );
34
  }
35
 
36
  /**
37
  * Output the activity component root slug.
38
  *
39
- * @since BuddyPress (1.5)
40
  *
41
- * @uses bp_get_activity_root_slug()
42
  */
43
  function bp_activity_root_slug() {
44
  echo bp_get_activity_root_slug();
@@ -46,312 +55,51 @@ function bp_activity_root_slug() {
46
  /**
47
  * Return the activity component root slug.
48
  *
49
- * @since BuddyPress (1.5)
50
  *
51
- * @uses apply_filters() To call the 'bp_get_activity_root_slug' hook.
52
  *
53
  * @return string The activity component root slug.
54
  */
55
  function bp_get_activity_root_slug() {
 
 
 
 
 
 
 
 
56
  return apply_filters( 'bp_get_activity_root_slug', buddypress()->activity->root_slug );
57
  }
58
 
59
  /**
60
  * Output activity directory permalink.
61
  *
62
- * @since BuddyPress (1.5)
63
  *
64
- * @uses bp_get_activity_directory_permalink()
65
  */
66
  function bp_activity_directory_permalink() {
67
- echo bp_get_activity_directory_permalink();
68
  }
69
  /**
70
- * Return activity directory permalink
71
  *
72
- * @since BuddyPress (1.5)
73
  *
74
- * @uses traisingslashit()
75
- * @uses bp_get_root_domain()
76
- * @uses bp_get_activity_root_slug()
77
- * @uses apply_filters() To call the 'bp_get_activity_directory_permalink' hook.
78
  *
79
  * @return string Activity directory permalink.
80
  */
81
  function bp_get_activity_directory_permalink() {
82
- return apply_filters( 'bp_get_activity_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_activity_root_slug() ) );
83
- }
84
-
85
- /**
86
- * The main activity template loop class.
87
- *
88
- * This is responsible for loading a group of activity items and displaying them.
89
- *
90
- * @since BuddyPress (1.0)
91
- */
92
- class BP_Activity_Template {
93
- var $current_activity = -1;
94
- var $activity_count;
95
- var $total_activity_count;
96
- var $activities;
97
- var $activity;
98
-
99
- var $in_the_loop;
100
-
101
- var $pag_page;
102
- var $pag_num;
103
- var $pag_links;
104
-
105
- var $full_name;
106
-
107
- /**
108
- * Constructor method.
109
- *
110
- * The arguments passed to this class constructor are of the same
111
- * format as {@link BP_Activity_Activity::get()}.
112
- *
113
- * @see BP_Activity_Activity::get() for a description of the argument
114
- * structure, as well as default values.
115
- *
116
- * @param array $args {
117
- * Array of arguments. Supports all arguments from
118
- * BP_Activity_Activity::get(), as well as 'page_arg' and
119
- * 'include'. Default values for 'per_page' and 'display_comments'
120
- * differ from the originating function, and are described below.
121
- * @type string $page_arg The string used as a query parameter in
122
- * pagination links. Default: 'acpage'.
123
- * @type array|bool $include Pass an array of activity IDs to
124
- * retrieve only those items, or false to noop the 'include'
125
- * parameter. 'include' differs from 'in' in that 'in' forms
126
- * an IN clause that works in conjunction with other filters
127
- * passed to the function, while 'include' is interpreted as
128
- * an exact list of items to retrieve, which skips all other
129
- * filter-related parameters. Default: false.
130
- * @type int|bool $per_page Default: 20.
131
- * @type string|bool $display_comments Default: 'threaded'.
132
- * }
133
- */
134
- function __construct( $args ) {
135
- global $bp;
136
-
137
- // Backward compatibility with old method of passing arguments
138
- if ( !is_array( $args ) || func_num_args() > 1 ) {
139
- _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__ ) );
140
-
141
- $old_args_keys = array(
142
- 0 => 'page',
143
- 1 => 'per_page',
144
- 2 => 'max',
145
- 3 => 'include',
146
- 4 => 'sort',
147
- 5 => 'filter',
148
- 6 => 'search_terms',
149
- 7 => 'display_comments',
150
- 8 => 'show_hidden',
151
- 9 => 'exclude',
152
- 10 => 'in',
153
- 11 => 'spam',
154
- 12 => 'page_arg'
155
- );
156
-
157
- $func_args = func_get_args();
158
- $args = bp_core_parse_args_array( $old_args_keys, $func_args );
159
- }
160
-
161
- $defaults = array(
162
- 'page' => 1,
163
- 'per_page' => 20,
164
- 'page_arg' => 'acpage',
165
- 'max' => false,
166
- 'sort' => false,
167
- 'include' => false,
168
- 'exclude' => false,
169
- 'in' => false,
170
- 'filter' => false,
171
- 'search_terms' => false,
172
- 'meta_query' => false,
173
- 'display_comments' => 'threaded',
174
- 'show_hidden' => false,
175
- 'spam' => 'ham_only',
176
- 'update_meta_cache' => true,
177
- );
178
- $r = wp_parse_args( $args, $defaults );
179
- extract( $r );
180
-
181
- $this->pag_page = isset( $_REQUEST[$page_arg] ) ? intval( $_REQUEST[$page_arg] ) : $page;
182
- $this->pag_num = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
183
-
184
- // Check if blog/forum replies are disabled
185
- $this->disable_blogforum_replies = isset( $bp->site_options['bp-disable-blogforum-comments'] ) ? $bp->site_options['bp-disable-blogforum-comments'] : false;
186
-
187
- // Get an array of the logged in user's favorite activities
188
- $this->my_favs = maybe_unserialize( bp_get_user_meta( bp_loggedin_user_id(), 'bp_favorite_activities', true ) );
189
-
190
- // Fetch specific activity items based on ID's
191
- if ( !empty( $include ) ) {
192
- $this->activities = bp_activity_get_specific( array(
193
- 'activity_ids' => explode( ',', $include ),
194
- 'max' => $max,
195
- 'page' => $this->pag_page,
196
- 'per_page' => $this->pag_num,
197
- 'sort' => $sort,
198
- 'display_comments' => $display_comments,
199
- 'show_hidden' => $show_hidden,
200
- 'spam' => $spam,
201
- 'update_meta_cache' => $update_meta_cache,
202
- ) );
203
-
204
- // Fetch all activity items
205
- } else {
206
- $this->activities = bp_activity_get( array(
207
- 'display_comments' => $display_comments,
208
- 'max' => $max,
209
- 'per_page' => $this->pag_num,
210
- 'page' => $this->pag_page,
211
- 'sort' => $sort,
212
- 'search_terms' => $search_terms,
213
- 'meta_query' => $meta_query,
214
- 'filter' => $filter,
215
- 'show_hidden' => $show_hidden,
216
- 'exclude' => $exclude,
217
- 'in' => $in,
218
- 'spam' => $spam,
219
- 'update_meta_cache' => $update_meta_cache,
220
- ) );
221
- }
222
-
223
- if ( !$max || $max >= (int) $this->activities['total'] )
224
- $this->total_activity_count = (int) $this->activities['total'];
225
- else
226
- $this->total_activity_count = (int) $max;
227
-
228
- $this->activities = $this->activities['activities'];
229
-
230
- if ( $max ) {
231
- if ( $max >= count($this->activities) ) {
232
- $this->activity_count = count( $this->activities );
233
- } else {
234
- $this->activity_count = (int) $max;
235
- }
236
- } else {
237
- $this->activity_count = count( $this->activities );
238
- }
239
-
240
- $this->full_name = bp_get_displayed_user_fullname();
241
-
242
- // Fetch parent content for activity comments so we do not have to query in the loop
243
- foreach ( (array) $this->activities as $activity ) {
244
- if ( 'activity_comment' != $activity->type )
245
- continue;
246
-
247
- $parent_ids[] = $activity->item_id;
248
- }
249
-
250
- if ( !empty( $parent_ids ) )
251
- $activity_parents = bp_activity_get_specific( array( 'activity_ids' => $parent_ids ) );
252
-
253
- if ( !empty( $activity_parents['activities'] ) ) {
254
- foreach( $activity_parents['activities'] as $parent )
255
- $this->activity_parents[$parent->id] = $parent;
256
-
257
- unset( $activity_parents );
258
- }
259
-
260
- if ( (int) $this->total_activity_count && (int) $this->pag_num ) {
261
- $this->pag_links = paginate_links( array(
262
- 'base' => add_query_arg( $page_arg, '%#%' ),
263
- 'format' => '',
264
- 'total' => ceil( (int) $this->total_activity_count / (int) $this->pag_num ),
265
- 'current' => (int) $this->pag_page,
266
- 'prev_text' => _x( '&larr;', 'Activity pagination previous text', 'buddypress' ),
267
- 'next_text' => _x( '&rarr;', 'Activity pagination next text', 'buddypress' ),
268
- 'mid_size' => 1
269
- ) );
270
- }
271
- }
272
-
273
- /**
274
- * Whether there are activity items available in the loop.
275
- *
276
- * @see bp_has_activities()
277
- *
278
- * @return bool True if there are items in the loop, otherwise false.
279
- */
280
- function has_activities() {
281
- if ( $this->activity_count )
282
- return true;
283
 
284
- return false;
285
- }
286
-
287
- /**
288
- * Set up the next activity item and iterate index.
289
- *
290
- * @return object The next activity item to iterate over.
291
- */
292
- function next_activity() {
293
- $this->current_activity++;
294
- $this->activity = $this->activities[$this->current_activity];
295
-
296
- return $this->activity;
297
- }
298
-
299
- /**
300
- * Rewind the posts and reset post index.
301
- */
302
- function rewind_activities() {
303
- $this->current_activity = -1;
304
- if ( $this->activity_count > 0 ) {
305
- $this->activity = $this->activities[0];
306
- }
307
- }
308
-
309
- /**
310
- * Whether there are activity items left in the loop to iterate over.
311
- *
312
- * This method is used by {@link bp_activities()} as part of the while loop
313
- * that controls iteration inside the activities loop, eg:
314
- * while ( bp_activities() ) { ...
315
- *
316
- * @see bp_activities()
317
- *
318
- * @return bool True if there are more activity items to show,
319
- * otherwise false.
320
- */
321
- function user_activities() {
322
- if ( $this->current_activity + 1 < $this->activity_count ) {
323
- return true;
324
- } elseif ( $this->current_activity + 1 == $this->activity_count ) {
325
- do_action('activity_loop_end');
326
- // Do some cleaning up after the loop
327
- $this->rewind_activities();
328
- }
329
-
330
- $this->in_the_loop = false;
331
- return false;
332
- }
333
-
334
- /**
335
- * Set up the current activity item inside the loop.
336
- *
337
- * Used by {@link bp_the_activity()} to set up the current activity item
338
- * data while looping, so that template tags used during that iteration
339
- * make reference to the current activity item.
340
- *
341
- * @see bp_the_activity()
342
- */
343
- function the_activity() {
344
-
345
- $this->in_the_loop = true;
346
- $this->activity = $this->next_activity();
347
-
348
- if ( is_array( $this->activity ) )
349
- $this->activity = (object) $this->activity;
350
-
351
- if ( $this->current_activity == 0 ) // loop has just started
352
- do_action('activity_loop_start');
353
  }
354
- }
355
 
356
  /**
357
  * Initialize the activity loop.
@@ -360,327 +108,268 @@ class BP_Activity_Template {
360
  * $activities_template global, enabling the use of BuddyPress templates and
361
  * template functions to display a list of activity items.
362
  *
363
- * @since BuddyPress (1.0)
 
364
  *
365
  * @global object $activities_template {@link BP_Activity_Template}
366
- * @global object $bp BuddyPress global settings.
367
- * @uses groups_is_user_member()
368
- * @uses bp_current_action()
369
- * @uses bp_is_current_action()
370
- * @uses bp_get_activity_slug()
371
- * @uses bp_action_variable()
372
- * @uses wp_parse_args()
373
- * @uses bp_is_active()
374
- * @uses friends_get_friend_user_ids()
375
- * @uses groups_get_user_groups()
376
- * @uses bp_activity_get_user_favorites()
377
- * @uses apply_filters() To call the 'bp_has_activities' hook.
378
- *
379
- * @param array $args {
380
- * Arguments for limiting the contents of the activity loop. Most
381
- * arguments are in the same format as {@link BP_Activity_Activity::get()}.
382
- * However, because the format of the arguments accepted here differs in
383
- * a number of ways, and because bp_has_activities() determines some
384
- * default arguments in a dynamic fashion, we list all accepted arguments
385
- * here as well.
386
- *
387
- * Arguments can be passed as an associative array, or as a URL query
388
- * string (eg, 'user_id=4&display_comments=threaded').
389
- *
390
- * @type int $page Which page of results to fetch. Using page=1 without
391
- * per_page will result in no pagination. Default: 1.
392
- * @type int|bool $per_page Number of results per page. Default: 20.
393
- * @type string $page_arg The string used as a query parameter in
394
- * pagination links. Default: 'acpage'.
395
- * @type int|bool $max Maximum number of results to return.
396
- * Default: false (unlimited).
397
- * @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.
398
- * @type array|bool $exclude Array of activity IDs to exclude. Default: false.
399
- * @type array|bool $in Array of IDs to limit query by (IN). 'in' is
400
- * intended to be used in conjunction with other filter parameters.
401
- * Default: false.
402
- * @type array|bool $include Array of exact activity IDs to query.
403
- * Providing an 'include' array will override all other filters
404
- * passed in the argument array. When viewing a the permalink page
405
- * for a single activity item, this value defaults to the ID of that
406
- * item. Otherwise the default is false.
407
- * @type array $meta_query Limit by activitymeta by passing an array of
408
- * meta_query conditions. See {@link WP_Meta_Query::queries} for a
409
- * description of the syntax.
410
- * @type string $search_terms Limit results by a search term. Default: false.
411
- * @type string|bool $scope Use one of BuddyPress's pre-built filters. In
412
- * each case, the term 'current user' refers to the displayed user
413
- * when looking at a user profile, and otherwise to the logged-in user.
414
- * - 'just-me' retrieves items belonging only to the logged-in user;
415
- * this is equivalent to passing a 'user_id' argument
416
- * - 'friends' retrieves items belonging to the friends of the
417
- * current user
418
- * - 'groups' retrieves items associated with the groups to which
419
- * the current user belongs
420
- * - 'favorites' retrieves the current user's favorited activity
421
- * items
422
- * - 'mentions' retrieves activity items where the current user has
423
- * received an @-mention
424
- * The default value of 'scope' is set to one of the above if that
425
- * value appears in the appropriate place in the URL; eg, 'scope' will
426
- * be 'groups' when visiting http://example.com/members/joe/activity/groups/.
427
- * Otherwise defaults to false.
428
- * @type int|array|bool $user_id The ID(s) of user(s) whose activity should
429
- * be fetched. Pass a single ID or an array of IDs. When viewing a
430
- * user profile page (but not that user's activity subpages, ie My
431
- * Friends, My Groups, etc), 'user_id' defaults to the ID of the
432
- * displayed user. Otherwise the default is false.
433
- * @type string|array|bool $object Filters by the `component` column in the
434
- * database, which is generally the component ID in the case of
435
- * BuddyPress components, or the plugin slug in the case of plugins.
436
- * For example, 'groups' will limit results to those that are
437
- * associated with the BP Groups component. Accepts a single
438
- * component string, or an array of multiple components. Defaults to
439
- * 'groups' when viewing the page of a single group, the My Groups
440
- * activity filter, or the Activity > Groups filter of a user profile.
441
- * Otherwise defaults to false.
442
- * @type string|array|bool $action Filters by the `type` column in the
443
- * database, which is a string categorizing the activity item (eg,
444
- * 'new_blog_post', 'created_group'). Accepts a single type string,
445
- * or an array of multiple types. Defaults to false.
446
- * @type int|array|bool $primary_id Filters by the `item_id` column in the
447
- * database. The meaning of 'primary_id' differs between components/
448
- * types; for example, in the case of 'created_group', 'primary_id'
449
- * is the ID of the group. Accepts a single ID, or an array of
450
- * multiple IDs. When viewing a single group, defaults to the current
451
- * group ID. When viewing a user's Groups stream page, defaults to
452
- * the IDs of the user's groups. Otherwise defaults to false.
453
- * @type int|array|bool $secondary_id Filters by the `secondary_item_id`
454
- * column in the database. The meaning of 'secondary_id' differs
455
- * between components/types. Accepts a single ID, or an array of
456
- * multiple IDs. Defaults to false.
457
- * @type int $offset Return only activity items with an ID greater than or
458
- * equal to this one. Note that providing an offset will disable
459
- * pagination. Default: false.
460
- * @type string|bool $display_comments How to handle activity comments.
461
- * Possible values:
462
- * - 'threaded' - comments appear in a threaded tree, under their
463
- * parent items
464
- * - 'stream' - the activity stream is presented in a flat manner,
465
- * with comments sorted in chronological order alongside other
466
- * activity items
467
- * - false - don't fetch activity comments at all
468
- * Default: 'threaded'.
469
- * @type bool $show_hidden Whether to show items marked hide_sitewide.
470
- * Defaults to false, except in the following cases:
471
- * - User is viewing his own activity stream
472
- * - User is viewing the activity stream of a non-public group of
473
- * which he is a member
474
- * @type bool $show_hidden Normally defaults to false, except when:
475
- * - a user is viewing his own activity stream
476
- * - a user is viewing the activity stream of a non-public group of
477
- * which he is a member
478
- * @type string|bool $spam Spam status. 'ham_only', 'spam_only', or false
479
- * to show all activity regardless of spam status. Default: 'ham_only'.
480
- * @type bool $populate_extras Whether to pre-fetch the activity metadata
481
- * for the queried items. Default: true.
482
  * }
483
  * @return bool Returns true when activities are found, otherwise false.
484
  */
485
  function bp_has_activities( $args = '' ) {
486
- global $activities_template, $bp;
487
-
488
- /***
489
- * Set the defaults based on the current page. Any of these will be overridden
490
- * if arguments are directly passed into the loop. Custom plugins should always
491
- * pass their parameters directly to the loop.
492
- */
493
- $user_id = false;
494
- $include = false;
495
- $exclude = false;
496
- $in = false;
497
- $show_hidden = false;
498
- $object = false;
499
- $primary_id = false;
500
-
501
- // User filtering
502
- if ( bp_displayed_user_id() )
503
- $user_id = bp_displayed_user_id();
504
-
505
- // Group filtering
506
- if ( !empty( $bp->groups->current_group ) ) {
507
- $object = $bp->groups->id;
508
- $primary_id = $bp->groups->current_group->id;
509
-
510
- if ( ( 'public' != $bp->groups->current_group->status ) && ( groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) || bp_current_user_can( 'bp_moderate' ) ) )
511
- $show_hidden = true;
512
- }
513
-
514
- // The default scope should recognize custom slugs
515
- if ( array_key_exists( bp_current_action(), (array) $bp->loaded_components ) ) {
516
- $scope = $bp->loaded_components[bp_current_action()];
517
- }
518
- else
519
- $scope = bp_current_action();
520
-
521
- // Support for permalinks on single item pages: /groups/my-group/activity/124/
522
- if ( bp_is_current_action( bp_get_activity_slug() ) )
523
- $include = bp_action_variable( 0 );
524
-
525
- // Note: any params used for filtering can be a single value, or multiple values comma separated.
526
- $defaults = array(
527
- 'display_comments' => 'threaded', // false for none, stream/threaded - show comments in the stream or threaded under items
528
- 'include' => $include, // pass an activity_id or string of IDs comma-separated
529
- 'exclude' => $exclude, // pass an activity_id or string of IDs comma-separated
530
- 'in' => $in, // comma-separated list or array of activity IDs among which to search
531
- 'sort' => 'DESC', // sort DESC or ASC
532
- 'page' => 1, // which page to load
533
- 'per_page' => 20, // number of items per page
534
- 'max' => false, // max number to return
535
- 'show_hidden' => $show_hidden, // Show activity items that are hidden site-wide?
536
- 'spam' => 'ham_only', // Hide spammed items
537
 
538
- 'page_arg' => 'acpage', // See https://buddypress.trac.wordpress.org/ticket/3679
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
 
540
- // Scope - pre-built activity filters for a user (friends/groups/favorites/mentions)
541
  'scope' => $scope,
542
 
543
  // Filtering
544
- 'user_id' => $user_id, // user_id to filter on
545
- 'object' => $object, // object to filter on e.g. groups, profile, status, friends
546
- 'action' => false, // action to filter on e.g. activity_update, new_forum_post, profile_updated
547
- 'primary_id' => $primary_id, // object ID to filter on e.g. a group_id or forum_id or blog_id etc.
548
- 'secondary_id' => false, // secondary object ID to filter on e.g. a post_id
549
- 'offset' => false, // return only items >= this ID
550
- 'since' => false, // return only items recorded since this Y-m-d H:i:s date
551
-
552
- 'meta_query' => false, // filter on activity meta. See WP_Meta_Query for format
553
-
554
- // Searching
555
- 'search_terms' => false, // specify terms to search on
 
 
556
  'update_meta_cache' => true,
557
- );
558
 
559
- $r = bp_parse_args( $args, $defaults, 'has_activities' );
560
- extract( $r );
 
561
 
562
  // Translate various values for 'display_comments'
563
  // This allows disabling comments via ?display_comments=0
564
- // or =none or =false. Final true is a strict type check. See #5029
565
- if ( in_array( $display_comments, array( 0, '0', 'none', 'false' ), true ) ) {
566
- $display_comments = false;
567
  }
568
 
569
- // Ignore pagination if an offset is passed
570
- if ( ! empty( $offset ) ) {
571
- $page = 0;
572
  }
573
 
574
- if ( empty( $search_terms ) && ! empty( $_REQUEST['s'] ) )
575
- $search_terms = $_REQUEST['s'];
576
-
577
- // If you have passed a "scope" then this will override any filters you have passed.
578
- if ( 'just-me' == $scope || 'friends' == $scope || 'groups' == $scope || 'favorites' == $scope || 'mentions' == $scope ) {
579
- if ( 'just-me' == $scope )
580
- $display_comments = 'stream';
581
-
582
- // determine which user_id applies
583
- if ( empty( $user_id ) )
584
- $user_id = bp_displayed_user_id() ? bp_displayed_user_id() : bp_loggedin_user_id();
585
-
586
- // are we displaying user specific activity?
587
- if ( is_numeric( $user_id ) ) {
588
- $show_hidden = ( $user_id == bp_loggedin_user_id() && $scope != 'friends' ) ? 1 : 0;
589
-
590
- switch ( $scope ) {
591
- case 'friends':
592
- if ( bp_is_active( 'friends' ) )
593
- $friends = friends_get_friend_user_ids( $user_id );
594
- if ( empty( $friends ) )
595
- return false;
596
-
597
- $user_id = implode( ',', (array) $friends );
598
- break;
599
- case 'groups':
600
- if ( bp_is_active( 'groups' ) ) {
601
- $groups = groups_get_user_groups( $user_id );
602
- if ( empty( $groups['groups'] ) )
603
- return false;
604
 
605
- $object = $bp->groups->id;
606
- $primary_id = implode( ',', (array) $groups['groups'] );
 
 
607
 
608
- $user_id = 0;
609
- }
610
- break;
611
- case 'favorites':
612
- $favs = bp_activity_get_user_favorites( $user_id );
613
- if ( empty( $favs ) )
614
- return false;
615
-
616
- $in = implode( ',', (array) $favs );
617
- $display_comments = true;
618
- $user_id = 0;
619
- break;
620
- case 'mentions':
621
-
622
- // Are mentions disabled?
623
- if ( ! bp_activity_do_mentions() ) {
624
- return false;
625
- }
 
 
 
 
 
 
 
 
 
 
626
 
627
- // Start search at @ symbol and stop search at closing tag delimiter.
628
- $search_terms = '@' . bp_activity_get_user_mentionname( $user_id ) . '<';
629
- $display_comments = 'stream';
630
- $user_id = 0;
631
- break;
632
- }
633
- }
634
  }
635
 
636
- // Do not exceed the maximum per page
637
- if ( !empty( $max ) && ( (int) $per_page > (int) $max ) )
638
- $per_page = $max;
639
-
640
- // Support for basic filters in earlier BP versions is disabled by default. To enable, put
641
- // add_filter( 'bp_activity_enable_afilter_support', '__return_true' );
642
- // into bp-custom.php or your theme's functions.php
643
- if ( isset( $_GET['afilter'] ) && apply_filters( 'bp_activity_enable_afilter_support', false ) )
644
- $filter = array( 'object' => $_GET['afilter'] );
645
- else if ( ! empty( $user_id ) || ! empty( $object ) || ! empty( $action ) || ! empty( $primary_id ) || ! empty( $secondary_id ) || ! empty( $offset ) || ! empty( $since ) )
646
- $filter = array( 'user_id' => $user_id, 'object' => $object, 'action' => $action, 'primary_id' => $primary_id, 'secondary_id' => $secondary_id, 'offset' => $offset, 'since' => $since );
647
- else
648
- $filter = false;
649
-
650
- // If specific activity items have been requested, override the $hide_spam argument. This prevents backpat errors with AJAX.
651
- if ( !empty( $include ) && ( 'ham_only' == $spam ) )
652
- $spam = 'all';
653
-
654
- $template_args = array(
655
- 'page' => $page,
656
- 'per_page' => $per_page,
657
- 'page_arg' => $page_arg,
658
- 'max' => $max,
659
- 'sort' => $sort,
660
- 'include' => $include,
661
- 'exclude' => $exclude,
662
- 'in' => $in,
663
- 'filter' => $filter,
664
- 'search_terms' => $search_terms,
665
- 'meta_query' => $meta_query,
666
- 'display_comments' => $display_comments,
667
- 'show_hidden' => $show_hidden,
668
- 'spam' => $spam,
669
- 'update_meta_cache' => $update_meta_cache,
670
- );
671
 
672
- $activities_template = new BP_Activity_Template( $template_args );
673
 
674
- return apply_filters( 'bp_has_activities', $activities_template->has_activities(), $activities_template, $template_args );
 
 
 
 
 
 
 
 
 
675
  }
676
 
677
  /**
678
  * Determine if there are still activities left in the loop.
679
  *
680
- * @since BuddyPress (1.0)
681
  *
682
  * @global object $activities_template {@link BP_Activity_Template}
683
- * @uses BP_Activity_Template::user_activities() {@link BP_Activity_Template::user_activities()}
684
  *
685
  * @return bool Returns true when activities are found.
686
  */
@@ -692,10 +381,9 @@ function bp_activities() {
692
  /**
693
  * Get the current activity object in the loop.
694
  *
695
- * @since BuddyPress (1.0)
696
  *
697
  * @global object $activities_template {@link BP_Activity_Template}
698
- * @uses BP_Activity_Template::the_activity() {@link BP_Activity_Template::the_activity()}
699
  *
700
  * @return object The current activity within the loop.
701
  */
@@ -704,13 +392,45 @@ function bp_the_activity() {
704
  return $activities_template->the_activity();
705
  }
706
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
707
  /**
708
  * Output the activity pagination count.
709
  *
710
- * @since BuddyPress (1.0)
711
  *
712
  * @global object $activities_template {@link BP_Activity_Template}
713
- * @uses BP_Activity_Template::the_activity() {@link BP_Activity_Template::the_activity()}
714
  */
715
  function bp_activity_pagination_count() {
716
  echo bp_get_activity_pagination_count();
@@ -719,10 +439,9 @@ function bp_activity_pagination_count() {
719
  /**
720
  * Return the activity pagination count.
721
  *
722
- * @since BuddyPress (1.2)
723
  *
724
  * @global object $activities_template {@link BP_Activity_Template}
725
- * @uses bp_core_number_format()
726
  *
727
  * @return string The pagination text.
728
  */
@@ -734,15 +453,20 @@ function bp_activity_pagination_count() {
734
  $to_num = bp_core_number_format( ( $start_num + ( $activities_template->pag_num - 1 ) > $activities_template->total_activity_count ) ? $activities_template->total_activity_count : $start_num + ( $activities_template->pag_num - 1 ) );
735
  $total = bp_core_number_format( $activities_template->total_activity_count );
736
 
737
- return sprintf( _n( 'Viewing item %1$s to %2$s (of %3$s item)', 'Viewing item %1$s to %2$s (of %3$s items)', $total, 'buddypress' ), $from_num, $to_num, $total );
 
 
 
 
 
 
738
  }
739
 
740
  /**
741
  * Output the activity pagination links.
742
  *
743
- * @since BuddyPress (1.0)
744
  *
745
- * @uses bp_get_activity_pagination_links()
746
  */
747
  function bp_activity_pagination_links() {
748
  echo bp_get_activity_pagination_links();
@@ -751,49 +475,64 @@ function bp_activity_pagination_links() {
751
  /**
752
  * Return the activity pagination links.
753
  *
754
- * @since BuddyPress (1.0)
755
  *
756
  * @global object $activities_template {@link BP_Activity_Template}
757
- * @uses apply_filters() To call the 'bp_get_activity_pagination_links' hook.
758
  *
759
  * @return string The pagination links.
760
  */
761
  function bp_get_activity_pagination_links() {
762
  global $activities_template;
763
 
 
 
 
 
 
 
 
764
  return apply_filters( 'bp_get_activity_pagination_links', $activities_template->pag_links );
765
  }
766
 
767
  /**
768
  * Return true when there are more activity items to be shown than currently appear.
769
  *
770
- * @since BuddyPress (1.5)
771
  *
772
  * @global object $activities_template {@link BP_Activity_Template}
773
- * @uses apply_filters() To call the 'bp_activity_has_more_items' hook.
774
  *
775
  * @return bool $has_more_items True if more items, false if not.
776
  */
777
  function bp_activity_has_more_items() {
778
  global $activities_template;
779
 
780
- $remaining_pages = 0;
 
 
 
781
 
782
- if ( ! empty( $activities_template->pag_page ) ) {
783
- $remaining_pages = floor( ( $activities_template->total_activity_count - 1 ) / ( $activities_template->pag_num * $activities_template->pag_page ) );
784
- }
785
 
786
- $has_more_items = (int) $remaining_pages ? true : false;
 
787
 
 
 
 
 
 
 
 
788
  return apply_filters( 'bp_activity_has_more_items', $has_more_items );
789
  }
790
 
791
  /**
792
  * Output the activity count.
793
  *
794
- * @since BuddyPress (1.2)
795
  *
796
- * @uses bp_get_activity_count()
797
  */
798
  function bp_activity_count() {
799
  echo bp_get_activity_count();
@@ -802,25 +541,30 @@ function bp_activity_count() {
802
  /**
803
  * Return the activity count.
804
  *
805
- * @since BuddyPress (1.2)
806
  *
807
  * @global object $activities_template {@link BP_Activity_Template}
808
- * @uses apply_filters() To call the 'bp_get_activity_count' hook.
809
  *
810
  * @return int The activity count.
811
  */
812
  function bp_get_activity_count() {
813
  global $activities_template;
814
 
 
 
 
 
 
 
 
815
  return apply_filters( 'bp_get_activity_count', (int) $activities_template->activity_count );
816
  }
817
 
818
  /**
819
  * Output the number of activities per page.
820
  *
821
- * @since BuddyPress (1.2)
822
  *
823
- * @uses bp_get_activity_per_page()
824
  */
825
  function bp_activity_per_page() {
826
  echo bp_get_activity_per_page();
@@ -829,25 +573,30 @@ function bp_activity_per_page() {
829
  /**
830
  * Return the number of activities per page.
831
  *
832
- * @since BuddyPress (1.2)
833
  *
834
  * @global object $activities_template {@link BP_Activity_Template}
835
- * @uses apply_filters() To call the 'bp_get_activity_per_page' hook.
836
  *
837
  * @return int The activities per page.
838
  */
839
  function bp_get_activity_per_page() {
840
  global $activities_template;
841
 
 
 
 
 
 
 
 
842
  return apply_filters( 'bp_get_activity_per_page', (int) $activities_template->pag_num );
843
  }
844
 
845
  /**
846
  * Output the activities title.
847
  *
848
- * @since BuddyPress (1.0)
849
  *
850
- * @uses bp_get_activities_title()
851
  * @todo Deprecate.
852
  */
853
  function bp_activities_title() {
@@ -857,26 +606,31 @@ function bp_activities_title() {
857
  /**
858
  * Return the activities title.
859
  *
860
- * @since BuddyPress (1.0)
861
  *
862
  * @global string $bp_activity_title
863
- * @uses apply_filters() To call the 'bp_get_activities_title' hook.
864
  * @todo Deprecate.
865
  *
866
- * @return int The activities title.
867
  */
868
  function bp_get_activities_title() {
869
  global $bp_activity_title;
870
 
 
 
 
 
 
 
 
871
  return apply_filters( 'bp_get_activities_title', $bp_activity_title );
872
  }
873
 
874
  /**
875
  * {@internal Missing Description}
876
  *
877
- * @since BuddyPress (1.0)
878
  *
879
- * @uses bp_get_activities_no_activity()
880
  * @todo Deprecate.
881
  */
882
  function bp_activities_no_activity() {
@@ -886,10 +640,9 @@ function bp_activities_no_activity() {
886
  /**
887
  * {@internal Missing Description}
888
  *
889
- * @since BuddyPress (1.0)
890
  *
891
  * @global string $bp_activity_no_activity
892
- * @uses apply_filters() To call the 'bp_get_activities_no_activity' hook
893
  * @todo Deprecate.
894
  *
895
  * @return string
@@ -897,15 +650,21 @@ function bp_activities_no_activity() {
897
  function bp_get_activities_no_activity() {
898
  global $bp_activity_no_activity;
899
 
 
 
 
 
 
 
 
900
  return apply_filters( 'bp_get_activities_no_activity', $bp_activity_no_activity );
901
  }
902
 
903
  /**
904
  * Output the activity ID.
905
  *
906
- * @since BuddyPress (1.2)
907
  *
908
- * @uses bp_get_activity_id()
909
  */
910
  function bp_activity_id() {
911
  echo bp_get_activity_id();
@@ -914,24 +673,30 @@ function bp_activity_id() {
914
  /**
915
  * Return the activity ID.
916
  *
917
- * @since BuddyPress (1.2)
918
  *
919
  * @global object $activities_template {@link BP_Activity_Template}
920
- * @uses apply_filters() To call the 'bp_get_activity_id' hook.
921
  *
922
  * @return int The activity ID.
923
  */
924
  function bp_get_activity_id() {
925
  global $activities_template;
 
 
 
 
 
 
 
 
926
  return apply_filters( 'bp_get_activity_id', $activities_template->activity->id );
927
  }
928
 
929
  /**
930
  * Output the activity item ID.
931
  *
932
- * @since BuddyPress (1.2)
933
  *
934
- * @uses bp_get_activity_item_id()
935
  */
936
  function bp_activity_item_id() {
937
  echo bp_get_activity_item_id();
@@ -940,24 +705,30 @@ function bp_activity_item_id() {
940
  /**
941
  * Return the activity item ID.
942
  *
943
- * @since BuddyPress (1.2)
944
  *
945
  * @global object $activities_template {@link BP_Activity_Template}
946
- * @uses apply_filters() To call the 'bp_get_activity_item_id' hook.
947
  *
948
  * @return int The activity item ID.
949
  */
950
  function bp_get_activity_item_id() {
951
  global $activities_template;
 
 
 
 
 
 
 
 
952
  return apply_filters( 'bp_get_activity_item_id', $activities_template->activity->item_id );
953
  }
954
 
955
  /**
956
  * Output the activity secondary item ID.
957
  *
958
- * @since BuddyPress (1.2)
959
  *
960
- * @uses bp_get_activity_secondary_item_id()
961
  */
962
  function bp_activity_secondary_item_id() {
963
  echo bp_get_activity_secondary_item_id();
@@ -966,24 +737,30 @@ function bp_activity_secondary_item_id() {
966
  /**
967
  * Return the activity secondary item ID.
968
  *
969
- * @since BuddyPress (1.2)
970
  *
971
  * @global object $activities_template {@link BP_Activity_Template}
972
- * @uses apply_filters() To call the 'bp_get_activity_secondary_item_id' hook.
973
  *
974
  * @return int The activity secondary item ID.
975
  */
976
  function bp_get_activity_secondary_item_id() {
977
  global $activities_template;
 
 
 
 
 
 
 
 
978
  return apply_filters( 'bp_get_activity_secondary_item_id', $activities_template->activity->secondary_item_id );
979
  }
980
 
981
  /**
982
  * Output the date the activity was recorded.
983
  *
984
- * @since BuddyPress (1.2)
985
  *
986
- * @uses bp_get_activity_date_recorded()
987
  */
988
  function bp_activity_date_recorded() {
989
  echo bp_get_activity_date_recorded();
@@ -992,24 +769,66 @@ function bp_activity_date_recorded() {
992
  /**
993
  * Return the date the activity was recorded.
994
  *
995
- * @since BuddyPress (1.2)
996
  *
997
  * @global object $activities_template {@link BP_Activity_Template}
998
- * @uses apply_filters() To call the 'bp_get_activity_date_recorded' hook.
999
  *
1000
  * @return string The date the activity was recorded.
1001
  */
1002
  function bp_get_activity_date_recorded() {
1003
  global $activities_template;
 
 
 
 
 
 
 
 
1004
  return apply_filters( 'bp_get_activity_date_recorded', $activities_template->activity->date_recorded );
1005
  }
1006
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1007
  /**
1008
  * Output the activity object name.
1009
  *
1010
- * @since BuddyPress (1.2)
1011
  *
1012
- * @uses bp_get_activity_object_name()
1013
  */
1014
  function bp_activity_object_name() {
1015
  echo bp_get_activity_object_name();
@@ -1018,24 +837,30 @@ function bp_activity_object_name() {
1018
  /**
1019
  * Return the activity object name.
1020
  *
1021
- * @since BuddyPress (1.2)
1022
  *
1023
  * @global object $activities_template {@link BP_Activity_Template}
1024
- * @uses apply_filters() To call the 'bp_get_activity_object_name' hook.
1025
  *
1026
  * @return string The activity object name.
1027
  */
1028
  function bp_get_activity_object_name() {
1029
  global $activities_template;
 
 
 
 
 
 
 
 
1030
  return apply_filters( 'bp_get_activity_object_name', $activities_template->activity->component );
1031
  }
1032
 
1033
  /**
1034
  * Output the activity type.
1035
  *
1036
- * @since BuddyPress (1.2)
1037
  *
1038
- * @uses bp_get_activity_type()
1039
  */
1040
  function bp_activity_type() {
1041
  echo bp_get_activity_type();
@@ -1044,15 +869,22 @@ function bp_activity_type() {
1044
  /**
1045
  * Return the activity type.
1046
  *
1047
- * @since BuddyPress (1.2)
1048
  *
1049
  * @global object $activities_template {@link BP_Activity_Template}
1050
- * @uses apply_filters() To call the 'bp_get_activity_type' hook.
1051
  *
1052
  * @return string The activity type.
1053
  */
1054
  function bp_get_activity_type() {
1055
  global $activities_template;
 
 
 
 
 
 
 
 
1056
  return apply_filters( 'bp_get_activity_type', $activities_template->activity->type );
1057
  }
1058
 
@@ -1061,13 +893,12 @@ function bp_activity_type() {
1061
  *
1062
  * Just a wrapper for bp_activity_type().
1063
  *
1064
- * @since BuddyPress (1.2)
1065
- * @deprecated BuddyPress (1.5)
1066
  *
1067
  * @todo Properly deprecate in favor of bp_activity_type() and
1068
- * remove redundant echo
1069
  *
1070
- * @uses bp_activity_type()
1071
  */
1072
  function bp_activity_action_name() { echo bp_activity_type(); }
1073
 
@@ -1076,12 +907,11 @@ function bp_activity_type() {
1076
  *
1077
  * Just a wrapper for bp_get_activity_type().
1078
  *
1079
- * @since BuddyPress (1.2)
1080
- * @deprecated BuddyPress (1.5)
1081
  *
1082
  * @todo Properly deprecate in favor of bp_get_activity_type().
1083
  *
1084
- * @uses bp_get_activity_type()
1085
  *
1086
  * @return string The activity type.
1087
  */
@@ -1090,9 +920,8 @@ function bp_activity_type() {
1090
  /**
1091
  * Output the activity user ID.
1092
  *
1093
- * @since BuddyPress (1.1)
1094
  *
1095
- * @uses bp_get_activity_user_id()
1096
  */
1097
  function bp_activity_user_id() {
1098
  echo bp_get_activity_user_id();
@@ -1101,24 +930,30 @@ function bp_activity_user_id() {
1101
  /**
1102
  * Return the activity user ID.
1103
  *
1104
- * @since BuddyPress (1.1)
1105
  *
1106
  * @global object $activities_template {@link BP_Activity_Template}
1107
- * @uses apply_filters() To call the 'bp_get_activity_user_id' hook.
1108
  *
1109
  * @return int The activity user ID.
1110
  */
1111
  function bp_get_activity_user_id() {
1112
  global $activities_template;
 
 
 
 
 
 
 
 
1113
  return apply_filters( 'bp_get_activity_user_id', $activities_template->activity->user_id );
1114
  }
1115
 
1116
  /**
1117
  * Output the activity user link.
1118
  *
1119
- * @since BuddyPress (1.2)
1120
  *
1121
- * @uses bp_get_activity_user_link()
1122
  */
1123
  function bp_activity_user_link() {
1124
  echo bp_get_activity_user_link();
@@ -1127,34 +962,39 @@ function bp_activity_user_link() {
1127
  /**
1128
  * Return the activity user link.
1129
  *
1130
- * @since BuddyPress (1.2)
1131
  *
1132
  * @global object $activities_template {@link BP_Activity_Template}
1133
- * @uses bp_core_get_user_domain()
1134
- * @uses apply_filters() To call the 'bp_get_activity_user_link' hook.
1135
  *
1136
  * @return string $link The activity user link.
1137
  */
1138
  function bp_get_activity_user_link() {
1139
  global $activities_template;
1140
 
1141
- if ( empty( $activities_template->activity->user_id ) )
1142
  $link = $activities_template->activity->primary_link;
1143
- else
1144
  $link = bp_core_get_user_domain( $activities_template->activity->user_id, $activities_template->activity->user_nicename, $activities_template->activity->user_login );
 
1145
 
 
 
 
 
 
 
 
1146
  return apply_filters( 'bp_get_activity_user_link', $link );
1147
  }
1148
 
1149
  /**
1150
  * Output the avatar of the user that performed the action.
1151
  *
1152
- * @since BuddyPress (1.1)
1153
  *
1154
  * @see bp_get_activity_avatar() for description of arguments.
1155
- * @uses bp_get_activity_avatar()
1156
  *
1157
- * @param array $args See {@link bp_get_activity_avatar()} for description.
1158
  */
1159
  function bp_activity_avatar( $args = '' ) {
1160
  echo bp_get_activity_avatar( $args );
@@ -1162,30 +1002,23 @@ function bp_activity_avatar( $args = '' ) {
1162
  /**
1163
  * Return the avatar of the user that performed the action.
1164
  *
1165
- * @since BuddyPress (1.1)
1166
  *
1167
  * @see bp_core_fetch_avatar() For a description of the arguments.
1168
  * @global object $activities_template {@link BP_Activity_Template}
1169
- * @global object $bp BuddyPress global settings
1170
- * @uses bp_is_single_activity()
1171
- * @uses wp_parse_args()
1172
- * @uses apply_filters() To call the 'bp_get_activity_avatar_object_' . $current_activity_item->component hook
1173
- * @uses apply_filters() To call the 'bp_get_activity_avatar_item_id' hook
1174
- * @uses bp_core_fetch_avatar()
1175
- * @uses apply_filters() To call the 'bp_get_activity_avatar' hook
1176
- *
1177
- * @param array $args {
1178
  * Arguments are listed here with an explanation of their defaults.
1179
  * For more information about the arguments, see
1180
  * {@link bp_core_fetch_avatar()}.
1181
- * @type string $alt Default: 'Profile picture of [user name]' if
1182
- * activity user name is available, otherwise 'Profile picture'.
1183
- * @type string $class Default: 'avatar'.
1184
- * @type string|bool $email Default: Email of the activity's
1185
- * associated user, if available. Otherwise false.
1186
- * @type string $type Default: 'full' when viewing a single activity
1187
- * permalink page, otherwise 'thumb'.
1188
- * @type int|bool $user_id Default: ID of the activity's user.
1189
  * }
1190
  * @return string User avatar string.
1191
  */
@@ -1194,17 +1027,17 @@ function bp_activity_avatar( $args = '' ) {
1194
 
1195
  $bp = buddypress();
1196
 
1197
- // On activity permalink pages, default to the full-size avatar
1198
  $type_default = bp_is_single_activity() ? 'full' : 'thumb';
1199
 
1200
  // Within the activity comment loop, the current activity should be set
1201
  // to current_comment. Otherwise, just use activity.
1202
  $current_activity_item = isset( $activities_template->activity->current_comment ) ? $activities_template->activity->current_comment : $activities_template->activity;
1203
 
1204
- // Activity user display name
1205
  $dn_default = isset( $current_activity_item->display_name ) ? $current_activity_item->display_name : '';
1206
 
1207
- // Prepend some descriptive text to alt
1208
  $alt_default = !empty( $dn_default ) ? sprintf( __( 'Profile picture of %s', 'buddypress' ), $dn_default ) : __( 'Profile picture', 'buddypress' );
1209
 
1210
  $defaults = array(
@@ -1220,14 +1053,14 @@ function bp_activity_avatar( $args = '' ) {
1220
 
1221
  if ( !isset( $height ) && !isset( $width ) ) {
1222
 
1223
- // Backpat
1224
  if ( isset( $bp->avatar->full->height ) || isset( $bp->avatar->thumb->height ) ) {
1225
  $height = ( 'full' == $type ) ? $bp->avatar->full->height : $bp->avatar->thumb->height;
1226
  } else {
1227
  $height = 20;
1228
  }
1229
 
1230
- // Backpat
1231
  if ( isset( $bp->avatar->full->width ) || isset( $bp->avatar->thumb->width ) ) {
1232
  $width = ( 'full' == $type ) ? $bp->avatar->full->width : $bp->avatar->thumb->width;
1233
  } else {
@@ -1235,15 +1068,41 @@ function bp_activity_avatar( $args = '' ) {
1235
  }
1236
  }
1237
 
1238
- // Primary activity avatar is always a user, but can be modified via a filter
 
 
 
 
 
 
 
 
 
 
1239
  $object = apply_filters( 'bp_get_activity_avatar_object_' . $current_activity_item->component, 'user' );
1240
  $item_id = !empty( $user_id ) ? $user_id : $current_activity_item->user_id;
 
 
 
 
 
 
 
 
1241
  $item_id = apply_filters( 'bp_get_activity_avatar_item_id', $item_id );
1242
 
1243
- // If this is a user object pass the users' email address for Gravatar so we don't have to refetch it.
1244
- if ( 'user' == $object && empty( $user_id ) && empty( $email ) && isset( $current_activity_item->user_email ) )
1245
  $email = $current_activity_item->user_email;
 
1246
 
 
 
 
 
 
 
 
1247
  return apply_filters( 'bp_get_activity_avatar', bp_core_fetch_avatar( array(
1248
  'item_id' => $item_id,
1249
  'object' => $object,
@@ -1259,42 +1118,35 @@ function bp_activity_avatar( $args = '' ) {
1259
  /**
1260
  * Output the avatar of the object that action was performed on.
1261
  *
1262
- * @since BuddyPress (1.2)
1263
  *
1264
  * @see bp_get_activity_secondary_avatar() for description of arguments.
1265
- * @uses bp_get_activity_secondary_avatar()
1266
  *
1267
- * @param array $args See {@link bp_get_activity_secondary_avatar} for description.
1268
  */
1269
  function bp_activity_secondary_avatar( $args = '' ) {
1270
  echo bp_get_activity_secondary_avatar( $args );
1271
  }
1272
 
1273
  /**
1274
- * Return the avatar of the object that action was performed on
1275
  *
1276
- * @since BuddyPress (1.2)
1277
  *
1278
  * @see bp_core_fetch_avatar() for description of arguments.
1279
  * @global object $activities_template {@link BP_Activity_Template}
1280
- * @uses wp_parse_args()
1281
- * @uses get_blog_option()
1282
- * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component hook.
1283
- * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar_item_id' hook.
1284
- * @uses bp_core_fetch_avatar()
1285
- * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar' hook.
1286
- *
1287
- * @param array $args {
1288
  * For a complete description of arguments, see {@link bp_core_fetch_avatar()}.
1289
- * @type string $alt Default value varies based on current activity
1290
- * item component.
1291
- * @type string $type Default: 'full' when viewing a single activity
1292
- * permalink page, otherwise 'thumb'.
1293
- * @type string $class Default: 'avatar'.
1294
- * @type string|bool $email Default: email of the activity's user.
1295
- * @type int|bool $user_id Default: ID of the activity's user.
1296
  * }
1297
- * @return string The secondary avatar
1298
  */
1299
  function bp_get_activity_secondary_avatar( $args = '' ) {
1300
  global $activities_template;
@@ -1311,21 +1163,21 @@ function bp_activity_secondary_avatar( $args = '' ) {
1311
  ) );
1312
  extract( $r, EXTR_SKIP );
1313
 
1314
- // Set item_id and object (default to user)
1315
  switch ( $activities_template->activity->component ) {
1316
  case 'groups' :
 
 
 
 
1317
  $object = 'group';
1318
  $item_id = $activities_template->activity->item_id;
1319
  $link = '';
1320
  $name = '';
1321
 
1322
- // Only if groups is active
1323
  if ( bp_is_active( 'groups' ) ) {
1324
- $group = groups_get_group( array(
1325
- 'group_id' => $item_id,
1326
- 'populate_extras' => false,
1327
- 'update_meta_cache' => false,
1328
- ) );
1329
  $link = bp_get_group_permalink( $group );
1330
  $name = $group->name;
1331
  }
@@ -1372,16 +1224,34 @@ function bp_activity_secondary_avatar( $args = '' ) {
1372
  break;
1373
  }
1374
 
1375
- // Allow object, item_id, and link to be filtered
 
 
 
 
 
 
 
 
 
 
1376
  $object = apply_filters( 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component, $object );
 
 
 
 
 
 
 
 
1377
  $item_id = apply_filters( 'bp_get_activity_secondary_avatar_item_id', $item_id );
1378
 
1379
- // If we have no item_id or object, there is no avatar to display
1380
  if ( empty( $item_id ) || empty( $object ) ) {
1381
  return false;
1382
  }
1383
 
1384
- // Get the avatar
1385
  $avatar = bp_core_fetch_avatar( array(
1386
  'item_id' => $item_id,
1387
  'object' => $object,
@@ -1394,102 +1264,141 @@ function bp_activity_secondary_avatar( $args = '' ) {
1394
  ) );
1395
 
1396
  if ( !empty( $linked ) ) {
 
 
 
 
 
 
 
 
 
1397
  $link = apply_filters( 'bp_get_activity_secondary_avatar_link', $link, $activities_template->activity->component );
1398
 
 
 
 
 
 
 
 
 
 
1399
  return sprintf( '<a href="%s" class="%s">%s</a>',
1400
  $link,
1401
  $link_class,
1402
- apply_filters( 'bp_get_activity_secondary_avatar', $avatar )
1403
  );
1404
  }
1405
 
1406
- // else
1407
  return apply_filters( 'bp_get_activity_secondary_avatar', $avatar );
1408
  }
1409
 
1410
  /**
1411
- * Output the activity action
1412
  *
1413
- * @since BuddyPress (1.2)
1414
  *
1415
- * @param array $args See bp_get_activity_action()
1416
- * @uses bp_get_activity_action()
1417
  */
1418
  function bp_activity_action( $args = array() ) {
1419
  echo bp_get_activity_action( $args );
1420
  }
1421
 
1422
  /**
1423
- * Return the activity action
1424
  *
1425
- * @since BuddyPress (1.2)
1426
  *
1427
  * @global object $activities_template {@link BP_Activity_Template}
1428
- * @param array $args Only parameter is "no_timestamp". If true, timestamp is shown in output.
1429
- * @uses apply_filters_ref_array() To call the 'bp_get_activity_action_pre_meta' hook
1430
- * @uses bp_insert_activity_meta()
1431
- * @uses apply_filters_ref_array() To call the 'bp_get_activity_action' hook.
1432
  *
1433
  * @param array $args {
1434
  * @type bool $no_timestamp Whether to exclude the timestamp.
1435
  * }
 
1436
  * @return string The activity action.
1437
  */
1438
  function bp_get_activity_action( $args = array() ) {
1439
  global $activities_template;
1440
 
1441
- $defaults = array(
1442
  'no_timestamp' => false,
1443
- );
1444
-
1445
- $args = wp_parse_args( $args, $defaults );
1446
- extract( $args, EXTR_SKIP );
1447
 
1448
- $action = $activities_template->activity->action;
1449
- $action = apply_filters_ref_array( 'bp_get_activity_action_pre_meta', array( $action, &$activities_template->activity, $args ) );
 
 
 
 
 
 
 
 
 
 
1450
 
1451
- if ( ! empty( $action ) && ! $no_timestamp )
 
1452
  $action = bp_insert_activity_meta( $action );
 
1453
 
1454
- return apply_filters_ref_array( 'bp_get_activity_action', array( $action, &$activities_template->activity, $args ) );
 
 
 
 
 
 
 
 
 
 
 
1455
  }
1456
 
1457
  /**
1458
- * Output the activity content body
1459
  *
1460
- * @since BuddyPress (1.2)
1461
  *
1462
- * @uses bp_get_activity_content_body()
1463
  */
1464
  function bp_activity_content_body() {
1465
  echo bp_get_activity_content_body();
1466
  }
1467
 
1468
  /**
1469
- * Return the activity content body
1470
  *
1471
- * @since BuddyPress (1.2)
1472
  *
1473
  * @global object $activities_template {@link BP_Activity_Template}
1474
- * @uses bp_insert_activity_meta()
1475
- * @uses apply_filters_ref_array() To call the 'bp_get_activity_content_body' hook.
1476
  *
1477
  * @return string The activity content body.
1478
  */
1479
  function bp_get_activity_content_body() {
1480
  global $activities_template;
1481
 
1482
- // Backwards compatibility if action is not being used
1483
- if ( empty( $activities_template->activity->action ) && !empty( $activities_template->activity->content ) )
1484
  $activities_template->activity->content = bp_insert_activity_meta( $activities_template->activity->content );
 
1485
 
 
 
 
 
 
 
 
1486
  return apply_filters_ref_array( 'bp_get_activity_content_body', array( $activities_template->activity->content, &$activities_template->activity ) );
1487
  }
1488
 
1489
  /**
1490
  * Does the activity have content?
1491
  *
1492
- * @since BuddyPress (1.2)
1493
  *
1494
  * @global object $activities_template {@link BP_Activity_Template}
1495
  *
@@ -1498,8 +1407,9 @@ function bp_activity_content_body() {
1498
  function bp_activity_has_content() {
1499
  global $activities_template;
1500
 
1501
- if ( !empty( $activities_template->activity->content ) )
1502
  return true;
 
1503
 
1504
  return false;
1505
  }
@@ -1507,12 +1417,11 @@ function bp_activity_has_content() {
1507
  /**
1508
  * Output the activity content.
1509
  *
1510
- * @since BuddyPress (1.0)
1511
- * @deprecated BuddyPress (1.5)
1512
  *
1513
  * @todo properly deprecate this function.
1514
  *
1515
- * @uses bp_get_activity_content()
1516
  */
1517
  function bp_activity_content() {
1518
  echo bp_get_activity_content();
@@ -1521,25 +1430,22 @@ function bp_activity_content() {
1521
  /**
1522
  * Return the activity content.
1523
  *
1524
- * @since BuddyPress (1.0)
1525
- * @deprecated BuddyPress (1.5)
1526
  *
1527
  * @todo properly deprecate this function.
1528
  *
1529
- * @uses bp_get_activity_action()
1530
- * @uses bp_get_activity_content_body()
1531
- * @uses apply_filters() To call the 'bp_get_activity_content' hook.
1532
  *
1533
  * @return string The activity content.
1534
  */
1535
  function bp_get_activity_content() {
 
1536
  /**
1537
  * If you want to filter activity update content, please use
1538
- * the filter 'bp_get_activity_content_body'
1539
  *
1540
- * This function is mainly for backwards comptibility.
1541
  */
1542
-
1543
  $content = bp_get_activity_action() . ' ' . bp_get_activity_content_body();
1544
  return apply_filters( 'bp_get_activity_content', $content );
1545
  }
@@ -1550,81 +1456,145 @@ function bp_activity_content() {
1550
  * This metadata includes the time since the item was posted (which will appear
1551
  * as a link to the item's permalink).
1552
  *
1553
- * @since BuddyPress (1.2)
1554
  *
1555
  * @global object $activities_template {@link BP_Activity_Template}
1556
- * @uses bp_core_time_since()
1557
- * @uses apply_filters_ref_array() To call the 'bp_activity_time_since' hook.
1558
- * @uses bp_is_single_activity()
1559
- * @uses bp_activity_get_permalink()
1560
- * @uses esc_attr__()
1561
- * @uses apply_filters_ref_array() To call the 'bp_activity_permalink' hook.
1562
- * @uses apply_filters() To call the 'bp_insert_activity_meta' hook.
1563
  *
1564
  * @param string $content The activity content.
1565
  * @return string The activity content with the metadata string attached.
1566
  */
1567
- function bp_insert_activity_meta( $content ) {
1568
  global $activities_template;
1569
 
1570
- // Strip any legacy time since placeholders from BP 1.0-1.1
1571
- $content = str_replace( '<span class="time-since">%s</span>', '', $content );
 
 
 
1572
 
1573
- // Insert the time since.
1574
- $time_since = apply_filters_ref_array( 'bp_activity_time_since', array( '<span class="time-since">' . bp_core_time_since( $activities_template->activity->date_recorded ) . '</span>', &$activities_template->activity ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1575
 
1576
- // Insert the permalink
1577
- if ( !bp_is_single_activity() )
1578
- $content = apply_filters_ref_array( 'bp_activity_permalink', array( sprintf( '%1$s <a href="%2$s" class="view activity-time-since" title="%3$s">%4$s</a>', $content, bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity ), esc_attr__( 'View Discussion', 'buddypress' ), $time_since ), &$activities_template->activity ) );
1579
- else
1580
- $content .= str_pad( $time_since, strlen( $time_since ) + 2, ' ', STR_PAD_BOTH );
 
 
 
 
 
 
 
 
 
 
1581
 
1582
- return apply_filters( 'bp_insert_activity_meta', $content );
 
 
 
 
 
 
 
1583
  }
1584
 
1585
  /**
1586
  * Determine if the current user can delete an activity item.
1587
  *
1588
- * @since BuddyPress (1.2)
1589
  *
1590
  * @global object $activities_template {@link BP_Activity_Template}
1591
- * @uses apply_filters() To call the 'bp_activity_user_can_delete' hook
1592
  *
1593
- * @param object $activity Optional. Falls back on the current item in the loop.
1594
  * @return bool True if can delete, false otherwise.
1595
  */
1596
  function bp_activity_user_can_delete( $activity = false ) {
1597
  global $activities_template;
1598
 
1599
- if ( !$activity )
 
1600
  $activity = $activities_template->activity;
 
1601
 
1602
- if ( isset( $activity->current_comment ) )
 
1603
  $activity = $activity->current_comment;
 
1604
 
 
1605
  $can_delete = false;
1606
 
1607
- if ( bp_current_user_can( 'bp_moderate' ) )
1608
- $can_delete = true;
 
 
 
 
 
1609
 
1610
- if ( is_user_logged_in() && $activity->user_id == bp_loggedin_user_id() )
1611
- $can_delete = true;
 
 
 
 
1612
 
1613
- if ( bp_is_item_admin() && bp_is_single_item() )
1614
- $can_delete = true;
 
 
 
1615
 
1616
- return apply_filters( 'bp_activity_user_can_delete', $can_delete, $activity );
 
 
 
 
 
 
 
 
1617
  }
1618
 
1619
  /**
1620
  * Output the activity parent content.
1621
  *
1622
- * @since BuddyPress (1.2)
1623
  *
1624
  * @see bp_get_activity_parent_content() for a description of arguments.
1625
- * @uses bp_get_activity_parent_content()
1626
  *
1627
- * @param array $args See {@link bp_get_activity_parent_content} for description.
1628
  */
1629
  function bp_activity_parent_content( $args = '' ) {
1630
  echo bp_get_activity_parent_content($args);
@@ -1633,60 +1603,62 @@ function bp_activity_parent_content( $args = '' ) {
1633
  /**
1634
  * Return the activity content.
1635
  *
1636
- * @since BuddyPress (1.2)
1637
  *
1638
  * @global object $activities_template {@link BP_Activity_Template}
1639
- * @uses wp_parse_args()
1640
- * @uses apply_filters() To call the 'bp_get_activity_parent_content' hook.
1641
  *
1642
- * @param array $args {
1643
- * Array of optional arguments.
1644
- * @deprecated bool $hide_user No longer used.
1645
- * }
1646
- * @return mixed False on failure, otherwise the activity parent content
1647
  */
1648
  function bp_get_activity_parent_content( $args = '' ) {
1649
  global $activities_template;
1650
 
1651
- $defaults = array(
1652
- 'hide_user' => false
1653
- );
1654
-
1655
- $r = wp_parse_args( $args, $defaults );
1656
- extract( $r, EXTR_SKIP );
1657
-
1658
- // Get the ID of the parent activity content
1659
- if ( !$parent_id = $activities_template->activity->item_id )
1660
  return false;
 
 
 
 
1661
 
1662
- // Bail if no parent content
1663
- if ( empty( $activities_template->activity_parents[$parent_id] ) )
1664
  return false;
 
1665
 
1666
- // Bail if no action
1667
- if ( empty( $activities_template->activity_parents[$parent_id]->action ) )
1668
  return false;
 
1669
 
1670
- // Content always includes action
1671
- $content = $activities_template->activity_parents[$parent_id]->action;
1672
 
1673
- // Maybe append activity content, if it exists
1674
- if ( ! empty( $activities_template->activity_parents[$parent_id]->content ) )
1675
- $content .= ' ' . $activities_template->activity_parents[$parent_id]->content;
 
1676
 
1677
- // Remove the time since content for backwards compatibility
1678
  $content = str_replace( '<span class="time-since">%s</span>', '', $content );
1679
 
1680
- // Remove images
1681
  $content = preg_replace( '/<img[^>]*>/Ui', '', $content );
1682
 
 
 
 
 
 
 
 
1683
  return apply_filters( 'bp_get_activity_parent_content', $content );
1684
  }
1685
 
1686
  /**
1687
  * Output the parent activity's user ID.
1688
  *
1689
- * @since BuddyPress (1.7)
1690
  */
1691
  function bp_activity_parent_user_id() {
1692
  echo bp_get_activity_parent_user_id();
@@ -1695,43 +1667,51 @@ function bp_activity_parent_user_id() {
1695
  /**
1696
  * Return the parent activity's user ID.
1697
  *
1698
- * @since BuddyPress (1.7)
1699
  *
1700
  * @global BP_Activity_Template $activities_template
1701
  *
1702
  * @return bool|int False if parent activity can't be found, otherwise
1703
- * the parent activity's user ID.
1704
  */
1705
  function bp_get_activity_parent_user_id() {
1706
  global $activities_template;
1707
 
1708
- // Bail if no activity on no item ID
1709
- if ( empty( $activities_template->activity ) || empty( $activities_template->activity->item_id ) )
1710
  return false;
 
1711
 
1712
- // Get the ID of the parent activity content
1713
- if ( !$parent_id = $activities_template->activity->item_id )
1714
- return false;
1715
 
1716
- // Bail if no parent item
1717
- if ( empty( $activities_template->activity_parents[$parent_id] ) )
1718
  return false;
 
1719
 
1720
- // Bail if no parent user ID
1721
- if ( empty( $activities_template->activity_parents[$parent_id]->user_id ) )
1722
  return false;
 
1723
 
1724
- $retval = $activities_template->activity_parents[$parent_id]->user_id;
1725
 
 
 
 
 
 
 
 
1726
  return (int) apply_filters( 'bp_get_activity_parent_user_id', $retval );
1727
  }
1728
 
1729
  /**
1730
  * Output whether or not the current activity is in a current user's favorites.
1731
  *
1732
- * @since BuddyPress (1.2)
1733
  *
1734
- * @uses bp_get_activity_is_favorite()
1735
  */
1736
  function bp_activity_is_favorite() {
1737
  echo bp_get_activity_is_favorite();
@@ -1740,27 +1720,33 @@ function bp_activity_is_favorite() {
1740
  /**
1741
  * Return whether the current activity is in a current user's favorites.
1742
  *
1743
- * @since BuddyPress (1.2)
1744
  *
1745
  * @global object $activities_template {@link BP_Activity_Template}
1746
- * @uses apply_filters() To call the 'bp_get_activity_is_favorite' hook.
1747
  *
1748
  * @return bool True if user favorite, false otherwise.
1749
  */
1750
  function bp_get_activity_is_favorite() {
1751
  global $activities_template;
1752
 
1753
- return apply_filters( 'bp_get_activity_is_favorite', in_array( $activities_template->activity->id, (array) $activities_template->my_favs ) );
 
 
 
 
 
 
 
1754
  }
1755
 
1756
  /**
1757
  * Output the comment markup for an activity item.
1758
  *
1759
- * @since BuddyPress (1.2)
1760
  *
1761
  * @todo deprecate $args param
1762
  *
1763
- * @param string $args Unused. Appears to be left over from an earlier implementation.
1764
  */
1765
  function bp_activity_comments( $args = '' ) {
1766
  echo bp_activity_get_comments( $args );
@@ -1769,52 +1755,62 @@ function bp_activity_comments( $args = '' ) {
1769
  /**
1770
  * Get the comment markup for an activity item.
1771
  *
1772
- * @since BuddyPress (1.2)
1773
  *
1774
  * @todo deprecate $args param
1775
- *
1776
  * @todo Given that checks for children already happen in bp_activity_recurse_comments(),
1777
- * this function can probably be streamlined or removed.
1778
- *
1779
- * @param string $args Unused. Appears to be left over from an earlier implementation.
1780
  *
1781
  * @global object $activities_template {@link BP_Activity_Template}
1782
- * @uses bp_activity_recurse_comments()
 
 
1783
  */
1784
  function bp_activity_get_comments( $args = '' ) {
1785
  global $activities_template;
1786
 
1787
- if ( !isset( $activities_template->activity->children ) || !$activities_template->activity->children )
1788
  return false;
 
1789
 
1790
  bp_activity_recurse_comments( $activities_template->activity );
1791
  }
1792
 
1793
  /**
1794
- * Loops through a level of activity comments and loads the template for each
1795
  *
1796
  * Note: The recursion itself used to happen entirely in this function. Now it is
1797
  * split between here and the comment.php template.
1798
  *
1799
- * @since BuddyPress (1.2)
1800
- *
1801
- * @param object $comment The activity object currently being recursed
1802
  *
1803
  * @global object $activities_template {@link BP_Activity_Template}
1804
- * @uses locate_template()
 
 
1805
  */
1806
  function bp_activity_recurse_comments( $comment ) {
1807
  global $activities_template;
1808
 
1809
- if ( empty( $comment ) )
1810
  return false;
 
1811
 
1812
- if ( empty( $comment->children ) )
1813
  return false;
 
1814
 
1815
- echo apply_filters( 'bp_activity_recurse_comments_start_ul', '<ul>');
 
 
 
 
 
 
 
1816
  foreach ( (array) $comment->children as $comment_child ) {
1817
- // Put the comment into the global so it's available to filters
 
1818
  $activities_template->activity->current_comment = $comment_child;
1819
 
1820
  $template = bp_locate_template( 'activity/comment.php', false, false );
@@ -1831,25 +1827,41 @@ function bp_activity_comments( $args = '' ) {
1831
 
1832
  unset( $activities_template->activity->current_comment );
1833
  }
1834
- echo apply_filters( 'bp_activity_recurse_comments_end_ul', '</ul>');
 
 
 
 
 
 
 
 
1835
  }
1836
 
1837
  /**
1838
  * Utility function that returns the comment currently being recursed.
1839
  *
1840
- * @since BuddyPress (1.5)
1841
  *
1842
  * @global object $activities_template {@link BP_Activity_Template}
1843
- * @uses apply_filters() To call the 'bp_activity_current_comment' hook.
1844
  *
1845
  * @return object|bool $current_comment The activity comment currently being
1846
- * displayed. False on failure.
1847
  */
1848
  function bp_activity_current_comment() {
1849
  global $activities_template;
1850
 
1851
- $current_comment = !empty( $activities_template->activity->current_comment ) ? $activities_template->activity->current_comment : false;
 
 
1852
 
 
 
 
 
 
 
 
1853
  return apply_filters( 'bp_activity_current_comment', $current_comment );
1854
  }
1855
 
@@ -1857,9 +1869,8 @@ function bp_activity_current_comment() {
1857
  /**
1858
  * Output the ID of the activity comment currently being displayed.
1859
  *
1860
- * @since BuddyPress (1.5)
1861
  *
1862
- * @uses bp_get_activity_comment_id()
1863
  */
1864
  function bp_activity_comment_id() {
1865
  echo bp_get_activity_comment_id();
@@ -1868,28 +1879,33 @@ function bp_activity_comment_id() {
1868
  /**
1869
  * Return the ID of the activity comment currently being displayed.
1870
  *
1871
- * @since BuddyPress (1.5)
1872
  *
1873
  * @global object $activities_template {@link BP_Activity_Template}
1874
- * @uses apply_filters() To call the 'bp_activity_comment_id' hook.
1875
  *
1876
- * @return int|bool $comment_id The ID of the activity comment
1877
- * currently being displayed, false if none is found.
1878
  */
1879
  function bp_get_activity_comment_id() {
1880
  global $activities_template;
1881
 
1882
  $comment_id = isset( $activities_template->activity->current_comment->id ) ? $activities_template->activity->current_comment->id : false;
1883
 
 
 
 
 
 
 
 
1884
  return apply_filters( 'bp_activity_comment_id', $comment_id );
1885
  }
1886
 
1887
  /**
1888
  * Output the ID of the author of the activity comment currently being displayed.
1889
  *
1890
- * @since BuddyPress (1.5)
1891
  *
1892
- * @uses bp_get_activity_comment_user_id()
1893
  */
1894
  function bp_activity_comment_user_id() {
1895
  echo bp_get_activity_comment_user_id();
@@ -1898,28 +1914,33 @@ function bp_activity_comment_user_id() {
1898
  /**
1899
  * Return the ID of the author of the activity comment currently being displayed.
1900
  *
1901
- * @since BuddyPress (1.5)
1902
  *
1903
  * @global object $activities_template {@link BP_Activity_Template}
1904
- * @uses apply_filters() To call the 'bp_activity_comment_user_id' hook.
1905
  *
1906
  * @return int|bool $user_id The user_id of the author of the displayed
1907
- * activity comment. False on failure.
1908
  */
1909
  function bp_get_activity_comment_user_id() {
1910
  global $activities_template;
1911
 
1912
  $user_id = isset( $activities_template->activity->current_comment->user_id ) ? $activities_template->activity->current_comment->user_id : false;
1913
 
 
 
 
 
 
 
 
1914
  return apply_filters( 'bp_activity_comment_user_id', $user_id );
1915
  }
1916
 
1917
  /**
1918
  * Output the author link for the activity comment currently being displayed.
1919
  *
1920
- * @since BuddyPress (1.5)
1921
  *
1922
- * @uses bp_get_activity_comment_user_link()
1923
  */
1924
  function bp_activity_comment_user_link() {
1925
  echo bp_get_activity_comment_user_link();
@@ -1928,26 +1949,29 @@ function bp_activity_comment_user_link() {
1928
  /**
1929
  * Return the author link for the activity comment currently being displayed.
1930
  *
1931
- * @since BuddyPress (1.5)
1932
  *
1933
- * @uses bp_core_get_user_domain()
1934
- * @uses bp_get_activity_comment_user_id()
1935
- * @uses apply_filters() To call the 'bp_activity_comment_user_link' hook
1936
  *
1937
  * @return string $user_link The URL of the activity comment author's profile.
1938
  */
1939
  function bp_get_activity_comment_user_link() {
1940
  $user_link = bp_core_get_user_domain( bp_get_activity_comment_user_id() );
1941
 
 
 
 
 
 
 
 
1942
  return apply_filters( 'bp_activity_comment_user_link', $user_link );
1943
  }
1944
 
1945
  /**
1946
  * Output the author name for the activity comment currently being displayed.
1947
  *
1948
- * @since BuddyPress (1.5)
1949
  *
1950
- * @uses bp_get_activity_comment_name()
1951
  */
1952
  function bp_activity_comment_name() {
1953
  echo bp_get_activity_comment_name();
@@ -1959,96 +1983,133 @@ function bp_activity_comment_name() {
1959
  * The use of the 'bp_acomment_name' filter is deprecated. Please use
1960
  * 'bp_activity_comment_name'.
1961
  *
1962
- * @since BuddyPress (1.5)
1963
  *
1964
  * @global object $activities_template {@link BP_Activity_Template}
1965
- * @uses apply_filters() To call the 'bp_acomment_name' hook.
1966
- * @uses apply_filters() To call the 'bp_activity_comment_name' hook.
1967
  *
1968
  * @return string $name The full name of the activity comment author.
1969
  */
1970
  function bp_get_activity_comment_name() {
1971
  global $activities_template;
1972
 
1973
- if ( isset( $activities_template->activity->current_comment->user_fullname ) )
1974
- $name = apply_filters( 'bp_acomment_name', $activities_template->activity->current_comment->user_fullname, $activities_template->activity->current_comment ); // backward compatibility
1975
- else
 
1976
  $name = $activities_template->activity->current_comment->display_name;
 
1977
 
 
 
 
 
 
 
 
1978
  return apply_filters( 'bp_activity_comment_name', $name );
1979
  }
1980
 
1981
  /**
1982
- * Output the date_recorded of the activity comment currently being displayed.
1983
  *
1984
- * @since BuddyPress (1.5)
1985
  *
1986
- * @uses bp_get_activity_comment_date_recorded()
1987
  */
1988
  function bp_activity_comment_date_recorded() {
1989
  echo bp_get_activity_comment_date_recorded();
1990
  }
1991
 
1992
  /**
1993
- * Return the date_recorded for the activity comment currently being displayed.
1994
  *
1995
- * @since BuddyPress (1.5)
1996
  *
1997
- * @global object $activities_template {@link BP_Activity_Template}
1998
- * @uses bp_core_time_since()
1999
- * @uses apply_filters() To call the 'bp_activity_comment_date_recorded' hook
2000
  *
2001
  * @return string|bool $date_recorded Time since the activity was recorded,
2002
- * in the form "%s ago". False on failure.
2003
  */
2004
  function bp_get_activity_comment_date_recorded() {
2005
- global $activities_template;
2006
 
2007
- if ( empty( $activities_template->activity->current_comment->date_recorded ) )
2008
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2009
 
2010
- $date_recorded = bp_core_time_since( $activities_template->activity->current_comment->date_recorded );
 
 
 
 
 
 
 
 
 
 
 
2011
 
2012
- return apply_filters( 'bp_activity_comment_date_recorded', $date_recorded );
 
 
 
 
 
 
 
2013
  }
2014
 
2015
  /**
2016
  * Output the 'delete' URL for the activity comment currently being displayed.
2017
  *
2018
- * @since BuddyPress (1.5)
2019
  *
2020
- * @uses bp_get_activity_comment_delete_link()
2021
  */
2022
  function bp_activity_comment_delete_link() {
2023
  echo bp_get_activity_comment_delete_link();
2024
  }
2025
 
2026
  /**
2027
- * Gets the 'delete' URL for the activity comment currently being displayed
2028
  *
2029
- * @since BuddyPress (1.5)
2030
  *
2031
- * @uses wp_nonce_url()
2032
- * @uses bp_get_root_domain()
2033
- * @uses bp_get_activity_slug()
2034
- * @uses bp_get_activity_comment_id()
2035
- * @uses apply_filters() To call the 'bp_activity_comment_delete_link' hook.
2036
  *
2037
  * @return string $link The nonced URL for deleting the current
2038
- * activity comment.
2039
  */
2040
  function bp_get_activity_comment_delete_link() {
2041
- $link = wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/delete/' . bp_get_activity_comment_id() . '?cid=' . bp_get_activity_comment_id(), 'bp_activity_delete_link' );
2042
 
 
 
 
 
 
 
 
2043
  return apply_filters( 'bp_activity_comment_delete_link', $link );
2044
  }
2045
 
2046
  /**
2047
  * Output the content of the activity comment currently being displayed.
2048
  *
2049
- * @since BuddyPress (1.5)
2050
  *
2051
- * @uses bp_get_activity_comment_content()
2052
  */
2053
  function bp_activity_comment_content() {
2054
  echo bp_get_activity_comment_content();
@@ -2062,97 +2123,113 @@ function bp_activity_comment_content() {
2062
  * 'bp_activity_comment_content' to modify the content of activity
2063
  * comments only.
2064
  *
2065
- * @since BuddyPress (1.5)
2066
  *
2067
  * @global object $activities_template {@link BP_Activity_Template}
2068
- * @uses apply_filters() To call the 'bp_get_activity_content' hook.
2069
- * @uses apply_filters() To call the 'bp_activity_comment_content' hook.
2070
  *
2071
  * @return string $content The content of the current activity comment.
2072
  */
2073
  function bp_get_activity_comment_content() {
2074
  global $activities_template;
2075
 
 
2076
  $content = apply_filters( 'bp_get_activity_content', $activities_template->activity->current_comment->content );
2077
 
 
 
 
 
 
 
 
2078
  return apply_filters( 'bp_activity_comment_content', $content );
2079
  }
2080
 
2081
  /**
2082
  * Output the activity comment count.
2083
  *
2084
- * @since BuddyPress (1.2)
2085
  *
2086
- * @uses bp_activity_get_comment_count()
2087
  */
2088
  function bp_activity_comment_count() {
2089
  echo bp_activity_get_comment_count();
2090
  }
2091
 
2092
  /**
2093
- * Return the content of the activity comment currently being displayed.
2094
- *
2095
- * The content is run through two filters. 'bp_get_activity_content'
2096
- * will apply all filters applied to activity items in general. Use
2097
- * 'bp_activity_comment_content' to modify the content of activity
2098
- * comments only.
2099
  *
2100
- * @since BuddyPress (1.2)
2101
  *
2102
  * @global object $activities_template {@link BP_Activity_Template}
2103
- * @uses bp_activity_recurse_comment_count()
2104
- * @uses apply_filters() To call the 'bp_activity_get_comment_count' hook.
2105
- * @todo deprecate $args
2106
  *
2107
- * @param array $args Deprecated.
2108
  * @return int $count The activity comment count.
2109
  */
2110
- function bp_activity_get_comment_count( $args = '' ) {
2111
  global $activities_template;
2112
 
2113
- if ( !isset( $activities_template->activity->children ) || !$activities_template->activity->children )
2114
- return 0;
 
 
2115
 
2116
- $count = bp_activity_recurse_comment_count( $activities_template->activity );
 
 
 
2117
 
 
 
 
 
 
 
 
2118
  return apply_filters( 'bp_activity_get_comment_count', (int) $count );
2119
  }
2120
 
2121
  /**
2122
- * Return the content of the activity comment currently being displayed.
2123
  *
2124
- * The content is run through two filters. 'bp_get_activity_content'
2125
- * will apply all filters applied to activity items in general.
2126
- * Use bp_activity_comment_content to modify the content of
2127
- * activity comments only.
2128
  *
2129
- * @since BuddyPress (1.2)
2130
  *
2131
- * @uses bp_activity_recurse_comment_count()
2132
- * @uses apply_filters() To call the 'bp_activity_get_comment_count' hook
2133
- * @todo investigate why bp_activity_recurse_comment_count() is used while being declared
2134
  *
2135
  * @param object $comment Activity comment object.
2136
- * @param int $count The current iteration count.
2137
  * @return int $count The activity comment count.
2138
  */
2139
  function bp_activity_recurse_comment_count( $comment, $count = 0 ) {
2140
 
2141
- if ( empty( $comment->children ) )
2142
- return $count;
2143
 
2144
- foreach ( (array) $comment->children as $comment ) {
2145
- $count++;
2146
- $count = bp_activity_recurse_comment_count( $comment, $count );
 
 
 
2147
  }
2148
 
2149
- return $count;
 
 
 
 
 
 
 
 
 
2150
  }
2151
 
2152
  /**
2153
  * Output the depth of the current activity comment.
2154
  *
2155
- * @since BuddyPress (2.0.0)
2156
  */
2157
  function bp_activity_comment_depth() {
2158
  echo bp_activity_get_comment_depth();
@@ -2160,21 +2237,28 @@ function bp_activity_comment_depth() {
2160
  /**
2161
  * Return the current activity comment depth.
2162
  *
2163
- * @since BuddyPress (2.0.0)
2164
  *
2165
- * @return int
2166
  */
2167
  function bp_activity_get_comment_depth() {
2168
  global $activities_template;
 
 
 
 
 
 
 
 
2169
  return apply_filters( 'bp_activity_get_comment_depth', $activities_template->activity->current_comment->depth );
2170
  }
2171
 
2172
  /**
2173
  * Output the activity comment link.
2174
  *
2175
- * @since BuddyPress (1.2)
2176
  *
2177
- * @uses bp_get_activity_comment_link()
2178
  */
2179
  function bp_activity_comment_link() {
2180
  echo bp_get_activity_comment_link();
@@ -2183,43 +2267,51 @@ function bp_activity_comment_link() {
2183
  /**
2184
  * Return the activity comment link.
2185
  *
2186
- * @since BuddyPress (1.2)
2187
  *
2188
  * @global object $activities_template {@link BP_Activity_Template}
2189
- * @uses apply_filters() To call the 'bp_get_activity_comment_link' hook.
2190
  *
2191
  * @return string The activity comment link.
2192
  */
2193
  function bp_get_activity_comment_link() {
2194
  global $activities_template;
 
 
 
 
 
 
 
 
2195
  return apply_filters( 'bp_get_activity_comment_link', '?ac=' . $activities_template->activity->id . '/#ac-form-' . $activities_template->activity->id );
2196
  }
2197
 
2198
  /**
2199
- * Output the activity comment form no javascript display CSS.
2200
  *
2201
- * @since BuddyPress (1.2)
2202
  *
2203
- * @uses bp_get_activity_comment_form_nojs_display()
2204
  */
2205
  function bp_activity_comment_form_nojs_display() {
2206
  echo bp_get_activity_comment_form_nojs_display();
2207
  }
2208
 
2209
  /**
2210
- * Return the activity comment form no javascript display CSS.
2211
  *
2212
- * @since BuddyPress (1.2)
2213
  *
2214
  * @global object $activities_template {@link BP_Activity_Template}
2215
  *
2216
- * @return string|bool The activity comment form no javascript
2217
- * display CSS. False on failure
2218
  */
2219
  function bp_get_activity_comment_form_nojs_display() {
2220
  global $activities_template;
2221
- if ( isset( $_GET['ac'] ) && $_GET['ac'] == $activities_template->activity->id . '/' )
 
2222
  return 'style="display: block"';
 
2223
 
2224
  return false;
2225
  }
@@ -2227,9 +2319,8 @@ function bp_activity_comment_form_nojs_display() {
2227
  /**
2228
  * Output the activity comment form action.
2229
  *
2230
- * @since BuddyPress (1.2)
2231
  *
2232
- * @uses bp_get_activity_comment_form_action()
2233
  */
2234
  function bp_activity_comment_form_action() {
2235
  echo bp_get_activity_comment_form_action();
@@ -2238,24 +2329,28 @@ function bp_activity_comment_form_action() {
2238
  /**
2239
  * Return the activity comment form action.
2240
  *
2241
- * @since BuddyPress (1.2)
2242
  *
2243
- * @uses home_url()
2244
- * @uses bp_get_activity_root_slug()
2245
- * @uses apply_filters() To call the 'bp_get_activity_comment_form_action' hook.
2246
  *
2247
  * @return string The activity comment form action.
2248
  */
2249
  function bp_get_activity_comment_form_action() {
 
 
 
 
 
 
 
 
2250
  return apply_filters( 'bp_get_activity_comment_form_action', home_url( bp_get_activity_root_slug() . '/reply/' ) );
2251
  }
2252
 
2253
  /**
2254
  * Output the activity permalink ID.
2255
  *
2256
- * @since BuddyPress (1.2)
2257
  *
2258
- * @uses bp_get_activity_permalink_id()
2259
  */
2260
  function bp_activity_permalink_id() {
2261
  echo bp_get_activity_permalink_id();
@@ -2264,34 +2359,38 @@ function bp_activity_permalink_id() {
2264
  /**
2265
  * Return the activity permalink ID.
2266
  *
2267
- * @since BuddyPress (1.2)
2268
  *
2269
- * @uses apply_filters() To call the 'bp_get_activity_permalink_id' hook.
2270
  *
2271
  * @return string The activity permalink ID.
2272
  */
2273
  function bp_get_activity_permalink_id() {
 
 
 
 
 
 
 
 
2274
  return apply_filters( 'bp_get_activity_permalink_id', bp_current_action() );
2275
  }
2276
 
2277
  /**
2278
  * Output the activity thread permalink.
2279
  *
2280
- * @since BuddyPress (1.2)
2281
  *
2282
- * @uses bp_get_activity_permalink_id()
2283
  */
2284
  function bp_activity_thread_permalink() {
2285
- echo bp_get_activity_thread_permalink();
2286
  }
2287
 
2288
  /**
2289
  * Return the activity thread permalink.
2290
  *
2291
- * @since BuddyPress (1.2)
2292
  *
2293
- * @uses bp_activity_get_permalink()
2294
- * @uses apply_filters() To call the 'bp_get_activity_thread_permalink' hook.
2295
  *
2296
  * @return string $link The activity thread permalink.
2297
  */
@@ -2300,43 +2399,58 @@ function bp_activity_thread_permalink() {
2300
 
2301
  $link = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity );
2302
 
2303
- return apply_filters( 'bp_get_activity_thread_permalink', $link );
 
 
 
 
 
 
 
2304
  }
2305
 
2306
  /**
2307
  * Output the activity comment permalink.
2308
  *
2309
- * @since BuddyPress (1.8)
2310
  *
2311
- * @uses bp_get_activity_permalink_id()
2312
  */
2313
  function bp_activity_comment_permalink() {
2314
- echo bp_get_activity_comment_permalink();
2315
  }
2316
  /**
2317
  * Return the activity comment permalink.
2318
  *
2319
- * @since BuddyPress (1.8)
2320
- *
2321
- * @uses bp_activity_get_permalink()
2322
- * @uses apply_filters() To call the 'bp_get_activity_comment_permalink' hook.
2323
  *
2324
  * @return string $link The activity comment permalink.
2325
  */
2326
  function bp_get_activity_comment_permalink() {
2327
  global $activities_template;
2328
 
2329
- $link = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity ) . '#acomment-' . $activities_template->activity->current_comment->id;
 
 
 
 
 
2330
 
2331
- return apply_filters( 'bp_get_activity_comment_permalink', $link );
 
 
 
 
 
 
 
 
2332
  }
2333
 
2334
  /**
2335
  * Output the activity favorite link.
2336
  *
2337
- * @since BuddyPress (1.2)
2338
  *
2339
- * @uses bp_get_activity_favorite_link()
2340
  */
2341
  function bp_activity_favorite_link() {
2342
  echo bp_get_activity_favorite_link();
@@ -2345,27 +2459,30 @@ function bp_activity_favorite_link() {
2345
  /**
2346
  * Return the activity favorite link.
2347
  *
2348
- * @since BuddyPress (1.2)
2349
  *
2350
  * @global object $activities_template {@link BP_Activity_Template}
2351
- * @uses wp_nonce_url()
2352
- * @uses home_url()
2353
- * @uses bp_get_activity_root_slug()
2354
- * @uses apply_filters() To call the 'bp_get_activity_favorite_link' hook
2355
  *
2356
  * @return string The activity favorite link.
2357
  */
2358
  function bp_get_activity_favorite_link() {
2359
  global $activities_template;
 
 
 
 
 
 
 
 
2360
  return apply_filters( 'bp_get_activity_favorite_link', wp_nonce_url( home_url( bp_get_activity_root_slug() . '/favorite/' . $activities_template->activity->id . '/' ), 'mark_favorite' ) );
2361
  }
2362
 
2363
  /**
2364
  * Output the activity unfavorite link.
2365
  *
2366
- * @since BuddyPress (1.2)
2367
  *
2368
- * @uses bp_get_activity_unfavorite_link()
2369
  */
2370
  function bp_activity_unfavorite_link() {
2371
  echo bp_get_activity_unfavorite_link();
@@ -2374,27 +2491,30 @@ function bp_activity_unfavorite_link() {
2374
  /**
2375
  * Return the activity unfavorite link.
2376
  *
2377
- * @since BuddyPress (1.2)
2378
  *
2379
  * @global object $activities_template {@link BP_Activity_Template}
2380
- * @uses wp_nonce_url()
2381
- * @uses home_url()
2382
- * @uses bp_get_activity_root_slug()
2383
- * @uses apply_filters() To call the 'bp_get_activity_unfavorite_link' hook.
2384
  *
2385
  * @return string The activity unfavorite link.
2386
  */
2387
  function bp_get_activity_unfavorite_link() {
2388
  global $activities_template;
 
 
 
 
 
 
 
 
2389
  return apply_filters( 'bp_get_activity_unfavorite_link', wp_nonce_url( home_url( bp_get_activity_root_slug() . '/unfavorite/' . $activities_template->activity->id . '/' ), 'unmark_favorite' ) );
2390
  }
2391
 
2392
  /**
2393
  * Output the activity CSS class.
2394
  *
2395
- * @since BuddyPress (1.0)
2396
  *
2397
- * @uses bp_get_activity_css_class()
2398
  */
2399
  function bp_activity_css_class() {
2400
  echo bp_get_activity_css_class();
@@ -2403,19 +2523,22 @@ function bp_activity_css_class() {
2403
  /**
2404
  * Return the current activity item's CSS class.
2405
  *
2406
- * @since BuddyPress (1.0)
2407
  *
2408
  * @global object $activities_template {@link BP_Activity_Template}
2409
- * @uses apply_filters() To call the 'bp_activity_mini_activity_types' hook.
2410
- * @uses bp_activity_get_comment_count()
2411
- * @uses bp_activity_can_comment()
2412
- * @uses apply_filters() To call the 'bp_get_activity_css_class' hook.
2413
  *
2414
  * @return string The activity item's CSS class.
2415
  */
2416
  function bp_get_activity_css_class() {
2417
  global $activities_template;
2418
 
 
 
 
 
 
 
 
2419
  $mini_activity_actions = apply_filters( 'bp_activity_mini_activity_types', array(
2420
  'friendship_accepted',
2421
  'friendship_created',
@@ -2427,67 +2550,113 @@ function bp_activity_css_class() {
2427
 
2428
  $class = ' activity-item';
2429
 
2430
- if ( in_array( $activities_template->activity->type, (array) $mini_activity_actions ) || empty( $activities_template->activity->content ) )
2431
  $class .= ' mini';
 
2432
 
2433
- if ( bp_activity_get_comment_count() && bp_activity_can_comment() )
2434
  $class .= ' has-comments';
 
2435
 
 
 
 
 
 
 
 
2436
  return apply_filters( 'bp_get_activity_css_class', $activities_template->activity->component . ' ' . $activities_template->activity->type . $class );
2437
  }
2438
 
2439
  /**
2440
  * Output the activity delete link.
2441
  *
2442
- * @since BuddyPress (1.1)
2443
  *
2444
- * @uses bp_get_activity_delete_link()
2445
  */
2446
  function bp_activity_delete_link() {
2447
  echo bp_get_activity_delete_link();
2448
  }
2449
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2450
  /**
2451
- * Return the activity delete link.
2452
  *
2453
- * @since BuddyPress (1.1)
2454
  *
2455
  * @global object $activities_template {@link BP_Activity_Template}
2456
- * @uses bp_get_root_domain()
2457
- * @uses bp_get_activity_root_slug()
2458
- * @uses bp_is_activity_component()
2459
- * @uses bp_current_action()
2460
- * @uses add_query_arg()
2461
- * @uses wp_get_referer()
2462
- * @uses wp_nonce_url()
2463
- * @uses apply_filters() To call the 'bp_get_activity_delete_link' hook.
2464
  *
2465
  * @return string $link Activity delete link. Contains $redirect_to arg
2466
- * if on single activity page.
2467
  */
2468
- function bp_get_activity_delete_link() {
2469
  global $activities_template;
2470
 
2471
- $url = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/delete/' . $activities_template->activity->id;
2472
- $class = 'delete-activity';
2473
 
2474
- // Determine if we're on a single activity page, and customize accordingly
2475
  if ( bp_is_activity_component() && is_numeric( bp_current_action() ) ) {
2476
- $url = add_query_arg( array( 'redirect_to' => wp_get_referer() ), $url );
2477
- $class = 'delete-activity-single';
2478
  }
2479
 
2480
- $link = '<a href="' . wp_nonce_url( $url, 'bp_activity_delete_link' ) . '" class="button item-button bp-secondary-action ' . $class . ' confirm" rel="nofollow">' . __( 'Delete', 'buddypress' ) . '</a>';
2481
- return apply_filters( 'bp_get_activity_delete_link', $link );
 
 
 
 
 
 
 
 
2482
  }
2483
 
2484
  /**
2485
  * Output the activity latest update link.
2486
  *
2487
- * @since BuddyPress (1.2)
2488
  *
2489
  * @see bp_get_activity_latest_update() for description of parameters.
2490
- * @uses bp_get_activity_latest_update()
2491
  *
2492
  * @param int $user_id See {@link bp_get_activity_latest_update()} for description.
2493
  */
@@ -2498,47 +2667,65 @@ function bp_activity_latest_update( $user_id = 0 ) {
2498
  /**
2499
  * Return the activity latest update link.
2500
  *
2501
- * @since BuddyPress (1.2)
2502
  *
2503
- * @uses bp_is_user_inactive()
2504
- * @uses bp_core_is_user_deleted()
2505
- * @uses bp_get_user_meta()
2506
- * @uses apply_filters() To call the 'bp_get_activity_latest_update_excerpt' hook
2507
- * @uses bp_create_excerpt()
2508
- * @uses bp_get_root_domain()
2509
- * @uses bp_get_activity_root_slug()
2510
- * @uses apply_filters() To call the 'bp_get_activity_latest_update' hook
2511
  *
2512
  * @param int $user_id If empty, will fall back on displayed user.
2513
  * @return string|bool $latest_update The activity latest update link.
2514
- * False on failure
2515
  */
2516
  function bp_get_activity_latest_update( $user_id = 0 ) {
2517
 
2518
- if ( empty( $user_id ) )
2519
  $user_id = bp_displayed_user_id();
 
2520
 
2521
- if ( bp_is_user_inactive( $user_id ) )
2522
  return false;
 
2523
 
2524
- if ( !$update = bp_get_user_meta( $user_id, 'bp_latest_update', true ) )
2525
  return false;
 
 
 
 
 
 
 
 
 
 
 
 
2526
 
2527
- $latest_update = apply_filters( 'bp_get_activity_latest_update_excerpt', trim( strip_tags( bp_create_excerpt( $update['content'], 358 ) ) ) );
2528
- $latest_update .= ' <a href="' . bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $update['id'] . '/"> ' . __( 'View', 'buddypress' ) . '</a>';
 
 
 
 
2529
 
2530
- return apply_filters( 'bp_get_activity_latest_update', $latest_update );
 
 
 
 
 
 
 
 
 
2531
  }
2532
 
2533
  /**
2534
  * Output the activity filter links.
2535
  *
2536
- * @since BuddyPress (1.1)
2537
  *
2538
  * @see bp_get_activity_filter_links() for description of parameters.
2539
- * @uses bp_get_activity_filter_links()
2540
  *
2541
- * @param array $args See {@link bp_get_activity_filter_links()} for description.
2542
  */
2543
  function bp_activity_filter_links( $args = false ) {
2544
  echo bp_get_activity_filter_links( $args );
@@ -2547,55 +2734,48 @@ function bp_activity_filter_links( $args = false ) {
2547
  /**
2548
  * Return the activity filter links.
2549
  *
2550
- * @since BuddyPress (1.1)
2551
  *
2552
- * @uses wp_parse_args()
2553
- * @uses BP_Activity_Activity::get_recorded_components() {@link BP_Activity_Activity}
2554
- * @uses esc_attr()
2555
- * @uses add_query_arg()
2556
- * @uses remove_query_arg()
2557
- * @uses apply_filters() To call the 'bp_get_activity_filter_link_href' hook.
2558
- * @uses apply_filters() To call the 'bp_get_activity_filter_links' hook.
2559
  *
2560
- * @param array $args {
2561
  * @type string $style The type of markup to use for the links.
2562
- * 'list', 'paragraph', or 'span'. Default: 'list'.
2563
  * }
2564
  * @return string|bool $component_links The activity filter links.
2565
  * False on failure.
2566
  */
2567
  function bp_get_activity_filter_links( $args = false ) {
2568
 
2569
- $defaults = array(
2570
  'style' => 'list'
2571
- );
2572
-
2573
- $r = wp_parse_args( $args, $defaults );
2574
- extract( $r, EXTR_SKIP );
2575
 
2576
- // Define local variable
2577
  $component_links = array();
2578
 
2579
- // Fetch the names of components that have activity recorded in the DB
2580
  $components = BP_Activity_Activity::get_recorded_components();
2581
 
2582
- if ( empty( $components ) )
2583
  return false;
 
2584
 
2585
  foreach ( (array) $components as $component ) {
2586
 
2587
- // Skip the activity comment filter
2588
- if ( 'activity' == $component )
2589
  continue;
 
2590
 
2591
- if ( isset( $_GET['afilter'] ) && $component == $_GET['afilter'] )
2592
  $selected = ' class="selected"';
2593
- else
2594
- unset($selected);
 
2595
 
2596
  $component = esc_attr( $component );
2597
 
2598
- switch ( $style ) {
2599
  case 'list':
2600
  $tag = 'li';
2601
  $before = '<li id="afilter-' . $component . '"' . $selected . '>';
@@ -2615,92 +2795,148 @@ function bp_activity_filter_links( $args = false ) {
2615
 
2616
  $link = add_query_arg( 'afilter', $component );
2617
  $link = remove_query_arg( 'acpage' , $link );
 
 
 
 
 
 
 
 
 
2618
  $link = apply_filters( 'bp_get_activity_filter_link_href', $link, $component );
2619
 
2620
- $component_links[] = $before . '<a href="' . esc_attr( $link ) . '">' . ucwords( $component ) . '</a>' . $after;
2621
  }
2622
 
2623
  $link = remove_query_arg( 'afilter' , $link );
2624
 
2625
- if ( isset( $_GET['afilter'] ) )
2626
- $component_links[] = '<' . $tag . ' id="afilter-clear"><a href="' . esc_attr( $link ) . '">' . __( 'Clear Filter', 'buddypress' ) . '</a></' . $tag . '>';
 
2627
 
2628
- return apply_filters( 'bp_get_activity_filter_links', implode( "\n", $component_links ) );
 
 
 
 
 
 
 
 
 
2629
  }
2630
 
2631
  /**
2632
  * Determine if a comment can be made on an activity item.
2633
  *
2634
- * @since BuddyPress (1.2)
2635
  *
2636
  * @global object $activities_template {@link BP_Activity_Template}
2637
- * @uses bp_get_activity_action_name()
2638
- * @uses apply_filters() To call the 'bp_activity_can_comment' hook.
2639
  *
2640
  * @return bool $can_comment True if item can receive comments.
2641
  */
2642
  function bp_activity_can_comment() {
2643
  global $activities_template;
 
2644
 
2645
- $can_comment = true;
 
2646
 
2647
- if ( false === $activities_template->disable_blogforum_replies || (int) $activities_template->disable_blogforum_replies ) {
2648
- if ( 'new_blog_post' == bp_get_activity_action_name() || 'new_blog_comment' == bp_get_activity_action_name() || 'new_forum_topic' == bp_get_activity_action_name() || 'new_forum_post' == bp_get_activity_action_name() )
2649
- $can_comment = false;
2650
- }
2651
 
2652
- if ( 'activity_comment' == bp_get_activity_action_name() )
 
2653
  $can_comment = false;
 
2654
 
2655
- return apply_filters( 'bp_activity_can_comment', $can_comment );
 
 
 
 
 
 
 
 
 
2656
  }
2657
 
2658
  /**
2659
- * Determine if a comment can be made on an activity reply item.
2660
- *
2661
- * Defaults to true, but can be modified by plugins.
2662
- *
2663
- * @since BuddyPress (1.5)
2664
  *
2665
- * @uses apply_filters() To call the 'bp_activity_can_comment_reply' hook
2666
  *
2667
- * @param object $comment Activity comment.
2668
- * @return bool $can_comment True if comment can receive comments.
 
2669
  */
2670
- function bp_activity_can_comment_reply( $comment ) {
 
 
2671
  $can_comment = true;
2672
 
2673
- if ( get_option( 'thread_comments' ) && bp_activity_get_comment_depth() >= get_option( 'thread_comments_depth' ) ) {
2674
- $can_comment = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2675
  }
2676
 
2677
- return apply_filters( 'bp_activity_can_comment_reply', $can_comment, $comment );
 
 
 
 
 
 
 
 
2678
  }
2679
 
2680
  /**
2681
- * Determine if an favorites are allowed.
2682
  *
2683
  * Defaults to true, but can be modified by plugins.
2684
  *
2685
- * @since BuddyPress (1.5)
2686
  *
2687
- * @uses apply_filters() To call the 'bp_activity_can_favorite' hook.
2688
- *
2689
- * @return bool $can_favorite True if comment can receive comments.
2690
  */
2691
  function bp_activity_can_favorite() {
2692
- $can_favorite = true;
2693
 
2694
- return apply_filters( 'bp_activity_can_favorite', $can_favorite );
 
 
 
 
 
 
 
2695
  }
2696
 
2697
  /**
2698
  * Output the total favorite count for a specified user.
2699
  *
2700
- * @since BuddyPress (1.2)
2701
  *
2702
  * @see bp_get_total_favorite_count_for_user() for description of parameters.
2703
- * @uses bp_get_total_favorite_count_for_user()
2704
  *
2705
  * @param int $user_id See {@link bp_get_total_favorite_count_for_user()}.
2706
  */
@@ -2711,30 +2947,46 @@ function bp_total_favorite_count_for_user( $user_id = 0 ) {
2711
  /**
2712
  * Return the total favorite count for a specified user.
2713
  *
2714
- * @since BuddyPress (1.2)
2715
  *
2716
- * @uses bp_activity_total_favorites_for_user()
2717
- * @uses apply_filters() To call the 'bp_get_total_favorite_count_for_user' hook
2718
  *
2719
  * @param int $user_id ID of user being queried. Default: displayed user ID.
2720
  * @return int The total favorite count for the specified user.
2721
  */
2722
  function bp_get_total_favorite_count_for_user( $user_id = 0 ) {
2723
- if ( ! $user_id ) {
2724
- $user_id = bp_displayed_user_id();
 
 
 
 
 
 
 
 
 
 
2725
  }
2726
 
2727
- return apply_filters( 'bp_get_total_favorite_count_for_user', bp_activity_total_favorites_for_user( $user_id ) );
 
 
 
 
 
 
 
 
 
2728
  }
2729
- add_filter( 'bp_get_total_favorite_count_for_user', 'bp_core_number_format' );
2730
 
2731
  /**
2732
  * Output the total mention count for a specified user.
2733
  *
2734
- * @since BuddyPress (1.2)
2735
  *
2736
  * @see bp_get_total_mention_count_for_user() for description of parameters.
2737
- * @uses bp_get_total_favorite_count_for_user()
2738
  *
2739
  * @param int $user_id See {@link bp_get_total_mention_count_for_user()}.
2740
  */
@@ -2745,60 +2997,79 @@ function bp_total_mention_count_for_user( $user_id = 0 ) {
2745
  /**
2746
  * Return the total mention count for a specified user.
2747
  *
2748
- * @since BuddyPress (1.2)
2749
  *
2750
- * @uses bp_get_user_meta()
2751
- * @uses apply_filters() To call the 'bp_get_total_mention_count_for_user' hook.
2752
  *
2753
  * @param int $user_id ID of user being queried. Default: displayed user ID.
2754
  * @return int The total mention count for the specified user.
2755
  */
2756
  function bp_get_total_mention_count_for_user( $user_id = 0 ) {
2757
- if ( ! $user_id ) {
2758
- $user_id = bp_displayed_user_id();
2759
- }
2760
 
2761
- return apply_filters( 'bp_get_total_mention_count_for_user', bp_get_user_meta( $user_id, 'bp_new_mention_count', true ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2762
  }
2763
- add_filter( 'bp_get_total_mention_count_for_user', 'bp_core_number_format' );
2764
 
2765
  /**
2766
  * Output the public message link for displayed user.
2767
  *
2768
- * @since BuddyPress (1.2)
2769
  *
2770
- * @uses bp_get_send_public_message_link()
2771
  */
2772
  function bp_send_public_message_link() {
2773
- echo bp_get_send_public_message_link();
2774
  }
2775
 
2776
  /**
2777
  * Return the public message link for the displayed user.
2778
  *
2779
- * @since BuddyPress (1.2)
2780
  *
2781
- * @uses is_user_logged_in()
2782
- * @uses bp_is_my_profile()
2783
- * @uses bp_is_user()
2784
- * @uses wp_nonce_url()
2785
- * @uses bp_get_activity_directory_permalink()
2786
- * @uses apply_filters() To call the 'bp_get_send_public_message_link' hook
2787
  *
2788
  * @return string The public message link for the displayed user.
2789
  */
2790
  function bp_get_send_public_message_link() {
2791
 
2792
- if ( ! is_user_logged_in() || ! bp_is_user() || bp_is_my_profile() )
2793
- return false;
 
 
 
 
 
 
2794
 
2795
- return apply_filters( 'bp_get_send_public_message_link', wp_nonce_url( bp_get_activity_directory_permalink() . '?r=' . bp_get_displayed_user_mentionname() ) );
 
 
 
 
 
 
 
2796
  }
2797
 
2798
  /**
2799
  * Recurse through all activity comments and return the activity comment IDs.
2800
  *
2801
- * @since BuddyPress (2.0.0)
2802
  *
2803
  * @param array $activity Array of activities generated from {@link bp_activity_get()}.
2804
  * @param array $activity_ids Used for recursion purposes in this function.
@@ -2825,44 +3096,54 @@ function bp_activity_recurse_comments_activity_ids( $activity = array(), $activi
2825
  /**
2826
  * Output the mentioned user display name.
2827
  *
2828
- * @since BuddyPress (1.2)
2829
  *
2830
  * @see bp_get_mentioned_user_display_name() for description of parameters.
2831
- * @uses bp_get_mentioned_user_display_name()
2832
  *
2833
- * @param int|string $user_id_or_username See {@link bp_get_mentioned_user_display_name()}.
2834
  */
2835
- function bp_mentioned_user_display_name( $user_id_or_username ) {
2836
  echo bp_get_mentioned_user_display_name( $user_id_or_username );
2837
  }
2838
 
2839
  /**
2840
- * Returns the mentioned user display name
2841
  *
2842
- * @since BuddyPress (1.2)
2843
  *
2844
- * @uses bp_core_get_user_displayname()
2845
- * @uses apply_filters() To call the 'bp_get_mentioned_user_display_name' hook.
2846
  *
2847
- * @param int|string User ID or username.
2848
  * @return string The mentioned user's display name.
2849
  */
2850
- function bp_get_mentioned_user_display_name( $user_id_or_username ) {
2851
- if ( !$name = bp_core_get_user_displayname( $user_id_or_username ) )
 
 
 
 
 
2852
  $name = __( 'a user', 'buddypress' );
 
2853
 
 
 
 
 
 
 
 
 
2854
  return apply_filters( 'bp_get_mentioned_user_display_name', $name, $user_id_or_username );
2855
  }
2856
 
2857
  /**
2858
  * Output button for sending a public message (an @-mention).
2859
  *
2860
- * @since BuddyPress (1.2)
2861
  *
2862
  * @see bp_get_send_public_message_button() for description of parameters.
2863
- * @uses bp_get_send_public_message_button()
2864
  *
2865
- * @param array $args See {@link bp_get_send_public_message_button()}.
2866
  */
2867
  function bp_send_public_message_button( $args = '' ) {
2868
  echo bp_get_send_public_message_button( $args );
@@ -2871,55 +3152,52 @@ function bp_send_public_message_button( $args = '' ) {
2871
  /**
2872
  * Return button for sending a public message (an @-mention).
2873
  *
2874
- * @since BuddyPress (1.2)
2875
  *
2876
- * @uses bp_get_send_public_message_link()
2877
- * @uses wp_parse_args()
2878
- * @uses bp_get_button()
2879
- * @uses apply_filters() To call the 'bp_get_send_public_message_button' hook.
2880
  *
2881
- * @param array $args {
2882
  * All arguments are optional. See {@link BP_Button} for complete
2883
  * descriptions.
2884
- * @type string $id Default: 'public_message'.
2885
- * @type string $component Default: 'activity'.
2886
- * @type bool $must_be_logged_in Default: true.
2887
- * @type bool $block_self Default: true.
2888
- * @type string $wrapper_id Default: 'post-mention'.
2889
- * @type string $link_href Default: the public message link for
2890
- * the current member in the loop.
2891
- * @type string $link_title Default: 'Send a public message on your
2892
- * activity stream.'.
2893
- * @type string $link_text Default: 'Public Message'.
2894
- * @type string $link_class Default: 'activity-button mention'.
2895
  * }
2896
  * @return string The button for sending a public message.
2897
  */
2898
  function bp_get_send_public_message_button( $args = '' ) {
2899
- $defaults = array(
 
2900
  'id' => 'public_message',
2901
  'component' => 'activity',
2902
  'must_be_logged_in' => true,
2903
  'block_self' => true,
2904
  'wrapper_id' => 'post-mention',
2905
  'link_href' => bp_get_send_public_message_link(),
2906
- 'link_title' => __( 'Send a public message on your activity stream.', 'buddypress' ),
2907
  'link_text' => __( 'Public Message', 'buddypress' ),
2908
  'link_class' => 'activity-button mention'
2909
- );
2910
-
2911
- $button = wp_parse_args( $args, $defaults );
2912
 
2913
- // Filter and return the HTML button
2914
- return bp_get_button( apply_filters( 'bp_get_send_public_message_button', $button ) );
 
 
 
 
 
 
2915
  }
2916
 
2917
  /**
2918
  * Output the activity post form action.
2919
  *
2920
- * @since BuddyPress (1.2)
2921
  *
2922
- * @uses bp_get_activity_post_form_action()
2923
  */
2924
  function bp_activity_post_form_action() {
2925
  echo bp_get_activity_post_form_action();
@@ -2928,15 +3206,20 @@ function bp_activity_post_form_action() {
2928
  /**
2929
  * Return the activity post form action.
2930
  *
2931
- * @since BuddyPress (1.2)
2932
  *
2933
- * @uses home_url()
2934
- * @uses bp_get_activity_root_slug()
2935
- * @uses apply_filters() To call the 'bp_get_activity_post_form_action' hook.
2936
  *
2937
  * @return string The activity post form action.
2938
  */
2939
  function bp_get_activity_post_form_action() {
 
 
 
 
 
 
 
 
2940
  return apply_filters( 'bp_get_activity_post_form_action', home_url( bp_get_activity_root_slug() . '/post/' ) );
2941
  }
2942
 
@@ -2948,82 +3231,142 @@ function bp_activity_post_form_action() {
2948
  * Avatars are wrapped in <li> elements, but you've got to provide your own
2949
  * <ul> or <ol> wrapper markup.
2950
  *
2951
- * @since BuddyPress (1.7)
2952
  *
2953
  * @see bp_core_fetch_avatar() for a description of arguments.
2954
  *
2955
  * @param array $args See {@link bp_core_fetch_avatar()}.
2956
  */
2957
  function bp_activity_comments_user_avatars( $args = array() ) {
2958
- $defaults = array(
 
2959
  'height' => false,
2960
  'html' => true,
2961
  'type' => 'thumb',
2962
  'width' => false,
2963
- );
2964
-
2965
- $args = wp_parse_args( $args, $defaults );
2966
- extract( $args, EXTR_SKIP );
2967
 
2968
- // Get the user IDs of everyone who has left a comment to the current activity item
2969
  $user_ids = bp_activity_get_comments_user_ids();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2970
 
2971
- $output = array();
2972
- foreach ( (array) $user_ids as $user_id ) {
2973
- $profile_link = bp_core_get_user_domain( $user_id );
2974
- $image_html = bp_core_fetch_avatar( array( 'item_id' => $user_id, 'height' => $height, 'html' => $html, 'type' => $type, 'width' => $width, ) );
 
2975
 
2976
- $output[] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $profile_link ), $image_html );
 
 
 
2977
  }
2978
 
2979
- echo apply_filters( 'bp_activity_comments_user_avatars', '<li>' . implode( '</li><li>', $output ) . '</li>', $args, $output );
 
 
 
 
 
 
 
 
 
2980
  }
2981
 
2982
  /**
2983
  * Return the IDs of every user who's left a comment on the current activity item.
2984
  *
2985
- * @since BuddyPress (1.7)
2986
  *
2987
  * @return bool|array An array of IDs, or false if none are found.
2988
  */
2989
  function bp_activity_get_comments_user_ids() {
2990
- if ( empty( $GLOBALS['activities_template']->activity ) || empty( $GLOBALS['activities_template']->activity->children ) )
2991
- return false;
2992
 
2993
- $user_ids = (array) bp_activity_recurse_comments_user_ids( $GLOBALS['activities_template']->activity->children );
 
 
 
 
 
 
 
 
 
 
2994
  return apply_filters( 'bp_activity_get_comments_user_ids', array_unique( $user_ids ) );
2995
  }
2996
 
2997
  /**
2998
  * Recurse through all activity comments and collect the IDs of the users who wrote them.
2999
  *
3000
- * @since BuddyPress (1.7)
3001
  *
3002
  * @param array $comments Array of {@link BP_Activity_Activity} items.
3003
  * @return array Array of user IDs.
3004
  */
3005
- function bp_activity_recurse_comments_user_ids( array $comments ) {
 
 
3006
  $user_ids = array();
3007
 
3008
- foreach ( $comments as $comment ) {
3009
- // If a user is a spammer, their activity items will have been automatically marked as spam. Skip these.
3010
- if ( $comment->is_spam )
3011
- continue;
 
 
 
 
 
3012
 
3013
- $user_ids[] = $comment->user_id;
 
3014
 
3015
- // Check for commentception
3016
- if ( ! empty( $comment->children ) )
3017
- $user_ids = array_merge( $user_ids, bp_activity_recurse_comments_user_ids( $comment->children ) );
 
 
3018
  }
3019
 
3020
- return $user_ids;
 
 
 
 
 
 
 
 
3021
  }
3022
 
3023
  /**
3024
  * Output the mentionname for the displayed user.
3025
  *
3026
- * @since BuddyPress (1.9.0)
3027
  */
3028
  function bp_displayed_user_mentionname() {
3029
  echo bp_get_displayed_user_mentionname();
@@ -3031,58 +3374,82 @@ function bp_displayed_user_mentionname() {
3031
  /**
3032
  * Get the mentionname for the displayed user.
3033
  *
3034
- * @since BuddyPress (1.9.0)
3035
  *
3036
  * @return string Mentionname for the displayed user, if available.
3037
  */
3038
  function bp_get_displayed_user_mentionname() {
 
 
 
 
 
 
 
 
3039
  return apply_filters( 'bp_get_displayed_user_mentionname', bp_activity_get_user_mentionname( bp_displayed_user_id() ) );
3040
  }
3041
 
3042
  /**
3043
  * Echo a list of all registered activity types for use in dropdowns or checkbox lists.
3044
  *
3045
- * @since BuddyPress (1.7)
3046
  *
3047
- * @param string $output Optional. Either 'select' or 'checkbox'. Default: 'select'.
3048
- * @param array $args {
3049
  * Optional extra arguments.
3050
- * @type string $checkbox_name When returning checkboxes, sets the 'name'
3051
- * attribute.
3052
- * @type array|string $selected A list of types that should be checked/
3053
- * selected.
3054
  * }
3055
  */
3056
  function bp_activity_types_list( $output = 'select', $args = '' ) {
3057
- $defaults = array(
 
3058
  'checkbox_name' => 'bp_activity_types',
3059
  'selected' => array(),
3060
- );
3061
- $args = wp_parse_args( $args, $defaults );
3062
 
3063
  $activities = bp_activity_get_types();
3064
  natsort( $activities );
3065
 
3066
- // Loop through the activity types and output markup
3067
  foreach ( $activities as $type => $description ) {
3068
 
3069
- // See if we need to preselect the current type
3070
  $checked = checked( true, in_array( $type, (array) $args['selected'] ), false );
3071
  $selected = selected( true, in_array( $type, (array) $args['selected'] ), false );
3072
 
3073
- if ( 'select' == $output )
3074
- printf( '<option value="%1$s" %2$s>%3$s</option>', esc_attr( $type ), $selected, esc_html( $description ) );
3075
-
3076
- elseif ( 'checkbox' == $output )
3077
- printf( '<label style="">%1$s<input type="checkbox" name="%2$s[]" value="%3$s" %4$s/></label>', esc_html( $description ), esc_attr( $args['checkbox_name'] ), esc_attr( $type ), $checked );
 
 
 
 
3078
 
3079
- // Allow custom markup
 
 
 
 
 
 
 
 
 
 
 
3080
  do_action( 'bp_activity_types_list_' . $output, $args, $type, $description );
3081
  }
3082
 
3083
- // Backpat with BP-Default for dropdown boxes only
3084
- if ( 'select' == $output )
3085
  do_action( 'bp_activity_filter_options' );
 
3086
  }
3087
 
3088
 
@@ -3091,9 +3458,8 @@ function bp_activity_types_list( $output = 'select', $args = '' ) {
3091
  /**
3092
  * Output the sitewide activity feed link.
3093
  *
3094
- * @since BuddyPress (1.0)
3095
  *
3096
- * @uses bp_get_sitewide_activity_feed_link()
3097
  */
3098
  function bp_sitewide_activity_feed_link() {
3099
  echo bp_get_sitewide_activity_feed_link();
@@ -3102,24 +3468,28 @@ function bp_sitewide_activity_feed_link() {
3102
  /**
3103
  * Returns the sitewide activity feed link.
3104
  *
3105
- * @since BuddyPress (1.0)
3106
  *
3107
- * @uses home_url()
3108
- * @uses bp_get_activity_root_slug()
3109
- * @uses apply_filters() To call the 'bp_get_sitewide_activity_feed_link' hook.
3110
  *
3111
  * @return string The sitewide activity feed link.
3112
  */
3113
  function bp_get_sitewide_activity_feed_link() {
 
 
 
 
 
 
 
 
3114
  return apply_filters( 'bp_get_sitewide_activity_feed_link', bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/feed/' );
3115
  }
3116
 
3117
  /**
3118
  * Output the member activity feed link.
3119
  *
3120
- * @since BuddyPress (1.2)
3121
  *
3122
- * @uses bp_get_member_activity_feed_link()
3123
  */
3124
  function bp_member_activity_feed_link() {
3125
  echo bp_get_member_activity_feed_link();
@@ -3128,58 +3498,67 @@ function bp_member_activity_feed_link() {
3128
  /**
3129
  * Output the member activity feed link.
3130
  *
3131
- * @since BuddyPress (1.0)
3132
- * @deprecated BuddyPress (1.2)
3133
  *
3134
  * @todo properly deprecate in favor of bp_member_activity_feed_link().
3135
  *
3136
- * @uses bp_get_member_activity_feed_link()
3137
  */
3138
  function bp_activities_member_rss_link() { echo bp_get_member_activity_feed_link(); }
3139
 
3140
  /**
3141
  * Return the member activity feed link.
3142
  *
3143
- * @since BuddyPress (1.2)
3144
  *
3145
- * @uses bp_is_profile_component()
3146
- * @uses bp_is_current_action()
3147
- * @uses bp_displayed_user_domain()
3148
- * @uses bp_get_activity_slug()
3149
- * @uses bp_is_active()
3150
- * @uses bp_get_friends_slug()
3151
- * @uses bp_get_groups_slug()
3152
- * @uses apply_filters() To call the 'bp_get_activities_member_rss_link' hook.
3153
  *
3154
  * @return string $link The member activity feed link.
3155
  */
3156
  function bp_get_member_activity_feed_link() {
3157
 
3158
- if ( bp_is_profile_component() || bp_is_current_action( 'just-me' ) )
 
3159
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/feed/';
3160
- elseif ( bp_is_active( 'friends' ) && bp_is_current_action( bp_get_friends_slug() ) )
 
 
3161
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/feed/';
3162
- elseif ( bp_is_active( 'groups' ) && bp_is_current_action( bp_get_groups_slug() ) )
 
 
3163
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/feed/';
3164
- elseif ( 'favorites' == bp_current_action() )
 
 
3165
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/favorites/feed/';
3166
- elseif ( 'mentions' == bp_current_action() && bp_activity_do_mentions() )
 
 
3167
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/mentions/feed/';
3168
- else
 
 
3169
  $link = '';
 
3170
 
 
 
 
 
 
 
 
3171
  return apply_filters( 'bp_get_activities_member_rss_link', $link );
3172
  }
3173
 
3174
  /**
3175
  * Return the member activity feed link.
3176
  *
3177
- * @since BuddyPress (1.0)
3178
- * @deprecated BuddyPress (1.2)
3179
  *
3180
  * @todo properly deprecate in favor of bp_get_member_activity_feed_link().
3181
  *
3182
- * @uses bp_get_member_activity_feed_link()
3183
  *
3184
  * @return string The member activity feed link.
3185
  */
@@ -3191,9 +3570,8 @@ function bp_activities_member_rss_link() { echo bp_get_member_activity_feed_link
3191
  /**
3192
  * Outputs the activity feed item guid.
3193
  *
3194
- * @since BuddyPress (1.0)
3195
  *
3196
- * @uses bp_activity_feed_item_guid()
3197
  */
3198
  function bp_activity_feed_item_guid() {
3199
  echo bp_get_activity_feed_item_guid();
@@ -3202,25 +3580,30 @@ function bp_activity_feed_item_guid() {
3202
  /**
3203
  * Returns the activity feed item guid.
3204
  *
3205
- * @since BuddyPress (1.2)
3206
  *
3207
  * @global object $activities_template {@link BP_Activity_Template}
3208
- * @uses apply_filters() To call the 'bp_get_activity_feed_item_guid' hook.
3209
  *
3210
  * @return string The activity feed item guid.
3211
  */
3212
  function bp_get_activity_feed_item_guid() {
3213
  global $activities_template;
3214
 
 
 
 
 
 
 
 
3215
  return apply_filters( 'bp_get_activity_feed_item_guid', md5( $activities_template->activity->date_recorded . '-' . $activities_template->activity->content ) );
3216
  }
3217
 
3218
  /**
3219
  * Output the activity feed item title.
3220
  *
3221
- * @since BuddyPress (1.0)
3222
  *
3223
- * @uses bp_get_activity_feed_item_title()
3224
  */
3225
  function bp_activity_feed_item_title() {
3226
  echo bp_get_activity_feed_item_title();
@@ -3229,69 +3612,83 @@ function bp_activity_feed_item_title() {
3229
  /**
3230
  * Return the activity feed item title.
3231
  *
3232
- * @since BuddyPress (1.0)
3233
  *
3234
  * @global object $activities_template {@link BP_Activity_Template}
3235
- * @uses ent2ncr()
3236
- * @uses convert_chars()
3237
- * @uses bp_create_excerpt()
3238
- * @uses apply_filters() To call the 'bp_get_activity_feed_item_title' hook.
3239
  *
3240
  * @return string $title The activity feed item title.
3241
  */
3242
  function bp_get_activity_feed_item_title() {
3243
  global $activities_template;
3244
 
3245
- if ( !empty( $activities_template->activity->action ) )
3246
  $content = $activities_template->activity->action;
3247
- else
3248
  $content = $activities_template->activity->content;
 
3249
 
3250
  $content = explode( '<span', $content );
3251
- $title = strip_tags( ent2ncr( trim( convert_chars( $content[0] ) ) ) );
3252
 
3253
- if ( ':' == substr( $title, -1 ) )
3254
  $title = substr( $title, 0, -1 );
 
3255
 
3256
- if ( 'activity_update' == $activities_template->activity->type )
3257
  $title .= ': ' . strip_tags( ent2ncr( trim( convert_chars( bp_create_excerpt( $activities_template->activity->content, 70, array( 'ending' => " [&#133;]" ) ) ) ) ) );
 
3258
 
 
 
 
 
 
 
 
3259
  return apply_filters( 'bp_get_activity_feed_item_title', $title );
3260
  }
3261
 
3262
  /**
3263
- * Output the activity feed item link
3264
  *
3265
- * @since BuddyPress (1.0)
3266
  *
3267
- * @uses bp_get_activity_feed_item_link()
3268
  */
3269
  function bp_activity_feed_item_link() {
3270
  echo bp_get_activity_feed_item_link();
3271
  }
3272
 
3273
  /**
3274
- * Return the activity feed item link
3275
  *
3276
- * @since BuddyPress (1.0)
3277
  *
3278
  * @global object $activities_template {@link BP_Activity_Template}
3279
- * @uses apply_filters() To call the 'bp_get_activity_feed_item_link' hook.
3280
  *
3281
  * @return string The activity feed item link.
3282
  */
3283
  function bp_get_activity_feed_item_link() {
3284
  global $activities_template;
3285
 
3286
- return apply_filters( 'bp_get_activity_feed_item_link', $activities_template->activity->primary_link );
 
 
 
 
 
 
 
 
 
 
 
3287
  }
3288
 
3289
  /**
3290
  * Output the activity feed item date.
3291
  *
3292
- * @since BuddyPress (1.0)
3293
  *
3294
- * @uses bp_get_activity_feed_item_date()
3295
  */
3296
  function bp_activity_feed_item_date() {
3297
  echo bp_get_activity_feed_item_date();
@@ -3300,25 +3697,34 @@ function bp_activity_feed_item_date() {
3300
  /**
3301
  * Return the activity feed item date.
3302
  *
3303
- * @since BuddyPress (1.0)
3304
  *
3305
  * @global object $activities_template {@link BP_Activity_Template}
3306
- * @uses apply_filters() To call the 'bp_get_activity_feed_item_date' hook.
3307
  *
3308
  * @return string The activity feed item date.
3309
  */
3310
  function bp_get_activity_feed_item_date() {
3311
  global $activities_template;
3312
 
3313
- return apply_filters( 'bp_get_activity_feed_item_date', $activities_template->activity->date_recorded );
 
 
 
 
 
 
 
 
 
 
 
3314
  }
3315
 
3316
  /**
3317
  * Output the activity feed item description.
3318
  *
3319
- * @since BuddyPress (1.0)
3320
  *
3321
- * @uses bp_get_activity_feed_item_description()
3322
  */
3323
  function bp_activity_feed_item_description() {
3324
  echo bp_get_activity_feed_item_description();
@@ -3327,32 +3733,40 @@ function bp_activity_feed_item_description() {
3327
  /**
3328
  * Return the activity feed item description.
3329
  *
3330
- * @since BuddyPress (1.0)
3331
  *
3332
  * @global object $activities_template {@link BP_Activity_Template}
3333
- * @uses ent2ncr()
3334
- * @uses convert_chars()
3335
- * @uses apply_filters() To call the 'bp_get_activity_feed_item_description' hook.
3336
  *
3337
  * @return string The activity feed item description.
3338
  */
3339
  function bp_get_activity_feed_item_description() {
3340
  global $activities_template;
3341
 
3342
- $content = '';
3343
- if ( ! empty( $activities_template->activity->content ) )
3344
- $content = $activities_template->activity->content;
 
 
 
 
 
 
3345
 
3346
- return apply_filters( 'bp_get_activity_feed_item_description', ent2ncr( convert_chars( str_replace( '%s', '', $content ) ) ) );
 
 
 
 
 
 
 
3347
  }
3348
 
3349
  /**
3350
  * Template tag so we can hook activity feed to <head>.
3351
  *
3352
- * @since BuddyPress (1.5)
3353
  *
3354
- * @uses bloginfo()
3355
- * @uses bp_sitewide_activity_feed_link()
3356
  */
3357
  function bp_activity_sitewide_feed() {
3358
  ?>
@@ -3362,3 +3776,97 @@ function bp_activity_sitewide_feed() {
3362
  <?php
3363
  }
3364
  add_action( 'bp_head', 'bp_activity_sitewide_feed' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * BuddyPress Activity Template Functions.
4
  *
5
  * @package BuddyPress
6
  * @subpackage ActivityTemplate
7
+ * @since 1.5.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ if ( ! buddypress()->do_autoload ) {
14
+ require dirname( __FILE__ ) . '/classes/class-bp-activity-template.php';
15
+ }
16
 
17
  /**
18
  * Output the activity component slug.
19
  *
20
+ * @since 1.5.0
21
  *
 
22
  */
23
  function bp_activity_slug() {
24
  echo bp_get_activity_slug();
26
  /**
27
  * Return the activity component slug.
28
  *
29
+ * @since 1.5.0
30
  *
 
31
  *
32
  * @return string The activity component slug.
33
  */
34
  function bp_get_activity_slug() {
35
+
36
+ /**
37
+ * Filters the activity component slug.
38
+ *
39
+ * @since 1.5.0
40
+ *
41
+ * @param string $slug Activity component slug.
42
+ */
43
  return apply_filters( 'bp_get_activity_slug', buddypress()->activity->slug );
44
  }
45
 
46
  /**
47
  * Output the activity component root slug.
48
  *
49
+ * @since 1.5.0
50
  *
 
51
  */
52
  function bp_activity_root_slug() {
53
  echo bp_get_activity_root_slug();
55
  /**
56
  * Return the activity component root slug.
57
  *
58
+ * @since 1.5.0
59
  *
 
60
  *
61
  * @return string The activity component root slug.
62
  */
63
  function bp_get_activity_root_slug() {
64
+
65
+ /**
66
+ * Filters the activity component root slug.
67
+ *
68
+ * @since 1.5.0
69
+ *
70
+ * @param string $root_slug Activity component root slug.
71
+ */
72
  return apply_filters( 'bp_get_activity_root_slug', buddypress()->activity->root_slug );
73
  }
74
 
75
  /**
76
  * Output activity directory permalink.
77
  *
78
+ * @since 1.5.0
79
  *
 
80
  */
81
  function bp_activity_directory_permalink() {
82
+ echo esc_url( bp_get_activity_directory_permalink() );
83
  }
84
  /**
85
+ * Return activity directory permalink.
86
  *
87
+ * @since 1.5.0
88
  *
 
 
 
 
89
  *
90
  * @return string Activity directory permalink.
91
  */
92
  function bp_get_activity_directory_permalink() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
+ /**
95
+ * Filters the activity directory permalink.
96
+ *
97
+ * @since 1.5.0
98
+ *
99
+ * @param string $url Permalink url for the activity directory.
100
+ */
101
+ return apply_filters( 'bp_get_activity_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_activity_root_slug() ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
 
103
 
104
  /**
105
  * Initialize the activity loop.
108
  * $activities_template global, enabling the use of BuddyPress templates and
109
  * template functions to display a list of activity items.
110
  *
111
+ * @since 1.0.0
112
+ * @since 2.4.0 Introduced the `$fields` parameter.
113
  *
114
  * @global object $activities_template {@link BP_Activity_Template}
115
+ *
116
+ * @param array|string $args {
117
+ * Arguments for limiting the contents of the activity loop. Most arguments
118
+ * are in the same format as {@link BP_Activity_Activity::get()}. However,
119
+ * because the format of the arguments accepted here differs in a number of
120
+ * ways, and because bp_has_activities() determines some default arguments in
121
+ * a dynamic fashion, we list all accepted arguments here as well.
122
+ *
123
+ * Arguments can be passed as an associative array, or as a URL querystring
124
+ * (eg, 'user_id=4&display_comments=threaded').
125
+ *
126
+ * @type int $page Which page of results to fetch. Using page=1 without per_page will result
127
+ * in no pagination. Default: 1.
128
+ * @type int|bool $per_page Number of results per page. Default: 20.
129
+ * @type string $page_arg String used as a query parameter in pagination links. Default: 'acpage'.
130
+ * @type int|bool $max Maximum number of results to return. Default: false (unlimited).
131
+ * @type string $fields Activity fields to retrieve. 'all' to fetch entire activity objects,
132
+ * 'ids' to get only the activity IDs. Default 'all'.
133
+ * @type string|bool $count_total If true, an additional DB query is run to count the total activity items
134
+ * for the query. Default: false.
135
+ * @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.
136
+ * @type array|bool $exclude Array of activity IDs to exclude. Default: false.
137
+ * @type array|bool $in Array of IDs to limit query by (IN). 'in' is intended to be used in
138
+ * conjunction with other filter parameters. Default: false.
139
+ * @type array|bool $include Array of exact activity IDs to query. Providing an 'include' array will
140
+ * override all other filters passed in the argument array. When viewing the
141
+ * permalink page for a single activity item, this value defaults to the ID of
142
+ * that item. Otherwise the default is false.
143
+ * @type array $meta_query Limit by activitymeta by passing an array of meta_query conditions. See
144
+ * {@link WP_Meta_Query::queries} for a description of the syntax.
145
+ * @type array $date_query Limit by date by passing an array of date_query conditions. See first
146
+ * parameter of {@link WP_Date_Query::__construct()} for syntax.
147
+ * @type array $filter_query Advanced activity filtering. See {@link BP_Activity_Query::__construct()}.
148
+ * @type string $search_terms Limit results by a search term. Default: false.
149
+ * @type string $scope Use a BuddyPress pre-built filter.
150
+ * - 'just-me' retrieves items belonging only to a user; this is equivalent
151
+ * to passing a 'user_id' argument.
152
+ * - 'friends' retrieves items belonging to the friends of a user.
153
+ * - 'groups' retrieves items belonging to groups to which a user belongs to.
154
+ * - 'favorites' retrieves a user's favorited activity items.
155
+ * - 'mentions' retrieves items where a user has received an @-mention.
156
+ * The default value of 'scope' is set to one of the above if that value
157
+ * appears in the appropriate place in the URL; eg, 'scope' will be 'groups'
158
+ * when visiting http://example.com/members/joe/activity/groups/. Otherwise
159
+ * defaults to false.
160
+ * @type int|array|bool $user_id The ID(s) of user(s) whose activity should be fetched. Pass a single ID or
161
+ * an array of IDs. When viewing a user profile page (but not that user's
162
+ * activity subpages, ie My Friends, My Groups, etc), 'user_id' defaults to
163
+ * the ID of the displayed user. Otherwise the default is false.
164
+ * @type string|array|bool $object Filters by the `component` column in the database, which is generally the
165
+ * component ID in the case of BuddyPress components, or the plugin slug in
166
+ * the case of plugins. For example, 'groups' will limit results to those that
167
+ * are associated with the BP Groups component. Accepts a single component
168
+ * string, or an array of multiple components. Defaults to 'groups' when
169
+ * viewing the page of a single group, the My Groups activity filter, or the
170
+ * Activity > Groups filter of a user profile. Otherwise defaults to false.
171
+ * @type string|array|bool $action Filters by the `type` column in the database, which is a string
172
+ * categorizing the activity item (eg, 'new_blog_post', 'created_group').
173
+ * Accepts a comma-delimited string or an array of types. Default: false.
174
+ * @type int|array|bool $primary_id Filters by the `item_id` column in the database. The meaning of
175
+ * 'primary_id' differs between components/types; for example, in the case of
176
+ * 'created_group', 'primary_id' is the ID of the group. Accepts a single ID,
177
+ * or an array of multiple IDs. When viewing a single group, defaults to the
178
+ * current group ID. When viewing a user's Groups stream page, defaults to the
179
+ * IDs of the user's groups. Otherwise defaults to false.
180
+ * @type int|array|bool $secondary_id Filters by the `secondary_item_id` column in the database. The meaning of
181
+ * 'secondary_id' differs between components/types. Accepts a single ID, or an
182
+ * array of multiple IDs. Defaults to false.
183
+ * @type int $offset Return only activity items with an ID greater than or equal to this one.
184
+ * Note that providing an offset will disable pagination. Default: false.
185
+ * @type string|bool $display_comments How to handle activity comments. Possible values:
186
+ * - 'threaded' - comments appear in a threaded tree, under their parent
187
+ * items.
188
+ * - 'stream' - the activity stream is presented in a flat manner, with
189
+ * comments sorted in chronological order alongside other activity items.
190
+ * - false - don't fetch activity comments at all.
191
+ * Default: 'threaded'.
192
+ * @type bool $show_hidden Whether to show items marked hide_sitewide. Defaults to false, except in
193
+ * the following cases:
194
+ * - User is viewing his own activity stream.
195
+ * - User is viewing the activity stream of a non-public group of which he
196
+ * is a member.
197
+ * @type string|bool $spam Spam status. 'ham_only', 'spam_only', or false to show all activity
198
+ * regardless of spam status. Default: 'ham_only'.
199
+ * @type bool $populate_extras Whether to pre-fetch the activity metadata for the queried items.
200
+ * Default: true.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  * }
202
  * @return bool Returns true when activities are found, otherwise false.
203
  */
204
  function bp_has_activities( $args = '' ) {
205
+ global $activities_template;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
+ // Get BuddyPress.
208
+ $bp = buddypress();
209
+
210
+ /*
211
+ * Smart Defaults.
212
+ */
213
+
214
+ // User filtering.
215
+ $user_id = bp_displayed_user_id()
216
+ ? bp_displayed_user_id()
217
+ : false;
218
+
219
+ // Group filtering.
220
+ if ( bp_is_group() ) {
221
+ $object = $bp->groups->id;
222
+ $primary_id = bp_get_current_group_id();
223
+ $show_hidden = (bool) ( groups_is_user_member( bp_loggedin_user_id(), $primary_id ) || bp_current_user_can( 'bp_moderate' ) );
224
+ } else {
225
+ $object = false;
226
+ $primary_id = false;
227
+ $show_hidden = false;
228
+ }
229
+
230
+ // The default scope should recognize custom slugs.
231
+ $scope = array_key_exists( bp_current_action(), (array) $bp->loaded_components )
232
+ ? $bp->loaded_components[ bp_current_action() ]
233
+ : bp_current_action();
234
+
235
+ // Support for permalinks on single item pages: /groups/my-group/activity/124/.
236
+ $include = bp_is_current_action( bp_get_activity_slug() )
237
+ ? bp_action_variable( 0 )
238
+ : false;
239
+
240
+ $search_terms_default = false;
241
+ $search_query_arg = bp_core_get_component_search_query_arg( 'activity' );
242
+ if ( ! empty( $_REQUEST[ $search_query_arg ] ) ) {
243
+ $search_terms_default = stripslashes( $_REQUEST[ $search_query_arg ] );
244
+ }
245
+
246
+ /*
247
+ * Parse Args.
248
+ */
249
+
250
+ // Note: any params used for filtering can be a single value, or multiple
251
+ // values comma separated.
252
+ $r = bp_parse_args( $args, array(
253
+ 'display_comments' => 'threaded', // False for none, stream/threaded - show comments in the stream or threaded under items.
254
+ 'include' => $include, // Pass an activity_id or string of IDs comma-separated.
255
+ 'exclude' => false, // Pass an activity_id or string of IDs comma-separated.
256
+ 'in' => false, // Comma-separated list or array of activity IDs among which to search.
257
+ 'sort' => 'DESC', // Sort DESC or ASC.
258
+ 'page' => 1, // Which page to load.
259
+ 'per_page' => 20, // Number of items per page.
260
+ 'page_arg' => 'acpage', // See https://buddypress.trac.wordpress.org/ticket/3679.
261
+ 'max' => false, // Max number to return.
262
+ 'fields' => 'all',
263
+ 'count_total' => false,
264
+ 'show_hidden' => $show_hidden, // Show activity items that are hidden site-wide?
265
+ 'spam' => 'ham_only', // Hide spammed items.
266
 
267
+ // Scope - pre-built activity filters for a user (friends/groups/favorites/mentions).
268
  'scope' => $scope,
269
 
270
  // Filtering
271
+ 'user_id' => $user_id, // user_id to filter on.
272
+ 'object' => $object, // Object to filter on e.g. groups, profile, status, friends.
273
+ 'action' => false, // Action to filter on e.g. activity_update, new_forum_post, profile_updated.
274
+ 'primary_id' => $primary_id, // Object ID to filter on e.g. a group_id or forum_id or blog_id etc.
275
+ 'secondary_id' => false, // Secondary object ID to filter on e.g. a post_id.
276
+ 'offset' => false, // Return only items >= this ID.
277
+ 'since' => false, // Return only items recorded since this Y-m-d H:i:s date.
278
+
279
+ 'meta_query' => false, // Filter on activity meta. See WP_Meta_Query for format.
280
+ 'date_query' => false, // Filter by date. See first parameter of WP_Date_Query for format.
281
+ 'filter_query' => false, // Advanced filtering. See BP_Activity_Query for format.
282
+
283
+ // Searching.
284
+ 'search_terms' => $search_terms_default,
285
  'update_meta_cache' => true,
286
+ ), 'has_activities' );
287
 
288
+ /*
289
+ * Smart Overrides.
290
+ */
291
 
292
  // Translate various values for 'display_comments'
293
  // This allows disabling comments via ?display_comments=0
294
+ // or =none or =false. Final true is a strict type check. See #5029.
295
+ if ( in_array( $r['display_comments'], array( 0, '0', 'none', 'false' ), true ) ) {
296
+ $r['display_comments'] = false;
297
  }
298
 
299
+ // Ignore pagination if an offset is passed.
300
+ if ( ! empty( $r['offset'] ) ) {
301
+ $r['page'] = 0;
302
  }
303
 
304
+ // Search terms.
305
+ if ( ! empty( $_REQUEST['s'] ) && empty( $r['search_terms'] ) ) {
306
+ $r['search_terms'] = $_REQUEST['s'];
307
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
+ // Do not exceed the maximum per page.
310
+ if ( ! empty( $r['max'] ) && ( (int) $r['per_page'] > (int) $r['max'] ) ) {
311
+ $r['per_page'] = $r['max'];
312
+ }
313
 
314
+ /**
315
+ * Filters whether BuddyPress should enable afilter support.
316
+ *
317
+ * Support for basic filters in earlier BP versions is disabled by default.
318
+ * To enable, put add_filter( 'bp_activity_enable_afilter_support', '__return_true' );
319
+ * into bp-custom.php or your theme's functions.php.
320
+ *
321
+ * @since 1.6.0
322
+ *
323
+ * @param bool $value True if BuddyPress should enable afilter support.
324
+ */
325
+ if ( isset( $_GET['afilter'] ) && apply_filters( 'bp_activity_enable_afilter_support', false ) ) {
326
+ $r['filter'] = array(
327
+ 'object' => $_GET['afilter']
328
+ );
329
+ } elseif ( ! empty( $r['user_id'] ) || ! empty( $r['object'] ) || ! empty( $r['action'] ) || ! empty( $r['primary_id'] ) || ! empty( $r['secondary_id'] ) || ! empty( $r['offset'] ) || ! empty( $r['since'] ) ) {
330
+ $r['filter'] = array(
331
+ 'user_id' => $r['user_id'],
332
+ 'object' => $r['object'],
333
+ 'action' => $r['action'],
334
+ 'primary_id' => $r['primary_id'],
335
+ 'secondary_id' => $r['secondary_id'],
336
+ 'offset' => $r['offset'],
337
+ 'since' => $r['since']
338
+ );
339
+ } else {
340
+ $r['filter'] = false;
341
+ }
342
 
343
+ // If specific activity items have been requested, override the $hide_spam
344
+ // argument. This prevents backpat errors with AJAX.
345
+ if ( ! empty( $r['include'] ) && ( 'ham_only' === $r['spam'] ) ) {
346
+ $r['spam'] = 'all';
 
 
 
347
  }
348
 
349
+ /*
350
+ * Query
351
+ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
 
353
+ $activities_template = new BP_Activity_Template( $r );
354
 
355
+ /**
356
+ * Filters whether or not there are activity items to display.
357
+ *
358
+ * @since 1.1.0
359
+ *
360
+ * @param bool $value Whether or not there are activity items to display.
361
+ * @param string $activities_template Current activities template being used.
362
+ * @param array $r Array of arguments passed into the BP_Activity_Template class.
363
+ */
364
+ return apply_filters( 'bp_has_activities', $activities_template->has_activities(), $activities_template, $r );
365
  }
366
 
367
  /**
368
  * Determine if there are still activities left in the loop.
369
  *
370
+ * @since 1.0.0
371
  *
372
  * @global object $activities_template {@link BP_Activity_Template}
 
373
  *
374
  * @return bool Returns true when activities are found.
375
  */
381
  /**
382
  * Get the current activity object in the loop.
383
  *
384
+ * @since 1.0.0
385
  *
386
  * @global object $activities_template {@link BP_Activity_Template}
 
387
  *
388
  * @return object The current activity within the loop.
389
  */
392
  return $activities_template->the_activity();
393
  }
394
 
395
+ /**
396
+ * Output the URL for the Load More link.
397
+ *
398
+ * @since 2.1.0
399
+ */
400
+ function bp_activity_load_more_link() {
401
+ echo esc_url( bp_get_activity_load_more_link() );
402
+ }
403
+ /**
404
+ * Get the URL for the Load More link.
405
+ *
406
+ * @since 2.1.0
407
+ *
408
+ * @return string $link
409
+ */
410
+ function bp_get_activity_load_more_link() {
411
+ global $activities_template;
412
+
413
+ $url = bp_get_requested_url();
414
+ $link = add_query_arg( $activities_template->pag_arg, $activities_template->pag_page + 1, $url );
415
+
416
+ /**
417
+ * Filters the Load More link URL.
418
+ *
419
+ * @since 2.1.0
420
+ *
421
+ * @param string $link The "Load More" link URL with appropriate query args.
422
+ * @param string $url The original URL.
423
+ * @param object $activities_template The activity template loop global.
424
+ */
425
+ return apply_filters( 'bp_get_activity_load_more_link', $link, $url, $activities_template );
426
+ }
427
+
428
  /**
429
  * Output the activity pagination count.
430
  *
431
+ * @since 1.0.0
432
  *
433
  * @global object $activities_template {@link BP_Activity_Template}
 
434
  */
435
  function bp_activity_pagination_count() {
436
  echo bp_get_activity_pagination_count();
439
  /**
440
  * Return the activity pagination count.
441
  *
442
+ * @since 1.2.0
443
  *
444
  * @global object $activities_template {@link BP_Activity_Template}
 
445
  *
446
  * @return string The pagination text.
447
  */
453
  $to_num = bp_core_number_format( ( $start_num + ( $activities_template->pag_num - 1 ) > $activities_template->total_activity_count ) ? $activities_template->total_activity_count : $start_num + ( $activities_template->pag_num - 1 ) );
454
  $total = bp_core_number_format( $activities_template->total_activity_count );
455
 
456
+ if ( 1 == $activities_template->total_activity_count ) {
457
+ $message = __( 'Viewing 1 item', 'buddypress' );
458
+ } else {
459
+ $message = sprintf( _n( 'Viewing %1$s - %2$s of %3$s item', 'Viewing %1$s - %2$s of %3$s items', $activities_template->total_activity_count, 'buddypress' ), $from_num, $to_num, $total );
460
+ }
461
+
462
+ return $message;
463
  }
464
 
465
  /**
466
  * Output the activity pagination links.
467
  *
468
+ * @since 1.0.0
469
  *
 
470
  */
471
  function bp_activity_pagination_links() {
472
  echo bp_get_activity_pagination_links();
475
  /**
476
  * Return the activity pagination links.
477
  *
478
+ * @since 1.0.0
479
  *
480
  * @global object $activities_template {@link BP_Activity_Template}
 
481
  *
482
  * @return string The pagination links.
483
  */
484
  function bp_get_activity_pagination_links() {
485
  global $activities_template;
486
 
487
+ /**
488
+ * Filters the activity pagination link output.
489
+ *
490
+ * @since 1.0.0
491
+ *
492
+ * @param string $pag_links Output for the activity pagination links.
493
+ */
494
  return apply_filters( 'bp_get_activity_pagination_links', $activities_template->pag_links );
495
  }
496
 
497
  /**
498
  * Return true when there are more activity items to be shown than currently appear.
499
  *
500
+ * @since 1.5.0
501
  *
502
  * @global object $activities_template {@link BP_Activity_Template}
 
503
  *
504
  * @return bool $has_more_items True if more items, false if not.
505
  */
506
  function bp_activity_has_more_items() {
507
  global $activities_template;
508
 
509
+ if ( ! empty( $activities_template->has_more_items ) ) {
510
+ $has_more_items = true;
511
+ } else {
512
+ $remaining_pages = 0;
513
 
514
+ if ( ! empty( $activities_template->pag_page ) ) {
515
+ $remaining_pages = floor( ( $activities_template->total_activity_count - 1 ) / ( $activities_template->pag_num * $activities_template->pag_page ) );
516
+ }
517
 
518
+ $has_more_items = (int) $remaining_pages > 0;
519
+ }
520
 
521
+ /**
522
+ * Filters whether there are more activity items to display.
523
+ *
524
+ * @since 1.5.0
525
+ *
526
+ * @param bool $has_more_items Whether or not there are more activity items to display.
527
+ */
528
  return apply_filters( 'bp_activity_has_more_items', $has_more_items );
529
  }
530
 
531
  /**
532
  * Output the activity count.
533
  *
534
+ * @since 1.2.0
535
  *
 
536
  */
537
  function bp_activity_count() {
538
  echo bp_get_activity_count();
541
  /**
542
  * Return the activity count.
543
  *
544
+ * @since 1.2.0
545
  *
546
  * @global object $activities_template {@link BP_Activity_Template}
 
547
  *
548
  * @return int The activity count.
549
  */
550
  function bp_get_activity_count() {
551
  global $activities_template;
552
 
553
+ /**
554
+ * Filters the activity count for the activity template.
555
+ *
556
+ * @since 1.2.0
557
+ *
558
+ * @param int $activity_count The count for total activity.
559
+ */
560
  return apply_filters( 'bp_get_activity_count', (int) $activities_template->activity_count );
561
  }
562
 
563
  /**
564
  * Output the number of activities per page.
565
  *
566
+ * @since 1.2.0
567
  *
 
568
  */
569
  function bp_activity_per_page() {
570
  echo bp_get_activity_per_page();
573
  /**
574
  * Return the number of activities per page.
575
  *
576
+ * @since 1.2.0
577
  *
578
  * @global object $activities_template {@link BP_Activity_Template}
 
579
  *
580
  * @return int The activities per page.
581
  */
582
  function bp_get_activity_per_page() {
583
  global $activities_template;
584
 
585
+ /**
586
+ * Filters the activity posts per page value.
587
+ *
588
+ * @since 1.2.0
589
+ *
590
+ * @param int $pag_num How many post should be displayed for pagination.
591
+ */
592
  return apply_filters( 'bp_get_activity_per_page', (int) $activities_template->pag_num );
593
  }
594
 
595
  /**
596
  * Output the activities title.
597
  *
598
+ * @since 1.0.0
599
  *
 
600
  * @todo Deprecate.
601
  */
602
  function bp_activities_title() {
606
  /**
607
  * Return the activities title.
608
  *
609
+ * @since 1.0.0
610
  *
611
  * @global string $bp_activity_title
 
612
  * @todo Deprecate.
613
  *
614
+ * @return string The activities title.
615
  */
616
  function bp_get_activities_title() {
617
  global $bp_activity_title;
618
 
619
+ /**
620
+ * Filters the activities title for the activity template.
621
+ *
622
+ * @since 1.0.0
623
+ *
624
+ * @param string $bp_activity_title The title to be displayed.
625
+ */
626
  return apply_filters( 'bp_get_activities_title', $bp_activity_title );
627
  }
628
 
629
  /**
630
  * {@internal Missing Description}
631
  *
632
+ * @since 1.0.0
633
  *
 
634
  * @todo Deprecate.
635
  */
636
  function bp_activities_no_activity() {
640
  /**
641
  * {@internal Missing Description}
642
  *
643
+ * @since 1.0.0
644
  *
645
  * @global string $bp_activity_no_activity
 
646
  * @todo Deprecate.
647
  *
648
  * @return string
650
  function bp_get_activities_no_activity() {
651
  global $bp_activity_no_activity;
652
 
653
+ /**
654
+ * Filters the text used when there is no activity to display.
655
+ *
656
+ * @since 1.0.0
657
+ *
658
+ * @param string $bp_activity_no_activity Text to display for no activity.
659
+ */
660
  return apply_filters( 'bp_get_activities_no_activity', $bp_activity_no_activity );
661
  }
662
 
663
  /**
664
  * Output the activity ID.
665
  *
666
+ * @since 1.2.0
667
  *
 
668
  */
669
  function bp_activity_id() {
670
  echo bp_get_activity_id();
673
  /**
674
  * Return the activity ID.
675
  *
676
+ * @since 1.2.0
677
  *
678
  * @global object $activities_template {@link BP_Activity_Template}
 
679
  *
680
  * @return int The activity ID.
681
  */
682
  function bp_get_activity_id() {
683
  global $activities_template;
684
+
685
+ /**
686
+ * Filters the activity ID being displayed.
687
+ *
688
+ * @since 1.2.0
689
+ *
690
+ * @param int $id The activity ID.
691
+ */
692
  return apply_filters( 'bp_get_activity_id', $activities_template->activity->id );
693
  }
694
 
695
  /**
696
  * Output the activity item ID.
697
  *
698
+ * @since 1.2.0
699
  *
 
700
  */
701
  function bp_activity_item_id() {
702
  echo bp_get_activity_item_id();
705
  /**
706
  * Return the activity item ID.
707
  *
708
+ * @since 1.2.0
709
  *
710
  * @global object $activities_template {@link BP_Activity_Template}
 
711
  *
712
  * @return int The activity item ID.
713
  */
714
  function bp_get_activity_item_id() {
715
  global $activities_template;
716
+
717
+ /**
718
+ * Filters the activity item ID being displayed.
719
+ *
720
+ * @since 1.2.0
721
+ *
722
+ * @param int $item_id The activity item ID.
723
+ */
724
  return apply_filters( 'bp_get_activity_item_id', $activities_template->activity->item_id );
725
  }
726
 
727
  /**
728
  * Output the activity secondary item ID.
729
  *
730
+ * @since 1.2.0
731
  *
 
732
  */
733
  function bp_activity_secondary_item_id() {
734
  echo bp_get_activity_secondary_item_id();
737
  /**
738
  * Return the activity secondary item ID.
739
  *
740
+ * @since 1.2.0
741
  *
742
  * @global object $activities_template {@link BP_Activity_Template}
 
743
  *
744
  * @return int The activity secondary item ID.
745
  */
746
  function bp_get_activity_secondary_item_id() {
747
  global $activities_template;
748
+
749
+ /**
750
+ * Filters the activity secondary item ID being displayed.
751
+ *
752
+ * @since 1.2.0
753
+ *
754
+ * @param int $secondary_item_id The activity secondary item ID.
755
+ */
756
  return apply_filters( 'bp_get_activity_secondary_item_id', $activities_template->activity->secondary_item_id );
757
  }
758
 
759
  /**
760
  * Output the date the activity was recorded.
761
  *
762
+ * @since 1.2.0
763
  *
 
764
  */
765
  function bp_activity_date_recorded() {
766
  echo bp_get_activity_date_recorded();
769
  /**
770
  * Return the date the activity was recorded.
771
  *
772
+ * @since 1.2.0
773
  *
774
  * @global object $activities_template {@link BP_Activity_Template}
 
775
  *
776
  * @return string The date the activity was recorded.
777
  */
778
  function bp_get_activity_date_recorded() {
779
  global $activities_template;
780
+
781
+ /**
782
+ * Filters the date the activity was recorded.
783
+ *
784
+ * @since 1.2.0
785
+ *
786
+ * @param int $date_recorded The activity's date.
787
+ */
788
  return apply_filters( 'bp_get_activity_date_recorded', $activities_template->activity->date_recorded );
789
  }
790
 
791
+ /**
792
+ * Output the display name of the member who posted the activity.
793
+ *
794
+ * @since 2.1.0
795
+ *
796
+ */
797
+ function bp_activity_member_display_name() {
798
+ echo bp_get_activity_member_display_name();
799
+ }
800
+
801
+ /**
802
+ * Return the display name of the member who posted the activity.
803
+ *
804
+ * @since 2.1.0
805
+ *
806
+ * @global object $activities_template {@link BP_Activity_Template}
807
+ *
808
+ * @return string The date the activity was recorded.
809
+ */
810
+ function bp_get_activity_member_display_name() {
811
+ global $activities_template;
812
+
813
+ $retval = isset( $activities_template->activity->display_name )
814
+ ? $activities_template->activity->display_name
815
+ : '';
816
+
817
+ /**
818
+ * Filters the display name of the member who posted the activity.
819
+ *
820
+ * @since 2.1.0
821
+ *
822
+ * @param int $retval Display name for the member who posted.
823
+ */
824
+ return apply_filters( 'bp_get_activity_member_display_name', $retval );
825
+ }
826
+
827
  /**
828
  * Output the activity object name.
829
  *
830
+ * @since 1.2.0
831
  *
 
832
  */
833
  function bp_activity_object_name() {
834
  echo bp_get_activity_object_name();
837
  /**
838
  * Return the activity object name.
839
  *
840
+ * @since 1.2.0
841
  *
842
  * @global object $activities_template {@link BP_Activity_Template}
 
843
  *
844
  * @return string The activity object name.
845
  */
846
  function bp_get_activity_object_name() {
847
  global $activities_template;
848
+
849
+ /**
850
+ * Filters the activity object name.
851
+ *
852
+ * @since 1.2.0
853
+ *
854
+ * @param string $activity_component The activity object name.
855
+ */
856
  return apply_filters( 'bp_get_activity_object_name', $activities_template->activity->component );
857
  }
858
 
859
  /**
860
  * Output the activity type.
861
  *
862
+ * @since 1.2.0
863
  *
 
864
  */
865
  function bp_activity_type() {
866
  echo bp_get_activity_type();
869
  /**
870
  * Return the activity type.
871
  *
872
+ * @since 1.2.0
873
  *
874
  * @global object $activities_template {@link BP_Activity_Template}
 
875
  *
876
  * @return string The activity type.
877
  */
878
  function bp_get_activity_type() {
879
  global $activities_template;
880
+
881
+ /**
882
+ * Filters the activity type.
883
+ *
884
+ * @since 1.2.0
885
+ *
886
+ * @param string $activity_type The activity type.
887
+ */
888
  return apply_filters( 'bp_get_activity_type', $activities_template->activity->type );
889
  }
890
 
893
  *
894
  * Just a wrapper for bp_activity_type().
895
  *
896
+ * @since 1.2.0
897
+ * @deprecated 1.5.0
898
  *
899
  * @todo Properly deprecate in favor of bp_activity_type() and
900
+ * remove redundant echo
901
  *
 
902
  */
903
  function bp_activity_action_name() { echo bp_activity_type(); }
904
 
907
  *
908
  * Just a wrapper for bp_get_activity_type().
909
  *
910
+ * @since 1.2.0
911
+ * @deprecated 1.5.0
912
  *
913
  * @todo Properly deprecate in favor of bp_get_activity_type().
914
  *
 
915
  *
916
  * @return string The activity type.
917
  */
920
  /**
921
  * Output the activity user ID.
922
  *
923
+ * @since 1.1.0
924
  *
 
925
  */
926
  function bp_activity_user_id() {
927
  echo bp_get_activity_user_id();
930
  /**
931
  * Return the activity user ID.
932
  *
933
+ * @since 1.1.0
934
  *
935
  * @global object $activities_template {@link BP_Activity_Template}
 
936
  *
937
  * @return int The activity user ID.
938
  */
939
  function bp_get_activity_user_id() {
940
  global $activities_template;
941
+
942
+ /**
943
+ * Filters the activity user ID.
944
+ *
945
+ * @since 1.1.0
946
+ *
947
+ * @param int $user_id The activity user ID.
948
+ */
949
  return apply_filters( 'bp_get_activity_user_id', $activities_template->activity->user_id );
950
  }
951
 
952
  /**
953
  * Output the activity user link.
954
  *
955
+ * @since 1.2.0
956
  *
 
957
  */
958
  function bp_activity_user_link() {
959
  echo bp_get_activity_user_link();
962
  /**
963
  * Return the activity user link.
964
  *
965
+ * @since 1.2.0
966
  *
967
  * @global object $activities_template {@link BP_Activity_Template}
 
 
968
  *
969
  * @return string $link The activity user link.
970
  */
971
  function bp_get_activity_user_link() {
972
  global $activities_template;
973
 
974
+ if ( empty( $activities_template->activity->user_id ) || empty( $activities_template->activity->user_nicename ) || empty( $activities_template->activity->user_login ) ) {
975
  $link = $activities_template->activity->primary_link;
976
+ } else {
977
  $link = bp_core_get_user_domain( $activities_template->activity->user_id, $activities_template->activity->user_nicename, $activities_template->activity->user_login );
978
+ }
979
 
980
+ /**
981
+ * Filters the activity user link.
982
+ *
983
+ * @since 1.2.0
984
+ *
985
+ * @param string $link The activity user link.
986
+ */
987
  return apply_filters( 'bp_get_activity_user_link', $link );
988
  }
989
 
990
  /**
991
  * Output the avatar of the user that performed the action.
992
  *
993
+ * @since 1.1.0
994
  *
995
  * @see bp_get_activity_avatar() for description of arguments.
 
996
  *
997
+ * @param array|string $args See {@link bp_get_activity_avatar()} for description.
998
  */
999
  function bp_activity_avatar( $args = '' ) {
1000
  echo bp_get_activity_avatar( $args );
1002
  /**
1003
  * Return the avatar of the user that performed the action.
1004
  *
1005
+ * @since 1.1.0
1006
  *
1007
  * @see bp_core_fetch_avatar() For a description of the arguments.
1008
  * @global object $activities_template {@link BP_Activity_Template}
1009
+ *
1010
+ * @param array|string $args {
 
 
 
 
 
 
 
1011
  * Arguments are listed here with an explanation of their defaults.
1012
  * For more information about the arguments, see
1013
  * {@link bp_core_fetch_avatar()}.
1014
+ * @type string $alt Default: 'Profile picture of [user name]' if
1015
+ * activity user name is available, otherwise 'Profile picture'.
1016
+ * @type string $class Default: 'avatar'.
1017
+ * @type string|bool $email Default: Email of the activity's
1018
+ * associated user, if available. Otherwise false.
1019
+ * @type string $type Default: 'full' when viewing a single activity
1020
+ * permalink page, otherwise 'thumb'.
1021
+ * @type int|bool $user_id Default: ID of the activity's user.
1022
  * }
1023
  * @return string User avatar string.
1024
  */
1027
 
1028
  $bp = buddypress();
1029
 
1030
+ // On activity permalink pages, default to the full-size avatar.
1031
  $type_default = bp_is_single_activity() ? 'full' : 'thumb';
1032
 
1033
  // Within the activity comment loop, the current activity should be set
1034
  // to current_comment. Otherwise, just use activity.
1035
  $current_activity_item = isset( $activities_template->activity->current_comment ) ? $activities_template->activity->current_comment : $activities_template->activity;
1036
 
1037
+ // Activity user display name.
1038
  $dn_default = isset( $current_activity_item->display_name ) ? $current_activity_item->display_name : '';
1039
 
1040
+ // Prepend some descriptive text to alt.
1041
  $alt_default = !empty( $dn_default ) ? sprintf( __( 'Profile picture of %s', 'buddypress' ), $dn_default ) : __( 'Profile picture', 'buddypress' );
1042
 
1043
  $defaults = array(
1053
 
1054
  if ( !isset( $height ) && !isset( $width ) ) {
1055
 
1056
+ // Backpat.
1057
  if ( isset( $bp->avatar->full->height ) || isset( $bp->avatar->thumb->height ) ) {
1058
  $height = ( 'full' == $type ) ? $bp->avatar->full->height : $bp->avatar->thumb->height;
1059
  } else {
1060
  $height = 20;
1061
  }
1062
 
1063
+ // Backpat.
1064
  if ( isset( $bp->avatar->full->width ) || isset( $bp->avatar->thumb->width ) ) {
1065
  $width = ( 'full' == $type ) ? $bp->avatar->full->width : $bp->avatar->thumb->width;
1066
  } else {
1068
  }
1069
  }
1070
 
1071
+ /**
1072
+ * Filters the activity avatar object based on current activity item component.
1073
+ *
1074
+ * This is a variable filter dependent on the component used.
1075
+ * Possible hooks are bp_get_activity_avatar_object_blog,
1076
+ * bp_get_activity_avatar_object_group, and bp_get_activity_avatar_object_user.
1077
+ *
1078
+ * @since 1.1.0
1079
+ *
1080
+ * @param string $component Component being displayed.
1081
+ */
1082
  $object = apply_filters( 'bp_get_activity_avatar_object_' . $current_activity_item->component, 'user' );
1083
  $item_id = !empty( $user_id ) ? $user_id : $current_activity_item->user_id;
1084
+
1085
+ /**
1086
+ * Filters the activity avatar item ID.
1087
+ *
1088
+ * @since 1.2.10
1089
+ *
1090
+ * @param int $item_id Item ID for the activity avatar.
1091
+ */
1092
  $item_id = apply_filters( 'bp_get_activity_avatar_item_id', $item_id );
1093
 
1094
+ // If this is a user object pass the users' email address for Gravatar so we don't have to prefetch it.
1095
+ if ( 'user' == $object && empty( $user_id ) && empty( $email ) && isset( $current_activity_item->user_email ) ) {
1096
  $email = $current_activity_item->user_email;
1097
+ }
1098
 
1099
+ /**
1100
+ * Filters the value returned by bp_core_fetch_avatar.
1101
+ *
1102
+ * @since 1.1.3
1103
+ *
1104
+ * @param array $value HTML image element containing the activity avatar.
1105
+ */
1106
  return apply_filters( 'bp_get_activity_avatar', bp_core_fetch_avatar( array(
1107
  'item_id' => $item_id,
1108
  'object' => $object,
1118
  /**
1119
  * Output the avatar of the object that action was performed on.
1120
  *
1121
+ * @since 1.2.0
1122
  *
1123
  * @see bp_get_activity_secondary_avatar() for description of arguments.
 
1124
  *
1125
+ * @param array|string $args See {@link bp_get_activity_secondary_avatar} for description.
1126
  */
1127
  function bp_activity_secondary_avatar( $args = '' ) {
1128
  echo bp_get_activity_secondary_avatar( $args );
1129
  }
1130
 
1131
  /**
1132
+ * Return the avatar of the object that action was performed on.
1133
  *
1134
+ * @since 1.2.0
1135
  *
1136
  * @see bp_core_fetch_avatar() for description of arguments.
1137
  * @global object $activities_template {@link BP_Activity_Template}
1138
+ *
1139
+ * @param array|string $args {
 
 
 
 
 
 
1140
  * For a complete description of arguments, see {@link bp_core_fetch_avatar()}.
1141
+ * @type string $alt Default value varies based on current activity
1142
+ * item component.
1143
+ * @type string $type Default: 'full' when viewing a single activity
1144
+ * permalink page, otherwise 'thumb'.
1145
+ * @type string $class Default: 'avatar'.
1146
+ * @type string|bool $email Default: email of the activity's user.
1147
+ * @type int|bool $user_id Default: ID of the activity's user.
1148
  * }
1149
+ * @return string The secondary avatar.
1150
  */
1151
  function bp_get_activity_secondary_avatar( $args = '' ) {
1152
  global $activities_template;
1163
  ) );
1164
  extract( $r, EXTR_SKIP );
1165
 
1166
+ // Set item_id and object (default to user).
1167
  switch ( $activities_template->activity->component ) {
1168
  case 'groups' :
1169
+ if ( bp_disable_group_avatar_uploads() ) {
1170
+ return false;
1171
+ }
1172
+
1173
  $object = 'group';
1174
  $item_id = $activities_template->activity->item_id;
1175
  $link = '';
1176
  $name = '';
1177
 
1178
+ // Only if groups is active.
1179
  if ( bp_is_active( 'groups' ) ) {
1180
+ $group = groups_get_group( $item_id );
 
 
 
 
1181
  $link = bp_get_group_permalink( $group );
1182
  $name = $group->name;
1183
  }
1224
  break;
1225
  }
1226
 
1227
+ /**
1228
+ * Filters the activity secondary avatar object based on current activity item component.
1229
+ *
1230
+ * This is a variable filter dependent on the component used. Possible hooks are
1231
+ * bp_get_activity_secondary_avatar_object_blog, bp_get_activity_secondary_avatar_object_group,
1232
+ * and bp_get_activity_secondary_avatar_object_user.
1233
+ *
1234
+ * @since 1.2.10
1235
+ *
1236
+ * @param string $object Component being displayed.
1237
+ */
1238
  $object = apply_filters( 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component, $object );
1239
+
1240
+ /**
1241
+ * Filters the activity secondary avatar item ID.
1242
+ *
1243
+ * @since 1.2.10
1244
+ *
1245
+ * @param int $item_id ID for the secondary avatar item.
1246
+ */
1247
  $item_id = apply_filters( 'bp_get_activity_secondary_avatar_item_id', $item_id );
1248
 
1249
+ // If we have no item_id or object, there is no avatar to display.
1250
  if ( empty( $item_id ) || empty( $object ) ) {
1251
  return false;
1252
  }
1253
 
1254
+ // Get the avatar.
1255
  $avatar = bp_core_fetch_avatar( array(
1256
  'item_id' => $item_id,
1257
  'object' => $object,
1264
  ) );
1265
 
1266
  if ( !empty( $linked ) ) {
1267
+
1268
+ /**
1269
+ * Filters the secondary avatar link for current activity.
1270
+ *
1271
+ * @since 1.7.0
1272
+ *
1273
+ * @param string $link Link to wrap the avatar image in.
1274
+ * @param string $component Activity component being acted on.
1275
+ */
1276
  $link = apply_filters( 'bp_get_activity_secondary_avatar_link', $link, $activities_template->activity->component );
1277
 
1278
+ /**
1279
+ * Filters the determined avatar for the secondary activity item.
1280
+ *
1281
+ * @since 1.2.10
1282
+ *
1283
+ * @param string $avatar Formatted HTML <img> element, or raw avatar URL.
1284
+ */
1285
+ $avatar = apply_filters( 'bp_get_activity_secondary_avatar', $avatar );
1286
+
1287
  return sprintf( '<a href="%s" class="%s">%s</a>',
1288
  $link,
1289
  $link_class,
1290
+ $avatar
1291
  );
1292
  }
1293
 
1294
+ /** This filter is documented in bp-activity/bp-activity-template.php */
1295
  return apply_filters( 'bp_get_activity_secondary_avatar', $avatar );
1296
  }
1297
 
1298
  /**
1299
+ * Output the activity action.
1300
  *
1301
+ * @since 1.2.0
1302
  *
1303
+ * @param array $args See bp_get_activity_action().
 
1304
  */
1305
  function bp_activity_action( $args = array() ) {
1306
  echo bp_get_activity_action( $args );
1307
  }
1308
 
1309
  /**
1310
+ * Return the activity action.
1311
  *
1312
+ * @since 1.2.0
1313
  *
1314
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
1315
  *
1316
  * @param array $args {
1317
  * @type bool $no_timestamp Whether to exclude the timestamp.
1318
  * }
1319
+ *
1320
  * @return string The activity action.
1321
  */
1322
  function bp_get_activity_action( $args = array() ) {
1323
  global $activities_template;
1324
 
1325
+ $r = wp_parse_args( $args, array(
1326
  'no_timestamp' => false,
1327
+ ) );
 
 
 
1328
 
1329
+ /**
1330
+ * Filters the activity action before the action is inserted as meta.
1331
+ *
1332
+ * @since 1.2.10
1333
+ *
1334
+ * @param array $value Array containing the current action, the current activity, and the $args array passed into the function.
1335
+ */
1336
+ $action = apply_filters_ref_array( 'bp_get_activity_action_pre_meta', array(
1337
+ $activities_template->activity->action,
1338
+ &$activities_template->activity,
1339
+ $r
1340
+ ) );
1341
 
1342
+ // Prepend the activity action meta (link, time since, etc...).
1343
+ if ( ! empty( $action ) && empty( $r['no_timestamp'] ) ) {
1344
  $action = bp_insert_activity_meta( $action );
1345
+ }
1346
 
1347
+ /**
1348
+ * Filters the activity action after the action has been inserted as meta.
1349
+ *
1350
+ * @since 1.2.0
1351
+ *
1352
+ * @param array $value Array containing the current action, the current activity, and the $args array passed into the function.
1353
+ */
1354
+ return apply_filters_ref_array( 'bp_get_activity_action', array(
1355
+ $action,
1356
+ &$activities_template->activity,
1357
+ $r
1358
+ ) );
1359
  }
1360
 
1361
  /**
1362
+ * Output the activity content body.
1363
  *
1364
+ * @since 1.2.0
1365
  *
 
1366
  */
1367
  function bp_activity_content_body() {
1368
  echo bp_get_activity_content_body();
1369
  }
1370
 
1371
  /**
1372
+ * Return the activity content body.
1373
  *
1374
+ * @since 1.2.0
1375
  *
1376
  * @global object $activities_template {@link BP_Activity_Template}
 
 
1377
  *
1378
  * @return string The activity content body.
1379
  */
1380
  function bp_get_activity_content_body() {
1381
  global $activities_template;
1382
 
1383
+ // Backwards compatibility if action is not being used.
1384
+ if ( empty( $activities_template->activity->action ) && ! empty( $activities_template->activity->content ) ) {
1385
  $activities_template->activity->content = bp_insert_activity_meta( $activities_template->activity->content );
1386
+ }
1387
 
1388
+ /**
1389
+ * Filters the activity content body.
1390
+ *
1391
+ * @since 1.2.0
1392
+ *
1393
+ * @param array $value Array containing the current activity content body and the current activity.
1394
+ */
1395
  return apply_filters_ref_array( 'bp_get_activity_content_body', array( $activities_template->activity->content, &$activities_template->activity ) );
1396
  }
1397
 
1398
  /**
1399
  * Does the activity have content?
1400
  *
1401
+ * @since 1.2.0
1402
  *
1403
  * @global object $activities_template {@link BP_Activity_Template}
1404
  *
1407
  function bp_activity_has_content() {
1408
  global $activities_template;
1409
 
1410
+ if ( ! empty( $activities_template->activity->content ) ) {
1411
  return true;
1412
+ }
1413
 
1414
  return false;
1415
  }
1417
  /**
1418
  * Output the activity content.
1419
  *
1420
+ * @since 1.0.0
1421
+ * @deprecated 1.5.0
1422
  *
1423
  * @todo properly deprecate this function.
1424
  *
 
1425
  */
1426
  function bp_activity_content() {
1427
  echo bp_get_activity_content();
1430
  /**
1431
  * Return the activity content.
1432
  *
1433
+ * @since 1.0.0
1434
+ * @deprecated 1.5.0
1435
  *
1436
  * @todo properly deprecate this function.
1437
  *
 
 
 
1438
  *
1439
  * @return string The activity content.
1440
  */
1441
  function bp_get_activity_content() {
1442
+
1443
  /**
1444
  * If you want to filter activity update content, please use
1445
+ * the filter 'bp_get_activity_content_body'.
1446
  *
1447
+ * This function is mainly for backwards compatibility.
1448
  */
 
1449
  $content = bp_get_activity_action() . ' ' . bp_get_activity_content_body();
1450
  return apply_filters( 'bp_get_activity_content', $content );
1451
  }
1456
  * This metadata includes the time since the item was posted (which will appear
1457
  * as a link to the item's permalink).
1458
  *
1459
+ * @since 1.2.0
1460
  *
1461
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
 
 
 
1462
  *
1463
  * @param string $content The activity content.
1464
  * @return string The activity content with the metadata string attached.
1465
  */
1466
+ function bp_insert_activity_meta( $content = '' ) {
1467
  global $activities_template;
1468
 
1469
+ // Strip any legacy time since placeholders from BP 1.0-1.1.
1470
+ $new_content = str_replace( '<span class="time-since">%s</span>', '', $content );
1471
+
1472
+ // Get the time since this activity was recorded.
1473
+ $date_recorded = bp_core_time_since( $activities_template->activity->date_recorded );
1474
 
1475
+ // Set up 'time-since' <span>.
1476
+ $time_since = sprintf(
1477
+ '<span class="time-since" data-livestamp="%1$s">%2$s</span>',
1478
+ bp_core_get_iso8601_date( $activities_template->activity->date_recorded ),
1479
+ $date_recorded
1480
+ );
1481
+
1482
+ /**
1483
+ * Filters the activity item time since markup.
1484
+ *
1485
+ * @since 1.2.0
1486
+ *
1487
+ * @param array $value Array containing the time since markup and the current activity component.
1488
+ */
1489
+ $time_since = apply_filters_ref_array( 'bp_activity_time_since', array(
1490
+ $time_since,
1491
+ &$activities_template->activity
1492
+ ) );
1493
+
1494
+ // Insert the permalink.
1495
+ if ( ! bp_is_single_activity() ) {
1496
+
1497
+ // Setup variables for activity meta.
1498
+ $activity_permalink = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity );
1499
+ $activity_meta = sprintf( '%1$s <a href="%2$s" class="view activity-time-since" title="%3$s">%4$s</a>',
1500
+ $new_content,
1501
+ $activity_permalink,
1502
+ esc_attr__( 'View Discussion', 'buddypress' ),
1503
+ $time_since
1504
+ );
1505
 
1506
+ /**
1507
+ * Filters the activity permalink to be added to the activity content.
1508
+ *
1509
+ * @since 1.2.0
1510
+ *
1511
+ * @param array $value Array containing the html markup for the activity permalink, after being parsed by
1512
+ * sprintf and current activity component.
1513
+ */
1514
+ $new_content = apply_filters_ref_array( 'bp_activity_permalink', array(
1515
+ $activity_meta,
1516
+ &$activities_template->activity
1517
+ ) );
1518
+ } else {
1519
+ $new_content .= str_pad( $time_since, strlen( $time_since ) + 2, ' ', STR_PAD_BOTH );
1520
+ }
1521
 
1522
+ /**
1523
+ * Filters the activity content after activity metadata has been attached.
1524
+ *
1525
+ * @since 1.2.0
1526
+ *
1527
+ * @param string $content Activity content with the activity metadata added.
1528
+ */
1529
+ return apply_filters( 'bp_insert_activity_meta', $new_content, $content );
1530
  }
1531
 
1532
  /**
1533
  * Determine if the current user can delete an activity item.
1534
  *
1535
+ * @since 1.2.0
1536
  *
1537
  * @global object $activities_template {@link BP_Activity_Template}
 
1538
  *
1539
+ * @param BP_Activity_Activity $activity Optional. Falls back on the current item in the loop.
1540
  * @return bool True if can delete, false otherwise.
1541
  */
1542
  function bp_activity_user_can_delete( $activity = false ) {
1543
  global $activities_template;
1544
 
1545
+ // Try to use current activity if none was passed.
1546
+ if ( empty( $activity ) && ! empty( $activities_template->activity ) ) {
1547
  $activity = $activities_template->activity;
1548
+ }
1549
 
1550
+ // If current_comment is set, we'll use that in place of the main activity.
1551
+ if ( isset( $activity->current_comment ) ) {
1552
  $activity = $activity->current_comment;
1553
+ }
1554
 
1555
+ // Assume the user cannot delete the activity item.
1556
  $can_delete = false;
1557
 
1558
+ // Only logged in users can delete activity.
1559
+ if ( is_user_logged_in() ) {
1560
+
1561
+ // Community moderators can always delete activity (at least for now).
1562
+ if ( bp_current_user_can( 'bp_moderate' ) ) {
1563
+ $can_delete = true;
1564
+ }
1565
 
1566
+ // Users are allowed to delete their own activity. This is actually
1567
+ // quite powerful, because doing so also deletes all comments to that
1568
+ // activity item. We should revisit this eventually.
1569
+ if ( isset( $activity->user_id ) && ( $activity->user_id === bp_loggedin_user_id() ) ) {
1570
+ $can_delete = true;
1571
+ }
1572
 
1573
+ // Viewing a single item, and this user is an admin of that item.
1574
+ if ( bp_is_single_item() && bp_is_item_admin() ) {
1575
+ $can_delete = true;
1576
+ }
1577
+ }
1578
 
1579
+ /**
1580
+ * Filters whether the current user can delete an activity item.
1581
+ *
1582
+ * @since 1.5.0
1583
+ *
1584
+ * @param bool $can_delete Whether the user can delete the item.
1585
+ * @param object $activity Current activity item object.
1586
+ */
1587
+ return (bool) apply_filters( 'bp_activity_user_can_delete', $can_delete, $activity );
1588
  }
1589
 
1590
  /**
1591
  * Output the activity parent content.
1592
  *
1593
+ * @since 1.2.0
1594
  *
1595
  * @see bp_get_activity_parent_content() for a description of arguments.
 
1596
  *
1597
+ * @param array|string $args See {@link bp_get_activity_parent_content} for description.
1598
  */
1599
  function bp_activity_parent_content( $args = '' ) {
1600
  echo bp_get_activity_parent_content($args);
1603
  /**
1604
  * Return the activity content.
1605
  *
1606
+ * @since 1.2.0
1607
  *
1608
  * @global object $activities_template {@link BP_Activity_Template}
 
 
1609
  *
1610
+ * @param string $args Unused. Left over from an earlier implementation.
1611
+ * @return mixed False on failure, otherwise the activity parent content.
 
 
 
1612
  */
1613
  function bp_get_activity_parent_content( $args = '' ) {
1614
  global $activities_template;
1615
 
1616
+ // Bail if no activity on no item ID.
1617
+ if ( empty( $activities_template->activity ) || empty( $activities_template->activity->item_id ) ) {
 
 
 
 
 
 
 
1618
  return false;
1619
+ }
1620
+
1621
+ // Get the ID of the parent activity content.
1622
+ $parent_id = $activities_template->activity->item_id;
1623
 
1624
+ // Bail if no parent content.
1625
+ if ( empty( $activities_template->activity_parents[ $parent_id ] ) ) {
1626
  return false;
1627
+ }
1628
 
1629
+ // Bail if no action.
1630
+ if ( empty( $activities_template->activity_parents[ $parent_id ]->action ) ) {
1631
  return false;
1632
+ }
1633
 
1634
+ // Content always includes action.
1635
+ $content = $activities_template->activity_parents[ $parent_id ]->action;
1636
 
1637
+ // Maybe append activity content, if it exists.
1638
+ if ( ! empty( $activities_template->activity_parents[ $parent_id ]->content ) ) {
1639
+ $content .= ' ' . $activities_template->activity_parents[ $parent_id ]->content;
1640
+ }
1641
 
1642
+ // Remove the time since content for backwards compatibility.
1643
  $content = str_replace( '<span class="time-since">%s</span>', '', $content );
1644
 
1645
+ // Remove images.
1646
  $content = preg_replace( '/<img[^>]*>/Ui', '', $content );
1647
 
1648
+ /**
1649
+ * Filters the activity parent content.
1650
+ *
1651
+ * @since 1.2.0
1652
+ *
1653
+ * @param string $content Content set to be displayed as parent content.
1654
+ */
1655
  return apply_filters( 'bp_get_activity_parent_content', $content );
1656
  }
1657
 
1658
  /**
1659
  * Output the parent activity's user ID.
1660
  *
1661
+ * @since 1.7.0
1662
  */
1663
  function bp_activity_parent_user_id() {
1664
  echo bp_get_activity_parent_user_id();
1667
  /**
1668
  * Return the parent activity's user ID.
1669
  *
1670
+ * @since 1.7.0
1671
  *
1672
  * @global BP_Activity_Template $activities_template
1673
  *
1674
  * @return bool|int False if parent activity can't be found, otherwise
1675
+ * the parent activity's user ID.
1676
  */
1677
  function bp_get_activity_parent_user_id() {
1678
  global $activities_template;
1679
 
1680
+ // Bail if no activity on no item ID.
1681
+ if ( empty( $activities_template->activity ) || empty( $activities_template->activity->item_id ) ) {
1682
  return false;
1683
+ }
1684
 
1685
+ // Get the ID of the parent activity content.
1686
+ $parent_id = $activities_template->activity->item_id;
 
1687
 
1688
+ // Bail if no parent item.
1689
+ if ( empty( $activities_template->activity_parents[ $parent_id ] ) ) {
1690
  return false;
1691
+ }
1692
 
1693
+ // Bail if no parent user ID.
1694
+ if ( empty( $activities_template->activity_parents[ $parent_id ]->user_id ) ) {
1695
  return false;
1696
+ }
1697
 
1698
+ $retval = $activities_template->activity_parents[ $parent_id ]->user_id;
1699
 
1700
+ /**
1701
+ * Filters the activity parent item's user ID.
1702
+ *
1703
+ * @since 1.7.0
1704
+ *
1705
+ * @param int $retval ID for the activity parent's user.
1706
+ */
1707
  return (int) apply_filters( 'bp_get_activity_parent_user_id', $retval );
1708
  }
1709
 
1710
  /**
1711
  * Output whether or not the current activity is in a current user's favorites.
1712
  *
1713
+ * @since 1.2.0
1714
  *
 
1715
  */
1716
  function bp_activity_is_favorite() {
1717
  echo bp_get_activity_is_favorite();
1720
  /**
1721
  * Return whether the current activity is in a current user's favorites.
1722
  *
1723
+ * @since 1.2.0
1724
  *
1725
  * @global object $activities_template {@link BP_Activity_Template}
 
1726
  *
1727
  * @return bool True if user favorite, false otherwise.
1728
  */
1729
  function bp_get_activity_is_favorite() {
1730
  global $activities_template;
1731
 
1732
+ /**
1733
+ * Filters whether the current activity item is in the current user's favorites.
1734
+ *
1735
+ * @since 1.2.0
1736
+ *
1737
+ * @param bool $value Whether or not the current activity item is in the current user's favorites.
1738
+ */
1739
+ return (bool) apply_filters( 'bp_get_activity_is_favorite', in_array( $activities_template->activity->id, (array) $activities_template->my_favs ) );
1740
  }
1741
 
1742
  /**
1743
  * Output the comment markup for an activity item.
1744
  *
1745
+ * @since 1.2.0
1746
  *
1747
  * @todo deprecate $args param
1748
  *
1749
+ * @param array|string $args See {@link bp_activity_get_comments} for description.
1750
  */
1751
  function bp_activity_comments( $args = '' ) {
1752
  echo bp_activity_get_comments( $args );
1755
  /**
1756
  * Get the comment markup for an activity item.
1757
  *
1758
+ * @since 1.2.0
1759
  *
1760
  * @todo deprecate $args param
 
1761
  * @todo Given that checks for children already happen in bp_activity_recurse_comments(),
1762
+ * this function can probably be streamlined or removed.
 
 
1763
  *
1764
  * @global object $activities_template {@link BP_Activity_Template}
1765
+ *
1766
+ * @param string $args Unused. Left over from an earlier implementation.
1767
+ * @return bool
1768
  */
1769
  function bp_activity_get_comments( $args = '' ) {
1770
  global $activities_template;
1771
 
1772
+ if ( empty( $activities_template->activity->children ) ) {
1773
  return false;
1774
+ }
1775
 
1776
  bp_activity_recurse_comments( $activities_template->activity );
1777
  }
1778
 
1779
  /**
1780
+ * Loops through a level of activity comments and loads the template for each.
1781
  *
1782
  * Note: The recursion itself used to happen entirely in this function. Now it is
1783
  * split between here and the comment.php template.
1784
  *
1785
+ * @since 1.2.0
 
 
1786
  *
1787
  * @global object $activities_template {@link BP_Activity_Template}
1788
+ *
1789
+ * @param object $comment The activity object currently being recursed.
1790
+ * @return bool|string
1791
  */
1792
  function bp_activity_recurse_comments( $comment ) {
1793
  global $activities_template;
1794
 
1795
+ if ( empty( $comment ) ) {
1796
  return false;
1797
+ }
1798
 
1799
+ if ( empty( $comment->children ) ) {
1800
  return false;
1801
+ }
1802
 
1803
+ /**
1804
+ * Filters the opening tag for the template that lists activity comments.
1805
+ *
1806
+ * @since 1.6.0
1807
+ *
1808
+ * @param string $value Opening tag for the HTML markup to use.
1809
+ */
1810
+ echo apply_filters( 'bp_activity_recurse_comments_start_ul', '<ul>' );
1811
  foreach ( (array) $comment->children as $comment_child ) {
1812
+
1813
+ // Put the comment into the global so it's available to filters.
1814
  $activities_template->activity->current_comment = $comment_child;
1815
 
1816
  $template = bp_locate_template( 'activity/comment.php', false, false );
1827
 
1828
  unset( $activities_template->activity->current_comment );
1829
  }
1830
+
1831
+ /**
1832
+ * Filters the closing tag for the template that list activity comments.
1833
+ *
1834
+ * @since 1.6.0
1835
+ *
1836
+ * @param string $value Closing tag for the HTML markup to use.
1837
+ */
1838
+ echo apply_filters( 'bp_activity_recurse_comments_end_ul', '</ul>' );
1839
  }
1840
 
1841
  /**
1842
  * Utility function that returns the comment currently being recursed.
1843
  *
1844
+ * @since 1.5.0
1845
  *
1846
  * @global object $activities_template {@link BP_Activity_Template}
 
1847
  *
1848
  * @return object|bool $current_comment The activity comment currently being
1849
+ * displayed. False on failure.
1850
  */
1851
  function bp_activity_current_comment() {
1852
  global $activities_template;
1853
 
1854
+ $current_comment = !empty( $activities_template->activity->current_comment )
1855
+ ? $activities_template->activity->current_comment
1856
+ : false;
1857
 
1858
+ /**
1859
+ * Filters the current comment being recursed.
1860
+ *
1861
+ * @since 1.5.0
1862
+ *
1863
+ * @param object|bool $current_comment The activity comment currently being displayed. False on failure.
1864
+ */
1865
  return apply_filters( 'bp_activity_current_comment', $current_comment );
1866
  }
1867
 
1869
  /**
1870
  * Output the ID of the activity comment currently being displayed.
1871
  *
1872
+ * @since 1.5.0
1873
  *
 
1874
  */
1875
  function bp_activity_comment_id() {
1876
  echo bp_get_activity_comment_id();
1879
  /**
1880
  * Return the ID of the activity comment currently being displayed.
1881
  *
1882
+ * @since 1.5.0
1883
  *
1884
  * @global object $activities_template {@link BP_Activity_Template}
 
1885
  *
1886
+ * @return int|bool $comment_id The ID of the activity comment currently
1887
+ * being displayed, false if none is found.
1888
  */
1889
  function bp_get_activity_comment_id() {
1890
  global $activities_template;
1891
 
1892
  $comment_id = isset( $activities_template->activity->current_comment->id ) ? $activities_template->activity->current_comment->id : false;
1893
 
1894
+ /**
1895
+ * Filters the ID of the activity comment currently being displayed.
1896
+ *
1897
+ * @since 1.5.0
1898
+ *
1899
+ * @param int|bool $comment_id ID for the comment currently being displayed.
1900
+ */
1901
  return apply_filters( 'bp_activity_comment_id', $comment_id );
1902
  }
1903
 
1904
  /**
1905
  * Output the ID of the author of the activity comment currently being displayed.
1906
  *
1907
+ * @since 1.5.0
1908
  *
 
1909
  */
1910
  function bp_activity_comment_user_id() {
1911
  echo bp_get_activity_comment_user_id();
1914
  /**
1915
  * Return the ID of the author of the activity comment currently being displayed.
1916
  *
1917
+ * @since 1.5.0
1918
  *
1919
  * @global object $activities_template {@link BP_Activity_Template}
 
1920
  *
1921
  * @return int|bool $user_id The user_id of the author of the displayed
1922
+ * activity comment. False on failure.
1923
  */
1924
  function bp_get_activity_comment_user_id() {
1925
  global $activities_template;
1926
 
1927
  $user_id = isset( $activities_template->activity->current_comment->user_id ) ? $activities_template->activity->current_comment->user_id : false;
1928
 
1929
+ /**
1930
+ * Filters the ID of the author of the activity comment currently being displayed.
1931
+ *
1932
+ * @since 1.5.0
1933
+ *
1934
+ * @param int|bool $user_id ID for the author of the comment currently being displayed.
1935
+ */
1936
  return apply_filters( 'bp_activity_comment_user_id', $user_id );
1937
  }
1938
 
1939
  /**
1940
  * Output the author link for the activity comment currently being displayed.
1941
  *
1942
+ * @since 1.5.0
1943
  *
 
1944
  */
1945
  function bp_activity_comment_user_link() {
1946
  echo bp_get_activity_comment_user_link();
1949
  /**
1950
  * Return the author link for the activity comment currently being displayed.
1951
  *
1952
+ * @since 1.5.0
1953
  *
 
 
 
1954
  *
1955
  * @return string $user_link The URL of the activity comment author's profile.
1956
  */
1957
  function bp_get_activity_comment_user_link() {
1958
  $user_link = bp_core_get_user_domain( bp_get_activity_comment_user_id() );
1959
 
1960
+ /**
1961
+ * Filters the author link for the activity comment currently being displayed.
1962
+ *
1963
+ * @since 1.5.0
1964
+ *
1965
+ * @param string $user_link Link for the author of the activity comment currently being displayed.
1966
+ */
1967
  return apply_filters( 'bp_activity_comment_user_link', $user_link );
1968
  }
1969
 
1970
  /**
1971
  * Output the author name for the activity comment currently being displayed.
1972
  *
1973
+ * @since 1.5.0
1974
  *
 
1975
  */
1976
  function bp_activity_comment_name() {
1977
  echo bp_get_activity_comment_name();
1983
  * The use of the 'bp_acomment_name' filter is deprecated. Please use
1984
  * 'bp_activity_comment_name'.
1985
  *
1986
+ * @since 1.5.0
1987
  *
1988
  * @global object $activities_template {@link BP_Activity_Template}
 
 
1989
  *
1990
  * @return string $name The full name of the activity comment author.
1991
  */
1992
  function bp_get_activity_comment_name() {
1993
  global $activities_template;
1994
 
1995
+ if ( isset( $activities_template->activity->current_comment->user_fullname ) ) {
1996
+
1997
+ $name = apply_filters( 'bp_acomment_name', $activities_template->activity->current_comment->user_fullname, $activities_template->activity->current_comment ); // Backward compatibility.
1998
+ } else {
1999
  $name = $activities_template->activity->current_comment->display_name;
2000
+ }
2001
 
2002
+ /**
2003
+ * Filters the name of the author for the activity comment.
2004
+ *
2005
+ * @since 1.5.0
2006
+ *
2007
+ * @param string $name Name to be displayed with the activity comment.
2008
+ */
2009
  return apply_filters( 'bp_activity_comment_name', $name );
2010
  }
2011
 
2012
  /**
2013
+ * Output the formatted date_recorded of the activity comment currently being displayed.
2014
  *
2015
+ * @since 1.5.0
2016
  *
 
2017
  */
2018
  function bp_activity_comment_date_recorded() {
2019
  echo bp_get_activity_comment_date_recorded();
2020
  }
2021
 
2022
  /**
2023
+ * Return the formatted date_recorded for the activity comment currently being displayed.
2024
  *
2025
+ * @since 1.5.0
2026
  *
 
 
 
2027
  *
2028
  * @return string|bool $date_recorded Time since the activity was recorded,
2029
+ * in the form "%s ago". False on failure.
2030
  */
2031
  function bp_get_activity_comment_date_recorded() {
 
2032
 
2033
+ /**
2034
+ * Filters the recorded date of the activity comment currently being displayed.
2035
+ *
2036
+ * @since 1.5.0
2037
+ *
2038
+ * @param string|bool Date for the activity comment currently being displayed.
2039
+ */
2040
+ return apply_filters( 'bp_activity_comment_date_recorded', bp_core_time_since( bp_get_activity_comment_date_recorded_raw() ) );
2041
+ }
2042
+
2043
+ /**
2044
+ * Output the date_recorded of the activity comment currently being displayed.
2045
+ *
2046
+ * @since 2.3.0
2047
+ *
2048
+ */
2049
+ function bp_activity_comment_date_recorded_raw() {
2050
+ echo bp_get_activity_comment_date_recorded_raw();
2051
+ }
2052
 
2053
+ /**
2054
+ * Return the date_recorded for the activity comment currently being displayed.
2055
+ *
2056
+ * @since 2.3.0
2057
+ *
2058
+ * @global object $activities_template {@link BP_Activity_Template}
2059
+ *
2060
+ * @return string|bool $date_recorded Time since the activity was recorded,
2061
+ * in the form "%s ago". False on failure.
2062
+ */
2063
+ function bp_get_activity_comment_date_recorded_raw() {
2064
+ global $activities_template;
2065
 
2066
+ /**
2067
+ * Filters the raw recorded date of the activity comment currently being displayed.
2068
+ *
2069
+ * @since 2.3.0
2070
+ *
2071
+ * @param string|bool Raw date for the activity comment currently being displayed.
2072
+ */
2073
+ return apply_filters( 'bp_activity_comment_date_recorded', $activities_template->activity->current_comment->date_recorded );
2074
  }
2075
 
2076
  /**
2077
  * Output the 'delete' URL for the activity comment currently being displayed.
2078
  *
2079
+ * @since 1.5.0
2080
  *
 
2081
  */
2082
  function bp_activity_comment_delete_link() {
2083
  echo bp_get_activity_comment_delete_link();
2084
  }
2085
 
2086
  /**
2087
+ * Gets the 'delete' URL for the activity comment currently being displayed.
2088
  *
2089
+ * @since 1.5.0
2090
  *
 
 
 
 
 
2091
  *
2092
  * @return string $link The nonced URL for deleting the current
2093
+ * activity comment.
2094
  */
2095
  function bp_get_activity_comment_delete_link() {
2096
+ $link = wp_nonce_url( bp_get_activity_directory_permalink() . 'delete/' . bp_get_activity_comment_id() . '?cid=' . bp_get_activity_comment_id(), 'bp_activity_delete_link' );
2097
 
2098
+ /**
2099
+ * Filters the link used for deleting the activity comment currently being displayed.
2100
+ *
2101
+ * @since 1.5.0
2102
+ *
2103
+ * @param string $link Link to use for deleting the currently displayed activity comment.
2104
+ */
2105
  return apply_filters( 'bp_activity_comment_delete_link', $link );
2106
  }
2107
 
2108
  /**
2109
  * Output the content of the activity comment currently being displayed.
2110
  *
2111
+ * @since 1.5.0
2112
  *
 
2113
  */
2114
  function bp_activity_comment_content() {
2115
  echo bp_get_activity_comment_content();
2123
  * 'bp_activity_comment_content' to modify the content of activity
2124
  * comments only.
2125
  *
2126
+ * @since 1.5.0
2127
  *
2128
  * @global object $activities_template {@link BP_Activity_Template}
 
 
2129
  *
2130
  * @return string $content The content of the current activity comment.
2131
  */
2132
  function bp_get_activity_comment_content() {
2133
  global $activities_template;
2134
 
2135
+ /** This filter is documented in bp-activity/bp-activity-template.php */
2136
  $content = apply_filters( 'bp_get_activity_content', $activities_template->activity->current_comment->content );
2137
 
2138
+ /**
2139
+ * Filters the content of the current activity comment.
2140
+ *
2141
+ * @since 1.2.0
2142
+ *
2143
+ * @param string $content The content of the current activity comment.
2144
+ */
2145
  return apply_filters( 'bp_activity_comment_content', $content );
2146
  }
2147
 
2148
  /**
2149
  * Output the activity comment count.
2150
  *
2151
+ * @since 1.2.0
2152
  *
 
2153
  */
2154
  function bp_activity_comment_count() {
2155
  echo bp_activity_get_comment_count();
2156
  }
2157
 
2158
  /**
2159
+ * Return the comment count of an activity item.
 
 
 
 
 
2160
  *
2161
+ * @since 1.2.0
2162
  *
2163
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
2164
  *
2165
+ * @param array|null $deprecated Deprecated.
2166
  * @return int $count The activity comment count.
2167
  */
2168
+ function bp_activity_get_comment_count( $deprecated = null ) {
2169
  global $activities_template;
2170
 
2171
+ // Deprecated notice about $args.
2172
+ if ( ! empty( $deprecated ) ) {
2173
+ _deprecated_argument( __FUNCTION__, '1.2', sprintf( __( '%1$s no longer accepts arguments. See the inline documentation at %2$s for more details.', 'buddypress' ), __FUNCTION__, __FILE__ ) );
2174
+ }
2175
 
2176
+ // Get the count using the purpose-built recursive function.
2177
+ $count = ! empty( $activities_template->activity->children )
2178
+ ? bp_activity_recurse_comment_count( $activities_template->activity )
2179
+ : 0;
2180
 
2181
+ /**
2182
+ * Filters the activity comment count.
2183
+ *
2184
+ * @since 1.2.0
2185
+ *
2186
+ * @param int $count The activity comment count.
2187
+ */
2188
  return apply_filters( 'bp_activity_get_comment_count', (int) $count );
2189
  }
2190
 
2191
  /**
2192
+ * Return the total number of comments to the current comment.
2193
  *
2194
+ * This function recursively adds the total number of comments each
2195
+ * activity child has, and returns them.
 
 
2196
  *
2197
+ * @since 1.2.0
2198
  *
 
 
 
2199
  *
2200
  * @param object $comment Activity comment object.
2201
+ * @param int $count The current iteration count.
2202
  * @return int $count The activity comment count.
2203
  */
2204
  function bp_activity_recurse_comment_count( $comment, $count = 0 ) {
2205
 
2206
+ // Copy the count.
2207
+ $new_count = $count;
2208
 
2209
+ // Loop through children and recursively count comments.
2210
+ if ( ! empty( $comment->children ) ) {
2211
+ foreach ( (array) $comment->children as $comment ) {
2212
+ $new_count++;
2213
+ $new_count = bp_activity_recurse_comment_count( $comment, $new_count );
2214
+ }
2215
  }
2216
 
2217
+ /**
2218
+ * Filters the total number of comments for the current comment.
2219
+ *
2220
+ * @since 2.1.0
2221
+ *
2222
+ * @param int $new_count New total count for the current comment.
2223
+ * @param object $comment Activity comment object.
2224
+ * @param int $count Current iteration count for the current comment.
2225
+ */
2226
+ return apply_filters( 'bp_activity_recurse_comment_count', $new_count, $comment, $count );
2227
  }
2228
 
2229
  /**
2230
  * Output the depth of the current activity comment.
2231
  *
2232
+ * @since 2.0.0
2233
  */
2234
  function bp_activity_comment_depth() {
2235
  echo bp_activity_get_comment_depth();
2237
  /**
2238
  * Return the current activity comment depth.
2239
  *
2240
+ * @since 2.0.0
2241
  *
2242
+ * @return int $depth Depth for the current activity comment.
2243
  */
2244
  function bp_activity_get_comment_depth() {
2245
  global $activities_template;
2246
+
2247
+ /**
2248
+ * Filters the comment depth of the current activity comment.
2249
+ *
2250
+ * @since 2.0.0
2251
+ *
2252
+ * @param int $depth Depth for the current activity comment.
2253
+ */
2254
  return apply_filters( 'bp_activity_get_comment_depth', $activities_template->activity->current_comment->depth );
2255
  }
2256
 
2257
  /**
2258
  * Output the activity comment link.
2259
  *
2260
+ * @since 1.2.0
2261
  *
 
2262
  */
2263
  function bp_activity_comment_link() {
2264
  echo bp_get_activity_comment_link();
2267
  /**
2268
  * Return the activity comment link.
2269
  *
2270
+ * @since 1.2.0
2271
  *
2272
  * @global object $activities_template {@link BP_Activity_Template}
 
2273
  *
2274
  * @return string The activity comment link.
2275
  */
2276
  function bp_get_activity_comment_link() {
2277
  global $activities_template;
2278
+
2279
+ /**
2280
+ * Filters the comment link for the current activity comment.
2281
+ *
2282
+ * @since 1.2.0
2283
+ *
2284
+ * @param string $value Constructed URL parameters with activity IDs.
2285
+ */
2286
  return apply_filters( 'bp_get_activity_comment_link', '?ac=' . $activities_template->activity->id . '/#ac-form-' . $activities_template->activity->id );
2287
  }
2288
 
2289
  /**
2290
+ * Output the activity comment form no JavaScript display CSS.
2291
  *
2292
+ * @since 1.2.0
2293
  *
 
2294
  */
2295
  function bp_activity_comment_form_nojs_display() {
2296
  echo bp_get_activity_comment_form_nojs_display();
2297
  }
2298
 
2299
  /**
2300
+ * Return the activity comment form no JavaScript display CSS.
2301
  *
2302
+ * @since 1.2.0
2303
  *
2304
  * @global object $activities_template {@link BP_Activity_Template}
2305
  *
2306
+ * @return string|bool The activity comment form no JavaScript
2307
+ * display CSS. False on failure.
2308
  */
2309
  function bp_get_activity_comment_form_nojs_display() {
2310
  global $activities_template;
2311
+
2312
+ if ( isset( $_GET['ac'] ) && ( $_GET['ac'] === ( $activities_template->activity->id . '/' ) ) ) {
2313
  return 'style="display: block"';
2314
+ }
2315
 
2316
  return false;
2317
  }
2319
  /**
2320
  * Output the activity comment form action.
2321
  *
2322
+ * @since 1.2.0
2323
  *
 
2324
  */
2325
  function bp_activity_comment_form_action() {
2326
  echo bp_get_activity_comment_form_action();
2329
  /**
2330
  * Return the activity comment form action.
2331
  *
2332
+ * @since 1.2.0
2333
  *
 
 
 
2334
  *
2335
  * @return string The activity comment form action.
2336
  */
2337
  function bp_get_activity_comment_form_action() {
2338
+
2339
+ /**
2340
+ * Filters the activity comment form action URL.
2341
+ *
2342
+ * @since 1.2.0
2343
+ *
2344
+ * @param string $value URL to use in the comment form's action attribute.
2345
+ */
2346
  return apply_filters( 'bp_get_activity_comment_form_action', home_url( bp_get_activity_root_slug() . '/reply/' ) );
2347
  }
2348
 
2349
  /**
2350
  * Output the activity permalink ID.
2351
  *
2352
+ * @since 1.2.0
2353
  *
 
2354
  */
2355
  function bp_activity_permalink_id() {
2356
  echo bp_get_activity_permalink_id();
2359
  /**
2360
  * Return the activity permalink ID.
2361
  *
2362
+ * @since 1.2.0
2363
  *
 
2364
  *
2365
  * @return string The activity permalink ID.
2366
  */
2367
  function bp_get_activity_permalink_id() {
2368
+
2369
+ /**
2370
+ * Filters the activity action permalink ID.
2371
+ *
2372
+ * @since 1.2.0
2373
+ *
2374
+ * @param string $value Current action for the activity item.
2375
+ */
2376
  return apply_filters( 'bp_get_activity_permalink_id', bp_current_action() );
2377
  }
2378
 
2379
  /**
2380
  * Output the activity thread permalink.
2381
  *
2382
+ * @since 1.2.0
2383
  *
 
2384
  */
2385
  function bp_activity_thread_permalink() {
2386
+ echo esc_url( bp_get_activity_thread_permalink() );
2387
  }
2388
 
2389
  /**
2390
  * Return the activity thread permalink.
2391
  *
2392
+ * @since 1.2.0
2393
  *
 
 
2394
  *
2395
  * @return string $link The activity thread permalink.
2396
  */
2399
 
2400
  $link = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity );
2401
 
2402
+ /**
2403
+ * Filters the activity thread permalink.
2404
+ *
2405
+ * @since 1.2.0
2406
+ *
2407
+ * @param string $link The activity thread permalink.
2408
+ */
2409
+ return apply_filters( 'bp_get_activity_thread_permalink', $link );
2410
  }
2411
 
2412
  /**
2413
  * Output the activity comment permalink.
2414
  *
2415
+ * @since 1.8.0
2416
  *
 
2417
  */
2418
  function bp_activity_comment_permalink() {
2419
+ echo esc_url( bp_get_activity_comment_permalink() );
2420
  }
2421
  /**
2422
  * Return the activity comment permalink.
2423
  *
2424
+ * @since 1.8.0
 
 
 
2425
  *
2426
  * @return string $link The activity comment permalink.
2427
  */
2428
  function bp_get_activity_comment_permalink() {
2429
  global $activities_template;
2430
 
2431
+ $link = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity );
2432
+
2433
+ // Used for filter below.
2434
+ $comment_id = isset( $activities_template->activity->current_comment->id )
2435
+ ? $activities_template->activity->current_comment->id
2436
+ : 0;
2437
 
2438
+ /**
2439
+ * Filters the activity comment permalink.
2440
+ *
2441
+ * @since 1.8.0
2442
+ *
2443
+ * @param string $link Activity comment permalink.
2444
+ * @param int $comment_id ID for the current activity comment.
2445
+ */
2446
+ return apply_filters( 'bp_get_activity_comment_permalink', $link, $comment_id );
2447
  }
2448
 
2449
  /**
2450
  * Output the activity favorite link.
2451
  *
2452
+ * @since 1.2.0
2453
  *
 
2454
  */
2455
  function bp_activity_favorite_link() {
2456
  echo bp_get_activity_favorite_link();
2459
  /**
2460
  * Return the activity favorite link.
2461
  *
2462
+ * @since 1.2.0
2463
  *
2464
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
2465
  *
2466
  * @return string The activity favorite link.
2467
  */
2468
  function bp_get_activity_favorite_link() {
2469
  global $activities_template;
2470
+
2471
+ /**
2472
+ * Filters the activity favorite link.
2473
+ *
2474
+ * @since 1.2.0
2475
+ *
2476
+ * @param string $value Constructed link for favoriting the activity comment.
2477
+ */
2478
  return apply_filters( 'bp_get_activity_favorite_link', wp_nonce_url( home_url( bp_get_activity_root_slug() . '/favorite/' . $activities_template->activity->id . '/' ), 'mark_favorite' ) );
2479
  }
2480
 
2481
  /**
2482
  * Output the activity unfavorite link.
2483
  *
2484
+ * @since 1.2.0
2485
  *
 
2486
  */
2487
  function bp_activity_unfavorite_link() {
2488
  echo bp_get_activity_unfavorite_link();
2491
  /**
2492
  * Return the activity unfavorite link.
2493
  *
2494
+ * @since 1.2.0
2495
  *
2496
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
2497
  *
2498
  * @return string The activity unfavorite link.
2499
  */
2500
  function bp_get_activity_unfavorite_link() {
2501
  global $activities_template;
2502
+
2503
+ /**
2504
+ * Filters the activity unfavorite link.
2505
+ *
2506
+ * @since 1.2.0
2507
+ *
2508
+ * @param string $value Constructed link for unfavoriting the activity comment.
2509
+ */
2510
  return apply_filters( 'bp_get_activity_unfavorite_link', wp_nonce_url( home_url( bp_get_activity_root_slug() . '/unfavorite/' . $activities_template->activity->id . '/' ), 'unmark_favorite' ) );
2511
  }
2512
 
2513
  /**
2514
  * Output the activity CSS class.
2515
  *
2516
+ * @since 1.0.0
2517
  *
 
2518
  */
2519
  function bp_activity_css_class() {
2520
  echo bp_get_activity_css_class();
2523
  /**
2524
  * Return the current activity item's CSS class.
2525
  *
2526
+ * @since 1.0.0
2527
  *
2528
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
2529
  *
2530
  * @return string The activity item's CSS class.
2531
  */
2532
  function bp_get_activity_css_class() {
2533
  global $activities_template;
2534
 
2535
+ /**
2536
+ * Filters the available mini activity actions available as CSS classes.
2537
+ *
2538
+ * @since 1.2.0
2539
+ *
2540
+ * @param array $value Array of classes used to determine classes applied to HTML element.
2541
+ */
2542
  $mini_activity_actions = apply_filters( 'bp_activity_mini_activity_types', array(
2543
  'friendship_accepted',
2544
  'friendship_created',
2550
 
2551
  $class = ' activity-item';
2552
 
2553
+ if ( in_array( $activities_template->activity->type, (array) $mini_activity_actions ) || empty( $activities_template->activity->content ) ) {
2554
  $class .= ' mini';
2555
+ }
2556
 
2557
+ if ( bp_activity_get_comment_count() && bp_activity_can_comment() ) {
2558
  $class .= ' has-comments';
2559
+ }
2560
 
2561
+ /**
2562
+ * Filters the determined classes to add to the HTML element.
2563
+ *
2564
+ * @since 1.0.0
2565
+ *
2566
+ * @param string $value Classes to be added to the HTML element.
2567
+ */
2568
  return apply_filters( 'bp_get_activity_css_class', $activities_template->activity->component . ' ' . $activities_template->activity->type . $class );
2569
  }
2570
 
2571
  /**
2572
  * Output the activity delete link.
2573
  *
2574
+ * @since 1.1.0
2575
  *
 
2576
  */
2577
  function bp_activity_delete_link() {
2578
  echo bp_get_activity_delete_link();
2579
  }
2580
+
2581
+ /**
2582
+ * Return the activity delete link.
2583
+ *
2584
+ * @since 1.1.0
2585
+ *
2586
+ * @global object $activities_template {@link BP_Activity_Template}
2587
+ *
2588
+ * @return string $link Activity delete link. Contains $redirect_to arg
2589
+ * if on single activity page.
2590
+ */
2591
+ function bp_get_activity_delete_link() {
2592
+
2593
+ $url = bp_get_activity_delete_url();
2594
+ $class = 'delete-activity';
2595
+
2596
+ // Determine if we're on a single activity page, and customize accordingly.
2597
+ if ( bp_is_activity_component() && is_numeric( bp_current_action() ) ) {
2598
+ $class = 'delete-activity-single';
2599
+ }
2600
+
2601
+ $link = '<a href="' . esc_url( $url ) . '" class="button item-button bp-secondary-action ' . $class . ' confirm" rel="nofollow">' . __( 'Delete', 'buddypress' ) . '</a>';
2602
+
2603
+ /**
2604
+ * Filters the activity delete link.
2605
+ *
2606
+ * @since 1.1.0
2607
+ *
2608
+ * @param string $link Activity delete HTML link.
2609
+ */
2610
+ return apply_filters( 'bp_get_activity_delete_link', $link );
2611
+ }
2612
+
2613
+ /**
2614
+ * Output the URL to delete a single activity stream item.
2615
+ *
2616
+ * @since 2.1.0
2617
+ *
2618
+ */
2619
+ function bp_activity_delete_url() {
2620
+ echo esc_url( bp_get_activity_delete_url() );
2621
+ }
2622
  /**
2623
+ * Return the URL to delete a single activity item.
2624
  *
2625
+ * @since 2.1.0
2626
  *
2627
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
 
 
 
 
2628
  *
2629
  * @return string $link Activity delete link. Contains $redirect_to arg
2630
+ * if on single activity page.
2631
  */
2632
+ function bp_get_activity_delete_url() {
2633
  global $activities_template;
2634
 
2635
+ $url = trailingslashit( bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/delete/' . $activities_template->activity->id );
 
2636
 
2637
+ // Determine if we're on a single activity page, and customize accordingly.
2638
  if ( bp_is_activity_component() && is_numeric( bp_current_action() ) ) {
2639
+ $url = add_query_arg( array( 'redirect_to' => wp_get_referer() ), $url );
 
2640
  }
2641
 
2642
+ $url = wp_nonce_url( $url, 'bp_activity_delete_link' );
2643
+
2644
+ /**
2645
+ * Filters the activity delete URL.
2646
+ *
2647
+ * @since 2.1.0
2648
+ *
2649
+ * @param string $url Activity delete URL.
2650
+ */
2651
+ return apply_filters( 'bp_get_activity_delete_url', $url );
2652
  }
2653
 
2654
  /**
2655
  * Output the activity latest update link.
2656
  *
2657
+ * @since 1.2.0
2658
  *
2659
  * @see bp_get_activity_latest_update() for description of parameters.
 
2660
  *
2661
  * @param int $user_id See {@link bp_get_activity_latest_update()} for description.
2662
  */
2667
  /**
2668
  * Return the activity latest update link.
2669
  *
2670
+ * @since 1.2.0
2671
  *
 
 
 
 
 
 
 
 
2672
  *
2673
  * @param int $user_id If empty, will fall back on displayed user.
2674
  * @return string|bool $latest_update The activity latest update link.
2675
+ * False on failure.
2676
  */
2677
  function bp_get_activity_latest_update( $user_id = 0 ) {
2678
 
2679
+ if ( empty( $user_id ) ) {
2680
  $user_id = bp_displayed_user_id();
2681
+ }
2682
 
2683
+ if ( bp_is_user_inactive( $user_id ) ) {
2684
  return false;
2685
+ }
2686
 
2687
+ if ( !$update = bp_get_user_meta( $user_id, 'bp_latest_update', true ) ) {
2688
  return false;
2689
+ }
2690
+
2691
+ /**
2692
+ * Filters the latest update excerpt.
2693
+ *
2694
+ * @since 1.2.10
2695
+ * @since 2.6.0 Added the `$user_id` parameter.
2696
+ *
2697
+ * @param string $value The excerpt for the latest update.
2698
+ * @param int $user_id ID of the queried user.
2699
+ */
2700
+ $latest_update = apply_filters( 'bp_get_activity_latest_update_excerpt', trim( strip_tags( bp_create_excerpt( $update['content'], 358 ) ) ), $user_id );
2701
 
2702
+ $latest_update = sprintf(
2703
+ '%s <a href="%s">%s</a>',
2704
+ $latest_update,
2705
+ esc_url_raw( bp_activity_get_permalink( $update['id'] ) ),
2706
+ esc_attr__( 'View', 'buddypress' )
2707
+ );
2708
 
2709
+ /**
2710
+ * Filters the latest update excerpt with view link appended to the end.
2711
+ *
2712
+ * @since 1.2.0
2713
+ * @since 2.6.0 Added the `$user_id` parameter.
2714
+ *
2715
+ * @param string $latest_update The latest update with "view" link appended to it.
2716
+ * @param int $user_id ID of the queried user.
2717
+ */
2718
+ return apply_filters( 'bp_get_activity_latest_update', $latest_update, $user_id );
2719
  }
2720
 
2721
  /**
2722
  * Output the activity filter links.
2723
  *
2724
+ * @since 1.1.0
2725
  *
2726
  * @see bp_get_activity_filter_links() for description of parameters.
 
2727
  *
2728
+ * @param array|bool $args See {@link bp_get_activity_filter_links()} for description.
2729
  */
2730
  function bp_activity_filter_links( $args = false ) {
2731
  echo bp_get_activity_filter_links( $args );
2734
  /**
2735
  * Return the activity filter links.
2736
  *
2737
+ * @since 1.1.0
2738
  *
 
 
 
 
 
 
 
2739
  *
2740
+ * @param array|bool $args {
2741
  * @type string $style The type of markup to use for the links.
2742
+ * 'list', 'paragraph', or 'span'. Default: 'list'.
2743
  * }
2744
  * @return string|bool $component_links The activity filter links.
2745
  * False on failure.
2746
  */
2747
  function bp_get_activity_filter_links( $args = false ) {
2748
 
2749
+ $r = wp_parse_args( $args, array(
2750
  'style' => 'list'
2751
+ ) );
 
 
 
2752
 
2753
+ // Define local variable.
2754
  $component_links = array();
2755
 
2756
+ // Fetch the names of components that have activity recorded in the DB.
2757
  $components = BP_Activity_Activity::get_recorded_components();
2758
 
2759
+ if ( empty( $components ) ) {
2760
  return false;
2761
+ }
2762
 
2763
  foreach ( (array) $components as $component ) {
2764
 
2765
+ // Skip the activity comment filter.
2766
+ if ( 'activity' == $component ) {
2767
  continue;
2768
+ }
2769
 
2770
+ if ( isset( $_GET['afilter'] ) && $component == $_GET['afilter'] ) {
2771
  $selected = ' class="selected"';
2772
+ } else {
2773
+ $selected = '';
2774
+ }
2775
 
2776
  $component = esc_attr( $component );
2777
 
2778
+ switch ( $r['style'] ) {
2779
  case 'list':
2780
  $tag = 'li';
2781
  $before = '<li id="afilter-' . $component . '"' . $selected . '>';
2795
 
2796
  $link = add_query_arg( 'afilter', $component );
2797
  $link = remove_query_arg( 'acpage' , $link );
2798
+
2799
+ /**
2800
+ * Filters the activity filter link URL for the current activity component.
2801
+ *
2802
+ * @since 1.1.0
2803
+ *
2804
+ * @param string $link The URL for the current component.
2805
+ * @param string $component The current component getting links constructed for.
2806
+ */
2807
  $link = apply_filters( 'bp_get_activity_filter_link_href', $link, $component );
2808
 
2809
+ $component_links[] = $before . '<a href="' . esc_url( $link ) . '">' . ucwords( $component ) . '</a>' . $after;
2810
  }
2811
 
2812
  $link = remove_query_arg( 'afilter' , $link );
2813
 
2814
+ if ( isset( $_GET['afilter'] ) ) {
2815
+ $component_links[] = '<' . $tag . ' id="afilter-clear"><a href="' . esc_url( $link ) . '">' . __( 'Clear Filter', 'buddypress' ) . '</a></' . $tag . '>';
2816
+ }
2817
 
2818
+ /**
2819
+ * Filters all of the constructed filter links.
2820
+ *
2821
+ * @since 1.1.0
2822
+ * @since 2.6.0 Added the `$r` parameter.
2823
+ *
2824
+ * @param string $value All of the links to be displayed to the user.
2825
+ * @param array $r Array of parsed arguments.
2826
+ */
2827
+ return apply_filters( 'bp_get_activity_filter_links', implode( "\n", $component_links ), $r );
2828
  }
2829
 
2830
  /**
2831
  * Determine if a comment can be made on an activity item.
2832
  *
2833
+ * @since 1.2.0
2834
  *
2835
  * @global object $activities_template {@link BP_Activity_Template}
 
 
2836
  *
2837
  * @return bool $can_comment True if item can receive comments.
2838
  */
2839
  function bp_activity_can_comment() {
2840
  global $activities_template;
2841
+ $bp = buddypress();
2842
 
2843
+ // Determine ability to comment based on activity type name.
2844
+ $activity_type = bp_get_activity_type();
2845
 
2846
+ // Get the 'comment-reply' support for the current activity type.
2847
+ $can_comment = bp_activity_type_supports( $activity_type, 'comment-reply' );
 
 
2848
 
2849
+ // Neutralize activity_comment.
2850
+ if ( 'activity_comment' === $activity_type ) {
2851
  $can_comment = false;
2852
+ }
2853
 
2854
+ /**
2855
+ * Filters whether a comment can be made on an activity item.
2856
+ *
2857
+ * @since 1.5.0
2858
+ * @since 2.5.0 Use $activity_type instead of $activity_name for the second parameter.
2859
+ *
2860
+ * @param bool $can_comment Status on if activity can be commented on.
2861
+ * @param string $activity_type Current activity type being checked on.
2862
+ */
2863
+ return apply_filters( 'bp_activity_can_comment', $can_comment, $activity_type );
2864
  }
2865
 
2866
  /**
2867
+ * Determine whether a comment can be made on an activity reply item.
 
 
 
 
2868
  *
2869
+ * @since 1.5.0
2870
  *
2871
+ * @param bool|object $comment Activity comment.
2872
+ * @return bool $can_comment True if comment can receive comments,
2873
+ * otherwise false.
2874
  */
2875
+ function bp_activity_can_comment_reply( $comment = false ) {
2876
+
2877
+ // Assume activity can be commented on.
2878
  $can_comment = true;
2879
 
2880
+ // Check that comment exists.
2881
+ if ( empty( $comment ) ) {
2882
+ $comment = bp_activity_current_comment();
2883
+ }
2884
+
2885
+ if ( ! empty( $comment ) ) {
2886
+
2887
+ // Fall back on current comment in activity loop.
2888
+ $comment_depth = isset( $comment->depth )
2889
+ ? intval( $comment->depth )
2890
+ : bp_activity_get_comment_depth();
2891
+
2892
+ // Threading is turned on, so check the depth.
2893
+ if ( get_option( 'thread_comments' ) ) {
2894
+ $can_comment = (bool) ( $comment_depth < get_option( 'thread_comments_depth' ) );
2895
+
2896
+ // No threading for comment replies if no threading for comments.
2897
+ } else {
2898
+ $can_comment = false;
2899
+ }
2900
  }
2901
 
2902
+ /**
2903
+ * Filters whether a comment can be made on an activity reply item.
2904
+ *
2905
+ * @since 1.5.0
2906
+ *
2907
+ * @param bool $can_comment Status on if activity reply can be commented on.
2908
+ * @param string $comment Current comment being checked on.
2909
+ */
2910
+ return (bool) apply_filters( 'bp_activity_can_comment_reply', $can_comment, $comment );
2911
  }
2912
 
2913
  /**
2914
+ * Determine whether favorites are allowed.
2915
  *
2916
  * Defaults to true, but can be modified by plugins.
2917
  *
2918
+ * @since 1.5.0
2919
  *
2920
+ * @return bool True if comment can receive comments.
 
 
2921
  */
2922
  function bp_activity_can_favorite() {
 
2923
 
2924
+ /**
2925
+ * Filters whether or not users can favorite activity items.
2926
+ *
2927
+ * @since 1.5.0
2928
+ *
2929
+ * @param bool $value Whether or not favoriting is enabled.
2930
+ */
2931
+ return apply_filters( 'bp_activity_can_favorite', true );
2932
  }
2933
 
2934
  /**
2935
  * Output the total favorite count for a specified user.
2936
  *
2937
+ * @since 1.2.0
2938
  *
2939
  * @see bp_get_total_favorite_count_for_user() for description of parameters.
 
2940
  *
2941
  * @param int $user_id See {@link bp_get_total_favorite_count_for_user()}.
2942
  */
2947
  /**
2948
  * Return the total favorite count for a specified user.
2949
  *
2950
+ * @since 1.2.0
2951
  *
 
 
2952
  *
2953
  * @param int $user_id ID of user being queried. Default: displayed user ID.
2954
  * @return int The total favorite count for the specified user.
2955
  */
2956
  function bp_get_total_favorite_count_for_user( $user_id = 0 ) {
2957
+ $retval = false;
2958
+
2959
+ if ( bp_activity_can_favorite() ) {
2960
+ // Default to displayed user if none is passed.
2961
+ $user_id = empty( $user_id )
2962
+ ? bp_displayed_user_id()
2963
+ : $user_id;
2964
+
2965
+ // Get user meta if user ID exists.
2966
+ if ( ! empty( $user_id ) ) {
2967
+ $retval = bp_activity_total_favorites_for_user( $user_id );
2968
+ }
2969
  }
2970
 
2971
+ /**
2972
+ * Filters the total favorite count for a user.
2973
+ *
2974
+ * @since 1.2.0
2975
+ * @since 2.6.0 Added the `$user_id` parameter.
2976
+ *
2977
+ * @param int|bool $retval Total favorite count for a user. False on no favorites.
2978
+ * @param int $user_id ID of the queried user.
2979
+ */
2980
+ return apply_filters( 'bp_get_total_favorite_count_for_user', $retval, $user_id );
2981
  }
2982
+
2983
 
2984
  /**
2985
  * Output the total mention count for a specified user.
2986
  *
2987
+ * @since 1.2.0
2988
  *
2989
  * @see bp_get_total_mention_count_for_user() for description of parameters.
 
2990
  *
2991
  * @param int $user_id See {@link bp_get_total_mention_count_for_user()}.
2992
  */
2997
  /**
2998
  * Return the total mention count for a specified user.
2999
  *
3000
+ * @since 1.2.0
3001
  *
 
 
3002
  *
3003
  * @param int $user_id ID of user being queried. Default: displayed user ID.
3004
  * @return int The total mention count for the specified user.
3005
  */
3006
  function bp_get_total_mention_count_for_user( $user_id = 0 ) {
 
 
 
3007
 
3008
+ // Default to displayed user if none is passed.
3009
+ $user_id = empty( $user_id )
3010
+ ? bp_displayed_user_id()
3011
+ : $user_id;
3012
+
3013
+ // Get user meta if user ID exists.
3014
+ $retval = ! empty( $user_id )
3015
+ ? bp_get_user_meta( $user_id, 'bp_new_mention_count', true )
3016
+ : false;
3017
+
3018
+ /**
3019
+ * Filters the total mention count for a user.
3020
+ *
3021
+ * @since 1.2.0
3022
+ * @since 2.6.0 Added the `$user_id` parameter.
3023
+ *
3024
+ * @param int|bool $retval Total mention count for a user. False on no mentions.
3025
+ * @param int $user_id ID of the queried user.
3026
+ */
3027
+ return apply_filters( 'bp_get_total_mention_count_for_user', $retval, $user_id );
3028
  }
 
3029
 
3030
  /**
3031
  * Output the public message link for displayed user.
3032
  *
3033
+ * @since 1.2.0
3034
  *
 
3035
  */
3036
  function bp_send_public_message_link() {
3037
+ echo esc_url( bp_get_send_public_message_link() );
3038
  }
3039
 
3040
  /**
3041
  * Return the public message link for the displayed user.
3042
  *
3043
+ * @since 1.2.0
3044
  *
 
 
 
 
 
 
3045
  *
3046
  * @return string The public message link for the displayed user.
3047
  */
3048
  function bp_get_send_public_message_link() {
3049
 
3050
+ // No link if not logged in, not looking at someone else's profile.
3051
+ if ( ! is_user_logged_in() || ! bp_is_user() || bp_is_my_profile() ) {
3052
+ $retval = '';
3053
+ } else {
3054
+ $args = array( 'r' => bp_get_displayed_user_mentionname() );
3055
+ $url = add_query_arg( $args, bp_get_activity_directory_permalink() );
3056
+ $retval = wp_nonce_url( $url );
3057
+ }
3058
 
3059
+ /**
3060
+ * Filters the public message link for the displayed user.
3061
+ *
3062
+ * @since 1.2.0
3063
+ *
3064
+ * @param string $retval The URL for the public message link.
3065
+ */
3066
+ return apply_filters( 'bp_get_send_public_message_link', $retval );
3067
  }
3068
 
3069
  /**
3070
  * Recurse through all activity comments and return the activity comment IDs.
3071
  *
3072
+ * @since 2.0.0
3073
  *
3074
  * @param array $activity Array of activities generated from {@link bp_activity_get()}.
3075
  * @param array $activity_ids Used for recursion purposes in this function.
3096
  /**
3097
  * Output the mentioned user display name.
3098
  *
3099
+ * @since 1.2.0
3100
  *
3101
  * @see bp_get_mentioned_user_display_name() for description of parameters.
 
3102
  *
3103
+ * @param int|string|bool $user_id_or_username See {@link bp_get_mentioned_user_display_name()}.
3104
  */
3105
+ function bp_mentioned_user_display_name( $user_id_or_username = false ) {
3106
  echo bp_get_mentioned_user_display_name( $user_id_or_username );
3107
  }
3108
 
3109
  /**
3110
+ * Returns the mentioned user display name.
3111
  *
3112
+ * @since 1.2.0
3113
  *
 
 
3114
  *
3115
+ * @param int|string|bool $user_id_or_username User ID or username.
3116
  * @return string The mentioned user's display name.
3117
  */
3118
+ function bp_get_mentioned_user_display_name( $user_id_or_username = false ) {
3119
+
3120
+ // Get user display name.
3121
+ $name = bp_core_get_user_displayname( $user_id_or_username );
3122
+
3123
+ // If user somehow has no name, return this really lame string.
3124
+ if ( empty( $name ) ) {
3125
  $name = __( 'a user', 'buddypress' );
3126
+ }
3127
 
3128
+ /**
3129
+ * Filters the mentioned user display name.
3130
+ *
3131
+ * @since 1.2.0
3132
+ *
3133
+ * @param string $name Display name for the mentioned user.
3134
+ * @param int|string $user_id_or_username User ID or username use for query.
3135
+ */
3136
  return apply_filters( 'bp_get_mentioned_user_display_name', $name, $user_id_or_username );
3137
  }
3138
 
3139
  /**
3140
  * Output button for sending a public message (an @-mention).
3141
  *
3142
+ * @since 1.2.0
3143
  *
3144
  * @see bp_get_send_public_message_button() for description of parameters.
 
3145
  *
3146
+ * @param array|string $args See {@link bp_get_send_public_message_button()}.
3147
  */
3148
  function bp_send_public_message_button( $args = '' ) {
3149
  echo bp_get_send_public_message_button( $args );
3152
  /**
3153
  * Return button for sending a public message (an @-mention).
3154
  *
3155
+ * @since 1.2.0
3156
  *
 
 
 
 
3157
  *
3158
+ * @param array|string $args {
3159
  * All arguments are optional. See {@link BP_Button} for complete
3160
  * descriptions.
3161
+ * @type string $id Default: 'public_message'.
3162
+ * @type string $component Default: 'activity'.
3163
+ * @type bool $must_be_logged_in Default: true.
3164
+ * @type bool $block_self Default: true.
3165
+ * @type string $wrapper_id Default: 'post-mention'.
3166
+ * @type string $link_href Default: the public message link for
3167
+ * the current member in the loop.
3168
+ * @type string $link_text Default: 'Public Message'.
3169
+ * @type string $link_class Default: 'activity-button mention'.
 
 
3170
  * }
3171
  * @return string The button for sending a public message.
3172
  */
3173
  function bp_get_send_public_message_button( $args = '' ) {
3174
+
3175
+ $r = bp_parse_args( $args, array(
3176
  'id' => 'public_message',
3177
  'component' => 'activity',
3178
  'must_be_logged_in' => true,
3179
  'block_self' => true,
3180
  'wrapper_id' => 'post-mention',
3181
  'link_href' => bp_get_send_public_message_link(),
 
3182
  'link_text' => __( 'Public Message', 'buddypress' ),
3183
  'link_class' => 'activity-button mention'
3184
+ ) );
 
 
3185
 
3186
+ /**
3187
+ * Filters the public message button HTML.
3188
+ *
3189
+ * @since 1.2.10
3190
+ *
3191
+ * @param array $r Array of arguments for the public message button HTML.
3192
+ */
3193
+ return bp_get_button( apply_filters( 'bp_get_send_public_message_button', $r ) );
3194
  }
3195
 
3196
  /**
3197
  * Output the activity post form action.
3198
  *
3199
+ * @since 1.2.0
3200
  *
 
3201
  */
3202
  function bp_activity_post_form_action() {
3203
  echo bp_get_activity_post_form_action();
3206
  /**
3207
  * Return the activity post form action.
3208
  *
3209
+ * @since 1.2.0
3210
  *
 
 
 
3211
  *
3212
  * @return string The activity post form action.
3213
  */
3214
  function bp_get_activity_post_form_action() {
3215
+
3216
+ /**
3217
+ * Filters the action url used for the activity post form.
3218
+ *
3219
+ * @since 1.2.0
3220
+ *
3221
+ * @param string $value URL to be used for the activity post form.
3222
+ */
3223
  return apply_filters( 'bp_get_activity_post_form_action', home_url( bp_get_activity_root_slug() . '/post/' ) );
3224
  }
3225
 
3231
  * Avatars are wrapped in <li> elements, but you've got to provide your own
3232
  * <ul> or <ol> wrapper markup.
3233
  *
3234
+ * @since 1.7.0
3235
  *
3236
  * @see bp_core_fetch_avatar() for a description of arguments.
3237
  *
3238
  * @param array $args See {@link bp_core_fetch_avatar()}.
3239
  */
3240
  function bp_activity_comments_user_avatars( $args = array() ) {
3241
+
3242
+ $r = bp_parse_args( $args, array(
3243
  'height' => false,
3244
  'html' => true,
3245
  'type' => 'thumb',
3246
  'width' => false,
3247
+ ) );
 
 
 
3248
 
3249
+ // Get the user IDs of everyone who has left a comment to the current activity item.
3250
  $user_ids = bp_activity_get_comments_user_ids();
3251
+ $output = array();
3252
+ $retval = '';
3253
+
3254
+ if ( ! empty( $user_ids ) ) {
3255
+ foreach ( (array) $user_ids as $user_id ) {
3256
+
3257
+ // Skip an empty user ID.
3258
+ if ( empty( $user_id ) ) {
3259
+ continue;
3260
+ }
3261
+
3262
+ // Get profile link for this user.
3263
+ $profile_link = bp_core_get_user_domain( $user_id );
3264
+
3265
+ // Get avatar for this user.
3266
+ $image_html = bp_core_fetch_avatar( array(
3267
+ 'item_id' => $user_id,
3268
+ 'height' => $r['height'],
3269
+ 'html' => $r['html'],
3270
+ 'type' => $r['type'],
3271
+ 'width' => $r['width']
3272
+ ) );
3273
 
3274
+ // If user has link & avatar, add them to the output array.
3275
+ if ( ! empty( $profile_link ) && ! empty( $image_html ) ) {
3276
+ $output[] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $profile_link ), $image_html );
3277
+ }
3278
+ }
3279
 
3280
+ // If output array is not empty, wrap everything in some list items.
3281
+ if ( ! empty( $output ) ) {
3282
+ $retval = '<li>' . implode( '</li><li>', $output ) . '</li>';
3283
+ }
3284
  }
3285
 
3286
+ /**
3287
+ * Filters the list of linked avatars for users who have commented on the current activity item.
3288
+ *
3289
+ * @since 1.7.0
3290
+ *
3291
+ * @param string $retval HTML markup for the list of avatars.
3292
+ * @param array $r Array of arguments used for each avatar.
3293
+ * @param array $output Array of each avatar found, before imploded into single string.
3294
+ */
3295
+ echo apply_filters( 'bp_activity_comments_user_avatars', $retval, $r, $output );
3296
  }
3297
 
3298
  /**
3299
  * Return the IDs of every user who's left a comment on the current activity item.
3300
  *
3301
+ * @since 1.7.0
3302
  *
3303
  * @return bool|array An array of IDs, or false if none are found.
3304
  */
3305
  function bp_activity_get_comments_user_ids() {
3306
+ global $activities_template;
 
3307
 
3308
+ $user_ids = ! empty( $activities_template->activity->children )
3309
+ ? (array) bp_activity_recurse_comments_user_ids( $activities_template->activity->children )
3310
+ : array();
3311
+
3312
+ /**
3313
+ * Filters the list of user IDs for the current activity item.
3314
+ *
3315
+ * @since 1.7.0
3316
+ *
3317
+ * @param array $value Array of unique user IDs for the current activity item.
3318
+ */
3319
  return apply_filters( 'bp_activity_get_comments_user_ids', array_unique( $user_ids ) );
3320
  }
3321
 
3322
  /**
3323
  * Recurse through all activity comments and collect the IDs of the users who wrote them.
3324
  *
3325
+ * @since 1.7.0
3326
  *
3327
  * @param array $comments Array of {@link BP_Activity_Activity} items.
3328
  * @return array Array of user IDs.
3329
  */
3330
+ function bp_activity_recurse_comments_user_ids( array $comments = array() ) {
3331
+
3332
+ // Default user ID's array.
3333
  $user_ids = array();
3334
 
3335
+ // Loop through comments and try to get user ID's.
3336
+ if ( ! empty( $comments ) ) {
3337
+ foreach ( $comments as $comment ) {
3338
+
3339
+ // If a user is a spammer, their activity items will have been
3340
+ // automatically marked as spam. Skip these.
3341
+ if ( ! empty( $comment->is_spam ) ) {
3342
+ continue;
3343
+ }
3344
 
3345
+ // Add user ID to array.
3346
+ $user_ids[] = $comment->user_id;
3347
 
3348
+ // Check for commentception.
3349
+ if ( ! empty( $comment->children ) ) {
3350
+ $user_ids = array_merge( $user_ids, bp_activity_recurse_comments_user_ids( $comment->children ) );
3351
+ }
3352
+ }
3353
  }
3354
 
3355
+ /**
3356
+ * Filters the list of user IDs for the current activity comment item.
3357
+ *
3358
+ * @since 2.1.0
3359
+ *
3360
+ * @param array $user_ids Array of user IDs for the current activity comment item.
3361
+ * @param array $comments Array of comments being checked for user IDs.
3362
+ */
3363
+ return apply_filters( 'bp_activity_recurse_comments_user_ids', $user_ids, $comments );
3364
  }
3365
 
3366
  /**
3367
  * Output the mentionname for the displayed user.
3368
  *
3369
+ * @since 1.9.0
3370
  */
3371
  function bp_displayed_user_mentionname() {
3372
  echo bp_get_displayed_user_mentionname();
3374
  /**
3375
  * Get the mentionname for the displayed user.
3376
  *
3377
+ * @since 1.9.0
3378
  *
3379
  * @return string Mentionname for the displayed user, if available.
3380
  */
3381
  function bp_get_displayed_user_mentionname() {
3382
+
3383
+ /**
3384
+ * Filters the mentionname for the displayed user.
3385
+ *
3386
+ * @since 1.9.0
3387
+ *
3388
+ * @param string $value The mentionanme for the displayed user.
3389
+ */
3390
  return apply_filters( 'bp_get_displayed_user_mentionname', bp_activity_get_user_mentionname( bp_displayed_user_id() ) );
3391
  }
3392
 
3393
  /**
3394
  * Echo a list of all registered activity types for use in dropdowns or checkbox lists.
3395
  *
3396
+ * @since 1.7.0
3397
  *
3398
+ * @param string $output Optional. Either 'select' or 'checkbox'. Default: 'select'.
3399
+ * @param array|string $args {
3400
  * Optional extra arguments.
3401
+ * @type string $checkbox_name When returning checkboxes, sets the 'name'
3402
+ * attribute.
3403
+ * @type array|string $selected A list of types that should be checked/
3404
+ * selected.
3405
  * }
3406
  */
3407
  function bp_activity_types_list( $output = 'select', $args = '' ) {
3408
+
3409
+ $args = bp_parse_args( $args, array(
3410
  'checkbox_name' => 'bp_activity_types',
3411
  'selected' => array(),
3412
+ ) );
 
3413
 
3414
  $activities = bp_activity_get_types();
3415
  natsort( $activities );
3416
 
3417
+ // Loop through the activity types and output markup.
3418
  foreach ( $activities as $type => $description ) {
3419
 
3420
+ // See if we need to preselect the current type.
3421
  $checked = checked( true, in_array( $type, (array) $args['selected'] ), false );
3422
  $selected = selected( true, in_array( $type, (array) $args['selected'] ), false );
3423
 
3424
+ // Switch output based on the element.
3425
+ switch ( $output ) {
3426
+ case 'select' :
3427
+ printf( '<option value="%1$s" %2$s>%3$s</option>', esc_attr( $type ), $selected, esc_html( $description ) );
3428
+ break;
3429
+ case 'checkbox' :
3430
+ printf( '<label style="" for="%1$s[]">%2$s<input type="checkbox" id="%1$s[]" name="%1$s[]" value="%3$s" %4$s/></label>', esc_attr( $args['checkbox_name'] ), esc_html( $description ), esc_attr( $args['checkbox_name'] ), esc_attr( $args['checkbox_name'] ), esc_attr( $type ), $checked );
3431
+ break;
3432
+ }
3433
 
3434
+ /**
3435
+ * Fires at the end of the listing of activity types.
3436
+ *
3437
+ * This is a variable action hook. The actual hook to use will depend on the output type specified.
3438
+ * Two default hooks are bp_activity_types_list_select and bp_activity_types_list_checkbox.
3439
+ *
3440
+ * @since 1.7.0
3441
+ *
3442
+ * @param array $args Array of arguments passed into function.
3443
+ * @param string $type Activity type being rendered in the output.
3444
+ * @param string $description Description of the activity type being rendered.
3445
+ */
3446
  do_action( 'bp_activity_types_list_' . $output, $args, $type, $description );
3447
  }
3448
 
3449
+ // Backpat with BP-Default for dropdown boxes only.
3450
+ if ( 'select' === $output ) {
3451
  do_action( 'bp_activity_filter_options' );
3452
+ }
3453
  }
3454
 
3455
 
3458
  /**
3459
  * Output the sitewide activity feed link.
3460
  *
3461
+ * @since 1.0.0
3462
  *
 
3463
  */
3464
  function bp_sitewide_activity_feed_link() {
3465
  echo bp_get_sitewide_activity_feed_link();
3468
  /**
3469
  * Returns the sitewide activity feed link.
3470
  *
3471
+ * @since 1.0.0
3472
  *
 
 
 
3473
  *
3474
  * @return string The sitewide activity feed link.
3475
  */
3476
  function bp_get_sitewide_activity_feed_link() {
3477
+
3478
+ /**
3479
+ * Filters the sidewide activity feed link.
3480
+ *
3481
+ * @since 1.0.0
3482
+ *
3483
+ * @param string $value The feed link for sitewide activity.
3484
+ */
3485
  return apply_filters( 'bp_get_sitewide_activity_feed_link', bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/feed/' );
3486
  }
3487
 
3488
  /**
3489
  * Output the member activity feed link.
3490
  *
3491
+ * @since 1.2.0
3492
  *
 
3493
  */
3494
  function bp_member_activity_feed_link() {
3495
  echo bp_get_member_activity_feed_link();
3498
  /**
3499
  * Output the member activity feed link.
3500
  *
3501
+ * @since 1.0.0
3502
+ * @deprecated 1.2.0
3503
  *
3504
  * @todo properly deprecate in favor of bp_member_activity_feed_link().
3505
  *
 
3506
  */
3507
  function bp_activities_member_rss_link() { echo bp_get_member_activity_feed_link(); }
3508
 
3509
  /**
3510
  * Return the member activity feed link.
3511
  *
3512
+ * @since 1.2.0
3513
  *
 
 
 
 
 
 
 
 
3514
  *
3515
  * @return string $link The member activity feed link.
3516
  */
3517
  function bp_get_member_activity_feed_link() {
3518
 
3519
+ // Single member activity feed link.
3520
+ if ( bp_is_profile_component() || bp_is_current_action( 'just-me' ) ) {
3521
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/feed/';
3522
+
3523
+ // Friend feed link.
3524
+ } elseif ( bp_is_active( 'friends' ) && bp_is_current_action( bp_get_friends_slug() ) ) {
3525
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/feed/';
3526
+
3527
+ // Group feed link.
3528
+ } elseif ( bp_is_active( 'groups' ) && bp_is_current_action( bp_get_groups_slug() ) ) {
3529
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/feed/';
3530
+
3531
+ // Favorites activity feed link.
3532
+ } elseif ( 'favorites' === bp_current_action() ) {
3533
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/favorites/feed/';
3534
+
3535
+ // Mentions activity feed link.
3536
+ } elseif ( ( 'mentions' === bp_current_action() ) && bp_activity_do_mentions() ) {
3537
  $link = bp_displayed_user_domain() . bp_get_activity_slug() . '/mentions/feed/';
3538
+
3539
+ // No feed link.
3540
+ } else {
3541
  $link = '';
3542
+ }
3543
 
3544
+ /**
3545
+ * Filters the member activity feed link.
3546
+ *
3547
+ * @since 1.0.0
3548
+ *
3549
+ * @param string $link URL for the member activity feed.
3550
+ */
3551
  return apply_filters( 'bp_get_activities_member_rss_link', $link );
3552
  }
3553
 
3554
  /**
3555
  * Return the member activity feed link.
3556
  *
3557
+ * @since 1.0.0
3558
+ * @deprecated 1.2.0
3559
  *
3560
  * @todo properly deprecate in favor of bp_get_member_activity_feed_link().
3561
  *
 
3562
  *
3563
  * @return string The member activity feed link.
3564
  */
3570
  /**
3571
  * Outputs the activity feed item guid.
3572
  *
3573
+ * @since 1.0.0
3574
  *
 
3575
  */
3576
  function bp_activity_feed_item_guid() {
3577
  echo bp_get_activity_feed_item_guid();
3580
  /**
3581
  * Returns the activity feed item guid.
3582
  *
3583
+ * @since 1.2.0
3584
  *
3585
  * @global object $activities_template {@link BP_Activity_Template}
 
3586
  *
3587
  * @return string The activity feed item guid.
3588
  */
3589
  function bp_get_activity_feed_item_guid() {
3590
  global $activities_template;
3591
 
3592
+ /**
3593
+ * Filters the activity feed item guid.
3594
+ *
3595
+ * @since 1.1.3
3596
+ *
3597
+ * @param string $value Calculated md5 value for the activity feed item.
3598
+ */
3599
  return apply_filters( 'bp_get_activity_feed_item_guid', md5( $activities_template->activity->date_recorded . '-' . $activities_template->activity->content ) );
3600
  }
3601
 
3602
  /**
3603
  * Output the activity feed item title.
3604
  *
3605
+ * @since 1.0.0
3606
  *
 
3607
  */
3608
  function bp_activity_feed_item_title() {
3609
  echo bp_get_activity_feed_item_title();
3612
  /**
3613
  * Return the activity feed item title.
3614
  *
3615
+ * @since 1.0.0
3616
  *
3617
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
 
3618
  *
3619
  * @return string $title The activity feed item title.
3620
  */
3621
  function bp_get_activity_feed_item_title() {
3622
  global $activities_template;
3623
 
3624
+ if ( !empty( $activities_template->activity->action ) ) {
3625
  $content = $activities_template->activity->action;
3626
+ } else {
3627
  $content = $activities_template->activity->content;
3628
+ }
3629
 
3630
  $content = explode( '<span', $content );
3631
+ $title = strip_tags( ent2ncr( trim( convert_chars( $content[0] ) ) ) );
3632
 
3633
+ if ( ':' === substr( $title, -1 ) ) {
3634
  $title = substr( $title, 0, -1 );
3635
+ }
3636
 
3637
+ if ( 'activity_update' === $activities_template->activity->type ) {
3638
  $title .= ': ' . strip_tags( ent2ncr( trim( convert_chars( bp_create_excerpt( $activities_template->activity->content, 70, array( 'ending' => " [&#133;]" ) ) ) ) ) );
3639
+ }
3640
 
3641
+ /**
3642
+ * Filters the activity feed item title.
3643
+ *
3644
+ * @since 1.0.0
3645
+ *
3646
+ * @param string $title The title for the activity feed item.
3647
+ */
3648
  return apply_filters( 'bp_get_activity_feed_item_title', $title );
3649
  }
3650
 
3651
  /**
3652
+ * Output the activity feed item link.
3653
  *
3654
+ * @since 1.0.0
3655
  *
 
3656
  */
3657
  function bp_activity_feed_item_link() {
3658
  echo bp_get_activity_feed_item_link();
3659
  }
3660
 
3661
  /**
3662
+ * Return the activity feed item link.
3663
  *
3664
+ * @since 1.0.0
3665
  *
3666
  * @global object $activities_template {@link BP_Activity_Template}
 
3667
  *
3668
  * @return string The activity feed item link.
3669
  */
3670
  function bp_get_activity_feed_item_link() {
3671
  global $activities_template;
3672
 
3673
+ $retval = ! empty( $activities_template->activity->primary_link )
3674
+ ? $activities_template->activity->primary_link
3675
+ : '';
3676
+
3677
+ /**
3678
+ * Filters the activity feed item link.
3679
+ *
3680
+ * @since 1.0.0
3681
+ *
3682
+ * @param string $retval The URL for the activity feed item.
3683
+ */
3684
+ return apply_filters( 'bp_get_activity_feed_item_link', $retval );
3685
  }
3686
 
3687
  /**
3688
  * Output the activity feed item date.
3689
  *
3690
+ * @since 1.0.0
3691
  *
 
3692
  */
3693
  function bp_activity_feed_item_date() {
3694
  echo bp_get_activity_feed_item_date();
3697
  /**
3698
  * Return the activity feed item date.
3699
  *
3700
+ * @since 1.0.0
3701
  *
3702
  * @global object $activities_template {@link BP_Activity_Template}
 
3703
  *
3704
  * @return string The activity feed item date.
3705
  */
3706
  function bp_get_activity_feed_item_date() {
3707
  global $activities_template;
3708
 
3709
+ $retval = ! empty( $activities_template->activity->date_recorded )
3710
+ ? $activities_template->activity->date_recorded
3711
+ : '';
3712
+
3713
+ /**
3714
+ * Filters the activity feed item date.
3715
+ *
3716
+ * @since 1.0.0
3717
+ *
3718
+ * @param string $retval The date for the activity feed item.
3719
+ */
3720
+ return apply_filters( 'bp_get_activity_feed_item_date', $retval );
3721
  }
3722
 
3723
  /**
3724
  * Output the activity feed item description.
3725
  *
3726
+ * @since 1.0.0
3727
  *
 
3728
  */
3729
  function bp_activity_feed_item_description() {
3730
  echo bp_get_activity_feed_item_description();
3733
  /**
3734
  * Return the activity feed item description.
3735
  *
3736
+ * @since 1.0.0
3737
  *
3738
  * @global object $activities_template {@link BP_Activity_Template}
 
 
 
3739
  *
3740
  * @return string The activity feed item description.
3741
  */
3742
  function bp_get_activity_feed_item_description() {
3743
  global $activities_template;
3744
 
3745
+ // Get the content, if exists.
3746
+ $content = ! empty( $activities_template->activity->content )
3747
+ ? $activities_template->activity->content
3748
+ : '';
3749
+
3750
+ // Perform a few string conversions on the content, if it's not empty.
3751
+ if ( ! empty( $content ) ) {
3752
+ $content = ent2ncr( convert_chars( str_replace( '%s', '', $content ) ) );
3753
+ }
3754
 
3755
+ /**
3756
+ * Filters the activity feed item description.
3757
+ *
3758
+ * @since 1.0.0
3759
+ *
3760
+ * @param string $content The description for the activity feed item.
3761
+ */
3762
+ return apply_filters( 'bp_get_activity_feed_item_description', $content );
3763
  }
3764
 
3765
  /**
3766
  * Template tag so we can hook activity feed to <head>.
3767
  *
3768
+ * @since 1.5.0
3769
  *
 
 
3770
  */
3771
  function bp_activity_sitewide_feed() {
3772
  ?>
3776
  <?php
3777
  }
3778
  add_action( 'bp_head', 'bp_activity_sitewide_feed' );
3779
+
3780
+ /**
3781
+ * Display available filters depending on the scope.
3782
+ *
3783
+ * @since 2.1.0
3784
+ *
3785
+ * @param string $context The current context. 'activity', 'member',
3786
+ * 'member_groups', 'group'.
3787
+ */
3788
+ function bp_activity_show_filters( $context = '' ) {
3789
+ echo bp_get_activity_show_filters( $context );
3790
+ }
3791
+ /**
3792
+ * Get available filters depending on the scope.
3793
+ *
3794
+ * @since 2.1.0
3795
+ *
3796
+ * @param string $context The current context. 'activity', 'member',
3797
+ * 'member_groups', 'group'.
3798
+ *
3799
+ * @return string HTML for <option> values.
3800
+ */
3801
+ function bp_get_activity_show_filters( $context = '' ) {
3802
+ // Set default context based on current page.
3803
+ if ( empty( $context ) ) {
3804
+
3805
+ // On member pages, default to 'member', unless this
3806
+ // is a user's Groups activity.
3807
+ if ( bp_is_user() ) {
3808
+ if ( bp_is_active( 'groups' ) && bp_is_current_action( bp_get_groups_slug() ) ) {
3809
+ $context = 'member_groups';
3810
+ } else {
3811
+ $context = 'member';
3812
+ }
3813
+
3814
+ // On individual group pages, default to 'group'.
3815
+ } elseif ( bp_is_active( 'groups' ) && bp_is_group() ) {
3816
+ $context = 'group';
3817
+
3818
+ // 'activity' everywhere else.
3819
+ } else {
3820
+ $context = 'activity';
3821
+ }
3822
+ }
3823
+
3824
+ $filters = array();
3825
+
3826
+ // Walk through the registered actions, and prepare an the
3827
+ // select box options.
3828
+ foreach ( bp_activity_get_actions() as $actions ) {
3829
+ foreach ( $actions as $action ) {
3830
+ if ( ! in_array( $context, (array) $action['context'] ) ) {
3831
+ continue;
3832
+ }
3833
+
3834
+ // Friends activity collapses two filters into one.
3835
+ if ( in_array( $action['key'], array( 'friendship_accepted', 'friendship_created' ) ) ) {
3836
+ $action['key'] = 'friendship_accepted,friendship_created';
3837
+ }
3838
+
3839
+ $filters[ $action['key'] ] = $action['label'];
3840
+ }
3841
+ }
3842
+
3843
+ /**
3844
+ * Filters the options available in the activity filter dropdown.
3845
+ *
3846
+ * @since 2.2.0
3847
+ *
3848
+ * @param array $filters Array of filter options for the given context, in the following format: $option_value => $option_name.
3849
+ * @param string $context Context for the filter. 'activity', 'member', 'member_groups', 'group'.
3850
+ */
3851
+ $filters = apply_filters( 'bp_get_activity_show_filters_options', $filters, $context );
3852
+
3853
+ // Build the options output.
3854
+ $output = '';
3855
+
3856
+ if ( ! empty( $filters ) ) {
3857
+ foreach ( $filters as $value => $filter ) {
3858
+ $output .= '<option value="' . esc_attr( $value ) . '">' . esc_html( $filter ) . '</option>' . "\n";
3859
+ }
3860
+ }
3861
+
3862
+ /**
3863
+ * Filters the HTML markup result for the activity filter dropdown.
3864
+ *
3865
+ * @since 2.1.0
3866
+ *
3867
+ * @param string $output HTML output for the activity filter dropdown.
3868
+ * @param array $filters Array of filter options for the given context, in the following format: $option_value => $option_name.
3869
+ * @param string $context Context for the filter. 'activity', 'member', 'member_groups', 'group'.
3870
+ */
3871
+ return apply_filters( 'bp_get_activity_show_filters', $output, $filters, $context );
3872
+ }
bp-activity/classes/class-bp-activity-activity.php ADDED
@@ -0,0 +1,1923 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Classes
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Activity
7
+ * @since 1.0.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Database interaction class for the BuddyPress activity component.
15
+ * Instance methods are available for creating/editing an activity,
16
+ * static methods for querying activities.
17
+ *
18
+ * @since 1.0.0
19
+ */
20
+ class BP_Activity_Activity {
21
+
22
+ /** Properties ************************************************************/
23
+
24
+ /**
25
+ * ID of the activity item.
26
+ *
27
+ * @since 1.0.0
28
+ * @var int
29
+ */
30
+ var $id;
31
+
32
+ /**
33
+ * ID of the associated item.
34
+ *
35
+ * @since 1.0.0
36
+ * @var int
37
+ */
38
+ var $item_id;
39
+
40
+ /**
41
+ * ID of the associated secondary item.
42
+ *
43
+ * @since 1.0.0
44
+ * @var int
45
+ */
46
+ var $secondary_item_id;
47
+
48
+ /**
49
+ * ID of user associated with the activity item.
50
+ *
51
+ * @since 1.0.0
52
+ * @var int
53
+ */
54
+ var $user_id;
55
+
56
+ /**
57
+ * The primary URL for the activity in RSS feeds.
58
+ *
59
+ * @since 1.0.0
60
+ * @var string
61
+ */
62
+ var $primary_link;
63
+
64
+ /**
65
+ * BuddyPress component the activity item relates to.
66
+ *
67
+ * @since 1.2.0
68
+ * @var string
69
+ */
70
+ var $component;
71
+
72
+ /**
73
+ * Activity type, eg 'new_blog_post'.
74
+ *
75
+ * @since 1.2.0
76
+ * @var string
77
+ */
78
+ var $type;
79
+
80
+ /**
81
+ * Description of the activity, eg 'Alex updated his profile.'.
82
+ *
83
+ * @since 1.2.0
84
+ * @var string
85
+ */
86
+ var $action;
87
+
88
+ /**
89
+ * The content of the activity item.
90
+ *
91
+ * @since 1.2.0
92
+ * @var string
93
+ */
94
+ var $content;
95
+
96
+ /**
97
+ * The date the activity item was recorded, in 'Y-m-d h:i:s' format.
98
+ *
99
+ * @since 1.0.0
100
+ * @var string
101
+ */
102
+ var $date_recorded;
103
+
104
+ /**
105
+ * Whether the item should be hidden in sitewide streams.
106
+ *
107
+ * @since 1.1.0
108
+ * @var int
109
+ */
110
+ var $hide_sitewide = 0;
111
+
112
+ /**
113
+ * Node boundary start for activity or activity comment.
114
+ *
115
+ * @since 1.5.0
116
+ * @var int
117
+ */
118
+ var $mptt_left;
119
+
120
+ /**
121
+ * Node boundary end for activity or activity comment.
122
+ *
123
+ * @since 1.5.0
124
+ * @var int
125
+ */
126
+ var $mptt_right;
127
+
128
+ /**
129
+ * Whether this item is marked as spam.
130
+ *
131
+ * @since 1.6.0
132
+ * @var int
133
+ */
134
+ var $is_spam;
135
+
136
+ /**
137
+ * Error holder.
138
+ *
139
+ * @since 2.6.0
140
+ *
141
+ * @var WP_Error
142
+ */
143
+ public $errors;
144
+
145
+ /**
146
+ * Error type to return. Either 'bool' or 'wp_error'.
147
+ *
148
+ * @since 2.6.0
149
+ *
150
+ * @var string
151
+ */
152
+ public $error_type = 'bool';
153
+
154
+ /**
155
+ * Constructor method.
156
+ *
157
+ * @since 1.5.0
158
+ *
159
+ * @param int|bool $id Optional. The ID of a specific activity item.
160
+ */
161
+ public function __construct( $id = false ) {
162
+ // Instantiate errors object.
163
+ $this->errors = new WP_Error;
164
+
165
+ if ( !empty( $id ) ) {
166
+ $this->id = (int) $id;
167
+ $this->populate();
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Populate the object with data about the specific activity item.
173
+ *
174
+ * @since 1.0.0
175
+ */
176
+ public function populate() {
177
+ global $wpdb;
178
+
179
+ $row = wp_cache_get( $this->id, 'bp_activity' );
180
+
181
+ if ( false === $row ) {
182
+ $bp = buddypress();
183
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->activity->table_name} WHERE id = %d", $this->id ) );
184
+
185
+ wp_cache_set( $this->id, $row, 'bp_activity' );
186
+ }
187
+
188
+ if ( ! empty( $row ) ) {
189
+ $this->id = (int) $row->id;
190
+ $this->item_id = (int) $row->item_id;
191
+ $this->secondary_item_id = (int) $row->secondary_item_id;
192
+ $this->user_id = (int) $row->user_id;
193
+ $this->primary_link = $row->primary_link;
194
+ $this->component = $row->component;
195
+ $this->type = $row->type;
196
+ $this->action = $row->action;
197
+ $this->content = $row->content;
198
+ $this->date_recorded = $row->date_recorded;
199
+ $this->hide_sitewide = (int) $row->hide_sitewide;
200
+ $this->mptt_left = (int) $row->mptt_left;
201
+ $this->mptt_right = (int) $row->mptt_right;
202
+ $this->is_spam = (int) $row->is_spam;
203
+ }
204
+
205
+ // Generate dynamic 'action' when possible.
206
+ $action = bp_activity_generate_action_string( $this );
207
+ if ( false !== $action ) {
208
+ $this->action = $action;
209
+
210
+ // If no callback is available, use the literal string from
211
+ // the database row.
212
+ } elseif ( ! empty( $row->action ) ) {
213
+ $this->action = $row->action;
214
+
215
+ // Provide a fallback to avoid PHP notices.
216
+ } else {
217
+ $this->action = '';
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Save the activity item to the database.
223
+ *
224
+ * @since 1.0.0
225
+ *
226
+ * @return bool True on success.
227
+ */
228
+ public function save() {
229
+ global $wpdb;
230
+
231
+ $bp = buddypress();
232
+
233
+ $this->id = apply_filters_ref_array( 'bp_activity_id_before_save', array( $this->id, &$this ) );
234
+ $this->item_id = apply_filters_ref_array( 'bp_activity_item_id_before_save', array( $this->item_id, &$this ) );
235
+ $this->secondary_item_id = apply_filters_ref_array( 'bp_activity_secondary_item_id_before_save', array( $this->secondary_item_id, &$this ) );
236
+ $this->user_id = apply_filters_ref_array( 'bp_activity_user_id_before_save', array( $this->user_id, &$this ) );
237
+ $this->primary_link = apply_filters_ref_array( 'bp_activity_primary_link_before_save', array( $this->primary_link, &$this ) );
238
+ $this->component = apply_filters_ref_array( 'bp_activity_component_before_save', array( $this->component, &$this ) );
239
+ $this->type = apply_filters_ref_array( 'bp_activity_type_before_save', array( $this->type, &$this ) );
240
+ $this->action = apply_filters_ref_array( 'bp_activity_action_before_save', array( $this->action, &$this ) );
241
+ $this->content = apply_filters_ref_array( 'bp_activity_content_before_save', array( $this->content, &$this ) );
242
+ $this->date_recorded = apply_filters_ref_array( 'bp_activity_date_recorded_before_save', array( $this->date_recorded, &$this ) );
243
+ $this->hide_sitewide = apply_filters_ref_array( 'bp_activity_hide_sitewide_before_save', array( $this->hide_sitewide, &$this ) );
244
+ $this->mptt_left = apply_filters_ref_array( 'bp_activity_mptt_left_before_save', array( $this->mptt_left, &$this ) );
245
+ $this->mptt_right = apply_filters_ref_array( 'bp_activity_mptt_right_before_save', array( $this->mptt_right, &$this ) );
246
+ $this->is_spam = apply_filters_ref_array( 'bp_activity_is_spam_before_save', array( $this->is_spam, &$this ) );
247
+
248
+ /**
249
+ * Fires before the current activity item gets saved.
250
+ *
251
+ * Please use this hook to filter the properties above. Each part will be passed in.
252
+ *
253
+ * @since 1.0.0
254
+ *
255
+ * @param BP_Activity_Activity $this Current instance of the activity item being saved. Passed by reference.
256
+ */
257
+ do_action_ref_array( 'bp_activity_before_save', array( &$this ) );
258
+
259
+ if ( 'wp_error' === $this->error_type && $this->errors->get_error_code() ) {
260
+ return $this->errors;
261
+ }
262
+
263
+ if ( empty( $this->component ) || empty( $this->type ) ) {
264
+ if ( 'bool' === $this->error_type ) {
265
+ return false;
266
+ } else {
267
+ if ( empty( $this->component ) ) {
268
+ $this->errors->add( 'bp_activity_missing_component' );
269
+ } else {
270
+ $this->errors->add( 'bp_activity_missing_type' );
271
+ }
272
+
273
+ return $this->errors;
274
+ }
275
+ }
276
+
277
+ if ( empty( $this->primary_link ) ) {
278
+ $this->primary_link = bp_loggedin_user_domain();
279
+ }
280
+
281
+ // If we have an existing ID, update the activity item, otherwise insert it.
282
+ if ( ! empty( $this->id ) ) {
283
+ $q = $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET user_id = %d, component = %s, type = %s, action = %s, content = %s, primary_link = %s, date_recorded = %s, item_id = %d, secondary_item_id = %d, hide_sitewide = %d, is_spam = %d WHERE id = %d", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam, $this->id );
284
+ } else {
285
+ $q = $wpdb->prepare( "INSERT INTO {$bp->activity->table_name} ( user_id, component, type, action, content, primary_link, date_recorded, item_id, secondary_item_id, hide_sitewide, is_spam ) VALUES ( %d, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d )", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam );
286
+ }
287
+
288
+ if ( false === $wpdb->query( $q ) ) {
289
+ return false;
290
+ }
291
+
292
+ // If this is a new activity item, set the $id property.
293
+ if ( empty( $this->id ) ) {
294
+ $this->id = $wpdb->insert_id;
295
+
296
+ // If an existing activity item, prevent any changes to the content generating new @mention notifications.
297
+ } else {
298
+ add_filter( 'bp_activity_at_name_do_notifications', '__return_false' );
299
+ }
300
+
301
+ /**
302
+ * Fires after an activity item has been saved to the database.
303
+ *
304
+ * @since 1.0.0
305
+ *
306
+ * @param BP_Activity_Activity $this Current instance of activity item being saved. Passed by reference.
307
+ */
308
+ do_action_ref_array( 'bp_activity_after_save', array( &$this ) );
309
+
310
+ return true;
311
+ }
312
+
313
+ /** Static Methods ***************************************************/
314
+
315
+ /**
316
+ * Get activity items, as specified by parameters.
317
+ *
318
+ * @since 1.2.0
319
+ * @since 2.4.0 Introduced the `$fields` parameter.
320
+ *
321
+ * @see BP_Activity_Activity::get_filter_sql() for a description of the
322
+ * 'filter' parameter.
323
+ * @see WP_Meta_Query::queries for a description of the 'meta_query'
324
+ * parameter format.
325
+ *
326
+ * @param array $args {
327
+ * An array of arguments. All items are optional.
328
+ * @type int $page Which page of results to fetch. Using page=1 without per_page will result
329
+ * in no pagination. Default: 1.
330
+ * @type int|bool $per_page Number of results per page. Default: 25.
331
+ * @type int|bool $max Maximum number of results to return. Default: false (unlimited).
332
+ * @type string $fields Activity fields to return. Pass 'ids' to get only the activity IDs.
333
+ * 'all' returns full activity objects.
334
+ * @type string $sort ASC or DESC. Default: 'DESC'.
335
+ * @type array $exclude Array of activity IDs to exclude. Default: false.
336
+ * @type array $in Array of ids to limit query by (IN). Default: false.
337
+ * @type array $meta_query Array of meta_query conditions. See WP_Meta_Query::queries.
338
+ * @type array $date_query Array of date_query conditions. See first parameter of
339
+ * WP_Date_Query::__construct().
340
+ * @type array $filter_query Array of advanced query conditions. See BP_Activity_Query::__construct().
341
+ * @type string|array $scope Pre-determined set of activity arguments.
342
+ * @type array $filter See BP_Activity_Activity::get_filter_sql().
343
+ * @type string $search_terms Limit results by a search term. Default: false.
344
+ * @type bool $display_comments Whether to include activity comments. Default: false.
345
+ * @type bool $show_hidden Whether to show items marked hide_sitewide. Default: false.
346
+ * @type string $spam Spam status. Default: 'ham_only'.
347
+ * @type bool $update_meta_cache Whether to pre-fetch metadata for queried activity items. Default: true.
348
+ * @type string|bool $count_total If true, an additional DB query is run to count the total activity items
349
+ * for the query. Default: false.
350
+ * }
351
+ * @return array The array returned has two keys:
352
+ * - 'total' is the count of located activities
353
+ * - 'activities' is an array of the located activities
354
+ */
355
+ public static function get( $args = array() ) {
356
+ global $wpdb;
357
+
358
+ // Backward compatibility with old method of passing arguments.
359
+ if ( !is_array( $args ) || func_num_args() > 1 ) {
360
+ _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__ ) );
361
+
362
+ $old_args_keys = array(
363
+ 0 => 'max',
364
+ 1 => 'page',
365
+ 2 => 'per_page',
366
+ 3 => 'sort',
367
+ 4 => 'search_terms',
368
+ 5 => 'filter',
369
+ 6 => 'display_comments',
370
+ 7 => 'show_hidden',
371
+ 8 => 'exclude',
372
+ 9 => 'in',
373
+ 10 => 'spam'
374
+ );
375
+
376
+ $func_args = func_get_args();
377
+ $args = bp_core_parse_args_array( $old_args_keys, $func_args );
378
+ }
379
+
380
+ $bp = buddypress();
381
+ $r = wp_parse_args( $args, array(
382
+ 'page' => 1, // The current page.
383
+ 'per_page' => 25, // Activity items per page.
384
+ 'max' => false, // Max number of items to return.
385
+ 'fields' => 'all', // Fields to include.
386
+ 'sort' => 'DESC', // ASC or DESC.
387
+ 'exclude' => false, // Array of ids to exclude.
388
+ 'in' => false, // Array of ids to limit query by (IN).
389
+ 'meta_query' => false, // Filter by activitymeta.
390
+ 'date_query' => false, // Filter by date.
391
+ 'filter_query' => false, // Advanced filtering - see BP_Activity_Query.
392
+ 'filter' => false, // See self::get_filter_sql().
393
+ 'scope' => false, // Preset activity arguments.
394
+ 'search_terms' => false, // Terms to search by.
395
+ 'display_comments' => false, // Whether to include activity comments.
396
+ 'show_hidden' => false, // Show items marked hide_sitewide.
397
+ 'spam' => 'ham_only', // Spam status.
398
+ 'update_meta_cache' => true, // Whether or not to update meta cache.
399
+ 'count_total' => false, // Whether or not to use count_total.
400
+ ) );
401
+
402
+ // Select conditions.
403
+ $select_sql = "SELECT DISTINCT a.id";
404
+
405
+ $from_sql = " FROM {$bp->activity->table_name} a";
406
+
407
+ $join_sql = '';
408
+
409
+ // Where conditions.
410
+ $where_conditions = array();
411
+
412
+ // Excluded types.
413
+ $excluded_types = array();
414
+
415
+ // Scope takes precedence.
416
+ if ( ! empty( $r['scope'] ) ) {
417
+ $scope_query = self::get_scope_query_sql( $r['scope'], $r );
418
+
419
+ // Add our SQL conditions if matches were found.
420
+ if ( ! empty( $scope_query['sql'] ) ) {
421
+ $where_conditions['scope_query_sql'] = $scope_query['sql'];
422
+ }
423
+
424
+ // Override some arguments if needed.
425
+ if ( ! empty( $scope_query['override'] ) ) {
426
+ $r = self::array_replace_recursive( $r, $scope_query['override'] );
427
+ }
428
+
429
+ // Advanced filtering.
430
+ } elseif ( ! empty( $r['filter_query'] ) ) {
431
+ $filter_query = new BP_Activity_Query( $r['filter_query'] );
432
+ $sql = $filter_query->get_sql();
433
+ if ( ! empty( $sql ) ) {
434
+ $where_conditions['filter_query_sql'] = $sql;
435
+ }
436
+ }
437
+
438
+ // Regular filtering.
439
+ if ( $r['filter'] && $filter_sql = BP_Activity_Activity::get_filter_sql( $r['filter'] ) ) {
440
+ $where_conditions['filter_sql'] = $filter_sql;
441
+ }
442
+
443
+ // Spam.
444
+ if ( 'ham_only' == $r['spam'] ) {
445
+ $where_conditions['spam_sql'] = 'a.is_spam = 0';
446
+ } elseif ( 'spam_only' == $r['spam'] ) {
447
+ $where_conditions['spam_sql'] = 'a.is_spam = 1';
448
+ }
449
+
450
+ // Searching.
451
+ if ( $r['search_terms'] ) {
452
+ $search_terms_like = '%' . bp_esc_like( $r['search_terms'] ) . '%';
453
+ $where_conditions['search_sql'] = $wpdb->prepare( 'a.content LIKE %s', $search_terms_like );
454
+ }
455
+
456
+ // Sorting.
457
+ $sort = $r['sort'];
458
+ if ( $sort != 'ASC' && $sort != 'DESC' ) {
459
+ $sort = 'DESC';
460
+ }
461
+
462
+ // Hide Hidden Items?
463
+ if ( ! $r['show_hidden'] ) {
464
+ $where_conditions['hidden_sql'] = "a.hide_sitewide = 0";
465
+ }
466
+
467
+ // Exclude specified items.
468
+ if ( ! empty( $r['exclude'] ) ) {
469
+ $exclude = implode( ',', wp_parse_id_list( $r['exclude'] ) );
470
+ $where_conditions['exclude'] = "a.id NOT IN ({$exclude})";
471
+ }
472
+
473
+ // The specific ids to which you want to limit the query.
474
+ if ( ! empty( $r['in'] ) ) {
475
+ $in = implode( ',', wp_parse_id_list( $r['in'] ) );
476
+ $where_conditions['in'] = "a.id IN ({$in})";
477
+ }
478
+
479
+ // Process meta_query into SQL.
480
+ $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
481
+
482
+ if ( ! empty( $meta_query_sql['join'] ) ) {
483
+ $join_sql .= $meta_query_sql['join'];
484
+ }
485
+
486
+ if ( ! empty( $meta_query_sql['where'] ) ) {
487
+ $where_conditions[] = $meta_query_sql['where'];
488
+ }
489
+
490
+ // Process date_query into SQL.
491
+ $date_query_sql = self::get_date_query_sql( $r['date_query'] );
492
+
493
+ if ( ! empty( $date_query_sql ) ) {
494
+ $where_conditions['date'] = $date_query_sql;
495
+ }
496
+
497
+ // Alter the query based on whether we want to show activity item
498
+ // comments in the stream like normal comments or threaded below
499
+ // the activity.
500
+ if ( false === $r['display_comments'] || 'threaded' === $r['display_comments'] ) {
501
+ $excluded_types[] = 'activity_comment';
502
+ }
503
+
504
+ // Exclude 'last_activity' items unless the 'action' filter has
505
+ // been explicitly set.
506
+ if ( empty( $r['filter']['object'] ) ) {
507
+ $excluded_types[] = 'last_activity';
508
+ }
509
+
510
+ // Build the excluded type sql part.
511
+ if ( ! empty( $excluded_types ) ) {
512
+ $not_in = "'" . implode( "', '", esc_sql( $excluded_types ) ) . "'";
513
+ $where_conditions['excluded_types'] = "a.type NOT IN ({$not_in})";
514
+ }
515
+
516
+ /**
517
+ * Filters the MySQL WHERE conditions for the Activity items get method.
518
+ *
519
+ * @since 1.9.0
520
+ *
521
+ * @param array $where_conditions Current conditions for MySQL WHERE statement.
522
+ * @param array $r Parsed arguments passed into method.
523
+ * @param string $select_sql Current SELECT MySQL statement at point of execution.
524
+ * @param string $from_sql Current FROM MySQL statement at point of execution.
525
+ * @param string $join_sql Current INNER JOIN MySQL statement at point of execution.
526
+ */
527
+ $where_conditions = apply_filters( 'bp_activity_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql );
528
+
529
+ // Join the where conditions together.
530
+ $where_sql = 'WHERE ' . join( ' AND ', $where_conditions );
531
+
532
+ /**
533
+ * Filter the MySQL JOIN clause for the main activity query.
534
+ *
535
+ * @since 2.5.0
536
+ *
537
+ * @param string $join_sql JOIN clause.
538
+ * @param array $r Method parameters.
539
+ * @param string $select_sql Current SELECT MySQL statement.
540
+ * @param string $from_sql Current FROM MySQL statement.
541
+ * @param string $where_sql Current WHERE MySQL statement.
542
+ */
543
+ $join_sql = apply_filters( 'bp_activity_get_join_sql', $join_sql, $r, $select_sql, $from_sql, $where_sql );
544
+
545
+ /**
546
+ * Filters the preferred order of indexes for activity item.
547
+ *
548
+ * @since 1.6.0
549
+ *
550
+ * @param array $value Array of indexes in preferred order.
551
+ */
552
+ $indexes = apply_filters( 'bp_activity_preferred_index_order', array( 'user_id', 'item_id', 'secondary_item_id', 'date_recorded', 'component', 'type', 'hide_sitewide', 'is_spam' ) );
553
+
554
+ foreach( $indexes as $key => $index ) {
555
+ if ( false !== strpos( $where_sql, $index ) ) {
556
+ $the_index = $index;
557
+ break; // Take the first one we find.
558
+ }
559
+ }
560
+
561
+ if ( !empty( $the_index ) ) {
562
+ $index_hint_sql = "USE INDEX ({$the_index})";
563
+ } else {
564
+ $index_hint_sql = '';
565
+ }
566
+
567
+ // Sanitize page and per_page parameters.
568
+ $page = absint( $r['page'] );
569
+ $per_page = absint( $r['per_page'] );
570
+
571
+ $retval = array(
572
+ 'activities' => null,
573
+ 'total' => null,
574
+ 'has_more_items' => null,
575
+ );
576
+
577
+ /**
578
+ * Filters if BuddyPress should use legacy query structure over current structure for version 2.0+.
579
+ *
580
+ * It is not recommended to use the legacy structure, but allowed to if needed.
581
+ *
582
+ * @since 2.0.0
583
+ *
584
+ * @param bool $value Whether to use legacy structure or not.
585
+ * @param BP_Activity_Activity $value Current method being called.
586
+ * @param array $r Parsed arguments passed into method.
587
+ */
588
+ if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, $r ) ) {
589
+
590
+ // Legacy queries joined against the user table.
591
+ $select_sql = "SELECT DISTINCT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name";
592
+ $from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID";
593
+
594
+ if ( ! empty( $page ) && ! empty( $per_page ) ) {
595
+ $pag_sql = $wpdb->prepare( "LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page );
596
+
597
+ /** This filter is documented in bp-activity/bp-activity-classes.php */
598
+ $activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort} {$pag_sql}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql ) );
599
+ } else {
600
+ $pag_sql = '';
601
+
602
+ /**
603
+ * Filters the legacy MySQL query statement so plugins can alter before results are fetched.
604
+ *
605
+ * @since 1.5.0
606
+ *
607
+ * @param string $value Concatenated MySQL statement pieces to be query results with for legacy query.
608
+ * @param string $select_sql Final SELECT MySQL statement portion for legacy query.
609
+ * @param string $from_sql Final FROM MySQL statement portion for legacy query.
610
+ * @param string $where_sql Final WHERE MySQL statement portion for legacy query.
611
+ * @param string $sort Final sort direction for legacy query.
612
+ */
613
+ $activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql ) );
614
+ }
615
+
616
+ // Integer casting for legacy activity query.
617
+ foreach ( (array) $activities as $i => $ac ) {
618
+ $activities[ $i ]->id = (int) $ac->id;
619
+ $activities[ $i ]->item_id = (int) $ac->item_id;
620
+ $activities[ $i ]->secondary_item_id = (int) $ac->secondary_item_id;
621
+ $activities[ $i ]->user_id = (int) $ac->user_id;
622
+ $activities[ $i ]->hide_sitewide = (int) $ac->hide_sitewide;
623
+ $activities[ $i ]->mptt_left = (int) $ac->mptt_left;
624
+ $activities[ $i ]->mptt_right = (int) $ac->mptt_right;
625
+ $activities[ $i ]->is_spam = (int) $ac->is_spam;
626
+ }
627
+
628
+ } else {
629
+ // Query first for activity IDs.
630
+ $activity_ids_sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort}";
631
+
632
+ if ( ! empty( $per_page ) && ! empty( $page ) ) {
633
+ // We query for $per_page + 1 items in order to
634
+ // populate the has_more_items flag.
635
+ $activity_ids_sql .= $wpdb->prepare( " LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page + 1 );
636
+ }
637
+
638
+ /**
639
+ * Filters the paged activities MySQL statement.
640
+ *
641
+ * @since 2.0.0
642
+ *
643
+ * @param string $activity_ids_sql MySQL statement used to query for Activity IDs.
644
+ * @param array $r Array of arguments passed into method.
645
+ */
646
+ $activity_ids_sql = apply_filters( 'bp_activity_paged_activities_sql', $activity_ids_sql, $r );
647
+
648
+ /*
649
+ * Queries that include 'last_activity' are cached separately,
650
+ * since they are generally much less long-lived.
651
+ */
652
+ if ( preg_match( '/a\.type NOT IN \([^\)]*\'last_activity\'[^\)]*\)/', $activity_ids_sql ) ) {
653
+ $cache_group = 'bp_activity';
654
+ } else {
655
+ $cache_group = 'bp_activity_with_last_activity';
656
+ }
657
+
658
+ $cached = bp_core_get_incremented_cache( $activity_ids_sql, $cache_group );
659
+ if ( false === $cached ) {
660
+ $activity_ids = $wpdb->get_col( $activity_ids_sql );
661
+ bp_core_set_incremented_cache( $activity_ids_sql, $cache_group, $activity_ids );
662
+ } else {
663
+ $activity_ids = $cached;
664
+ }
665
+
666
+ $retval['has_more_items'] = ! empty( $per_page ) && count( $activity_ids ) > $per_page;
667
+
668
+ // If we've fetched more than the $per_page value, we
669
+ // can discard the extra now.
670
+ if ( ! empty( $per_page ) && count( $activity_ids ) === $per_page + 1 ) {
671
+ array_pop( $activity_ids );
672
+ }
673
+
674
+ if ( 'ids' === $r['fields'] ) {
675
+ $activities = array_map( 'intval', $activity_ids );
676
+ } else {
677
+ $activities = self::get_activity_data( $activity_ids );
678
+ }
679
+ }
680
+
681
+ if ( 'ids' !== $r['fields'] ) {
682
+ // Get the fullnames of users so we don't have to query in the loop.
683
+ $activities = self::append_user_fullnames( $activities );
684
+
685
+ // Get activity meta.
686
+ $activity_ids = array();
687
+ foreach ( (array) $activities as $activity ) {
688
+ $activity_ids[] = $activity->id;
689
+ }
690
+
691
+ if ( ! empty( $activity_ids ) && $r['update_meta_cache'] ) {
692
+ bp_activity_update_meta_cache( $activity_ids );
693
+ }
694
+
695
+ if ( $activities && $r['display_comments'] ) {
696
+ $activities = BP_Activity_Activity::append_comments( $activities, $r['spam'] );
697
+ }
698
+
699
+ // Pre-fetch data associated with activity users and other objects.
700
+ BP_Activity_Activity::prefetch_object_data( $activities );
701
+
702
+ // Generate action strings.
703
+ $activities = BP_Activity_Activity::generate_action_strings( $activities );
704
+ }
705
+
706
+ $retval['activities'] = $activities;
707
+
708
+ // If $max is set, only return up to the max results.
709
+ if ( ! empty( $r['count_total'] ) ) {
710
+
711
+ /**
712
+ * Filters the total activities MySQL statement.
713
+ *
714
+ * @since 1.5.0
715
+ *
716
+ * @param string $value MySQL statement used to query for total activities.
717
+ * @param string $where_sql MySQL WHERE statement portion.
718
+ * @param string $sort Sort direction for query.
719
+ */
720
+ $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort );
721
+ $cached = bp_core_get_incremented_cache( $total_activities_sql, $cache_group );
722
+ if ( false === $cached ) {
723
+ $total_activities = $wpdb->get_var( $total_activities_sql );
724
+ bp_core_set_incremented_cache( $total_activities_sql, $cache_group, $total_activities );
725
+ } else {
726
+ $total_activities = $cached;
727
+ }
728
+
729
+ if ( !empty( $r['max'] ) ) {
730
+ if ( (int) $total_activities > (int) $r['max'] ) {
731
+ $total_activities = $r['max'];
732
+ }
733
+ }
734
+
735
+ $retval['total'] = $total_activities;
736
+ }
737
+
738
+ return $retval;
739
+ }
740
+
741
+ /**
742
+ * Convert activity IDs to activity objects, as expected in template loop.
743
+ *
744
+ * @since 2.0.0
745
+ *
746
+ * @param array $activity_ids Array of activity IDs.
747
+ * @return array
748
+ */
749
+ protected static function get_activity_data( $activity_ids = array() ) {
750
+ global $wpdb;
751
+
752
+ // Bail if no activity ID's passed.
753
+ if ( empty( $activity_ids ) ) {
754
+ return array();
755
+ }
756
+
757
+ // Get BuddyPress.
758
+ $bp = buddypress();
759
+
760
+ $activities = array();
761
+ $uncached_ids = bp_get_non_cached_ids( $activity_ids, 'bp_activity' );
762
+
763
+ // Prime caches as necessary.
764
+ if ( ! empty( $uncached_ids ) ) {
765
+ // Format the activity ID's for use in the query below.
766
+ $uncached_ids_sql = implode( ',', wp_parse_id_list( $uncached_ids ) );
767
+
768
+ // Fetch data from activity table, preserving order.
769
+ $queried_adata = $wpdb->get_results( "SELECT * FROM {$bp->activity->table_name} WHERE id IN ({$uncached_ids_sql})");
770
+
771
+ // Put that data into the placeholders created earlier,
772
+ // and add it to the cache.
773
+ foreach ( (array) $queried_adata as $adata ) {
774
+ wp_cache_set( $adata->id, $adata, 'bp_activity' );
775
+ }
776
+ }
777
+
778
+ // Now fetch data from the cache.
779
+ foreach ( $activity_ids as $activity_id ) {
780
+ // Integer casting.
781
+ $activity = wp_cache_get( $activity_id, 'bp_activity' );
782
+ if ( ! empty( $activity ) ) {
783
+ $activity->id = (int) $activity->id;
784
+ $activity->user_id = (int) $activity->user_id;
785
+ $activity->item_id = (int) $activity->item_id;
786
+ $activity->secondary_item_id = (int) $activity->secondary_item_id;
787
+ $activity->hide_sitewide = (int) $activity->hide_sitewide;
788
+ $activity->mptt_left = (int) $activity->mptt_left;
789
+ $activity->mptt_right = (int) $activity->mptt_right;
790
+ $activity->is_spam = (int) $activity->is_spam;
791
+ }
792
+
793
+ $activities[] = $activity;
794
+ }
795
+
796
+ // Then fetch user data.
797
+ $user_query = new BP_User_Query( array(
798
+ 'user_ids' => wp_list_pluck( $activities, 'user_id' ),
799
+ 'populate_extras' => false,
800
+ ) );
801
+
802
+ // Associated located user data with activity items.
803
+ foreach ( $activities as $a_index => $a_item ) {
804
+ $a_user_id = intval( $a_item->user_id );
805
+ $a_user = isset( $user_query->results[ $a_user_id ] ) ? $user_query->results[ $a_user_id ] : '';
806
+
807
+ if ( !empty( $a_user ) ) {
808
+ $activities[ $a_index ]->user_email = $a_user->user_email;
809
+ $activities[ $a_index ]->user_nicename = $a_user->user_nicename;
810
+ $activities[ $a_index ]->user_login = $a_user->user_login;
811
+ $activities[ $a_index ]->display_name = $a_user->display_name;
812
+ }
813
+ }
814
+
815
+ return $activities;
816
+ }
817
+
818
+ /**
819
+ * Append xProfile fullnames to an activity array.
820
+ *
821
+ * @since 2.0.0
822
+ *
823
+ * @param array $activities Activities array.
824
+ * @return array
825
+ */
826
+ protected static function append_user_fullnames( $activities ) {
827
+
828
+ if ( bp_is_active( 'xprofile' ) && ! empty( $activities ) ) {
829
+ $activity_user_ids = wp_list_pluck( $activities, 'user_id' );
830
+
831
+ if ( ! empty( $activity_user_ids ) ) {
832
+ $fullnames = bp_core_get_user_displaynames( $activity_user_ids );
833
+ if ( ! empty( $fullnames ) ) {
834
+ foreach ( (array) $activities as $i => $activity ) {
835
+ if ( ! empty( $fullnames[ $activity->user_id ] ) ) {
836
+ $activities[ $i ]->user_fullname = $fullnames[ $activity->user_id ];
837
+ }
838
+ }
839
+ }
840
+ }
841
+ }
842
+
843
+ return $activities;
844
+ }
845
+
846
+ /**
847
+ * Pre-fetch data for objects associated with activity items.
848
+ *
849
+ * Activity items are associated with users, and often with other
850
+ * BuddyPress data objects. Here, we pre-fetch data about these
851
+ * associated objects, so that inline lookups - done primarily when
852
+ * building action strings - do not result in excess database queries.
853
+ *
854
+ * The only object data required for activity component activity types
855
+ * (activity_update and activity_comment) is related to users, and that
856
+ * info is fetched separately in BP_Activity_Activity::get_activity_data().
857
+ * So this method contains nothing but a filter that allows other
858
+ * components, such as bp-friends and bp-groups, to hook in and prime
859
+ * their own caches at the beginning of an activity loop.
860
+ *
861
+ * @since 2.0.0
862
+ *
863
+ * @param array $activities Array of activities.
864
+ * @return array $activities Array of activities.
865
+ */
866
+ protected static function prefetch_object_data( $activities ) {
867
+
868
+ /**
869
+ * Filters inside prefetch_object_data method to aid in pre-fetching object data associated with activity item.
870
+ *
871
+ * @since 2.0.0
872
+ *
873
+ * @param array $activities Array of activities.
874
+ */
875
+ return apply_filters( 'bp_activity_prefetch_object_data', $activities );
876
+ }
877
+
878
+ /**
879
+ * Generate action strings for the activities located in BP_Activity_Activity::get().
880
+ *
881
+ * If no string can be dynamically generated for a given item
882
+ * (typically because the activity type has not been properly
883
+ * registered), the static 'action' value pulled from the database will
884
+ * be left in place.
885
+ *
886
+ * @since 2.0.0
887
+ *
888
+ * @param array $activities Array of activities.
889
+ * @return array
890
+ */
891
+ protected static function generate_action_strings( $activities ) {
892
+ foreach ( $activities as $key => $activity ) {
893
+ $generated_action = bp_activity_generate_action_string( $activity );
894
+ if ( false !== $generated_action ) {
895
+ $activity->action = $generated_action;
896
+ }
897
+
898
+ $activities[ $key ] = $activity;
899
+ }
900
+
901
+ return $activities;
902
+ }
903
+
904
+ /**
905
+ * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get().
906
+ *
907
+ * We use WP_Meta_Query to do the heavy lifting of parsing the
908
+ * meta_query array and creating the necessary SQL clauses. However,
909
+ * since BP_Activity_Activity::get() builds its SQL differently than
910
+ * WP_Query, we have to alter the return value (stripping the leading
911
+ * AND keyword from the 'where' clause).
912
+ *
913
+ * @since 1.8.0
914
+ *
915
+ * @param array $meta_query An array of meta_query filters. See the
916
+ * documentation for WP_Meta_Query for details.
917
+ * @return array $sql_array 'join' and 'where' clauses.
918
+ */
919
+ public static function get_meta_query_sql( $meta_query = array() ) {
920
+ global $wpdb;
921
+
922
+ $sql_array = array(
923
+ 'join' => '',
924
+ 'where' => '',
925
+ );
926
+
927
+ if ( ! empty( $meta_query ) ) {
928
+ $activity_meta_query = new WP_Meta_Query( $meta_query );
929
+
930
+ // WP_Meta_Query expects the table name at
931
+ // $wpdb->activitymeta.
932
+ $wpdb->activitymeta = buddypress()->activity->table_name_meta;
933
+
934
+ $meta_sql = $activity_meta_query->get_sql( 'activity', 'a', 'id' );
935
+
936
+ // Strip the leading AND - BP handles it in get().
937
+ $sql_array['where'] = preg_replace( '/^\sAND/', '', $meta_sql['where'] );
938
+ $sql_array['join'] = $meta_sql['join'];
939
+ }
940
+
941
+ return $sql_array;
942
+ }
943
+
944
+ /**
945
+ * Get the SQL for the 'date_query' param in BP_Activity_Activity::get().
946
+ *
947
+ * We use BP_Date_Query, which extends WP_Date_Query, to do the heavy lifting
948
+ * of parsing the date_query array and creating the necessary SQL clauses.
949
+ * However, since BP_Activity_Activity::get() builds its SQL differently than
950
+ * WP_Query, we have to alter the return value (stripping the leading AND
951
+ * keyword from the query).
952
+ *
953
+ * @since 2.1.0
954
+ *
955
+ * @param array $date_query An array of date_query parameters. See the
956
+ * documentation for the first parameter of WP_Date_Query.
957
+ * @return string
958
+ */
959
+ public static function get_date_query_sql( $date_query = array() ) {
960
+ $sql = '';
961
+
962
+ // Date query.
963
+ if ( ! empty( $date_query ) && is_array( $date_query ) ) {
964
+ $date_query = new BP_Date_Query( $date_query, 'date_recorded' );
965
+ $sql = preg_replace( '/^\sAND/', '', $date_query->get_sql() );
966
+ }
967
+
968
+ return $sql;
969
+ }
970
+
971
+ /**
972
+ * Get the SQL for the 'scope' param in BP_Activity_Activity::get().
973
+ *
974
+ * A scope is a predetermined set of activity arguments. This method is used
975
+ * to grab these activity arguments and override any existing args if needed.
976
+ *
977
+ * Can handle multiple scopes.
978
+ *
979
+ * @since 2.2.0
980
+ *
981
+ * @param mixed $scope The activity scope. Accepts string or array of scopes.
982
+ * @param array $r Current activity arguments. Same as those of BP_Activity_Activity::get(),
983
+ * but merged with defaults.
984
+ * @return array 'sql' WHERE SQL string and 'override' activity args.
985
+ */
986
+ public static function get_scope_query_sql( $scope = false, $r = array() ) {
987
+
988
+ // Define arrays for future use.
989
+ $query_args = array();
990
+ $override = array();
991
+ $retval = array();
992
+
993
+ // Check for array of scopes.
994
+ if ( is_array( $scope ) ) {
995
+ $scopes = $scope;
996
+
997
+ // Explode a comma separated string of scopes.
998
+ } elseif ( is_string( $scope ) ) {
999
+ $scopes = explode( ',', $scope );
1000
+ }
1001
+
1002
+ // Bail if no scope passed.
1003
+ if ( empty( $scopes ) ) {
1004
+ return false;
1005
+ }
1006
+
1007
+ // Helper to easily grab the 'user_id'.
1008
+ if ( ! empty( $r['filter']['user_id'] ) ) {
1009
+ $r['user_id'] = $r['filter']['user_id'];
1010
+ }
1011
+
1012
+ // Parse each scope; yes! we handle multiples!
1013
+ foreach ( $scopes as $scope ) {
1014
+ $scope_args = array();
1015
+
1016
+ /**
1017
+ * Plugins can hook here to set their activity arguments for custom scopes.
1018
+ *
1019
+ * This is a dynamic filter based on the activity scope. eg:
1020
+ * - 'bp_activity_set_groups_scope_args'
1021
+ * - 'bp_activity_set_friends_scope_args'
1022
+ *
1023
+ * To see how this filter is used, plugin devs should check out:
1024
+ * - bp_groups_filter_activity_scope() - used for 'groups' scope
1025
+ * - bp_friends_filter_activity_scope() - used for 'friends' scope
1026
+ *
1027
+ * @since 2.2.0
1028
+ *
1029
+ * @param array {
1030
+ * Activity query clauses.
1031
+ * @type array {
1032
+ * Activity arguments for your custom scope.
1033
+ * See {@link BP_Activity_Query::_construct()} for more details.
1034
+ * }
1035
+ * @type array $override Optional. Override existing activity arguments passed by $r.
1036
+ * }
1037
+ * }
1038
+ * @param array $r Current activity arguments passed in BP_Activity_Activity::get().
1039
+ */
1040
+ $scope_args = apply_filters( "bp_activity_set_{$scope}_scope_args", array(), $r );
1041
+
1042
+ if ( ! empty( $scope_args ) ) {
1043
+ // Merge override properties from other scopes
1044
+ // this might be a problem...
1045
+ if ( ! empty( $scope_args['override'] ) ) {
1046
+ $override = array_merge( $override, $scope_args['override'] );
1047
+ unset( $scope_args['override'] );
1048
+ }
1049
+
1050
+ // Save scope args.
1051
+ if ( ! empty( $scope_args ) ) {
1052
+ $query_args[] = $scope_args;
1053
+ }
1054
+ }
1055
+ }
1056
+
1057
+ if ( ! empty( $query_args ) ) {
1058
+ // Set relation to OR.
1059
+ $query_args['relation'] = 'OR';
1060
+
1061
+ $query = new BP_Activity_Query( $query_args );
1062
+ $sql = $query->get_sql();
1063
+ if ( ! empty( $sql ) ) {
1064
+ $retval['sql'] = $sql;
1065
+ }
1066
+ }
1067
+
1068
+ if ( ! empty( $override ) ) {
1069
+ $retval['override'] = $override;
1070
+ }
1071
+
1072
+ return $retval;
1073
+ }
1074
+
1075
+ /**
1076
+ * In BuddyPress 1.2.x, this was used to retrieve specific activity stream items (for example, on an activity's permalink page).
1077
+ *
1078
+ * As of 1.5.x, use BP_Activity_Activity::get() with an 'in' parameter instead.
1079
+ *
1080
+ * @since 1.2.0
1081
+ *
1082
+ * @deprecated 1.5
1083
+ * @deprecated Use BP_Activity_Activity::get() with an 'in' parameter instead.
1084
+ *
1085
+ * @param mixed $activity_ids Array or comma-separated string of activity IDs to retrieve.
1086
+ * @param int|bool $max Maximum number of results to return. (Optional; default is no maximum).
1087
+ * @param int $page The set of results that the user is viewing. Used in pagination. (Optional; default is 1).
1088
+ * @param int $per_page Specifies how many results per page. Used in pagination. (Optional; default is 25).
1089
+ * @param string $sort MySQL column sort; ASC or DESC. (Optional; default is DESC).
1090
+ * @param bool $display_comments Retrieve an activity item's associated comments or not. (Optional; default is false).
1091
+ * @return array
1092
+ */
1093
+ public static function get_specific( $activity_ids, $max = false, $page = 1, $per_page = 25, $sort = 'DESC', $display_comments = false ) {
1094
+ _deprecated_function( __FUNCTION__, '1.5', 'Use BP_Activity_Activity::get() with the "in" parameter instead.' );
1095
+ return BP_Activity_Activity::get( $max, $page, $per_page, $sort, false, false, $display_comments, false, false, $activity_ids );
1096
+ }
1097
+
1098
+ /**
1099
+ * Get the first activity ID that matches a set of criteria.
1100
+ *
1101
+ * @since 1.2.0
1102
+ *
1103
+ * @todo Should parameters be optional?
1104
+ *
1105
+ * @param int $user_id User ID to filter by.
1106
+ * @param string $component Component to filter by.
1107
+ * @param string $type Activity type to filter by.
1108
+ * @param int $item_id Associated item to filter by.
1109
+ * @param int $secondary_item_id Secondary associated item to filter by.
1110
+ * @param string $action Action to filter by.
1111
+ * @param string $content Content to filter by.
1112
+ * @param string $date_recorded Date to filter by.
1113
+ * @return int|bool Activity ID on success, false if none is found.
1114
+ */
1115
+ public static function get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) {
1116
+ global $wpdb;
1117
+
1118
+ $bp = buddypress();
1119
+
1120
+ $where_args = false;
1121
+
1122
+ if ( ! empty( $user_id ) ) {
1123
+ $where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
1124
+ }
1125
+
1126
+ if ( ! empty( $component ) ) {
1127
+ $where_args[] = $wpdb->prepare( "component = %s", $component );
1128
+ }
1129
+
1130
+ if ( ! empty( $type ) ) {
1131
+ $where_args[] = $wpdb->prepare( "type = %s", $type );
1132
+ }
1133
+
1134
+ if ( ! empty( $item_id ) ) {
1135
+ $where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
1136
+ }
1137
+
1138
+ if ( ! empty( $secondary_item_id ) ) {
1139
+ $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
1140
+ }
1141
+
1142
+ if ( ! empty( $action ) ) {
1143
+ $where_args[] = $wpdb->prepare( "action = %s", $action );
1144
+ }
1145
+
1146
+ if ( ! empty( $content ) ) {
1147
+ $where_args[] = $wpdb->prepare( "content = %s", $content );
1148
+ }
1149
+
1150
+ if ( ! empty( $date_recorded ) ) {
1151
+ $where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
1152
+ }
1153
+
1154
+ if ( ! empty( $where_args ) ) {
1155
+ $where_sql = 'WHERE ' . join( ' AND ', $where_args );
1156
+ $result = $wpdb->get_var( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
1157
+
1158
+ return is_numeric( $result ) ? (int) $result : false;
1159
+ }
1160
+
1161
+ return false;
1162
+ }
1163
+
1164
+ /**
1165
+ * Delete activity items from the database.
1166
+ *
1167
+ * To delete a specific activity item, pass an 'id' parameter.
1168
+ * Otherwise use the filters.
1169
+ *
1170
+ * @since 1.2.0
1171
+ *
1172
+ * @param array $args {
1173
+ * @int $id Optional. The ID of a specific item to delete.
1174
+ * @string $action Optional. The action to filter by.
1175
+ * @string $content Optional. The content to filter by.
1176
+ * @string $component Optional. The component name to filter by.
1177
+ * @string $type Optional. The activity type to filter by.
1178
+ * @string $primary_link Optional. The primary URL to filter by.
1179
+ * @int $user_id Optional. The user ID to filter by.
1180
+ * @int $item_id Optional. The associated item ID to filter by.
1181
+ * @int $secondary_item_id Optional. The secondary associated item ID to filter by.
1182
+ * @string $date_recorded Optional. The date to filter by.
1183
+ * @int $hide_sitewide Optional. Default: false.
1184
+ * }
1185
+ * @return array|bool An array of deleted activity IDs on success, false on failure.
1186
+ */
1187
+ public static function delete( $args = array() ) {
1188
+ global $wpdb;
1189
+
1190
+ $bp = buddypress();
1191
+ $r = wp_parse_args( $args, array(
1192
+ 'id' => false,
1193
+ 'action' => false,
1194
+ 'content' => false,
1195
+ 'component' => false,
1196
+ 'type' => false,
1197
+ 'primary_link' => false,
1198
+ 'user_id' => false,
1199
+ 'item_id' => false,
1200
+ 'secondary_item_id' => false,
1201
+ 'date_recorded' => false,
1202
+ 'hide_sitewide' => false
1203
+ ) );
1204
+
1205
+ // Setup empty array from where query arguments.
1206
+ $where_args = array();
1207
+
1208
+ // ID.
1209
+ if ( ! empty( $r['id'] ) ) {
1210
+ $where_args[] = $wpdb->prepare( "id = %d", $r['id'] );
1211
+ }
1212
+
1213
+ // User ID.
1214
+ if ( ! empty( $r['user_id'] ) ) {
1215
+ $where_args[] = $wpdb->prepare( "user_id = %d", $r['user_id'] );
1216
+ }
1217
+
1218
+ // Action.
1219
+ if ( ! empty( $r['action'] ) ) {
1220
+ $where_args[] = $wpdb->prepare( "action = %s", $r['action'] );
1221
+ }
1222
+
1223
+ // Content.
1224
+ if ( ! empty( $r['content'] ) ) {
1225
+ $where_args[] = $wpdb->prepare( "content = %s", $r['content'] );
1226
+ }
1227
+
1228
+ // Component.
1229
+ if ( ! empty( $r['component'] ) ) {
1230
+ $where_args[] = $wpdb->prepare( "component = %s", $r['component'] );
1231
+ }
1232
+
1233
+ // Type.
1234
+ if ( ! empty( $r['type'] ) ) {
1235
+ $where_args[] = $wpdb->prepare( "type = %s", $r['type'] );
1236
+ }
1237
+
1238
+ // Primary Link.
1239
+ if ( ! empty( $r['primary_link'] ) ) {
1240
+ $where_args[] = $wpdb->prepare( "primary_link = %s", $r['primary_link'] );
1241
+ }
1242
+
1243
+ // Item ID.
1244
+ if ( ! empty( $r['item_id'] ) ) {
1245
+ $where_args[] = $wpdb->prepare( "item_id = %d", $r['item_id'] );
1246
+ }
1247
+
1248
+ // Secondary item ID.
1249
+ if ( ! empty( $r['secondary_item_id'] ) ) {
1250
+ $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $r['secondary_item_id'] );
1251
+ }
1252
+
1253
+ // Date Recorded.
1254
+ if ( ! empty( $r['date_recorded'] ) ) {
1255
+ $where_args[] = $wpdb->prepare( "date_recorded = %s", $r['date_recorded'] );
1256
+ }
1257
+
1258
+ // Hidden sitewide.
1259
+ if ( ! empty( $r['hide_sitewide'] ) ) {
1260
+ $where_args[] = $wpdb->prepare( "hide_sitewide = %d", $r['hide_sitewide'] );
1261
+ }
1262
+
1263
+ // Bail if no where arguments.
1264
+ if ( empty( $where_args ) ) {
1265
+ return false;
1266
+ }
1267
+
1268
+ // Join the where arguments for querying.
1269
+ $where_sql = 'WHERE ' . join( ' AND ', $where_args );
1270
+
1271
+ // Fetch all activities being deleted so we can perform more actions.
1272
+ $activities = $wpdb->get_results( "SELECT * FROM {$bp->activity->table_name} {$where_sql}" );
1273
+
1274
+ /**
1275
+ * Action to allow intercepting activity items to be deleted.
1276
+ *
1277
+ * @since 2.3.0
1278
+ *
1279
+ * @param array $activities Array of activities.
1280
+ * @param array $r Array of parsed arguments.
1281
+ */
1282
+ do_action_ref_array( 'bp_activity_before_delete', array( $activities, $r ) );
1283
+
1284
+ // Attempt to delete activities from the database.
1285
+ $deleted = $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$where_sql}" );
1286
+
1287
+ // Bail if nothing was deleted.
1288
+ if ( empty( $deleted ) ) {
1289
+ return false;
1290
+ }
1291
+
1292
+ /**
1293
+ * Action to allow intercepting activity items just deleted.
1294
+ *
1295
+ * @since 2.3.0
1296
+ *
1297
+ * @param array $activities Array of activities.
1298
+ * @param array $r Array of parsed arguments.
1299
+ */
1300
+ do_action_ref_array( 'bp_activity_after_delete', array( $activities, $r ) );
1301
+
1302
+ // Pluck the activity IDs out of the $activities array.
1303
+ $activity_ids = wp_parse_id_list( wp_list_pluck( $activities, 'id' ) );
1304
+
1305
+ // Handle accompanying activity comments and meta deletion.
1306
+ if ( ! empty( $activity_ids ) ) {
1307
+
1308
+ // Delete all activity meta entries for activity items.
1309
+ BP_Activity_Activity::delete_activity_meta_entries( $activity_ids );
1310
+
1311
+ // Setup empty array for comments.
1312
+ $comment_ids = array();
1313
+
1314
+ // Loop through activity ids and attempt to delete comments.
1315
+ foreach ( $activity_ids as $activity_id ) {
1316
+
1317
+ // Attempt to delete comments.
1318
+ $comments = BP_Activity_Activity::delete( array(
1319
+ 'type' => 'activity_comment',
1320
+ 'item_id' => $activity_id
1321
+ ) );
1322
+
1323
+ // Merge IDs together.
1324
+ if ( ! empty( $comments ) ) {
1325
+ $comment_ids = array_merge( $comment_ids, $comments );
1326
+ }
1327
+ }
1328
+
1329
+ // Merge activity IDs with any deleted comment IDs.
1330
+ if ( ! empty( $comment_ids ) ) {
1331
+ $activity_ids = array_unique( array_merge( $activity_ids, $comment_ids ) );
1332
+ }
1333
+ }
1334
+
1335
+ return $activity_ids;
1336
+ }
1337
+
1338
+ /**
1339
+ * Delete the comments associated with a set of activity items.
1340
+ *
1341
+ * This method is no longer used by BuddyPress, and it is recommended not to
1342
+ * use it going forward, and use BP_Activity_Activity::delete() instead.
1343
+ *
1344
+ * @since 1.2.0
1345
+ *
1346
+ * @deprecated 2.3.0
1347
+ *
1348
+ * @param array $activity_ids Activity IDs whose comments should be deleted.
1349
+ * @param bool $delete_meta Should we delete the activity meta items for these comments.
1350
+ * @return bool True on success.
1351
+ */
1352
+ public static function delete_activity_item_comments( $activity_ids = array(), $delete_meta = true ) {
1353
+ global $wpdb;
1354
+
1355
+ $bp = buddypress();
1356
+
1357
+ $delete_meta = (bool) $delete_meta;
1358
+ $activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
1359
+
1360
+ if ( $delete_meta ) {
1361
+ // Fetch the activity comment IDs for our deleted activity items.
1362
+ $activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
1363
+
1364
+ if ( ! empty( $activity_comment_ids ) ) {
1365
+ self::delete_activity_meta_entries( $activity_comment_ids );
1366
+ }
1367
+ }
1368
+
1369
+ return $wpdb->query( "DELETE FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
1370
+ }
1371
+
1372
+ /**
1373
+ * Delete the meta entries associated with a set of activity items.
1374
+ *
1375
+ * @since 1.2.0
1376
+ *
1377
+ * @param array $activity_ids Activity IDs whose meta should be deleted.
1378
+ * @return bool True on success.
1379
+ */
1380
+ public static function delete_activity_meta_entries( $activity_ids = array() ) {
1381
+ $activity_ids = wp_parse_id_list( $activity_ids );
1382
+
1383
+ foreach ( $activity_ids as $activity_id ) {
1384
+ bp_activity_delete_meta( $activity_id );
1385
+ }
1386
+
1387
+ return true;
1388
+ }
1389
+
1390
+ /**
1391
+ * Append activity comments to their associated activity items.
1392
+ *
1393
+ * @since 1.2.0
1394
+ *
1395
+ * @global wpdb $wpdb WordPress database object.
1396
+ *
1397
+ * @param array $activities Activities to fetch comments for.
1398
+ * @param string $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
1399
+ * @return array The updated activities with nested comments.
1400
+ */
1401
+ public static function append_comments( $activities, $spam = 'ham_only' ) {
1402
+ $activity_comments = array();
1403
+
1404
+ // Now fetch the activity comments and parse them into the correct position in the activities array.
1405
+ foreach ( (array) $activities as $activity ) {
1406
+ $top_level_parent_id = 'activity_comment' == $activity->type ? $activity->item_id : 0;
1407
+ $activity_comments[$activity->id] = BP_Activity_Activity::get_activity_comments( $activity->id, $activity->mptt_left, $activity->mptt_right, $spam, $top_level_parent_id );
1408
+ }
1409
+
1410
+ // Merge the comments with the activity items.
1411
+ foreach ( (array) $activities as $key => $activity ) {
1412
+ if ( isset( $activity_comments[$activity->id] ) ) {
1413
+ $activities[$key]->children = $activity_comments[$activity->id];
1414
+ }
1415
+ }
1416
+
1417
+ return $activities;
1418
+ }
1419
+
1420
+ /**
1421
+ * Get activity comments that are associated with a specific activity ID.
1422
+ *
1423
+ * @since 1.2.0
1424
+ *
1425
+ * @global wpdb $wpdb WordPress database object.
1426
+ *
1427
+ * @param int $activity_id Activity ID to fetch comments for.
1428
+ * @param int $left Left-most node boundary.
1429
+ * @param int $right Right-most node boundary.
1430
+ * @param string $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
1431
+ * @param int $top_level_parent_id Optional. The id of the root-level parent activity item.
1432
+ * @return array The updated activities with nested comments.
1433
+ */
1434
+ public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
1435
+ global $wpdb;
1436
+
1437
+ if ( empty( $top_level_parent_id ) ) {
1438
+ $top_level_parent_id = $activity_id;
1439
+ }
1440
+
1441
+ $comments = wp_cache_get( $activity_id, 'bp_activity_comments' );
1442
+
1443
+ // We store the string 'none' to cache the fact that the
1444
+ // activity item has no comments.
1445
+ if ( 'none' === $comments ) {
1446
+ $comments = false;
1447
+
1448
+ // A true cache miss.
1449
+ } elseif ( empty( $comments ) ) {
1450
+
1451
+ $bp = buddypress();
1452
+
1453
+ // Select the user's fullname with the query.
1454
+ if ( bp_is_active( 'xprofile' ) ) {
1455
+ $fullname_select = ", pd.value as user_fullname";
1456
+ $fullname_from = ", {$bp->profile->table_name_data} pd ";
1457
+ $fullname_where = "AND pd.user_id = a.user_id AND pd.field_id = 1";
1458
+
1459
+ // Prevent debug errors.
1460
+ } else {
1461
+ $fullname_select = $fullname_from = $fullname_where = '';
1462
+ }
1463
+
1464
+ // Don't retrieve activity comments marked as spam.
1465
+ if ( 'ham_only' == $spam ) {
1466
+ $spam_sql = 'AND a.is_spam = 0';
1467
+ } elseif ( 'spam_only' == $spam ) {
1468
+ $spam_sql = 'AND a.is_spam = 1';
1469
+ } else {
1470
+ $spam_sql = '';
1471
+ }
1472
+
1473
+ // Legacy query - not recommended.
1474
+ $func_args = func_get_args();
1475
+
1476
+ /**
1477
+ * Filters if BuddyPress should use the legacy activity query.
1478
+ *
1479
+ * @since 2.0.0
1480
+ *
1481
+ * @param bool $value Whether or not to use the legacy query.
1482
+ * @param BP_Activity_Activity $value Magic method referring to currently called method.
1483
+ * @param array $func_args Array of the method's argument list.
1484
+ */
1485
+ if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, $func_args ) ) {
1486
+
1487
+ /**
1488
+ * Filters the MySQL prepared statement for the legacy activity query.
1489
+ *
1490
+ * @since 1.5.0
1491
+ *
1492
+ * @param string $value Prepared statement for the activity query.
1493
+ * @param int $activity_id Activity ID to fetch comments for.
1494
+ * @param int $left Left-most node boundary.
1495
+ * @param int $right Right-most node boundary.
1496
+ * @param string $spam_sql SQL Statement portion to differentiate between ham or spam.
1497
+ */
1498
+ $sql = apply_filters( 'bp_activity_comments_user_join_filter', $wpdb->prepare( "SELECT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name{$fullname_select} FROM {$bp->activity->table_name} a, {$wpdb->users} u{$fullname_from} WHERE u.ID = a.user_id {$fullname_where} AND a.type = 'activity_comment' {$spam_sql} AND a.item_id = %d AND a.mptt_left > %d AND a.mptt_left < %d ORDER BY a.date_recorded ASC", $top_level_parent_id, $left, $right ), $activity_id, $left, $right, $spam_sql );
1499
+
1500
+ $descendants = $wpdb->get_results( $sql );
1501
+
1502
+ // We use the mptt BETWEEN clause to limit returned
1503
+ // descendants to the correct part of the tree.
1504
+ } else {
1505
+ $sql = $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} a WHERE a.type = 'activity_comment' {$spam_sql} AND a.item_id = %d and a.mptt_left > %d AND a.mptt_left < %d ORDER BY a.date_recorded ASC", $top_level_parent_id, $left, $right );
1506
+
1507
+ $descendant_ids = $wpdb->get_col( $sql );
1508
+ $descendants = self::get_activity_data( $descendant_ids );
1509
+ $descendants = self::append_user_fullnames( $descendants );
1510
+ }
1511
+
1512
+ $ref = array();
1513
+
1514
+ // Loop descendants and build an assoc array.
1515
+ foreach ( (array) $descendants as $d ) {
1516
+ $d->children = array();
1517
+
1518
+ // If we have a reference on the parent.
1519
+ if ( isset( $ref[ $d->secondary_item_id ] ) ) {
1520
+ $ref[ $d->secondary_item_id ]->children[ $d->id ] = $d;
1521
+ $ref[ $d->id ] =& $ref[ $d->secondary_item_id ]->children[ $d->id ];
1522
+
1523
+ // If we don't have a reference on the parent, put in the root level.
1524
+ } else {
1525
+ $comments[ $d->id ] = $d;
1526
+ $ref[ $d->id ] =& $comments[ $d->id ];
1527
+ }
1528
+ }
1529
+
1530
+ // Calculate depth for each item.
1531
+ foreach ( $ref as &$r ) {
1532
+ $depth = 1;
1533
+ $parent_id = $r->secondary_item_id;
1534
+
1535
+ while ( $parent_id !== $r->item_id ) {
1536
+ $depth++;
1537
+
1538
+ // When display_comments=stream, the parent comment may not be part of the
1539
+ // returned results, so we manually fetch it.
1540
+ if ( empty( $ref[ $parent_id ] ) ) {
1541
+ $direct_parent = new BP_Activity_Activity( $parent_id );
1542
+ if ( isset( $direct_parent->secondary_item_id ) ) {
1543
+ // If the direct parent is not an activity update, that means we've reached
1544
+ // the parent activity item (eg. new_blog_post).
1545
+ if ( 'activity_update' !== $direct_parent->type ) {
1546
+ $parent_id = $r->item_id;
1547
+
1548
+ } else {
1549
+ $parent_id = $direct_parent->secondary_item_id;
1550
+ }
1551
+
1552
+ } else {
1553
+ // Something went wrong. Short-circuit the depth calculation.
1554
+ $parent_id = $r->item_id;
1555
+ }
1556
+ } else {
1557
+ $parent_id = $ref[ $parent_id ]->secondary_item_id;
1558
+ }
1559
+ }
1560
+ $r->depth = $depth;
1561
+ }
1562
+
1563
+ // If we cache a value of false, it'll count as a cache
1564
+ // miss the next time the activity comments are fetched.
1565
+ // Storing the string 'none' is a hack workaround to
1566
+ // avoid unnecessary queries.
1567
+ if ( false === $comments ) {
1568
+ $cache_value = 'none';
1569
+ } else {
1570
+ $cache_value = $comments;
1571
+ }
1572
+
1573
+ wp_cache_set( $activity_id, $cache_value, 'bp_activity_comments' );
1574
+ }
1575
+
1576
+ return $comments;
1577
+ }
1578
+
1579
+ /**
1580
+ * Rebuild nested comment tree under an activity or activity comment.
1581
+ *
1582
+ * @since 1.2.0
1583
+ *
1584
+ * @global wpdb $wpdb WordPress database object.
1585
+ *
1586
+ * @param int $parent_id ID of an activity or activity comment.
1587
+ * @param int $left Node boundary start for activity or activity comment.
1588
+ * @return int Right Node boundary of activity or activity comment.
1589
+ */
1590
+ public static function rebuild_activity_comment_tree( $parent_id, $left = 1 ) {
1591
+ global $wpdb;
1592
+
1593
+ $bp = buddypress();
1594
+
1595
+ // The right value of this node is the left value + 1.
1596
+ $right = intval( $left + 1 );
1597
+
1598
+ // Get all descendants of this node.
1599
+ $comments = BP_Activity_Activity::get_child_comments( $parent_id );
1600
+ $descendants = wp_list_pluck( $comments, 'id' );
1601
+
1602
+ // Loop the descendants and recalculate the left and right values.
1603
+ foreach ( (array) $descendants as $descendant_id ) {
1604
+ $right = BP_Activity_Activity::rebuild_activity_comment_tree( $descendant_id, $right );
1605
+ }
1606
+
1607
+ // We've got the left value, and now that we've processed the children
1608
+ // of this node we also know the right value.
1609
+ if ( 1 === $left ) {
1610
+ $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE id = %d", $left, $right, $parent_id ) );
1611
+ } else {
1612
+ $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE type = 'activity_comment' AND id = %d", $left, $right, $parent_id ) );
1613
+ }
1614
+
1615
+ // Return the right value of this node + 1.
1616
+ return intval( $right + 1 );
1617
+ }
1618
+
1619
+ /**
1620
+ * Get child comments of an activity or activity comment.
1621
+ *
1622
+ * @since 1.2.0
1623
+ *
1624
+ * @global wpdb $wpdb WordPress database object.
1625
+ *
1626
+ * @param int $parent_id ID of an activity or activity comment.
1627
+ * @return object Numerically indexed array of child comments.
1628
+ */
1629
+ public static function get_child_comments( $parent_id ) {
1630
+ global $wpdb;
1631
+
1632
+ $bp = buddypress();
1633
+
1634
+ return $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND secondary_item_id = %d", $parent_id ) );
1635
+ }
1636
+
1637
+ /**
1638
+ * Get a list of components that have recorded activity associated with them.
1639
+ *
1640
+ * @since 1.2.0
1641
+ *
1642
+ * @param bool $skip_last_activity If true, components will not be
1643
+ * included if the only activity type associated with them is
1644
+ * 'last_activity'. (Since 2.0.0, 'last_activity' is stored in
1645
+ * the activity table, but these items are not full-fledged
1646
+ * activity items.) Default: true.
1647
+ * @return array List of component names.
1648
+ */
1649
+ public static function get_recorded_components( $skip_last_activity = true ) {
1650
+ global $wpdb;
1651
+
1652
+ $bp = buddypress();
1653
+
1654
+ if ( true === $skip_last_activity ) {
1655
+ $components = $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} WHERE action != '' AND action != 'last_activity' ORDER BY component ASC" );
1656
+ } else {
1657
+ $components = $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} ORDER BY component ASC" );
1658
+ }
1659
+
1660
+ return $components;
1661
+ }
1662
+
1663
+ /**
1664
+ * Get sitewide activity items for use in an RSS feed.
1665
+ *
1666
+ * @since 1.0.0
1667
+ *
1668
+ * @param int $limit Optional. Number of items to fetch. Default: 35.
1669
+ * @return array $activity_feed List of activity items, with RSS data added.
1670
+ */
1671
+ public static function get_sitewide_items_for_feed( $limit = 35 ) {
1672
+ $activities = bp_activity_get_sitewide( array( 'max' => $limit ) );
1673
+ $activity_feed = array();
1674
+
1675
+ for ( $i = 0, $count = count( $activities ); $i < $count; ++$i ) {
1676
+ $title = explode( '<span', $activities[$i]['content'] );
1677
+ $activity_feed[$i]['title'] = trim( strip_tags( $title[0] ) );
1678
+ $activity_feed[$i]['link'] = $activities[$i]['primary_link'];
1679
+ $activity_feed[$i]['description'] = @sprintf( $activities[$i]['content'], '' );
1680
+ $activity_feed[$i]['pubdate'] = $activities[$i]['date_recorded'];
1681
+ }
1682
+
1683
+ return $activity_feed;
1684
+ }
1685
+
1686
+ /**
1687
+ * Create SQL IN clause for filter queries.
1688
+ *
1689
+ * @since 1.5.0
1690
+ *
1691
+ * @see BP_Activity_Activity::get_filter_sql()
1692
+ *
1693
+ * @param string $field The database field.
1694
+ * @param array|bool $items The values for the IN clause, or false when none are found.
1695
+ * @return string|bool
1696
+ */
1697
+ public static function get_in_operator_sql( $field, $items ) {
1698
+ global $wpdb;
1699
+
1700
+ // Split items at the comma.
1701
+ if ( ! is_array( $items ) ) {
1702
+ $items = explode( ',', $items );
1703
+ }
1704
+
1705
+ // Array of prepared integers or quoted strings.
1706
+ $items_prepared = array();
1707
+
1708
+ // Clean up and format each item.
1709
+ foreach ( $items as $item ) {
1710
+ // Clean up the string.
1711
+ $item = trim( $item );
1712
+ // Pass everything through prepare for security and to safely quote strings.
1713
+ $items_prepared[] = ( is_numeric( $item ) ) ? $wpdb->prepare( '%d', $item ) : $wpdb->prepare( '%s', $item );
1714
+ }
1715
+
1716
+ // Build IN operator sql syntax.
1717
+ if ( count( $items_prepared ) )
1718
+ return sprintf( '%s IN ( %s )', trim( $field ), implode( ',', $items_prepared ) );
1719
+ else
1720
+ return false;
1721
+ }
1722
+
1723
+ /**
1724
+ * Create filter SQL clauses.
1725
+ *
1726
+ * @since 1.5.0
1727
+ *
1728
+ * @param array $filter_array {
1729
+ * Fields and values to filter by.
1730
+ *
1731
+ * @type array|string|int $user_id User ID(s).
1732
+ * @type array|string $object Corresponds to the 'component'
1733
+ * column in the database.
1734
+ * @type array|string $action Corresponds to the 'type' column
1735
+ * in the database.
1736
+ * @type array|string|int $primary_id Corresponds to the 'item_id'
1737
+ * column in the database.
1738
+ * @type array|string|int $secondary_id Corresponds to the
1739
+ * 'secondary_item_id' column in the database.
1740
+ * @type int $offset Return only those items with an ID greater
1741
+ * than the offset value.
1742
+ * @type string $since Return only those items that have a
1743
+ * date_recorded value greater than a
1744
+ * given MySQL-formatted date.
1745
+ * }
1746
+ * @return string The filter clause, for use in a SQL query.
1747
+ */
1748
+ public static function get_filter_sql( $filter_array ) {
1749
+
1750
+ $filter_sql = array();
1751
+
1752
+ if ( !empty( $filter_array['user_id'] ) ) {
1753
+ $user_sql = BP_Activity_Activity::get_in_operator_sql( 'a.user_id', $filter_array['user_id'] );
1754
+ if ( !empty( $user_sql ) )
1755
+ $filter_sql[] = $user_sql;
1756
+ }
1757
+
1758
+ if ( !empty( $filter_array['object'] ) ) {
1759
+ $object_sql = BP_Activity_Activity::get_in_operator_sql( 'a.component', $filter_array['object'] );
1760
+ if ( !empty( $object_sql ) )
1761
+ $filter_sql[] = $object_sql;
1762
+ }
1763
+
1764
+ if ( !empty( $filter_array['action'] ) ) {
1765
+ $action_sql = BP_Activity_Activity::get_in_operator_sql( 'a.type', $filter_array['action'] );
1766
+ if ( ! empty( $action_sql ) )
1767
+ $filter_sql[] = $action_sql;
1768
+ }
1769
+
1770
+ if ( !empty( $filter_array['primary_id'] ) ) {
1771
+ $pid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.item_id', $filter_array['primary_id'] );
1772
+ if ( !empty( $pid_sql ) )
1773
+ $filter_sql[] = $pid_sql;
1774
+ }
1775
+
1776
+ if ( !empty( $filter_array['secondary_id'] ) ) {
1777
+ $sid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.secondary_item_id', $filter_array['secondary_id'] );
1778
+ if ( !empty( $sid_sql ) )
1779
+ $filter_sql[] = $sid_sql;
1780
+ }
1781
+
1782
+ if ( ! empty( $filter_array['offset'] ) ) {
1783
+ $sid_sql = absint( $filter_array['offset'] );
1784
+ $filter_sql[] = "a.id >= {$sid_sql}";
1785
+ }
1786
+
1787
+ if ( ! empty( $filter_array['since'] ) ) {
1788
+ // Validate that this is a proper Y-m-d H:i:s date.
1789
+ // Trick: parse to UNIX date then translate back.
1790
+ $translated_date = date( 'Y-m-d H:i:s', strtotime( $filter_array['since'] ) );
1791
+ if ( $translated_date === $filter_array['since'] ) {
1792
+ $filter_sql[] = "a.date_recorded > '{$translated_date}'";
1793
+ }
1794
+ }
1795
+
1796
+ if ( empty( $filter_sql ) )
1797
+ return false;
1798
+
1799
+ return join( ' AND ', $filter_sql );
1800
+ }
1801
+
1802
+ /**
1803
+ * Get the date/time of last recorded activity.
1804
+ *
1805
+ * @since 1.2.0
1806
+ *
1807
+ * @return string ISO timestamp.
1808
+ */
1809
+ public static function get_last_updated() {
1810
+ global $wpdb;
1811
+
1812
+ $bp = buddypress();
1813
+
1814
+ return $wpdb->get_var( "SELECT date_recorded FROM {$bp->activity->table_name} ORDER BY date_recorded DESC LIMIT 1" );
1815
+ }
1816
+
1817
+ /**
1818
+ * Get favorite count for a given user.
1819
+ *
1820
+ * @since 1.2.0
1821
+ *
1822
+ * @param int $user_id The ID of the user whose favorites you're counting.
1823
+ * @return int $value A count of the user's favorites.
1824
+ */
1825
+ public static function total_favorite_count( $user_id ) {
1826
+
1827
+ // Get activities from user meta.
1828
+ $favorite_activity_entries = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
1829
+ if ( ! empty( $favorite_activity_entries ) ) {
1830
+ return count( maybe_unserialize( $favorite_activity_entries ) );
1831
+ }
1832
+
1833
+ // No favorites.
1834
+ return 0;
1835
+ }
1836
+
1837
+ /**
1838
+ * Check whether an activity item exists with a given string content.
1839
+ *
1840
+ * @since 1.1.0
1841
+ *
1842
+ * @param string $content The content to filter by.
1843
+ * @return int|bool The ID of the first matching item if found, otherwise false.
1844
+ */
1845
+ public static function check_exists_by_content( $content ) {
1846
+ global $wpdb;
1847
+
1848
+ $bp = buddypress();
1849
+
1850
+ $result = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE content = %s", $content ) );
1851
+
1852
+ return is_numeric( $result ) ? (int) $result : false;
1853
+ }
1854
+
1855
+ /**
1856
+ * Hide all activity for a given user.
1857
+ *
1858
+ * @since 1.2.0
1859
+ *
1860
+ * @param int $user_id The ID of the user whose activity you want to mark hidden.
1861
+ * @return mixed
1862
+ */
1863
+ public static function hide_all_for_user( $user_id ) {
1864
+ global $wpdb;
1865
+
1866
+ $bp = buddypress();
1867
+
1868
+ return $wpdb->get_var( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET hide_sitewide = 1 WHERE user_id = %d", $user_id ) );
1869
+ }
1870
+
1871
+ /**
1872
+ * PHP-agnostic version of {@link array_replace_recursive()}.
1873
+ *
1874
+ * The array_replace_recursive() function is a PHP 5.3 function. BuddyPress (and
1875
+ * WordPress) currently supports down to PHP 5.2, so this method is a workaround
1876
+ * for PHP 5.2.
1877
+ *
1878
+ * Note: array_replace_recursive() supports infinite arguments, but for our use-
1879
+ * case, we only need to support two arguments.
1880
+ *
1881
+ * Subject to removal once WordPress makes PHP 5.3.0 the minimum requirement.
1882
+ *
1883
+ * @since 2.2.0
1884
+ *
1885
+ * @see http://php.net/manual/en/function.array-replace-recursive.php#109390
1886
+ *
1887
+ * @param array $base Array with keys needing to be replaced.
1888
+ * @param array $replacements Array with the replaced keys.
1889
+ * @return array
1890
+ */
1891
+ protected static function array_replace_recursive( $base = array(), $replacements = array() ) {
1892
+ if ( function_exists( 'array_replace_recursive' ) ) {
1893
+ return array_replace_recursive( $base, $replacements );
1894
+ }
1895
+
1896
+ // PHP 5.2-compatible version
1897
+ // http://php.net/manual/en/function.array-replace-recursive.php#109390.
1898
+ foreach ( array_slice( func_get_args(), 1 ) as $replacements ) {
1899
+ $bref_stack = array( &$base );
1900
+ $head_stack = array( $replacements );
1901
+
1902
+ do {
1903
+ end( $bref_stack );
1904
+
1905
+ $bref = &$bref_stack[ key( $bref_stack ) ];
1906
+ $head = array_pop( $head_stack );
1907
+
1908
+ unset( $bref_stack[ key($bref_stack) ] );
1909
+
1910
+ foreach ( array_keys( $head ) as $key ) {
1911
+ if ( isset( $key, $bref ) && is_array( $bref[$key] ) && is_array( $head[$key] ) ) {
1912
+ $bref_stack[] = &$bref[ $key ];
1913
+ $head_stack[] = $head[ $key ];
1914
+ } else {
1915
+ $bref[ $key ] = $head[ $key ];
1916
+ }
1917
+ }
1918
+ } while( count( $head_stack ) );
1919
+ }
1920
+
1921
+ return $base;
1922
+ }
1923
+ }
bp-activity/classes/class-bp-activity-component.php ADDED
@@ -0,0 +1,388 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Streams Loader.
4
+ *
5
+ * An activity stream component, for users, groups, and site tracking.
6
+ *
7
+ * @package BuddyPress
8
+ * @subpackage ActivityCore
9
+ * @since 1.5.0
10
+ */
11
+
12
+ // Exit if accessed directly.
13
+ defined( 'ABSPATH' ) || exit;
14
+
15
+ /**
16
+ * Main Activity Class.
17
+ *
18
+ * @since 1.5.0
19
+ */
20
+ class BP_Activity_Component extends BP_Component {
21
+
22
+ /**
23
+ * Start the activity component setup process.
24
+ *
25
+ * @since 1.5.0
26
+ */
27
+ public function __construct() {
28
+ parent::start(
29
+ 'activity',
30
+ __( 'Activity Streams', 'buddypress' ),
31
+ buddypress()->plugin_dir,
32
+ array(
33
+ 'adminbar_myaccount_order' => 10,
34
+ 'search_query_arg' => 'activity_search',
35
+ 'features' => array( 'embeds' )
36
+ )
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Include component files.
42
+ *
43
+ * @since 1.5.0
44
+ *
45
+ * @see BP_Component::includes() for a description of arguments.
46
+ *
47
+ * @param array $includes See BP_Component::includes() for a description.
48
+ */
49
+ public function includes( $includes = array() ) {
50
+
51
+ // Files to include.
52
+ $includes = array(
53
+ 'cssjs',
54
+ 'actions',
55
+ 'screens',
56
+ 'filters',
57
+ 'adminbar',
58
+ 'template',
59
+ 'functions',
60
+ 'cache'
61
+ );
62
+
63
+ // Notifications support.
64
+ if ( bp_is_active( 'notifications' ) ) {
65
+ $includes[] = 'notifications';
66
+ }
67
+
68
+ if ( ! buddypress()->do_autoload ) {
69
+ $includes[] = 'classes';
70
+ }
71
+
72
+ // Load Akismet support if Akismet is configured.
73
+ $akismet_key = bp_get_option( 'wordpress_api_key' );
74
+
75
+ /** This filter is documented in bp-activity/bp-activity-akismet.php */
76
+ if ( defined( 'AKISMET_VERSION' ) && class_exists( 'Akismet' ) && ( ! empty( $akismet_key ) || defined( 'WPCOM_API_KEY' ) ) && apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
77
+ $includes[] = 'akismet';
78
+ }
79
+
80
+ // Embeds - only applicable for WP 4.5+
81
+ if ( version_compare( $GLOBALS['wp_version'], '4.5', '>=' ) && bp_is_active( $this->id, 'embeds' ) ) {
82
+ $includes[] = 'embeds';
83
+ }
84
+
85
+ if ( is_admin() ) {
86
+ $includes[] = 'admin';
87
+ }
88
+
89
+ parent::includes( $includes );
90
+ }
91
+
92
+ /**
93
+ * Set up component global variables.
94
+ *
95
+ * The BP_ACTIVITY_SLUG constant is deprecated, and only used here for
96
+ * backwards compatibility.
97
+ *
98
+ * @since 1.5.0
99
+ *
100
+ * @see BP_Component::setup_globals() for a description of arguments.
101
+ *
102
+ * @param array $args See BP_Component::setup_globals() for a description.
103
+ */
104
+ public function setup_globals( $args = array() ) {
105
+ $bp = buddypress();
106
+
107
+ // Define a slug, if necessary.
108
+ if ( ! defined( 'BP_ACTIVITY_SLUG' ) ) {
109
+ define( 'BP_ACTIVITY_SLUG', $this->id );
110
+ }
111
+
112
+ // Global tables for activity component.
113
+ $global_tables = array(
114
+ 'table_name' => $bp->table_prefix . 'bp_activity',
115
+ 'table_name_meta' => $bp->table_prefix . 'bp_activity_meta',
116
+ );
117
+
118
+ // Metadata tables for groups component.
119
+ $meta_tables = array(
120
+ 'activity' => $bp->table_prefix . 'bp_activity_meta',
121
+ );
122
+
123
+ // Fetch the default directory title.
124
+ $default_directory_titles = bp_core_get_directory_page_default_titles();
125
+ $default_directory_title = $default_directory_titles[$this->id];
126
+
127
+ // All globals for activity component.
128
+ // Note that global_tables is included in this array.
129
+ $args = array(
130
+ 'slug' => BP_ACTIVITY_SLUG,
131
+ 'root_slug' => isset( $bp->pages->activity->slug ) ? $bp->pages->activity->slug : BP_ACTIVITY_SLUG,
132
+ 'has_directory' => true,
133
+ 'directory_title' => isset( $bp->pages->activity->title ) ? $bp->pages->activity->title : $default_directory_title,
134
+ 'notification_callback' => 'bp_activity_format_notifications',
135
+ 'search_string' => __( 'Search Activity...', 'buddypress' ),
136
+ 'global_tables' => $global_tables,
137
+ 'meta_tables' => $meta_tables,
138
+ );
139
+
140
+ parent::setup_globals( $args );
141
+ }
142
+
143
+ /**
144
+ * Set up component navigation.
145
+ *
146
+ * @since 1.5.0
147
+ *
148
+ * @see BP_Component::setup_nav() for a description of arguments.
149
+ *
150
+ * @param array $main_nav Optional. See BP_Component::setup_nav() for description.
151
+ * @param array $sub_nav Optional. See BP_Component::setup_nav() for description.
152
+ */
153
+ public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
154
+
155
+ // Stop if there is no user displayed or logged in.
156
+ if ( ! is_user_logged_in() && ! bp_displayed_user_id() ) {
157
+ return;
158
+ }
159
+
160
+ // Determine user to use.
161
+ if ( bp_displayed_user_domain() ) {
162
+ $user_domain = bp_displayed_user_domain();
163
+ } elseif ( bp_loggedin_user_domain() ) {
164
+ $user_domain = bp_loggedin_user_domain();
165
+ } else {
166
+ return;
167
+ }
168
+
169
+ $slug = bp_get_activity_slug();
170
+ $activity_link = trailingslashit( $user_domain . $slug );
171
+
172
+ // Add 'Activity' to the main navigation.
173
+ $main_nav = array(
174
+ 'name' => _x( 'Activity', 'Profile activity screen nav', 'buddypress' ),
175
+ 'slug' => $slug,
176
+ 'position' => 10,
177
+ 'screen_function' => 'bp_activity_screen_my_activity',
178
+ 'default_subnav_slug' => 'just-me',
179
+ 'item_css_id' => $this->id
180
+ );
181
+
182
+ // Add the subnav items to the activity nav item if we are using a theme that supports this.
183
+ $sub_nav[] = array(
184
+ 'name' => _x( 'Personal', 'Profile activity screen sub nav', 'buddypress' ),
185
+ 'slug' => 'just-me',
186
+ 'parent_url' => $activity_link,
187
+ 'parent_slug' => $slug,
188
+ 'screen_function' => 'bp_activity_screen_my_activity',
189
+ 'position' => 10
190
+ );
191
+
192
+ // Check @mentions.
193
+ if ( bp_activity_do_mentions() ) {
194
+ $sub_nav[] = array(
195
+ 'name' => _x( 'Mentions', 'Profile activity screen sub nav', 'buddypress' ),
196
+ 'slug' => 'mentions',
197
+ 'parent_url' => $activity_link,
198
+ 'parent_slug' => $slug,
199
+ 'screen_function' => 'bp_activity_screen_mentions',
200
+ 'position' => 20,
201
+ 'item_css_id' => 'activity-mentions'
202
+ );
203
+ }
204
+
205
+ // Favorite activity items.
206
+ if ( bp_activity_can_favorite() ) {
207
+ $sub_nav[] = array(
208
+ 'name' => _x( 'Favorites', 'Profile activity screen sub nav', 'buddypress' ),
209
+ 'slug' => 'favorites',
210
+ 'parent_url' => $activity_link,
211
+ 'parent_slug' => $slug,
212
+ 'screen_function' => 'bp_activity_screen_favorites',
213
+ 'position' => 30,
214
+ 'item_css_id' => 'activity-favs'
215
+ );
216
+ }
217
+
218
+ // Additional menu if friends is active.
219
+ if ( bp_is_active( 'friends' ) ) {
220
+ $sub_nav[] = array(
221
+ 'name' => _x( 'Friends', 'Profile activity screen sub nav', 'buddypress' ),
222
+ 'slug' => bp_get_friends_slug(),
223
+ 'parent_url' => $activity_link,
224
+ 'parent_slug' => $slug,
225
+ 'screen_function' => 'bp_activity_screen_friends',
226
+ 'position' => 40,
227
+ 'item_css_id' => 'activity-friends'
228
+ ) ;
229
+ }
230
+
231
+ // Additional menu if groups is active.
232
+ if ( bp_is_active( 'groups' ) ) {
233
+ $sub_nav[] = array(
234
+ 'name' => _x( 'Groups', 'Profile activity screen sub nav', 'buddypress' ),
235
+ 'slug' => bp_get_groups_slug(),
236
+ 'parent_url' => $activity_link,
237
+ 'parent_slug' => $slug,
238
+ 'screen_function' => 'bp_activity_screen_groups',
239
+ 'position' => 50,
240
+ 'item_css_id' => 'activity-groups'
241
+ );
242
+ }
243
+
244
+ parent::setup_nav( $main_nav, $sub_nav );
245
+ }
246
+
247
+ /**
248
+ * Set up the component entries in the WordPress Admin Bar.
249
+ *
250
+ * @since 1.5.0
251
+ *
252
+ * @see BP_Component::setup_nav() for a description of the $wp_admin_nav
253
+ * parameter array.
254
+ *
255
+ * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a
256
+ * description.
257
+ */
258
+ public function setup_admin_bar( $wp_admin_nav = array() ) {
259
+
260
+ // Menus for logged in user.
261
+ if ( is_user_logged_in() ) {
262
+
263
+ // Setup the logged in user variables.
264
+ $activity_link = trailingslashit( bp_loggedin_user_domain() . bp_get_activity_slug() );
265
+
266
+ // Unread message count.
267
+ if ( bp_activity_do_mentions() ) {
268
+ $count = bp_get_total_mention_count_for_user( bp_loggedin_user_id() );
269
+ if ( !empty( $count ) ) {
270
+ $title = sprintf(
271
+ /* translators: %s: Unread mention count for the current user */
272
+ _x( 'Mentions %s', 'Toolbar Mention logged in user', 'buddypress' ),
273
+ '<span class="count">' . bp_core_number_format( $count ) . '</span>'
274
+ );
275
+ } else {
276
+ $title = _x( 'Mentions', 'Toolbar Mention logged in user', 'buddypress' );
277
+ }
278
+ }
279
+
280
+ // Add the "Activity" sub menu.
281
+ $wp_admin_nav[] = array(
282
+ 'parent' => buddypress()->my_account_menu_id,
283
+ 'id' => 'my-account-' . $this->id,
284
+ 'title' => _x( 'Activity', 'My Account Activity sub nav', 'buddypress' ),
285
+ 'href' => $activity_link
286
+ );
287
+
288
+ // Personal.
289
+ $wp_admin_nav[] = array(
290
+ 'parent' => 'my-account-' . $this->id,
291
+ 'id' => 'my-account-' . $this->id . '-personal',
292
+ 'title' => _x( 'Personal', 'My Account Activity sub nav', 'buddypress' ),
293
+ 'href' => $activity_link,
294
+ 'position' => 10
295
+ );
296
+
297
+ // Mentions.
298
+ if ( bp_activity_do_mentions() ) {
299
+ $wp_admin_nav[] = array(
300
+ 'parent' => 'my-account-' . $this->id,
301
+ 'id' => 'my-account-' . $this->id . '-mentions',
302
+ 'title' => $title,
303
+ 'href' => trailingslashit( $activity_link . 'mentions' ),
304
+ 'position' => 20
305
+ );
306
+ }
307
+
308
+ // Favorite activity items.
309
+ if ( bp_activity_can_favorite() ) {
310
+ $wp_admin_nav[] = array(
311
+ 'parent' => 'my-account-' . $this->id,
312
+ 'id' => 'my-account-' . $this->id . '-favorites',
313
+ 'title' => _x( 'Favorites', 'My Account Activity sub nav', 'buddypress' ),
314
+ 'href' => trailingslashit( $activity_link . 'favorites' ),
315
+ 'position' => 30
316
+ );
317
+ }
318
+
319
+ // Friends?
320
+ if ( bp_is_active( 'friends' ) ) {
321
+ $wp_admin_nav[] = array(
322
+ 'parent' => 'my-account-' . $this->id,
323
+ 'id' => 'my-account-' . $this->id . '-friends',
324
+ 'title' => _x( 'Friends', 'My Account Activity sub nav', 'buddypress' ),
325
+ 'href' => trailingslashit( $activity_link . bp_get_friends_slug() ),
326
+ 'position' => 40
327
+ );
328
+ }
329
+
330
+ // Groups?
331
+ if ( bp_is_active( 'groups' ) ) {
332
+ $wp_admin_nav[] = array(
333
+ 'parent' => 'my-account-' . $this->id,
334
+ 'id' => 'my-account-' . $this->id . '-groups',
335
+ 'title' => _x( 'Groups', 'My Account Activity sub nav', 'buddypress' ),
336
+ 'href' => trailingslashit( $activity_link . bp_get_groups_slug() ),
337
+ 'position' => 50
338
+ );
339
+ }
340
+ }
341
+
342
+ parent::setup_admin_bar( $wp_admin_nav );
343
+ }
344
+
345
+ /**
346
+ * Set up the title for pages and <title>.
347
+ *
348
+ * @since 1.5.0
349
+ *
350
+ */
351
+ public function setup_title() {
352
+
353
+ // Adjust title based on view.
354
+ if ( bp_is_activity_component() ) {
355
+ $bp = buddypress();
356
+
357
+ if ( bp_is_my_profile() ) {
358
+ $bp->bp_options_title = _x( 'My Activity', 'Page and <title>', 'buddypress' );
359
+ } else {
360
+ $bp->bp_options_avatar = bp_core_fetch_avatar( array(
361
+ 'item_id' => bp_displayed_user_id(),
362
+ 'type' => 'thumb',
363
+ 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
364
+ ) );
365
+ $bp->bp_options_title = bp_get_displayed_user_fullname();
366
+ }
367
+ }
368
+
369
+ parent::setup_title();
370
+ }
371
+
372
+ /**
373
+ * Setup cache groups.
374
+ *
375
+ * @since 2.2.0
376
+ */
377
+ public function setup_cache_groups() {
378
+
379
+ // Global groups.
380
+ wp_cache_add_global_groups( array(
381
+ 'bp_activity',
382
+ 'bp_activity_comments',
383
+ 'activity_meta'
384
+ ) );
385
+
386
+ parent::setup_cache_groups();
387
+ }
388
+ }
bp-activity/classes/class-bp-activity-feed.php ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Classes.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage ActivityFeeds
7
+ * @since 1.8.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Create a RSS feed using the activity component.
15
+ *
16
+ * You should only construct a new feed when you've validated that you're on
17
+ * the appropriate screen.
18
+ *
19
+ * @since 1.8.0
20
+ *
21
+ * See {@link bp_activity_action_sitewide_feed()} as an example.
22
+ *
23
+ * @param array $args {
24
+ * @type string $id Required. Internal id for the feed; should be alphanumeric only.
25
+ * @type string $title Optional. RSS feed title.
26
+ * @type string $link Optional. Relevant link for the RSS feed.
27
+ * @type string $description Optional. RSS feed description.
28
+ * @type string $ttl Optional. Time-to-live. (see inline doc in constructor)
29
+ * @type string $update_period Optional. Part of the syndication module.
30
+ * (see inline doc in constructor for more info)
31
+ * @type string $update_frequency Optional. Part of the syndication module.
32
+ * (see inline doc in constructor for more info)
33
+ * @type string $max Optional. Number of feed items to display.
34
+ * @type array $activity_args Optional. Arguments passed to {@link bp_has_activities()}
35
+ * }
36
+ */
37
+ class BP_Activity_Feed {
38
+
39
+ /**
40
+ * Holds our custom class properties.
41
+ *
42
+ * These variables are stored in a protected array that is magically
43
+ * updated using PHP 5.2+ methods.
44
+ *
45
+ * @see BP_Feed::__construct() This is where $data is added.
46
+ *
47
+ * @since 1.8.0
48
+ * @var array
49
+ */
50
+ protected $data;
51
+
52
+ /**
53
+ * Magic method for checking the existence of a certain data variable.
54
+ *
55
+ * @since 1.8.0
56
+ *
57
+ * @param string $key Property to check.
58
+ * @return bool Whether or not data variable exists.
59
+ */
60
+ public function __isset( $key ) { return isset( $this->data[$key] ); }
61
+
62
+ /**
63
+ * Magic method for getting a certain data variable.
64
+ *
65
+ * @since 1.8.0
66
+ *
67
+ * @param string $key Property to get.
68
+ * @return mixed Data in variable if available or null.
69
+ */
70
+ public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
71
+
72
+ /**
73
+ * Magic method for setting a certain data variable.
74
+ *
75
+ * @since 2.4.0
76
+ *
77
+ * @param string $key The property to set.
78
+ * @param mixed $value The value to set.
79
+ */
80
+ public function __set( $key, $value ) { $this->data[$key] = $value; }
81
+
82
+ /**
83
+ * Constructor.
84
+ *
85
+ * @since 1.8.0
86
+ *
87
+ * @param array $args Optional.
88
+ */
89
+ public function __construct( $args = array() ) {
90
+
91
+ /**
92
+ * Filters if BuddyPress should consider feeds enabled. If disabled, it will return early.
93
+ *
94
+ * @since 1.8.0
95
+ *
96
+ * @param bool true Default true aka feeds are enabled.
97
+ */
98
+ if ( false === (bool) apply_filters( 'bp_activity_enable_feeds', true ) ) {
99
+ global $wp_query;
100
+
101
+ // Set feed flag to false.
102
+ $wp_query->is_feed = false;
103
+
104
+ return false;
105
+ }
106
+
107
+ // Setup data.
108
+ $this->data = wp_parse_args( $args, array(
109
+ // Internal identifier for the RSS feed - should be alphanumeric only.
110
+ 'id' => '',
111
+
112
+ // RSS title - should be plain-text.
113
+ 'title' => '',
114
+
115
+ // Relevant link for the RSS feed.
116
+ 'link' => '',
117
+
118
+ // RSS description - should be plain-text.
119
+ 'description' => '',
120
+
121
+ // Time-to-live - number of minutes to cache the data before an aggregator
122
+ // requests it again. This is only acknowledged if the RSS client supports it
123
+ //
124
+ // See: http://www.rssboard.org/rss-profile#element-channel-ttl.
125
+ // See: http://www.kbcafe.com/rss/rssfeedstate.html#ttl.
126
+ 'ttl' => '30',
127
+
128
+ // Syndication module - similar to ttl, but not really supported by RSS
129
+ // clients
130
+ //
131
+ // See: http://web.resource.org/rss/1.0/modules/syndication/#description.
132
+ // See: http://www.kbcafe.com/rss/rssfeedstate.html#syndicationmodule.
133
+ 'update_period' => 'hourly',
134
+ 'update_frequency' => 2,
135
+
136
+ // Number of items to display.
137
+ 'max' => 50,
138
+
139
+ // Activity arguments passed to bp_has_activities().
140
+ 'activity_args' => array()
141
+ ) );
142
+
143
+ /**
144
+ * Fires before the feed is setup so plugins can modify.
145
+ *
146
+ * @since 1.8.0
147
+ *
148
+ * @param BP_Activity_Feed $this Current instance of activity feed. Passed by reference.
149
+ */
150
+ do_action_ref_array( 'bp_activity_feed_prefetch', array( &$this ) );
151
+
152
+ // Setup class properties.
153
+ $this->setup_properties();
154
+
155
+ // Check if id is valid.
156
+ if ( empty( $this->id ) ) {
157
+ _doing_it_wrong( 'BP_Activity_Feed', __( "RSS feed 'id' must be defined", 'buddypress' ), 'BP 1.8' );
158
+ return false;
159
+ }
160
+
161
+ /**
162
+ * Fires after the feed is setup so plugins can modify.
163
+ *
164
+ * @since 1.8.0
165
+ *
166
+ * @param BP_Activity_Feed $this Current instance of activity feed. Passed by reference.
167
+ */
168
+ do_action_ref_array( 'bp_activity_feed_postfetch', array( &$this ) );
169
+
170
+ // Setup feed hooks.
171
+ $this->setup_hooks();
172
+
173
+ // Output the feed.
174
+ $this->output();
175
+
176
+ // Kill the rest of the output.
177
+ die();
178
+ }
179
+
180
+ /** SETUP ****************************************************************/
181
+
182
+ /**
183
+ * Setup and validate the class properties.
184
+ *
185
+ * @since 1.8.0
186
+ */
187
+ protected function setup_properties() {
188
+ $this->id = sanitize_title( $this->id );
189
+ $this->title = strip_tags( $this->title );
190
+ $this->link = esc_url_raw( $this->link );
191
+ $this->description = strip_tags( $this->description );
192
+ $this->ttl = (int) $this->ttl;
193
+ $this->update_period = strip_tags( $this->update_period );
194
+ $this->update_frequency = (int) $this->update_frequency;
195
+
196
+ $this->activity_args = wp_parse_args( $this->activity_args, array(
197
+ 'max' => $this->max,
198
+ 'per_page' => $this->max,
199
+ 'display_comments' => 'stream'
200
+ ) );
201
+
202
+ }
203
+
204
+ /**
205
+ * Setup some hooks that are used in the feed.
206
+ *
207
+ * Currently, these hooks are used to maintain backwards compatibility with
208
+ * the RSS feeds previous to BP 1.8.
209
+ *
210
+ * @since 1.8.0
211
+ */
212
+ protected function setup_hooks() {
213
+ add_action( 'bp_activity_feed_rss_attributes', array( $this, 'backpat_rss_attributes' ) );
214
+ add_action( 'bp_activity_feed_channel_elements', array( $this, 'backpat_channel_elements' ) );
215
+ add_action( 'bp_activity_feed_item_elements', array( $this, 'backpat_item_elements' ) );
216
+ }
217
+
218
+ /** BACKPAT HOOKS ********************************************************/
219
+
220
+ /**
221
+ * Fire a hook to ensure backward compatibility for RSS attributes.
222
+ *
223
+ * @since 1.8.0
224
+ */
225
+ public function backpat_rss_attributes() {
226
+
227
+ /**
228
+ * Fires inside backpat_rss_attributes method for backwards compatibility related to RSS attributes.
229
+ *
230
+ * This hook was originally separated out for individual components but has since been abstracted into the BP_Activity_Feed class.
231
+ *
232
+ * @since 1.0.0
233
+ */
234
+ do_action( 'bp_activity_' . $this->id . '_feed' );
235
+ }
236
+
237
+ /**
238
+ * Fire a hook to ensure backward compatibility for channel elements.
239
+ *
240
+ * @since 1.8.0
241
+ */
242
+ public function backpat_channel_elements() {
243
+
244
+ /**
245
+ * Fires inside backpat_channel_elements method for backwards compatibility related to RSS channel elements.
246
+ *
247
+ * This hook was originally separated out for individual components but has since been abstracted into the BP_Activity_Feed class.
248
+ *
249
+ * @since 1.0.0
250
+ */
251
+ do_action( 'bp_activity_' . $this->id . '_feed_head' );
252
+ }
253
+
254
+ /**
255
+ * Fire a hook to ensure backward compatibility for item elements.
256
+ *
257
+ * @since 1.8.0
258
+ */
259
+ public function backpat_item_elements() {
260
+ switch ( $this->id ) {
261
+
262
+ // Sitewide and friends feeds use the 'personal' hook.
263
+ case 'sitewide' :
264
+ case 'friends' :
265
+ $id = 'personal';
266
+
267
+ break;
268
+
269
+ default :
270
+ $id = $this->id;
271
+
272
+ break;
273
+ }
274
+
275
+ /**
276
+ * Fires inside backpat_item_elements method for backwards compatibility related to RSS item elements.
277
+ *
278
+ * This hook was originally separated out for individual components but has since been abstracted into the BP_Activity_Feed class.
279
+ *
280
+ * @since 1.0.0
281
+ */
282
+ do_action( 'bp_activity_' . $id . '_feed_item' );
283
+ }
284
+
285
+ /** HELPERS **************************************************************/
286
+
287
+ /**
288
+ * Output the feed's item content.
289
+ *
290
+ * @since 1.8.0
291
+ */
292
+ protected function feed_content() {
293
+ bp_activity_content_body();
294
+
295
+ switch ( $this->id ) {
296
+
297
+ // Also output parent activity item if we're on a specific feed.
298
+ case 'favorites' :
299
+ case 'friends' :
300
+ case 'mentions' :
301
+ case 'personal' :
302
+
303
+ if ( 'activity_comment' == bp_get_activity_action_name() ) :
304
+ ?>
305
+ <strong><?php _e( 'In reply to', 'buddypress' ) ?></strong> -
306
+ <?php bp_activity_parent_content() ?>
307
+ <?php
308
+ endif;
309
+
310
+ break;
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Sets various HTTP headers related to Content-Type and browser caching.
316
+ *
317
+ * Most of this class method is derived from {@link WP::send_headers()}.
318
+ *
319
+ * @since 1.9.0
320
+ */
321
+ protected function http_headers() {
322
+ // Set up some additional headers if not on a directory page
323
+ // this is done b/c BP uses pseudo-pages.
324
+ if ( ! bp_is_directory() ) {
325
+ global $wp_query;
326
+
327
+ $wp_query->is_404 = false;
328
+ status_header( 200 );
329
+ }
330
+
331
+ // Set content-type.
332
+ @header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
333
+ send_nosniff_header();
334
+
335
+ // Cache-related variables.
336
+ $last_modified = mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false );
337
+ $modified_timestamp = strtotime( $last_modified );
338
+ $etag = md5( $last_modified );
339
+
340
+ // Set cache-related headers.
341
+ @header( 'Last-Modified: ' . $last_modified );
342
+ @header( 'Pragma: no-cache' );
343
+ @header( 'ETag: ' . '"' . $etag . '"' );
344
+
345
+ // First commit of BuddyPress! (Easter egg).
346
+ @header( 'Expires: Tue, 25 Mar 2008 17:13:55 GMT');
347
+
348
+ // Get ETag from supported user agents.
349
+ if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
350
+ $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
351
+
352
+ // Remove quotes from ETag.
353
+ $client_etag = trim( $client_etag, '"' );
354
+
355
+ // Strip suffixes from ETag if they exist (eg. "-gzip").
356
+ $etag_suffix_pos = strpos( $client_etag, '-' );
357
+ if ( ! empty( $etag_suffix_pos ) ) {
358
+ $client_etag = substr( $client_etag, 0, $etag_suffix_pos );
359
+ }
360
+
361
+ // No ETag found.
362
+ } else {
363
+ $client_etag = false;
364
+ }
365
+
366
+ // Get client last modified timestamp from supported user agents.
367
+ $client_last_modified = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
368
+ $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
369
+
370
+ // Set 304 status if feed hasn't been updated since last fetch.
371
+ if ( ( $client_last_modified && $client_etag ) ?
372
+ ( ( $client_modified_timestamp >= $modified_timestamp ) && ( $client_etag == $etag ) ) :
373
+ ( ( $client_modified_timestamp >= $modified_timestamp ) || ( $client_etag == $etag ) ) ) {
374
+ $status = 304;
375
+ } else {
376
+ $status = false;
377
+ }
378
+
379
+ // If feed hasn't changed as reported by the user agent, set 304 status header.
380
+ if ( ! empty( $status ) ) {
381
+ status_header( $status );
382
+
383
+ // Cached response, so stop now!
384
+ if ( $status == 304 ) {
385
+ exit();
386
+ }
387
+ }
388
+ }
389
+
390
+ /** OUTPUT ***************************************************************/
391
+
392
+ /**
393
+ * Output the RSS feed.
394
+ *
395
+ * @since 1.8.0
396
+ */
397
+ protected function output() {
398
+ $this->http_headers();
399
+ echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?'.'>';
400
+ ?>
401
+
402
+ <rss version="2.0"
403
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
404
+ xmlns:atom="http://www.w3.org/2005/Atom"
405
+ xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
406
+ xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
407
+ <?php
408
+
409
+ /**
410
+ * Fires at the end of the opening RSS tag for feed output so plugins can add extra attributes.
411
+ *
412
+ * @since 1.8.0
413
+ */
414
+ do_action( 'bp_activity_feed_rss_attributes' ); ?>
415
+ >
416
+
417
+ <channel>
418
+ <title><?php echo $this->title; ?></title>
419
+ <link><?php echo $this->link; ?></link>
420
+ <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
421
+ <description><?php echo $this->description ?></description>
422
+ <lastBuildDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false ); ?></lastBuildDate>
423
+ <generator>https://buddypress.org/?v=<?php bp_version(); ?></generator>
424
+ <language><?php bloginfo_rss( 'language' ); ?></language>
425
+ <ttl><?php echo $this->ttl; ?></ttl>
426
+ <sy:updatePeriod><?php echo $this->update_period; ?></sy:updatePeriod>
427
+ <sy:updateFrequency><?php echo $this->update_frequency; ?></sy:updateFrequency>
428
+ <?php
429
+
430
+ /**
431
+ * Fires at the end of channel elements list in RSS feed so plugins can add extra channel elements.
432
+ *
433
+ * @since 1.8.0
434
+ */
435
+ do_action( 'bp_activity_feed_channel_elements' ); ?>
436
+
437
+ <?php if ( bp_has_activities( $this->activity_args ) ) : ?>
438
+ <?php while ( bp_activities() ) : bp_the_activity(); ?>
439
+ <item>
440
+ <guid isPermaLink="false"><?php bp_activity_feed_item_guid(); ?></guid>
441
+ <title><?php echo stripslashes( bp_get_activity_feed_item_title() ); ?></title>
442
+ <link><?php bp_activity_thread_permalink() ?></link>
443
+ <pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_get_activity_feed_item_date(), false ); ?></pubDate>
444
+
445
+ <?php if ( bp_get_activity_feed_item_description() ) : ?>
446
+ <content:encoded><![CDATA[<?php $this->feed_content(); ?>]]></content:encoded>
447
+ <?php endif; ?>
448
+
449
+ <?php if ( bp_activity_can_comment() ) : ?>
450
+ <slash:comments><?php bp_activity_comment_count(); ?></slash:comments>
451
+ <?php endif; ?>
452
+
453
+ <?php
454
+
455
+ /**
456
+ * Fires at the end of the individual RSS Item list in RSS feed so plugins can add extra item elements.
457
+ *
458
+ * @since 1.8.0
459
+ */
460
+ do_action( 'bp_activity_feed_item_elements' ); ?>
461
+ </item>
462
+ <?php endwhile; ?>
463
+
464
+ <?php endif; ?>
465
+ </channel>
466
+ </rss><?php
467
+ }
468
+ }
bp-activity/classes/class-bp-activity-list-table.php ADDED
@@ -0,0 +1,862 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity component admin list table.
4
+ *
5
+ * Props to WordPress core for the Comments admin screen, and its contextual
6
+ * help text, on which this implementation is heavily based.
7
+ *
8
+ * @package BuddyPress
9
+ * @subpackage ActivityAdmin
10
+ * @since 1.6.0
11
+ */
12
+
13
+ // Exit if accessed directly.
14
+ defined( 'ABSPATH' ) || exit;
15
+
16
+ /**
17
+ * List table class for the Activity component admin page.
18
+ *
19
+ * @since 1.6.0
20
+ */
21
+ class BP_Activity_List_Table extends WP_List_Table {
22
+
23
+ /**
24
+ * What type of view is being displayed?
25
+ *
26
+ * E.g. "all", "pending", "approved", "spam"...
27
+ *
28
+ * @since 1.6.0
29
+ * @var string $view
30
+ */
31
+ public $view = 'all';
32
+
33
+ /**
34
+ * How many activity items have been marked as spam.
35
+ *
36
+ * @since 1.6.0
37
+ * @var int $spam_count
38
+ */
39
+ public $spam_count = 0;
40
+
41
+ /**
42
+ * Store activity-to-user-ID mappings for use in the In Response To column.
43
+ *
44
+ * @since 1.6.0
45
+ * @var array $activity_user_id
46
+ */
47
+ protected $activity_user_id = array();
48
+
49
+ /**
50
+ * If users can comment on blog & forum activity items.
51
+ *
52
+ * @link https://buddypress.trac.wordpress.org/ticket/6277
53
+ *
54
+ * @since 2.2.2
55
+ * @var bool $disable_blogforum_comments
56
+ */
57
+ public $disable_blogforum_comments = false;
58
+
59
+ /**
60
+ * Constructor.
61
+ *
62
+ * @since 1.6.0
63
+ */
64
+ public function __construct() {
65
+
66
+ // See if activity commenting is enabled for blog / forum activity items.
67
+ $this->disable_blogforum_comments = bp_disable_blogforum_comments();
68
+
69
+ // Define singular and plural labels, as well as whether we support AJAX.
70
+ parent::__construct( array(
71
+ 'ajax' => false,
72
+ 'plural' => 'activities',
73
+ 'singular' => 'activity',
74
+ 'screen' => get_current_screen(),
75
+ ) );
76
+ }
77
+
78
+ /**
79
+ * Handle filtering of data, sorting, pagination, and any other data manipulation prior to rendering.
80
+ *
81
+ * @since 1.6.0
82
+ */
83
+ function prepare_items() {
84
+
85
+ // Option defaults.
86
+ $filter = array();
87
+ $filter_query = false;
88
+ $include_id = false;
89
+ $search_terms = false;
90
+ $sort = 'DESC';
91
+ $spam = 'ham_only';
92
+
93
+ // Set current page.
94
+ $page = $this->get_pagenum();
95
+
96
+ // Set per page from the screen options.
97
+ $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );
98
+
99
+ // Check if we're on the "Spam" view.
100
+ if ( !empty( $_REQUEST['activity_status'] ) && 'spam' == $_REQUEST['activity_status'] ) {
101
+ $spam = 'spam_only';
102
+ $this->view = 'spam';
103
+ }
104
+
105
+ // Sort order.
106
+ if ( !empty( $_REQUEST['order'] ) && 'desc' != $_REQUEST['order'] )
107
+ $sort = 'ASC';
108
+
109
+ // Order by.
110
+ /*if ( !empty( $_REQUEST['orderby'] ) ) {
111
+ }*/
112
+
113
+ // Filter.
114
+ if ( ! empty( $_REQUEST['activity_type'] ) ) {
115
+ $filter = array( 'action' => $_REQUEST['activity_type'] );
116
+
117
+ /**
118
+ * Filter here to override the filter with a filter query
119
+ *
120
+ * @since 2.5.0
121
+ *
122
+ * @param array $filter
123
+ */
124
+ $has_filter_query = apply_filters( 'bp_activity_list_table_filter_activity_type_items', $filter );
125
+
126
+ if ( ! empty( $has_filter_query['filter_query'] ) ) {
127
+ // Reset the filter
128
+ $filter = array();
129
+
130
+ // And use the filter query instead
131
+ $filter_query = $has_filter_query['filter_query'];
132
+ }
133
+ }
134
+
135
+ // Are we doing a search?
136
+ if ( !empty( $_REQUEST['s'] ) )
137
+ $search_terms = $_REQUEST['s'];
138
+
139
+ // Check if user has clicked on a specific activity (if so, fetch only that, and any related, activity).
140
+ if ( !empty( $_REQUEST['aid'] ) )
141
+ $include_id = (int) $_REQUEST['aid'];
142
+
143
+ // Get the spam total (ignoring any search query or filter).
144
+ $spams = bp_activity_get( array(
145
+ 'display_comments' => 'stream',
146
+ 'show_hidden' => true,
147
+ 'spam' => 'spam_only',
148
+ 'count_total' => 'count_query',
149
+ ) );
150
+ $this->spam_count = $spams['total'];
151
+ unset( $spams );
152
+
153
+ // Get the activities from the database.
154
+ $activities = bp_activity_get( array(
155
+ 'display_comments' => 'stream',
156
+ 'filter' => $filter,
157
+ 'in' => $include_id,
158
+ 'page' => $page,
159
+ 'per_page' => $per_page,
160
+ 'search_terms' => $search_terms,
161
+ 'filter_query' => $filter_query,
162
+ 'show_hidden' => true,
163
+ // 'sort' => $sort,
164
+ 'spam' => $spam,
165
+ 'count_total' => 'count_query',
166
+ ) );
167
+
168
+ // If we're viewing a specific activity, flatten all activities into a single array.
169
+ if ( $include_id ) {
170
+ $activities['activities'] = BP_Activity_List_Table::flatten_activity_array( $activities['activities'] );
171
+ $activities['total'] = count( $activities['activities'] );
172
+
173
+ // Sort the array by the activity object's date_recorded value.
174
+ usort( $activities['activities'], create_function( '$a, $b', 'return $a->date_recorded > $b->date_recorded;' ) );
175
+ }
176
+
177
+ // The bp_activity_get function returns an array of objects; cast these to arrays for WP_List_Table.
178
+ $new_activities = array();
179
+ foreach ( $activities['activities'] as $activity_item ) {
180
+ $new_activities[] = (array) $activity_item;
181
+
182
+ // Build an array of activity-to-user ID mappings for better efficiency in the In Response To column.
183
+ $this->activity_user_id[$activity_item->id] = $activity_item->user_id;
184
+ }
185
+
186
+ // Set raw data to display.
187
+ $this->items = $new_activities;
188
+
189
+ // Store information needed for handling table pagination.
190
+ $this->set_pagination_args( array(
191
+ 'per_page' => $per_page,
192
+ 'total_items' => $activities['total'],
193
+ 'total_pages' => ceil( $activities['total'] / $per_page )
194
+ ) );
195
+
196
+ // Don't truncate activity items; bp_activity_truncate_entry() needs to be used inside a BP_Activity_Template loop.
197
+ remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
198
+ }
199
+
200
+ /**
201
+ * Get an array of all the columns on the page.
202
+ *
203
+ * @since 1.6.0
204
+ *
205
+ * @return array Column headers.
206
+ */
207
+ function get_column_info() {
208
+ $this->_column_headers = array(
209
+ $this->get_columns(),
210
+ array(),
211
+ $this->get_sortable_columns(),
212
+ $this->get_default_primary_column_name(),
213
+ );
214
+
215
+ return $this->_column_headers;
216
+ }
217
+
218
+ /**
219
+ * Get name of default primary column
220
+ *
221
+ * @since 2.3.3
222
+ *
223
+ * @return string
224
+ */
225
+ protected function get_default_primary_column_name() {
226
+ return 'author';
227
+ }
228
+
229
+ /**
230
+ * Display a message on screen when no items are found (e.g. no search matches).
231
+ *
232
+ * @since 1.6.0
233
+ */
234
+ function no_items() {
235
+ _e( 'No activities found.', 'buddypress' );
236
+ }
237
+
238
+ /**
239
+ * Output the Activity data table.
240
+ *
241
+ * @since 1.6.0
242
+ */
243
+ function display() {
244
+ $this->display_tablenav( 'top' ); ?>
245
+
246
+ <h2 class="screen-reader-text"><?php
247
+ /* translators: accessibility text */
248
+ _e( 'Activities list', 'buddypress' );
249
+ ?></h2>
250
+
251
+ <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
252
+ <thead>
253
+ <tr>
254
+ <?php $this->print_column_headers(); ?>
255
+ </tr>
256
+ </thead>
257
+
258
+ <tbody id="the-comment-list">
259
+ <?php $this->display_rows_or_placeholder(); ?>
260
+ </tbody>
261
+
262
+ <tfoot>
263
+ <tr>
264
+ <?php $this->print_column_headers( false ); ?>
265
+ </tr>
266
+ </tfoot>
267
+ </table>
268
+ <?php
269
+
270
+ $this->display_tablenav( 'bottom' );
271
+ }
272
+
273
+ /**
274
+ * Generate content for a single row of the table.
275
+ *
276
+ * @since 1.6.0
277
+ *
278
+ * @param object $item The current item.
279
+ */
280
+ function single_row( $item ) {
281
+ static $even = false;
282
+
283
+ if ( $even ) {
284
+ $row_class = ' class="even"';
285
+ } else {
286
+ $row_class = ' class="alternate odd"';
287
+ }
288
+
289
+ if ( 'activity_comment' === $item['type'] ) {
290
+ $root_id = $item['item_id'];
291
+ } else {
292
+ $root_id = $item['id'];
293
+ }
294
+
295
+ echo '<tr' . $row_class . ' id="activity-' . esc_attr( $item['id'] ) . '" data-parent_id="' . esc_attr( $item['id'] ) . '" data-root_id="' . esc_attr( $root_id ) . '">';
296
+ echo $this->single_row_columns( $item );
297
+ echo '</tr>';
298
+
299
+ $even = ! $even;
300
+ }
301
+
302
+ /**
303
+ * Get the list of views available on this table (e.g. "all", "spam").
304
+ *
305
+ * @since 1.6.0
306
+ */
307
+ function get_views() {
308
+ $url_base = add_query_arg( array( 'page' => 'bp-activity' ), bp_get_admin_url( 'admin.php' ) ); ?>
309
+
310
+ <h2 class="screen-reader-text"><?php
311
+ /* translators: accessibility text */
312
+ _e( 'Filter activities list', 'buddypress' );
313
+ ?></h2>
314
+
315
+ <ul class="subsubsub">
316
+ <li class="all"><a href="<?php echo esc_url( $url_base ); ?>" class="<?php if ( 'spam' != $this->view ) echo 'current'; ?>"><?php _e( 'All', 'buddypress' ); ?></a> |</li>
317
+ <li class="spam"><a href="<?php echo esc_url( add_query_arg( array( 'activity_status' => 'spam' ), $url_base ) ); ?>" class="<?php if ( 'spam' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Spam <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->spam_count ) ); ?></a></li>
318
+
319
+ <?php
320
+
321
+ /**
322
+ * Fires inside listing of views so plugins can add their own.
323
+ *
324
+ * @since 1.6.0
325
+ *
326
+ * @param string $url_base Current URL base for view.
327
+ * @param string $view Current view being displayed.
328
+ */
329
+ do_action( 'bp_activity_list_table_get_views', $url_base, $this->view ); ?>
330
+ </ul>
331
+ <?php
332
+ }
333
+
334
+ /**
335
+ * Get bulk actions.
336
+ *
337
+ * @since 1.6.0
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.
349
+ *
350
+ * @since 1.6.0
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
+ /**
358
+ * Get the table column titles.
359
+ *
360
+ * @since 1.6.0
361
+ *
362
+ * @see WP_List_Table::single_row_columns()
363
+ *
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
+ *
370
+ * @since 2.4.0
371
+ *
372
+ * @param array $value Array of slugs and titles for the columns.
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' ),
380
+ ) );
381
+ }
382
+
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
+ /**
403
+ * Markup for the "filter" part of the form (i.e. which activity type to display).
404
+ *
405
+ * @since 1.6.0
406
+ *
407
+ * @param string $which 'top' or 'bottom'.
408
+ */
409
+ function extra_tablenav( $which ) {
410
+
411
+ // Bail on bottom table nav.
412
+ if ( 'bottom' === $which ) {
413
+ return;
414
+ }
415
+
416
+ // Is any filter currently selected?
417
+ $selected = ( ! empty( $_REQUEST['activity_type'] ) ) ? $_REQUEST['activity_type'] : '';
418
+
419
+ // Get the actions.
420
+ $activity_actions = bp_activity_get_actions(); ?>
421
+
422
+ <div class="alignleft actions">
423
+ <label for="activity-type" class="screen-reader-text"><?php
424
+ /* translators: accessibility text */
425
+ _e( 'Filter by activity type', 'buddypress' );
426
+ ?></label>
427
+ <select name="activity_type" id="activity-type">
428
+ <option value="" <?php selected( ! $selected ); ?>><?php _e( 'View all actions', 'buddypress' ); ?></option>
429
+
430
+ <?php foreach ( $activity_actions as $component => $actions ) : ?>
431
+ <?php
432
+ // Older avatar activity items use 'profile' for component. See r4273.
433
+ if ( $component === 'profile' ) {
434
+ $component = 'xprofile';
435
+ }
436
+
437
+ if ( bp_is_active( $component ) ) {
438
+ if ( $component === 'xprofile' ) {
439
+ $component_name = buddypress()->profile->name;
440
+ } else {
441
+ $component_name = buddypress()->$component->name;
442
+ }
443
+
444
+ } else {
445
+ // Prevent warnings by other plugins if a component is disabled but the activity type has been registered.
446
+ $component_name = ucfirst( $component );
447
+ }
448
+ ?>
449
+
450
+ <optgroup label="<?php echo esc_html( $component_name ); ?>">
451
+
452
+ <?php foreach ( $actions as $action_key => $action_values ) : ?>
453
+
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
+
461
+ <?php endif; ?>
462
+
463
+ <?php endforeach; ?>
464
+
465
+ </optgroup>
466
+
467
+ <?php endforeach; ?>
468
+
469
+ </select>
470
+
471
+ <?php submit_button( __( 'Filter', 'buddypress' ), 'secondary', false, false, array( 'id' => 'post-query-submit' ) ); ?>
472
+ </div>
473
+
474
+ <?php
475
+ }
476
+
477
+ /**
478
+ * Override WP_List_Table::row_actions().
479
+ *
480
+ * Basically a duplicate of the row_actions() method, but removes the
481
+ * unnecessary <button> addition.
482
+ *
483
+ * @since 2.3.3
484
+ * @since 2.3.4 Visibility set to public for compatibility with WP < 4.0.0.
485
+ *
486
+ * @param array $actions The list of actions.
487
+ * @param bool $always_visible Whether the actions should be always visible.
488
+ * @return string
489
+ */
490
+ public function row_actions( $actions, $always_visible = false ) {
491
+ $action_count = count( $actions );
492
+ $i = 0;
493
+
494
+ if ( !$action_count )
495
+ return '';
496
+
497
+ $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
498
+ foreach ( $actions as $action => $link ) {
499
+ ++$i;
500
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
501
+ $out .= "<span class='$action'>$link$sep</span>";
502
+ }
503
+ $out .= '</div>';
504
+
505
+ return $out;
506
+ }
507
+
508
+ /**
509
+ * Checkbox column markup.
510
+ *
511
+ * @since 1.6.0
512
+ *
513
+ * @see WP_List_Table::single_row_columns()
514
+ *
515
+ * @param array $item A singular item (one full row).
516
+ */
517
+ function column_cb( $item ) {
518
+ /* translators: accessibility text */
519
+ printf( '<label class="screen-reader-text" for="aid-%1$d">' . __( 'Select activity item %1$d', 'buddypress' ) . '</label><input type="checkbox" name="aid[]" value="%1$d" id="aid-%1$d" />', $item['id'] );
520
+ }
521
+
522
+ /**
523
+ * Author column markup.
524
+ *
525
+ * @since 1.6.0
526
+ *
527
+ * @see WP_List_Table::single_row_columns()
528
+ *
529
+ * @param array $item A singular item (one full row).
530
+ */
531
+ function column_author( $item ) {
532
+ echo '<strong>' . get_avatar( $item['user_id'], '32' ) . ' ' . bp_core_get_userlink( $item['user_id'] ) . '</strong>';
533
+ }
534
+
535
+ /**
536
+ * Action column markup.
537
+ *
538
+ * @since 2.0.0
539
+ *
540
+ * @see WP_List_Table::single_row_columns()
541
+ *
542
+ * @param array $item A singular item (one full row).
543
+ */
544
+ function column_action( $item ) {
545
+ $actions = bp_activity_admin_get_activity_actions();
546
+
547
+ if ( isset( $actions[ $item['type'] ] ) ) {
548
+ echo $actions[ $item['type'] ];
549
+ } else {
550
+ printf( __( 'Unregistered action - %s', 'buddypress' ), $item['type'] );
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Content column, and "quick admin" rollover actions.
556
+ *
557
+ * Called "comment" in the CSS so we can re-use some WP core CSS.
558
+ *
559
+ * @since 1.6.0
560
+ *
561
+ * @see WP_List_Table::single_row_columns()
562
+ *
563
+ * @param array $item A singular item (one full row).
564
+ */
565
+ function column_comment( $item ) {
566
+ // Determine what type of item (row) we're dealing with.
567
+ if ( $item['is_spam'] )
568
+ $item_status = 'spam';
569
+ else
570
+ $item_status = 'all';
571
+
572
+ // Preorder items: Reply | Edit | Spam | Delete Permanently.
573
+ $actions = array(
574
+ 'reply' => '',
575
+ 'edit' => '',
576
+ 'spam' => '', 'unspam' => '',
577
+ 'delete' => '',
578
+ );
579
+
580
+ // Build actions URLs.
581
+ $base_url = bp_get_admin_url( 'admin.php?page=bp-activity&amp;aid=' . $item['id'] );
582
+ $spam_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'spam-activity_' . $item['id'] ) );
583
+
584
+ $delete_url = $base_url . "&amp;action=delete&amp;$spam_nonce";
585
+ $edit_url = $base_url . '&amp;action=edit';
586
+ $ham_url = $base_url . "&amp;action=ham&amp;$spam_nonce";
587
+ $spam_url = $base_url . "&amp;action=spam&amp;$spam_nonce";
588
+
589
+ // Rollover actions.
590
+ // Reply - JavaScript only; implemented by AJAX.
591
+ if ( 'spam' != $item_status ) {
592
+ if ( $this->can_comment( $item ) ) {
593
+ $actions['reply'] = sprintf( '<a href="#" class="reply hide-if-no-js">%s</a>', __( 'Reply', 'buddypress' ) );
594
+ } else {
595
+ $actions['reply'] = sprintf( '<span class="form-input-tip" title="%s">%s</span>', __( 'Replies are disabled for this activity item', 'buddypress' ), __( 'Replies disabled', 'buddypress' ) );
596
+ }
597
+
598
+ // Edit.
599
+ $actions['edit'] = sprintf( '<a href="%s">%s</a>', $edit_url, __( 'Edit', 'buddypress' ) );
600
+ }
601
+
602
+ // Spam/unspam.
603
+ if ( 'spam' == $item_status )
604
+ $actions['unspam'] = sprintf( '<a href="%s">%s</a>', $ham_url, __( 'Not Spam', 'buddypress' ) );
605
+ else
606
+ $actions['spam'] = sprintf( '<a href="%s">%s</a>', $spam_url, __( 'Spam', 'buddypress' ) );
607
+
608
+ // Delete.
609
+ $actions['delete'] = sprintf( '<a href="%s" onclick="%s">%s</a>', $delete_url, "javascript:return confirm('" . esc_js( __( 'Are you sure?', 'buddypress' ) ) . "'); ", __( 'Delete Permanently', 'buddypress' ) );
610
+
611
+ // Start timestamp.
612
+ echo '<div class="submitted-on">';
613
+
614
+ /**
615
+ * Filters available actions for plugins to alter.
616
+ *
617
+ * @since 1.6.0
618
+ *
619
+ * @param array $actions Array of available actions user could use.
620
+ * @param array $item Current item being added to page.
621
+ */
622
+ $actions = apply_filters( 'bp_activity_admin_comment_row_actions', array_filter( $actions ), $item );
623
+
624
+ printf(
625
+ /* translators: %s: activity date and time */
626
+ __( 'Submitted on %s', 'buddypress' ),
627
+ sprintf(
628
+ '<a href="%1$s">%2$s</a>',
629
+ bp_activity_get_permalink( $item['id'] ),
630
+ sprintf(
631
+ /* translators: 1: activity date, 2: activity time */
632
+ __( '%1$s at %2$s', 'buddypress' ),
633
+ date_i18n( bp_get_option( 'date_format' ), strtotime( $item['date_recorded'] ) ),
634
+ get_date_from_gmt( $item['date_recorded'], bp_get_option( 'time_format' ) )
635
+ )
636
+ )
637
+ );
638
+
639
+ // End timestamp.
640
+ echo '</div>';
641
+
642
+ // Get activity content - if not set, use the action.
643
+ if ( ! empty( $item['content'] ) ) {
644
+
645
+ /**
646
+ * Filters current activity item content.
647
+ *
648
+ * @since 1.2.0
649
+ *
650
+ * @param array $item Array index holding current activity item content.
651
+ */
652
+ $content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $item['content'] ) );
653
+ } else {
654
+ /**
655
+ * Filters current activity item action.
656
+ *
657
+ * @since 1.2.0
658
+ *
659
+ * @var array $item Array index holding current activity item action.
660
+ */
661
+ $content = apply_filters_ref_array( 'bp_get_activity_action', array( $item['action'] ) );
662
+ }
663
+
664
+ /**
665
+ * Filter here to add extra output to the activity content into the Administration.
666
+ *
667
+ * @since 2.4.0
668
+ *
669
+ * @param string $content The activity content.
670
+ * @param array $item The activity object converted into an array.
671
+ */
672
+ echo apply_filters( 'bp_activity_admin_comment_content', $content, $item ) . ' ' . $this->row_actions( $actions );
673
+ }
674
+
675
+ /**
676
+ * "In response to" column markup.
677
+ *
678
+ * @since 1.6.0
679
+ *
680
+ * @see WP_List_Table::single_row_columns()
681
+ *
682
+ * @param array $item A singular item (one full row).
683
+ */
684
+ function column_response( $item ) {
685
+
686
+ // Is $item is a root activity?
687
+ ?>
688
+
689
+ <div class="response-links">
690
+
691
+ <?php
692
+ // Activity permalink.
693
+ $activity_permalink = '';
694
+ if ( ! $item['is_spam'] ) {
695
+ $activity_permalink = '<a href="' . bp_activity_get_permalink( $item['id'], (object) $item ) . '" class="comments-view-item-link">' . __( 'View Activity', 'buddypress' ) . '</a>';
696
+ }
697
+
698
+ /**
699
+ * Filters default list of default root activity types.
700
+ *
701
+ * @since 1.6.0
702
+ *
703
+ * @param array $value Array of default activity types.
704
+ * @param array $item Current item being displayed.
705
+ */
706
+ if ( empty( $item['item_id'] ) || ! in_array( $item['type'], apply_filters( 'bp_activity_admin_root_activity_types', array( 'activity_comment' ), $item ) ) ) {
707
+ echo $activity_permalink;
708
+
709
+ $comment_count = !empty( $item['children'] ) ? bp_activity_recurse_comment_count( (object) $item ) : 0;
710
+ $root_activity_url = bp_get_admin_url( 'admin.php?page=bp-activity&amp;aid=' . $item['id'] );
711
+
712
+ // If the activity has comments, display a link to the activity's permalink, with its comment count in a speech bubble.
713
+ if ( $comment_count ) {
714
+ $title_attr = sprintf( _n( '%s related activity', '%s related activities', $comment_count, 'buddypress' ), number_format_i18n( $comment_count ) );
715
+ printf( '<a href="%1$s" title="%2$s" class="post-com-count post-com-count-approved"><span class="comment-count comment-count-approved">%3$s</span></a>', esc_url( $root_activity_url ), esc_attr( $title_attr ), number_format_i18n( $comment_count ) );
716
+ }
717
+
718
+ // For non-root activities, display a link to the replied-to activity's author's profile.
719
+ } else {
720
+ echo '<strong>' . get_avatar( $this->get_activity_user_id( $item['item_id'] ), '32' ) . ' ' . bp_core_get_userlink( $this->get_activity_user_id( $item['item_id'] ) ) . '</strong><br />';
721
+ echo $activity_permalink;
722
+ }
723
+ ?>
724
+
725
+ </div>
726
+
727
+ <?php
728
+ }
729
+
730
+ /**
731
+ * Allow plugins to add their custom column.
732
+ *
733
+ * @since 2.4.0
734
+ *
735
+ * @param array $item Information about the current row.
736
+ * @param string $column_name The column name.
737
+ * @return string
738
+ */
739
+ public function column_default( $item = array(), $column_name = '' ) {
740
+
741
+ /**
742
+ * Filters a string to allow plugins to add custom column content.
743
+ *
744
+ * @since 2.4.0
745
+ *
746
+ * @param string $value Empty string.
747
+ * @param string $column_name Name of the column being rendered.
748
+ * @param array $item The current activity item in the loop.
749
+ */
750
+ return apply_filters( 'bp_activity_admin_get_custom_column', '', $column_name, $item );
751
+ }
752
+
753
+ /**
754
+ * Get the user id associated with a given activity item.
755
+ *
756
+ * Wraps bp_activity_get_specific(), with some additional logic for
757
+ * avoiding duplicate queries.
758
+ *
759
+ * @since 1.6.0
760
+ *
761
+ * @param int $activity_id Activity ID to retrieve User ID for.
762
+ * @return int User ID of the activity item in question.
763
+ */
764
+ protected function get_activity_user_id( $activity_id ) {
765
+ // If there is an existing activity/user ID mapping, just return the user ID.
766
+ if ( ! empty( $this->activity_user_id[$activity_id] ) ) {
767
+ return $this->activity_user_id[$activity_id];
768
+
769
+ /*
770
+ * We don't have a mapping. This means the $activity_id is not on the current
771
+ * page of results, so fetch its details from the database.
772
+ */
773
+ } else {
774
+ $activity = bp_activity_get_specific( array( 'activity_ids' => $activity_id, 'show_hidden' => true, 'spam' => 'all', ) );
775
+
776
+ /*
777
+ * If, somehow, the referenced activity has been deleted, leaving its associated
778
+ * activities as orphans, use the logged in user's ID to avoid errors.
779
+ */
780
+ if ( empty( $activity['activities'] ) )
781
+ return bp_loggedin_user_id();
782
+
783
+ // Store the new activity/user ID mapping for any later re-use.
784
+ $this->activity_user_id[ $activity['activities'][0]->id ] = $activity['activities'][0]->user_id;
785
+
786
+ // Return the user ID.
787
+ return $activity['activities'][0]->user_id;
788
+ }
789
+ }
790
+
791
+ /**
792
+ * Checks if an activity item can be replied to.
793
+ *
794
+ * This method merges functionality from {@link bp_activity_can_comment()} and
795
+ * {@link bp_blogs_disable_activity_commenting()}. This is done because the activity
796
+ * list table doesn't use a BuddyPress activity loop, which prevents those
797
+ * functions from working as intended.
798
+ *
799
+ * @since 2.0.0
800
+ * @since 2.5.0 Include Post type activities types
801
+ *
802
+ * @param array $item An array version of the BP_Activity_Activity object.
803
+ * @return bool $can_comment
804
+ */
805
+ protected function can_comment( $item ) {
806
+ $can_comment = bp_activity_type_supports( $item['type'], 'comment-reply' );
807
+
808
+ if ( ! $this->disable_blogforum_comments && bp_is_active( 'blogs' ) ) {
809
+ $parent_activity = false;
810
+
811
+ if ( bp_activity_type_supports( $item['type'], 'post-type-comment-tracking' ) ) {
812
+ $parent_activity = (object) $item;
813
+ } elseif ( 'activity_comment' === $item['type'] ) {
814
+ $parent_activity = new BP_Activity_Activity( $item['item_id'] );
815
+ }
816
+
817
+ if ( isset( $parent_activity->type ) && bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' ) ) {
818
+ // Fetch blog post comment depth and if the blog post's comments are open.
819
+ bp_blogs_setup_activity_loop_globals( $parent_activity );
820
+
821
+ $can_comment = bp_blogs_can_comment_reply( true, $item );
822
+ }
823
+ }
824
+
825
+ /**
826
+ * Filters if an activity item can be commented on or not.
827
+ *
828
+ * @since 2.0.0
829
+ * @since 2.5.0 Add a second parameter to include the activity item into the filter.
830
+ *
831
+ * @param bool $can_comment Whether an activity item can be commented on or not.
832
+ * @param array $item An array version of the BP_Activity_Activity object.
833
+ */
834
+ return apply_filters( 'bp_activity_list_table_can_comment', $can_comment, $item );
835
+ }
836
+
837
+ /**
838
+ * Flatten the activity array.
839
+ *
840
+ * In some cases, BuddyPress gives us a structured tree of activity
841
+ * items plus their comments. This method converts it to a flat array.
842
+ *
843
+ * @since 1.6.0
844
+ *
845
+ * @param array $tree Source array.
846
+ * @return array Flattened array.
847
+ */
848
+ public static function flatten_activity_array( $tree ){
849
+ foreach ( (array) $tree as $node ) {
850
+ if ( isset( $node->children ) ) {
851
+
852
+ foreach ( BP_Activity_List_Table::flatten_activity_array( $node->children ) as $child ) {
853
+ $tree[] = $child;
854
+ }
855
+
856
+ unset( $node->children );
857
+ }
858
+ }
859
+
860
+ return $tree;
861
+ }
862
+ }
bp-activity/classes/class-bp-activity-oembed-extension.php ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Classes.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage Embeds
7
+ */
8
+
9
+ // Exit if accessed directly.
10
+ defined( 'ABSPATH' ) || exit;
11
+
12
+ /**
13
+ * oEmbed handler to respond and render single activity items.
14
+ *
15
+ * @since 2.6.0
16
+ */
17
+ class BP_Activity_oEmbed_Extension extends BP_Core_oEmbed_Extension {
18
+ /**
19
+ * Custom oEmbed slug endpoint.
20
+ *
21
+ * @since 2.6.0
22
+ *
23
+ * @var string
24
+ */
25
+ public $slug_endpoint = 'activity';
26
+
27
+ /**
28
+ * Custom hooks.
29
+ *
30
+ * @since 2.6.0
31
+ */
32
+ protected function custom_hooks() {
33
+ add_action( 'oembed_dataparse', array( $this, 'use_custom_iframe_sandbox_attribute' ), 20, 3 );
34
+ add_action( 'embed_content_meta', array( $this, 'embed_comments_button' ), 5 );
35
+ add_action( 'get_template_part_assets/embeds/header', array( $this, 'on_activity_header' ), 10, 2 );
36
+
37
+ add_filter( 'bp_activity_embed_html', array( $this, 'modify_iframe' ) );
38
+ }
39
+
40
+ /**
41
+ * Add custom endpoint arguments.
42
+ *
43
+ * Currently, includes 'hide_media'.
44
+ *
45
+ * @since 2.6.0
46
+ *
47
+ * @return array
48
+ */
49
+ protected function set_route_args() {
50
+ return array(
51
+ 'hide_media' => array(
52
+ 'default' => false,
53
+ 'sanitize_callback' => 'wp_validate_boolean'
54
+ )
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Output our custom embed template part.
60
+ *
61
+ * @since 2.6.0
62
+ */
63
+ protected function content() {
64
+ bp_get_asset_template_part( 'embeds/activity' );
65
+ }
66
+
67
+ /**
68
+ * Check if we're on our single activity page.
69
+ *
70
+ * @since 2.6.0
71
+ *
72
+ * @return bool
73
+ */
74
+ protected function is_page() {
75
+ return bp_is_single_activity();
76
+ }
77
+
78
+ /**
79
+ * Validates the URL to determine if the activity item is valid.
80
+ *
81
+ * @since 2.6.0
82
+ *
83
+ * @param string $url The URL to check.
84
+ * @return int|bool Activity ID on success; boolean false on failure.
85
+ */
86
+ protected function validate_url_to_item_id( $url ) {
87
+ if ( bp_core_enable_root_profiles() ) {
88
+ $domain = bp_get_root_domain();
89
+ } else {
90
+ $domain = bp_get_members_directory_permalink();
91
+ }
92
+
93
+ // Check the URL to see if this is a single activity URL.
94
+ if ( 0 !== strpos( $url, $domain ) ) {
95
+ return false;
96
+ }
97
+
98
+ // Check for activity slug.
99
+ if ( false === strpos( $url, '/' . bp_get_activity_slug() . '/' ) ) {
100
+ return false;
101
+ }
102
+
103
+ // Do more checks.
104
+ $url = trim( untrailingslashit( $url ) );
105
+
106
+ // Grab the activity ID.
107
+ $activity_id = (int) substr(
108
+ $url,
109
+ strrpos( $url, '/' ) + 1
110
+ );
111
+
112
+ if ( ! empty( $activity_id ) ) {
113
+ // Check if activity item still exists.
114
+ $activity = new BP_Activity_Activity( $activity_id );
115
+
116
+ // Okay, we're good to go!
117
+ if ( ! empty( $activity->component ) && 0 === (int) $activity->is_spam ) {
118
+ return $activity_id;
119
+ }
120
+ }
121
+
122
+ return false;
123
+ }
124
+
125
+ /**
126
+ * Sets the oEmbed response data for our activity item.
127
+ *
128
+ * @since 2.6.0
129
+ *
130
+ * @param int $item_id The activity ID.
131
+ * @return array
132
+ */
133
+ protected function set_oembed_response_data( $item_id ) {
134
+ $activity = new BP_Activity_Activity( $item_id );
135
+
136
+ return array(
137
+ 'content' => $activity->content,
138
+ 'title' => __( 'Activity', 'buddypress' ),
139
+ 'author_name' => bp_core_get_user_displayname( $activity->user_id ),
140
+ 'author_url' => bp_core_get_user_domain( $activity->user_id ),
141
+
142
+ // Custom identifier.
143
+ 'x_buddypress' => 'activity'
144
+ );
145
+ }
146
+
147
+ /**
148
+ * Sets a custom <blockquote> for our oEmbed fallback HTML.
149
+ *
150
+ * @since 2.6.0
151
+ *
152
+ * @param int $item_id The activity ID.
153
+ * @return string
154
+ */
155
+ protected function set_fallback_html( $item_id ) {
156
+ $activity = new BP_Activity_Activity( $item_id );
157
+ $mentionname = bp_activity_do_mentions() ? ' (@' . bp_activity_get_user_mentionname( $activity->user_id ) . ')' : '';
158
+ $date = date_i18n( get_option( 'date_format' ), strtotime( $activity->date_recorded ) );
159
+
160
+ // Make sure we can use some activity functions that depend on the loop.
161
+ $GLOBALS['activities_template'] = new stdClass;
162
+ $GLOBALS['activities_template']->activity = $activity;
163
+
164
+ // 'wp-embedded-content' CSS class is necessary due to how the embed JS works.
165
+ $blockquote = sprintf( '<blockquote class="wp-embedded-content bp-activity-item">%1$s%2$s %3$s</blockquote>',
166
+ bp_activity_get_embed_excerpt( $activity->content ),
167
+ '- ' . bp_core_get_user_displayname( $activity->user_id ) . $mentionname,
168
+ '<a href="' . esc_url( bp_activity_get_permalink( $item_id ) ) . '">' . $date . '</a>'
169
+ );
170
+
171
+ // Clean up.
172
+ unset( $GLOBALS['activities_template'] );
173
+
174
+ /**
175
+ * Filters the fallback HTML used when embedding a BP activity item.
176
+ *
177
+ * @since 2.6.0
178
+ *
179
+ * @param string $blockquote Current fallback HTML
180
+ * @param BP_Activity_Activity $activity Activity object
181
+ */
182
+ return apply_filters( 'bp_activity_embed_fallback_html', $blockquote, $activity );
183
+ }
184
+
185
+ /**
186
+ * Sets a custom <iframe> title for our oEmbed item.
187
+ *
188
+ * @since 2.6.0
189
+ *
190
+ * @param int $item_id The activity ID
191
+ * @return string
192
+ */
193
+ protected function set_iframe_title( $item_id ) {
194
+ return __( 'Embedded Activity Item', 'buddypress' );
195
+ }
196
+
197
+ /**
198
+ * Use our custom <iframe> sandbox attribute in our oEmbed response.
199
+ *
200
+ * WordPress sets the <iframe> sandbox attribute to 'allow-scripts' regardless
201
+ * of whatever the oEmbed response is in {@link wp_filter_oembed_result()}. We
202
+ * need to add back our custom sandbox value so links will work.
203
+ *
204
+ * @since 2.6.0
205
+ *
206
+ * @see BP_Activity_Component::modify_iframe() where our custom sandbox value is set.
207
+ *
208
+ * @param string $result The oEmbed HTML result.
209
+ * @param object $data A data object result from an oEmbed provider.
210
+ * @param string $url The URL of the content to be embedded.
211
+ * @return string
212
+ */
213
+ public function use_custom_iframe_sandbox_attribute( $result, $data, $url ) {
214
+ // Make sure we are on a BuddyPress activity oEmbed request.
215
+ if ( false === isset( $data->x_buddypress ) || 'activity' !== $data->x_buddypress ) {
216
+ return $result;
217
+ }
218
+
219
+ // Get unfiltered sandbox attribute from our own oEmbed response.
220
+ $sandbox_pos = strpos( $data->html, 'sandbox=' ) + 9;
221
+ $sandbox = substr( $data->html, $sandbox_pos, strpos( $data->html, '"', $sandbox_pos ) - $sandbox_pos );
222
+
223
+ // Replace only if our sandbox attribute contains 'allow-top-navigation'.
224
+ if ( false !== strpos( $sandbox, 'allow-top-navigation' ) ) {
225
+ $result = str_replace( ' sandbox="allow-scripts"', " sandbox=\"{$sandbox}\"", $result );
226
+
227
+ // Also remove 'security' attribute; this is only used for IE < 10.
228
+ $result = str_replace( 'security="restricted"', "", $result );
229
+ }
230
+
231
+ return $result;
232
+ }
233
+
234
+ /**
235
+ * Modify various IFRAME-related items if embeds are allowed.
236
+ *
237
+ * HTML modified:
238
+ * - Add sandbox="allow-top-navigation" attribute. This allows links to work
239
+ * within the iframe sandbox attribute.
240
+ *
241
+ * JS modified:
242
+ * - Remove IFRAME height restriction of 1000px. Fixes long embed items being
243
+ * truncated.
244
+ *
245
+ * @since 2.6.0
246
+ *
247
+ * @param string $retval Current embed HTML.
248
+ * @return string
249
+ */
250
+ public function modify_iframe( $retval ) {
251
+ // Add 'allow-top-navigation' to allow links to be clicked.
252
+ $retval = str_replace( 'sandbox="', 'sandbox="allow-top-navigation ', $retval );
253
+
254
+ // See /wp-includes/js/wp-embed.js.
255
+ if ( SCRIPT_DEBUG ) {
256
+ // Removes WP's hardcoded IFRAME height restriction.
257
+ $retval = str_replace( 'height = 1000;', 'height = height;', $retval );
258
+
259
+ // This is for the WP build minified version.
260
+ } else {
261
+ $retval = str_replace( 'g=1e3', 'g=g', $retval );
262
+ }
263
+
264
+ return $retval;
265
+ }
266
+
267
+ /**
268
+ * Do stuff when our oEmbed activity header template part is loading.
269
+ *
270
+ * Currently, removes wpautop() from the bp_activity_action() function.
271
+ *
272
+ * @since 2.6.0
273
+ *
274
+ * @param string $slug Template part slug requested.
275
+ * @param string $name Template part name requested.
276
+ */
277
+ public function on_activity_header( $slug, $name ) {
278
+ if ( false === $this->is_page() || 'activity' !== $name ) {
279
+ return;
280
+ }
281
+
282
+ remove_filter( 'bp_get_activity_action', 'wpautop' );
283
+ }
284
+
285
+ /**
286
+ * Prints the markup for the activity embed comments button.
287
+ *
288
+ * Basically a copy of {@link print_embed_comments_button()}, but modified for
289
+ * the BP activity component.
290
+ *
291
+ * @since 2.6.0
292
+ */
293
+ public function embed_comments_button() {
294
+ if ( ! did_action( 'bp_embed_content' ) || ! bp_is_single_activity() ) {
295
+ return;
296
+ }
297
+
298
+ // Make sure our custom permalink shows up in the 'WordPress Embed' block.
299
+ add_filter( 'the_permalink', array( $this, 'filter_embed_url' ) );
300
+
301
+ // Only show comment bubble if we have some activity comments.
302
+ $count = bp_activity_get_comment_count();
303
+ if ( empty( $count ) ) {
304
+ return;
305
+ }
306
+ ?>
307
+
308
+ <div class="wp-embed-comments">
309
+ <a href="<?php bp_activity_thread_permalink(); ?>">
310
+ <span class="dashicons dashicons-admin-comments"></span>
311
+ <?php
312
+ printf(
313
+ _n(
314
+ /* translators: accessibility text */
315
+ '%s <span class="screen-reader-text">Comment</span>',
316
+ /* translators: accessibility text */
317
+ '%s <span class="screen-reader-text">Comments</span>',
318
+ $count,
319
+ 'buddypress'
320
+ ),
321
+ number_format_i18n( $count )
322
+ );
323
+ ?>
324
+ </a>
325
+ </div>
326
+
327
+ <?php
328
+ }
329
+ }
bp-activity/classes/class-bp-activity-query.php ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Classes
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage ActivityQuery
7
+ * @since 2.2.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Class for generating the WHERE SQL clause for advanced activity fetching.
15
+ *
16
+ * This is notably used in {@link BP_Activity_Activity::get()} with the
17
+ * 'filter_query' parameter.
18
+ *
19
+ * @since 2.2.0
20
+ */
21
+ class BP_Activity_Query extends BP_Recursive_Query {
22
+ /**
23
+ * Array of activity queries.
24
+ *
25
+ * See {@see BP_Activity_Query::__construct()} for information on query arguments.
26
+ *
27
+ * @since 2.2.0
28
+ * @var array
29
+ */
30
+ public $queries = array();
31
+
32
+ /**
33
+ * Table alias.
34
+ *
35
+ * @since 2.2.0
36
+ * @var string
37
+ */
38
+ public $table_alias = '';
39
+
40
+ /**
41
+ * Supported DB columns.
42
+ *
43
+ * See the 'wp_bp_activity' DB table schema.
44
+ *
45
+ * @since 2.2.0
46
+ * @var array
47
+ */
48
+ public $db_columns = array(
49
+ 'id', 'user_id', 'component', 'type', 'action', 'content',
50
+ 'item_id', 'secondary_item_id', 'hide_sitewide', 'is_spam',
51
+ );
52
+
53
+ /**
54
+ * Constructor.
55
+ *
56
+ * @since 2.2.0
57
+ *
58
+ * @param array $query {
59
+ * Array of query clauses.
60
+ * @type array {
61
+ * @type string $column Required. The column to query against. Basically, any DB column in the main
62
+ * 'wp_bp_activity' table.
63
+ * @type string $value Required. Value to filter by.
64
+ * @type string $compare Optional. The comparison operator. Default '='.
65
+ * Accepts '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'LIKE',
66
+ * 'NOT LIKE', BETWEEN', 'NOT BETWEEN', 'REGEXP', 'NOT REGEXP', 'RLIKE'.
67
+ * @type string $relation Optional. The boolean relationship between the activity queries.
68
+ * Accepts 'OR', 'AND'. Default 'AND'.
69
+ * @type array {
70
+ * Optional. Another fully-formed activity query. See parameters above.
71
+ * }
72
+ * }
73
+ * }
74
+ */
75
+ public function __construct( $query = array() ) {
76
+ if ( ! is_array( $query ) ) {
77
+ return;
78
+ }
79
+
80
+ $this->queries = $this->sanitize_query( $query );
81
+ }
82
+
83
+ /**
84
+ * Generates WHERE SQL clause to be appended to a main query.
85
+ *
86
+ * @since 2.2.0
87
+ *
88
+ * @param string $alias An existing table alias that is compatible with the current query clause.
89
+ * Default: 'a'. BP_Activity_Activity::get() uses 'a', so we default to that.
90
+ * @return string SQL fragment to append to the main WHERE clause.
91
+ */
92
+ public function get_sql( $alias = 'a' ) {
93
+ if ( ! empty( $alias ) ) {
94
+ $this->table_alias = sanitize_title( $alias );
95
+ }
96
+
97
+ $sql = $this->get_sql_clauses();
98
+
99
+ // We only need the 'where' clause.
100
+ //
101
+ // Also trim trailing "AND" clause from parent BP_Recursive_Query class
102
+ // since it's not necessary for our needs.
103
+ return preg_replace( '/^\sAND/', '', $sql['where'] );
104
+ }
105
+
106
+ /**
107
+ * Generate WHERE clauses for a first-order clause.
108
+ *
109
+ * @since 2.2.0
110
+ *
111
+ * @param array $clause Array of arguments belonging to the clause.
112
+ * @param array $parent_query Parent query to which the clause belongs.
113
+ * @return array {
114
+ * @type array $where Array of subclauses for the WHERE statement.
115
+ * @type array $join Empty array. Not used.
116
+ * }
117
+ */
118
+ protected function get_sql_for_clause( $clause, $parent_query ) {
119
+ global $wpdb;
120
+
121
+ $sql_chunks = array(
122
+ 'where' => array(),
123
+ 'join' => array(),
124
+ );
125
+
126
+ $column = isset( $clause['column'] ) ? $this->validate_column( $clause['column'] ) : '';
127
+ $value = isset( $clause['value'] ) ? $clause['value'] : '';
128
+ if ( empty( $column ) || ! isset( $clause['value'] ) ) {
129
+ return $sql_chunks;
130
+ }
131
+
132
+ if ( isset( $clause['compare'] ) ) {
133
+ $clause['compare'] = strtoupper( $clause['compare'] );
134
+ } else {
135
+ $clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
136
+ }
137
+
138
+ // Default 'compare' to '=' if no valid operator is found.
139
+ if ( ! in_array( $clause['compare'], array(
140
+ '=', '!=', '>', '>=', '<', '<=',
141
+ 'LIKE', 'NOT LIKE',
142
+ 'IN', 'NOT IN',
143
+ 'BETWEEN', 'NOT BETWEEN',
144
+ 'REGEXP', 'NOT REGEXP', 'RLIKE'
145
+ ) ) ) {
146
+ $clause['compare'] = '=';
147
+ }
148
+
149
+ $compare = $clause['compare'];
150
+
151
+ $alias = ! empty( $this->table_alias ) ? "{$this->table_alias}." : '';
152
+
153
+ // Next, Build the WHERE clause.
154
+ $where = '';
155
+
156
+ // Value.
157
+ if ( isset( $clause['value'] ) ) {
158
+ if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
159
+ if ( ! is_array( $value ) ) {
160
+ $value = preg_split( '/[,\s]+/', $value );
161
+ }
162
+ }
163
+
164
+ // Tinyint.
165
+ if ( ! empty( $column ) && true === in_array( $column, array( 'hide_sitewide', 'is_spam' ) ) ) {
166
+ $sql_chunks['where'][] = $wpdb->prepare( "{$alias}{$column} = %d", $value );
167
+
168
+ } else {
169
+ switch ( $compare ) {
170
+ // IN uses different syntax.
171
+ case 'IN' :
172
+ case 'NOT IN' :
173
+ $in_sql = BP_Activity_Activity::get_in_operator_sql( "{$alias}{$column}", $value );
174
+
175
+ // 'NOT IN' operator is as easy as a string replace!
176
+ if ( 'NOT IN' === $compare ) {
177
+ $in_sql = str_replace( 'IN', 'NOT IN', $in_sql );
178
+ }
179
+
180
+ $sql_chunks['where'][] = $in_sql;
181
+ break;
182
+
183
+ case 'BETWEEN' :
184
+ case 'NOT BETWEEN' :
185
+ $value = array_slice( $value, 0, 2 );
186
+ $where = $wpdb->prepare( '%s AND %s', $value );
187
+ break;
188
+
189
+ case 'LIKE' :
190
+ case 'NOT LIKE' :
191
+ $value = '%' . bp_esc_like( $value ) . '%';
192
+ $where = $wpdb->prepare( '%s', $value );
193
+ break;
194
+
195
+ default :
196
+ $where = $wpdb->prepare( '%s', $value );
197
+ break;
198
+
199
+ }
200
+ }
201
+
202
+ if ( $where ) {
203
+ $sql_chunks['where'][] = "{$alias}{$column} {$compare} {$where}";
204
+ }
205
+ }
206
+
207
+ /*
208
+ * Multiple WHERE clauses should be joined in parentheses.
209
+ */
210
+ if ( 1 < count( $sql_chunks['where'] ) ) {
211
+ $sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' );
212
+ }
213
+
214
+ return $sql_chunks;
215
+ }
216
+
217
+ /**
218
+ * Determine whether a clause is first-order.
219
+ *
220
+ * @since 2.2.0
221
+ *
222
+ * @param array $query Clause to check.
223
+ * @return bool
224
+ */
225
+ protected function is_first_order_clause( $query ) {
226
+ return isset( $query['column'] ) || isset( $query['value'] );
227
+ }
228
+
229
+ /**
230
+ * Validates a column name parameter.
231
+ *
232
+ * Column names are checked against a whitelist of known tables.
233
+ * See {@link BP_Activity_Query::db_tables}.
234
+ *
235
+ * @since 2.2.0
236
+ *
237
+ * @param string $column The user-supplied column name.
238
+ * @return string A validated column name value.
239
+ */
240
+ public function validate_column( $column = '' ) {
241
+ if ( in_array( $column, $this->db_columns ) ) {
242
+ return $column;
243
+ } else {
244
+ return '';
245
+ }
246
+ }
247
+ }
bp-activity/classes/class-bp-activity-template.php ADDED
@@ -0,0 +1,409 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Template.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage ActivityTemplate
7
+ * @since 1.5.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * The main activity template loop class.
15
+ *
16
+ * This is responsible for loading a group of activity items and displaying them.
17
+ *
18
+ * @since 1.0.0
19
+ */
20
+ class BP_Activity_Template {
21
+
22
+ /**
23
+ * The loop iterator.
24
+ *
25
+ * @since 1.0.0
26
+ * @var int
27
+ */
28
+ public $current_activity = -1;
29
+
30
+ /**
31
+ * The activity count.
32
+ *
33
+ * @since 1.0.0
34
+ * @var int
35
+ */
36
+ public $activity_count;
37
+
38
+ /**
39
+ * The total activity count.
40
+ *
41
+ * @since 1.0.0
42
+ * @var int
43
+ */
44
+ public $total_activity_count;
45
+
46
+ /**
47
+ * Array of activities located by the query.
48
+ *
49
+ * @since 1.0.0
50
+ * @var array
51
+ */
52
+ public $activities;
53
+
54
+ /**
55
+ * The activity object currently being iterated on.
56
+ *
57
+ * @since 1.0.0
58
+ * @var object
59
+ */
60
+ public $activity;
61
+
62
+ /**
63
+ * A flag for whether the loop is currently being iterated.
64
+ *
65
+ * @since 1.0.0
66
+ * @var bool
67
+ */
68
+ public $in_the_loop;
69
+
70
+ /**
71
+ * URL parameter key for activity pagination. Default: 'acpage'.
72
+ *
73
+ * @since 2.1.0
74
+ * @var string
75
+ */
76
+ public $pag_arg;
77
+
78
+ /**
79
+ * The page number being requested.
80
+ *
81
+ * @since 1.0.0
82
+ * @var int
83
+ */
84
+ public $pag_page;
85
+
86
+ /**
87
+ * The number of items being requested per page.
88
+ *
89
+ * @since 1.0.0
90
+ * @var int
91
+ */
92
+ public $pag_num;
93
+
94
+ /**
95
+ * An HTML string containing pagination links.
96
+ *
97
+ * @since 1.0.0
98
+ * @var string
99
+ */
100
+ public $pag_links;
101
+
102
+ /**
103
+ * The displayed user's full name.
104
+ *
105
+ * @since 1.0.0
106
+ * @var string
107
+ */
108
+ public $full_name;
109
+
110
+ /**
111
+ * Constructor method.
112
+ *
113
+ * The arguments passed to this class constructor are of the same
114
+ * format as {@link BP_Activity_Activity::get()}.
115
+ *
116
+ * @since 1.5.0
117
+ *
118
+ * @see BP_Activity_Activity::get() for a description of the argument
119
+ * structure, as well as default values.
120
+ *
121
+ * @param array $args {
122
+ * Array of arguments. Supports all arguments from
123
+ * BP_Activity_Activity::get(), as well as 'page_arg' and
124
+ * 'include'. Default values for 'per_page' and 'display_comments'
125
+ * differ from the originating function, and are described below.
126
+ * @type string $page_arg The string used as a query parameter in
127
+ * pagination links. Default: 'acpage'.
128
+ * @type array|bool $include Pass an array of activity IDs to
129
+ * retrieve only those items, or false to noop the 'include'
130
+ * parameter. 'include' differs from 'in' in that 'in' forms
131
+ * an IN clause that works in conjunction with other filters
132
+ * passed to the function, while 'include' is interpreted as
133
+ * an exact list of items to retrieve, which skips all other
134
+ * filter-related parameters. Default: false.
135
+ * @type int|bool $per_page Default: 20.
136
+ * @type string|bool $display_comments Default: 'threaded'.
137
+ * }
138
+ */
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(
147
+ 0 => 'page',
148
+ 1 => 'per_page',
149
+ 2 => 'max',
150
+ 3 => 'include',
151
+ 4 => 'sort',
152
+ 5 => 'filter',
153
+ 6 => 'search_terms',
154
+ 7 => 'display_comments',
155
+ 8 => 'show_hidden',
156
+ 9 => 'exclude',
157
+ 10 => 'in',
158
+ 11 => 'spam',
159
+ 12 => 'page_arg'
160
+ );
161
+
162
+ $func_args = func_get_args();
163
+ $args = bp_core_parse_args_array( $old_args_keys, $func_args );
164
+ }
165
+
166
+ $defaults = array(
167
+ 'page' => 1,
168
+ 'per_page' => 20,
169
+ 'page_arg' => 'acpage',
170
+ 'max' => false,
171
+ 'fields' => 'all',
172
+ 'count_total' => false,
173
+ 'sort' => false,
174
+ 'include' => false,
175
+ 'exclude' => false,
176
+ 'in' => false,
177
+ 'filter' => false,
178
+ 'scope' => false,
179
+ 'search_terms' => false,
180
+ 'meta_query' => false,
181
+ 'date_query' => false,
182
+ 'filter_query' => false,
183
+ 'display_comments' => 'threaded',
184
+ 'show_hidden' => false,
185
+ 'spam' => 'ham_only',
186
+ 'update_meta_cache' => true,
187
+ );
188
+ $r = wp_parse_args( $args, $defaults );
189
+ extract( $r );
190
+
191
+ $this->pag_arg = sanitize_key( $r['page_arg'] );
192
+ $this->pag_page = bp_sanitize_pagination_arg( $this->pag_arg, $r['page'] );
193
+ $this->pag_num = bp_sanitize_pagination_arg( 'num', $r['per_page'] );
194
+
195
+ // Check if blog/forum replies are disabled.
196
+ $this->disable_blogforum_replies = (bool) bp_core_get_root_option( 'bp-disable-blogforum-comments' );
197
+
198
+ // Get an array of the logged in user's favorite activities.
199
+ $this->my_favs = maybe_unserialize( bp_get_user_meta( bp_loggedin_user_id(), 'bp_favorite_activities', true ) );
200
+
201
+ // Fetch specific activity items based on ID's.
202
+ if ( !empty( $include ) ) {
203
+ $this->activities = bp_activity_get_specific( array(
204
+ 'activity_ids' => explode( ',', $include ),
205
+ 'max' => $max,
206
+ 'count_total' => $count_total,
207
+ 'page' => $this->pag_page,
208
+ 'per_page' => $this->pag_num,
209
+ 'sort' => $sort,
210
+ 'display_comments' => $display_comments,
211
+ 'show_hidden' => $show_hidden,
212
+ 'spam' => $spam,
213
+ 'update_meta_cache' => $update_meta_cache,
214
+ ) );
215
+
216
+ // Fetch all activity items.
217
+ } else {
218
+ $this->activities = bp_activity_get( array(
219
+ 'display_comments' => $display_comments,
220
+ 'max' => $max,
221
+ 'count_total' => $count_total,
222
+ 'per_page' => $this->pag_num,
223
+ 'page' => $this->pag_page,
224
+ 'sort' => $sort,
225
+ 'search_terms' => $search_terms,
226
+ 'meta_query' => $meta_query,
227
+ 'date_query' => $date_query,
228
+ 'filter_query' => $filter_query,
229
+ 'filter' => $filter,
230
+ 'scope' => $scope,
231
+ 'show_hidden' => $show_hidden,
232
+ 'exclude' => $exclude,
233
+ 'in' => $in,
234
+ 'spam' => $spam,
235
+ 'update_meta_cache' => $update_meta_cache,
236
+ ) );
237
+ }
238
+
239
+ // The total_activity_count property will be set only if a
240
+ // 'count_total' query has taken place.
241
+ if ( ! is_null( $this->activities['total'] ) ) {
242
+ if ( ! $max || $max >= (int) $this->activities['total'] ) {
243
+ $this->total_activity_count = (int) $this->activities['total'];
244
+ } else {
245
+ $this->total_activity_count = (int) $max;
246
+ }
247
+ }
248
+
249
+ $this->has_more_items = $this->activities['has_more_items'];
250
+
251
+ $this->activities = $this->activities['activities'];
252
+
253
+ if ( $max ) {
254
+ if ( $max >= count($this->activities) ) {
255
+ $this->activity_count = count( $this->activities );
256
+ } else {
257
+ $this->activity_count = (int) $max;
258
+ }
259
+ } else {
260
+ $this->activity_count = count( $this->activities );
261
+ }
262
+
263
+ $this->full_name = bp_get_displayed_user_fullname();
264
+
265
+ // Fetch parent content for activity comments so we do not have to query in the loop.
266
+ foreach ( (array) $this->activities as $activity ) {
267
+ if ( 'activity_comment' != $activity->type ) {
268
+ continue;
269
+ }
270
+
271
+ $parent_ids[] = $activity->item_id;
272
+ }
273
+
274
+ if ( !empty( $parent_ids ) ) {
275
+ $activity_parents = bp_activity_get_specific( array( 'activity_ids' => $parent_ids ) );
276
+ }
277
+
278
+ if ( !empty( $activity_parents['activities'] ) ) {
279
+ foreach( $activity_parents['activities'] as $parent ) {
280
+ $this->activity_parents[$parent->id] = $parent;
281
+ }
282
+
283
+ unset( $activity_parents );
284
+ }
285
+
286
+ if ( (int) $this->total_activity_count && (int) $this->pag_num ) {
287
+ $this->pag_links = paginate_links( array(
288
+ 'base' => add_query_arg( $this->pag_arg, '%#%' ),
289
+ 'format' => '',
290
+ 'total' => ceil( (int) $this->total_activity_count / (int) $this->pag_num ),
291
+ 'current' => (int) $this->pag_page,
292
+ 'prev_text' => _x( '&larr;', 'Activity pagination previous text', 'buddypress' ),
293
+ 'next_text' => _x( '&rarr;', 'Activity pagination next text', 'buddypress' ),
294
+ 'mid_size' => 1,
295
+ 'add_args' => array(),
296
+ ) );
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Whether there are activity items available in the loop.
302
+ *
303
+ * @since 1.0.0
304
+ *
305
+ * @see bp_has_activities()
306
+ *
307
+ * @return bool True if there are items in the loop, otherwise false.
308
+ */
309
+ function has_activities() {
310
+ if ( $this->activity_count ) {
311
+ return true;
312
+ }
313
+
314
+ return false;
315
+ }
316
+
317
+ /**
318
+ * Set up the next activity item and iterate index.
319
+ *
320
+ * @since 1.0.0
321
+ *
322
+ * @return object The next activity item to iterate over.
323
+ */
324
+ public function next_activity() {
325
+ $this->current_activity++;
326
+ $this->activity = $this->activities[ $this->current_activity ];
327
+
328
+ return $this->activity;
329
+ }
330
+
331
+ /**
332
+ * Rewind the posts and reset post index.
333
+ *
334
+ * @since 1.0.0
335
+ */
336
+ public function rewind_activities() {
337
+ $this->current_activity = -1;
338
+ if ( $this->activity_count > 0 ) {
339
+ $this->activity = $this->activities[0];
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Whether there are activity items left in the loop to iterate over.
345
+ *
346
+ * This method is used by {@link bp_activities()} as part of the while loop
347
+ * that controls iteration inside the activities loop, eg:
348
+ * while ( bp_activities() ) { ...
349
+ *
350
+ * @since 1.0.0
351
+ *
352
+ * @see bp_activities()
353
+ *
354
+ * @return bool True if there are more activity items to show,
355
+ * otherwise false.
356
+ */
357
+ public function user_activities() {
358
+ if ( ( $this->current_activity + 1 ) < $this->activity_count ) {
359
+ return true;
360
+ } elseif ( ( $this->current_activity + 1 ) == $this->activity_count ) {
361
+
362
+ /**
363
+ * Fires right before the rewinding of activity posts.
364
+ *
365
+ * @since 1.1.0
366
+ */
367
+ do_action( 'activity_loop_end' );
368
+
369
+ // Do some cleaning up after the loop.
370
+ $this->rewind_activities();
371
+ }
372
+
373
+ $this->in_the_loop = false;
374
+
375
+ return false;
376
+ }
377
+
378
+ /**
379
+ * Set up the current activity item inside the loop.
380
+ *
381
+ * Used by {@link bp_the_activity()} to set up the current activity item
382
+ * data while looping, so that template tags used during that iteration
383
+ * make reference to the current activity item.
384
+ *
385
+ * @since 1.0.0
386
+ *
387
+ * @see bp_the_activity()
388
+ */
389
+ public function the_activity() {
390
+
391
+ $this->in_the_loop = true;
392
+ $this->activity = $this->next_activity();
393
+
394
+ if ( is_array( $this->activity ) ) {
395
+ $this->activity = (object) $this->activity;
396
+ }
397
+
398
+ // Loop has just started.
399
+ if ( $this->current_activity == 0 ) {
400
+
401
+ /**
402
+ * Fires if the current activity item is the first in the activity loop.
403
+ *
404
+ * @since 1.1.0
405
+ */
406
+ do_action('activity_loop_start');
407
+ }
408
+ }
409
+ }
bp-activity/classes/class-bp-activity-theme-compat.php ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BuddyPress Activity Theme Compatibility.
4
+ *
5
+ * @package BuddyPress
6
+ * @since 1.7.0
7
+ */
8
+
9
+ // Exit if accessed directly.
10
+ defined( 'ABSPATH' ) || exit;
11
+
12
+ /**
13
+ * The main theme compat class for BuddyPress Activity.
14
+ *
15
+ * This class sets up the necessary theme compatibility actions to safely output
16
+ * activity template parts to the_title and the_content areas of a theme.
17
+ *
18
+ * @since 1.7.0
19
+ */
20
+ class BP_Activity_Theme_Compat {
21
+
22
+ /**
23
+ * Set up the activity component theme compatibility.
24
+ *
25
+ * @since 1.7.0
26
+ */
27
+ public function __construct() {
28
+ add_action( 'bp_setup_theme_compat', array( $this, 'is_activity' ) );
29
+ }
30
+
31
+ /**
32
+ * Set up the theme compatibility hooks, if we're looking at an activity page.
33
+ *
34
+ * @since 1.7.0
35
+ */
36
+ public function is_activity() {
37
+
38
+ // Bail if not looking at a group.
39
+ if ( ! bp_is_activity_component() )
40
+ return;
41
+
42
+ // Activity Directory.
43
+ if ( ! bp_displayed_user_id() && ! bp_current_action() ) {
44
+ bp_update_is_directory( true, 'activity' );
45
+
46
+ /** This action is documented in bp-activity/bp-activity-screens.php */
47
+ do_action( 'bp_activity_screen_index' );
48
+
49
+ add_filter( 'bp_get_buddypress_template', array( $this, 'directory_template_hierarchy' ) );
50
+ add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
51
+ add_filter( 'bp_replace_the_content', array( $this, 'directory_content' ) );
52
+
53
+ // Single activity.
54
+ } elseif ( bp_is_single_activity() ) {
55
+ add_filter( 'bp_get_buddypress_template', array( $this, 'single_template_hierarchy' ) );
56
+ add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'single_dummy_post' ) );
57
+ add_filter( 'bp_replace_the_content', array( $this, 'single_dummy_content' ) );
58
+ }
59
+ }
60
+
61
+ /** Directory *************************************************************/
62
+
63
+ /**
64
+ * Add template hierarchy to theme compat for the activity directory page.
65
+ *
66
+ * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
67
+ *
68
+ * @since 1.8.0
69
+ *
70
+ * @param string $templates The templates from bp_get_theme_compat_templates().
71
+ * @return array $templates Array of custom templates to look for.
72
+ */
73
+ public function directory_template_hierarchy( $templates ) {
74
+
75
+ /**
76
+ * Filters the template hierarchy for the activity directory page.
77
+ *
78
+ * @since 1.8.0
79
+ *
80
+ * @param array $index-directory Array holding template names to be merged into template list.
81
+ */
82
+ $new_templates = apply_filters( 'bp_template_hierarchy_activity_directory', array(
83
+ 'activity/index-directory.php'
84
+ ) );
85
+
86
+ // Merge new templates with existing stack
87
+ // @see bp_get_theme_compat_templates().
88
+ $templates = array_merge( (array) $new_templates, $templates );
89
+
90
+ return $templates;
91
+ }
92
+
93
+ /**
94
+ * Update the global $post with directory data.
95
+ *
96
+ * @since 1.7.0
97
+ */
98
+ public function directory_dummy_post() {
99
+ bp_theme_compat_reset_post( array(
100
+ 'ID' => 0,
101
+ 'post_title' => bp_get_directory_title( 'activity' ),
102
+ 'post_author' => 0,
103
+ 'post_date' => 0,
104
+ 'post_content' => '',
105
+ 'post_type' => 'page',
106
+ 'post_status' => 'publish',
107
+ 'is_page' => true,
108
+ 'comment_status' => 'closed'
109
+ ) );
110
+ }
111
+
112
+ /**
113
+ * Filter the_content with the groups index template part.
114
+ *
115
+ * @since 1.7.0
116
+ */
117
+ public function directory_content() {
118
+ return bp_buffer_template_part( 'activity/index', null, false );
119
+ }
120
+
121
+ /** Single ****************************************************************/
122
+
123
+ /**
124
+ * Add custom template hierarchy to theme compat for activity permalink pages.
125
+ *
126
+ * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
127
+ *
128
+ * @since 1.8.0
129
+ *
130
+ * @param string $templates The templates from bp_get_theme_compat_templates().
131
+ * @return array $templates Array of custom templates to look for.
132
+ */
133
+ public function single_template_hierarchy( $templates ) {
134
+
135
+ /**
136
+ * Filters the template hierarchy for the activity permalink pages.
137
+ *
138
+ * @since 1.8.0
139
+ *
140
+ * @param array $index Array holding template names to be merged into template list.
141
+ */
142
+ $new_templates = apply_filters( 'bp_template_hierarchy_activity_single_item', array(
143
+ 'activity/single/index.php'
144
+ ) );
145
+
146
+ // Merge new templates with existing stack
147
+ // @see bp_get_theme_compat_templates().
148
+ $templates = array_merge( (array) $new_templates, $templates );
149
+
150
+ return $templates;
151
+ }
152
+
153
+ /**
154
+ * Update the global $post with the displayed user's data.
155
+ *
156
+ * @since 1.7.0
157
+ */
158
+ public function single_dummy_post() {
159
+ bp_theme_compat_reset_post( array(
160
+ 'ID' => 0,
161
+ 'post_title' => __( 'Activity', 'buddypress' ),
162
+ 'post_author' => 0,
163
+ 'post_date' => 0,
164
+ 'post_content' => '',
165
+ 'post_type' => 'page',
166
+ 'post_status' => 'publish',
167
+ 'is_page' => true,
168
+ 'comment_status' => 'closed'
169
+ ) );
170
+ }
171
+
172
+ /**
173
+ * Filter the_content with the members' activity permalink template part.
174
+ *
175
+ * @since 1.7.0
176
+ */
177
+ public function single_dummy_content() {
178
+ return bp_buffer_template_part( 'activity/single/home', null, false );
179
+ }
180
+ }
bp-activity/classes/class-bp-akismet.php ADDED
@@ -0,0 +1,651 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Akismet support for BuddyPress' Activity Stream.
4
+ *
5
+ * @package BuddyPress
6
+ * @subpackage ActivityAkismet
7
+ * @since 1.6.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ /**
14
+ * Akismet support for the Activity component.
15
+ *
16
+ * @since 1.6.0
17
+ * @since 2.3.0 We only support Akismet 3+.
18
+ */
19
+ class BP_Akismet {
20
+
21
+ /**
22
+ * The activity last marked as spam.
23
+ *
24
+ * @since 1.6.0
25
+ * @var BP_Activity_Activity
26
+ */
27
+ protected $last_activity = null;
28
+
29
+ /**
30
+ * Constructor.
31
+ *
32
+ * @since 1.6.0
33
+ */
34
+ public function __construct() {
35
+ $this->setup_actions();
36
+ }
37
+
38
+ /**
39
+ * Hook Akismet into the activity stream.
40
+ *
41
+ * @since 1.6.0
42
+ */
43
+ protected function setup_actions() {
44
+ // Add nonces to activity stream lists.
45
+ add_action( 'bp_after_activity_post_form', array( $this, 'add_activity_stream_nonce' ) );
46
+ add_action( 'bp_activity_entry_comments', array( $this, 'add_activity_stream_nonce' ) );
47
+
48
+ // Add a "mark as spam" button to individual activity items.
49
+ add_action( 'bp_activity_entry_meta', array( $this, 'add_activity_spam_button' ) );
50
+ add_action( 'bp_activity_comment_options', array( $this, 'add_activity_comment_spam_button' ) );
51
+
52
+ // Check activity for spam.
53
+ add_action( 'bp_activity_before_save', array( $this, 'check_activity' ), 4, 1 );
54
+
55
+ // Tidy up member's latest (activity) update.
56
+ add_action( 'bp_activity_posted_update', array( $this, 'check_member_activity_update' ), 1, 3 );
57
+
58
+ // Hooks to extend Activity core spam/ham functions for Akismet.
59
+ add_action( 'bp_activity_mark_as_spam', array( $this, 'mark_as_spam' ), 10, 2 );
60
+ add_action( 'bp_activity_mark_as_ham', array( $this, 'mark_as_ham' ), 10, 2 );
61
+
62
+ // Hook into the Activity wp-admin screen.
63
+ add_action( 'bp_activity_admin_comment_row_actions', array( $this, 'comment_row_action' ), 10, 2 );
64
+ add_action( 'bp_activity_admin_load', array( $this, 'add_history_metabox' ) );
65
+ }
66
+
67
+ /**
68
+ * Add a history item to the hover links in an activity's row.
69
+ *
70
+ * This function lifted with love from the Akismet WordPress plugin's
71
+ * akismet_comment_row_action() function. Thanks!
72
+ *
73
+ * @since 1.6.0
74
+ *
75
+ * @param array $actions The hover links.
76
+ * @param array $activity The activity for the current row being processed.
77
+ * @return array The hover links.
78
+ */
79
+ function comment_row_action( $actions, $activity ) {
80
+ $akismet_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_result' );
81
+ $user_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_user_result' );
82
+ $desc = '';
83
+
84
+ if ( !$user_result || $user_result == $akismet_result ) {
85
+ // Show the original Akismet result if the user hasn't overridden it, or if their decision was the same.
86
+ if ( 'true' == $akismet_result && $activity['is_spam'] )
87
+ $desc = __( 'Flagged as spam by Akismet', 'buddypress' );
88
+
89
+ elseif ( 'false' == $akismet_result && !$activity['is_spam'] )
90
+ $desc = __( 'Cleared by Akismet', 'buddypress' );
91
+
92
+ } else {
93
+ $who = bp_activity_get_meta( $activity['id'], '_bp_akismet_user' );
94
+
95
+ if ( 'true' == $user_result )
96
+ $desc = sprintf( __( 'Flagged as spam by %s', 'buddypress' ), $who );
97
+ else
98
+ $desc = sprintf( __( 'Un-spammed by %s', 'buddypress' ), $who );
99
+ }
100
+
101
+ // Add a History item to the hover links, just after Edit.
102
+ if ( $akismet_result ) {
103
+ $b = array();
104
+ foreach ( $actions as $k => $item ) {
105
+ $b[ $k ] = $item;
106
+ if ( $k == 'edit' )
107
+ $b['history'] = '<a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&amp;action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history"> '. __( 'History', 'buddypress' ) . '</a>';
108
+ }
109
+
110
+ $actions = $b;
111
+ }
112
+
113
+ if ( $desc )
114
+ echo '<span class="akismet-status"><a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&amp;action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history">' . htmlspecialchars( $desc ) . '</a></span>';
115
+
116
+ /**
117
+ * Filters the list of actions for the current activity's row.
118
+ *
119
+ * @since 1.6.0
120
+ *
121
+ * @param array $actions Array of available actions for the current activity item's row.
122
+ */
123
+ return apply_filters( 'bp_akismet_comment_row_action', $actions );
124
+ }
125
+
126
+ /**
127
+ * Generate nonces for activity forms.
128
+ *
129
+ * These nonces appear in the member profile status form, as well as in
130
+ * the reply form of each activity item. The nonces are, in turn, used
131
+ * by Akismet to help detect spam activity.
132
+ *
133
+ * @since 1.6.0
134
+ *
135
+ * @see https://plugins.trac.wordpress.org/ticket/1232
136
+ */
137
+ public function add_activity_stream_nonce() {
138
+ $form_id = '_bp_as_nonce';
139
+ $value = '_bp_as_nonce_' . bp_loggedin_user_id();
140
+
141
+ // If we're in the activity stream loop, we can use the current item's ID to make the nonce unique.
142
+ if ( 'bp_activity_entry_comments' == current_filter() ) {
143
+ $form_id .= '_' . bp_get_activity_id();
144
+ $value .= '_' . bp_get_activity_id();
145
+ }
146
+
147
+ wp_nonce_field( $value, $form_id, false );
148
+ }
149
+
150
+ /**
151
+ * Clean up the bp_latest_update usermeta in case of spamming.
152
+ *
153
+ * Run just after an update is posted, this method check to see whether
154
+ * the newly created update has been marked as spam by Akismet. If so,
155
+ * the cached update is cleared from the user's 'bp_latest_update'
156
+ * usermeta, ensuring that it won't appear in the member header and
157
+ * elsewhere in the theme.
158
+ *
159
+ * This can't be done in BP_Akismet::check_activity() due to the
160
+ * default AJAX implementation; see bp_dtheme_post_update().
161
+ *
162
+ * @since 1.6.0
163
+ *
164
+ * @see bp_dtheme_post_update()
165
+ *
166
+ * @param string $content Activity update text.
167
+ * @param int $user_id User ID.
168
+ * @param int $activity_id Activity ID.
169
+ */
170
+ public function check_member_activity_update( $content, $user_id, $activity_id ) {
171
+ // By default, only handle activity updates and activity comments.
172
+ if ( empty( $this->last_activity ) || !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )
173
+ return;
174
+
175
+ // Was this $activity_id just marked as spam? If not, bail out.
176
+ if ( !$this->last_activity->id || $activity_id != $this->last_activity->id || 'false' == $this->last_activity->akismet_submission['bp_as_result'] )
177
+ return;
178
+
179
+ // It was, so delete the member's latest activity update.
180
+ bp_delete_user_meta( $user_id, 'bp_latest_update' );
181
+ }
182
+
183
+ /**
184
+ * Adds a "mark as spam" button to each activity item for site admins.
185
+ *
186
+ * This function is intended to be used inside the activity stream loop.
187
+ *
188
+ * @since 1.6.0
189
+ */
190
+ public function add_activity_spam_button() {
191
+ if ( !bp_activity_user_can_mark_spam() )
192
+ return;
193
+
194
+ // By default, only handle activity updates and activity comments.
195
+ if ( !in_array( bp_get_activity_type(), BP_Akismet::get_activity_types() ) )
196
+ return;
197
+
198
+ bp_button(
199
+ array(
200
+ 'block_self' => false,
201
+ 'component' => 'activity',
202
+ 'id' => 'activity_make_spam_' . bp_get_activity_id(),
203
+ 'link_class' => 'bp-secondary-action spam-activity confirm button item-button',
204
+ 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_id() . '/', 'bp_activity_akismet_spam_' . bp_get_activity_id() ),
205
+ 'link_text' => __( 'Spam', 'buddypress' ),
206
+ 'wrapper' => false,
207
+ )
208
+ );
209
+ }
210
+
211
+ /**
212
+ * Adds a "mark as spam" button to each activity COMMENT item for site admins.
213
+ *
214
+ * This function is intended to be used inside the activity stream loop.
215
+ *
216
+ * @since 1.6.0
217
+ */
218
+ public function add_activity_comment_spam_button() {
219
+ if ( !bp_activity_user_can_mark_spam() )
220
+ return;
221
+
222
+ // By default, only handle activity updates and activity comments.
223
+ $current_comment = bp_activity_current_comment();
224
+ if ( empty( $current_comment ) || !in_array( $current_comment->type, BP_Akismet::get_activity_types() ) )
225
+ return;
226
+
227
+ bp_button(
228
+ array(
229
+ 'block_self' => false,
230
+ 'component' => 'activity',
231
+ 'id' => 'activity_make_spam_' . bp_get_activity_comment_id(),
232
+ 'link_class' => 'bp-secondary-action spam-activity-comment confirm',
233
+ 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_comment_id() . '/?cid=' . bp_get_activity_comment_id(), 'bp_activity_akismet_spam_' . bp_get_activity_comment_id() ),
234
+ 'link_text' => __( 'Spam', 'buddypress' ),
235
+ 'wrapper' => false,
236
+ )
237
+ );
238
+ }
239
+
240
+ /**
241
+ * Get a filterable list of activity types that Akismet should automatically check for spam.
242
+ *
243
+ * @since 1.6.0
244
+ *
245
+ * @static
246
+ *
247
+ * @return array $value List of activity types.
248
+ */
249
+ public static function get_activity_types() {
250
+
251
+ /**
252
+ * Filters the list of activity types that Akismet should automatically check for spam.
253
+ *
254
+ * @since 1.6.0
255
+ *
256
+ * @param array $value Array of default activity types for Akismet to check.
257
+ */
258
+ return apply_filters( 'bp_akismet_get_activity_types', array( 'activity_comment', 'activity_update' ) );
259
+ }
260
+
261
+ /**
262
+ * Mark activity item as spam.
263
+ *
264
+ * @since 1.6.0
265
+ *
266
+ * @param BP_Activity_Activity $activity Activity item being spammed.
267
+ * @param string $source Either "by_a_person" (e.g. a person has
268
+ * manually marked the activity as spam) or
269
+ * "by_akismet" (automatically spammed).
270
+ */
271
+ public function mark_as_spam( $activity, $source ) {
272
+ // Record this item so we can do some tidyup in BP_Akismet::check_member_activity_update().
273
+ $this->last_activity = $activity;
274
+
275
+ /**
276
+ * Fires after marking an activity item has been marked as spam.
277
+ *
278
+ * @since 1.6.0
279
+ *
280
+ * @param BP_Activity_Activity $activity Activity object being marked as spam.
281
+ * @param string $source Source of the whom marked as spam.
282
+ * Either "by_a_person" (e.g. a person has
283
+ * manually marked the activity as spam)
284
+ * or "by_akismet".
285
+ */
286
+ do_action( 'bp_activity_akismet_mark_as_spam', $activity, $source );
287
+ }
288
+
289
+ /**
290
+ * Mark activity item as ham.
291
+ *
292
+ * @since 1.6.0
293
+ *
294
+ * @param BP_Activity_Activity $activity Activity item being hammed.
295
+ * @param string $source Either "by_a_person" (e.g. a person has
296
+ * manually marked the activity as ham) or
297
+ * "by_akismet" (automatically hammed).
298
+ */
299
+ public function mark_as_ham( $activity, $source ) {
300
+ // If the activity was, originally, automatically marked as spam by Akismet, run the @mentions filter as it would have been skipped.
301
+ if ( 'true' == bp_activity_get_meta( $activity->id, '_bp_akismet_result' ) && !bp_activity_get_meta( $activity->id, '_bp_akismet_user_result' ) )
302
+ $activity->content = bp_activity_at_name_filter( $activity->content, $activity->id );
303
+
304
+ /**
305
+ * Fires after marking an activity item has been marked as ham.
306
+ *
307
+ * @since 1.6.0
308
+ *
309
+ * @param BP_Activity_Activity $activity Activity object being marked as ham.
310
+ * @param string $source Source of the whom marked as ham.
311
+ * Either "by_a_person" (e.g. a person has
312
+ * manually marked the activity as ham) or
313
+ * "by_akismet" (automatically hammed).
314
+ */
315
+ do_action( 'bp_activity_akismet_mark_as_ham', $activity, $source );
316
+ }
317
+
318
+ /**
319
+ * Build a data package for the Akismet service to inspect.
320
+ *
321
+ * @since 1.6.0
322
+ *
323
+ * @see http://akismet.com/development/api/#comment-check
324
+ * @static
325
+ *
326
+ * @param BP_Activity_Activity $activity Activity item data.
327
+ * @return array $activity_data
328
+ */
329
+ public static function build_akismet_data_package( $activity ) {
330
+ $userdata = get_userdata( $activity->user_id );
331
+
332
+ $activity_data = array();
333
+ $activity_data['akismet_comment_nonce'] = 'inactive';
334
+ $activity_data['comment_author'] = $userdata->display_name;
335
+ $activity_data['comment_author_email'] = $userdata->user_email;
336
+ $activity_data['comment_author_url'] = bp_core_get_userlink( $userdata->ID, false, true);
337
+ $activity_data['comment_content'] = $activity->content;
338
+ $activity_data['comment_type'] = $activity->type;
339
+ $activity_data['permalink'] = bp_activity_get_permalink( $activity->id, $activity );
340
+ $activity_data['user_ID'] = $userdata->ID;
341
+ $activity_data['user_role'] = Akismet::get_user_roles( $userdata->ID );
342
+
343
+ /**
344
+ * Get the nonce if the new activity was submitted through the "what's up, Paul?" form.
345
+ * This helps Akismet ensure that the update was a valid form submission.
346
+ */
347
+ if ( !empty( $_POST['_bp_as_nonce'] ) )
348
+ $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST['_bp_as_nonce'], "_bp_as_nonce_{$userdata->ID}" ) ? 'passed' : 'failed';
349
+
350
+ /**
351
+ * If the new activity was a reply to an existing item, check the nonce with the activity parent ID.
352
+ * This helps Akismet ensure that the update was a valid form submission.
353
+ */
354
+ elseif ( !empty( $activity->secondary_item_id ) && !empty( $_POST['_bp_as_nonce_' . $activity->secondary_item_id] ) )
355
+ $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST["_bp_as_nonce_{$activity->secondary_item_id}"], "_bp_as_nonce_{$userdata->ID}_{$activity->secondary_item_id}" ) ? 'passed' : 'failed';
356
+
357
+ /**
358
+ * Filters activity data before being sent to Akismet to inspect.
359
+ *
360
+ * @since 1.6.0
361
+ *
362
+ * @param array $activity_data Array of activity data for Akismet to inspect.
363
+ * @param BP_Activity_Activity $activity Activity item data.
364
+ */
365
+ return apply_filters( 'bp_akismet_build_akismet_data_package', $activity_data, $activity );
366
+ }
367
+
368
+ /**
369
+ * Check if the activity item is spam or ham.
370
+ *
371
+ * @since 1.6.0
372
+ *
373
+ * @see http://akismet.com/development/api/
374
+ * @todo Spam counter?
375
+ * @todo Auto-delete old spam?
376
+ *
377
+ * @param BP_Activity_Activity $activity The activity item to check.
378
+ */
379
+ public function check_activity( $activity ) {
380
+ // By default, only handle activity updates and activity comments.
381
+ if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
382
+ return;
383
+
384
+ // Make sure last_activity is clear to avoid any confusion.
385
+ $this->last_activity = null;
386
+
387
+ // Build data package for Akismet.
388
+ $activity_data = BP_Akismet::build_akismet_data_package( $activity );
389
+
390
+ // Check with Akismet to see if this is spam.
391
+ $activity_data = $this->send_akismet_request( $activity_data, 'check', 'spam' );
392
+
393
+ // Record this item.
394
+ $this->last_activity = $activity;
395
+
396
+ // Store a copy of the data that was submitted to Akismet.
397
+ $this->last_activity->akismet_submission = $activity_data;
398
+
399
+ // Spam.
400
+ if ( 'true' == $activity_data['bp_as_result'] ) {
401
+ /**
402
+ * Fires after an activity item has been proven to be spam, but before officially being marked as spam.
403
+ *
404
+ * @since 1.6.0
405
+ *
406
+ * @param BP_Activity_Activity $activity The activity item proven to be spam.
407
+ * @param array $activity_data Array of activity data for item including
408
+ * Akismet check results data.
409
+ */
410
+ do_action_ref_array( 'bp_activity_akismet_spam_caught', array( &$activity, $activity_data ) );
411
+
412
+ // Mark as spam.
413
+ bp_activity_mark_as_spam( $activity, 'by_akismet' );
414
+ }
415
+
416
+ // Update activity meta after a spam check.
417
+ add_action( 'bp_activity_after_save', array( $this, 'update_activity_akismet_meta' ), 1, 1 );
418
+ }
419
+
420
+ /**
421
+ * Update activity meta after a manual spam change (user-initiated).
422
+ *
423
+ * @since 1.6.0
424
+ *
425
+ * @param BP_Activity_Activity $activity The activity to check.
426
+ */
427
+ public function update_activity_spam_meta( $activity ) {
428
+ // By default, only handle activity updates and activity comments.
429
+ if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
430
+ return;
431
+
432
+ $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-spam' );
433
+ bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'true' );
434
+ bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );
435
+ }
436
+
437
+ /**
438
+ * Update activity meta after a manual ham change (user-initiated).
439
+ *
440
+ * @since 1.6.0
441
+ *
442
+ * @param BP_Activity_Activity $activity The activity to check.
443
+ */
444
+ public function update_activity_ham_meta( $activity ) {
445
+ // By default, only handle activity updates and activity comments.
446
+ if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
447
+ return;
448
+
449
+ $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as not spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-ham' );
450
+ bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'false' );
451
+ bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );
452
+ }
453
+
454
+ /**
455
+ * Update activity meta after an automatic spam check (not user-initiated).
456
+ *
457
+ * @since 1.6.0
458
+ *
459
+ * @param BP_Activity_Activity $activity The activity to check.
460
+ */
461
+ public function update_activity_akismet_meta( $activity ) {
462
+ // Check we're dealing with what was last updated by Akismet.
463
+ if ( empty( $this->last_activity ) || !empty( $this->last_activity ) && $activity->id != $this->last_activity->id )
464
+ return;
465
+
466
+ // By default, only handle activity updates and activity comments.
467
+ if ( !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )
468
+ return;
469
+
470
+ // Spam.
471
+ if ( 'true' == $this->last_activity->akismet_submission['bp_as_result'] ) {
472
+ bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'true' );
473
+ $this->update_activity_history( $activity->id, __( 'Akismet caught this item as spam', 'buddypress' ), 'check-spam' );
474
+
475
+ // Not spam.
476
+ } elseif ( 'false' == $this->last_activity->akismet_submission['bp_as_result'] ) {
477
+ bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'false' );
478
+ $this->update_activity_history( $activity->id, __( 'Akismet cleared this item', 'buddypress' ), 'check-ham' );
479
+
480
+ // Uh oh, something's gone horribly wrong. Unexpected result.
481
+ } else {
482
+ bp_activity_update_meta( $activity->id, '_bp_akismet_error', bp_core_current_time() );
483
+ $this->update_activity_history( $activity->id, sprintf( __( 'Akismet was unable to check this item (response: %s), will automatically retry again later.', 'buddypress' ), $this->last_activity->akismet_submission['bp_as_result'] ), 'check-error' );
484
+ }
485
+
486
+ // Record the original data which was submitted to Akismet for checking.
487
+ bp_activity_update_meta( $activity->id, '_bp_akismet_submission', $this->last_activity->akismet_submission );
488
+ }
489
+
490
+ /**
491
+ * Contact Akismet to check if this is spam or ham.
492
+ *
493
+ * Props to WordPress core Akismet plugin for a lot of this.
494
+ *
495
+ * @since 1.6.0
496
+ *
497
+ * @param array $activity_data Packet of information to submit to Akismet.
498
+ * @param string $check "check" or "submit".
499
+ * @param string $spam "spam" or "ham".
500
+ * @return array $activity_data Activity data, with Akismet data added.
501
+ */
502
+ public function send_akismet_request( $activity_data, $check = 'check', $spam = 'spam' ) {
503
+ $query_string = $path = '';
504
+
505
+ $activity_data['blog'] = bp_get_option( 'home' );
506
+ $activity_data['blog_charset'] = bp_get_option( 'blog_charset' );
507
+ $activity_data['blog_lang'] = get_locale();
508
+ $activity_data['referrer'] = $_SERVER['HTTP_REFERER'];
509
+ $activity_data['user_agent'] = bp_core_current_user_ua();
510
+ $activity_data['user_ip'] = bp_core_current_user_ip();
511
+
512
+ if ( Akismet::is_test_mode() )
513
+ $activity_data['is_test'] = 'true';
514
+
515
+ // Loop through _POST args and rekey strings.
516
+ foreach ( $_POST as $key => $value )
517
+ if ( is_string( $value ) && 'cookie' != $key )
518
+ $activity_data['POST_' . $key] = $value;
519
+
520
+ // Keys to ignore.
521
+ $ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );
522
+
523
+ // Loop through _SERVER args and remove whitelisted keys.
524
+ foreach ( $_SERVER as $key => $value ) {
525
+
526
+ // Key should not be ignored.
527
+ if ( !in_array( $key, $ignore ) && is_string( $value ) ) {
528
+ $activity_data[$key] = $value;
529
+
530
+ // Key should be ignored.
531
+ } else {
532
+ $activity_data[$key] = '';
533
+ }
534
+ }
535
+
536
+ foreach ( $activity_data as $key => $data )
537
+ $query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
538
+
539
+ if ( 'check' == $check )
540
+ $path = 'comment-check';
541
+ elseif ( 'submit' == $check )
542
+ $path = 'submit-' . $spam;
543
+
544
+ // Send to Akismet.
545
+ add_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );
546
+ $response = Akismet::http_post( $query_string, $path );
547
+ remove_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );
548
+
549
+ // Get the response.
550
+ if ( ! empty( $response[1] ) && ! is_wp_error( $response[1] ) )
551
+ $activity_data['bp_as_result'] = $response[1];
552
+ else
553
+ $activity_data['bp_as_result'] = false;
554
+
555
+ // Perform a daily tidy up.
556
+ if ( ! wp_next_scheduled( 'bp_activity_akismet_delete_old_metadata' ) )
557
+ wp_schedule_event( time(), 'daily', 'bp_activity_akismet_delete_old_metadata' );
558
+
559
+ return $activity_data;
560
+ }
561
+
562
+ /**
563
+ * Filters user agent when sending to Akismet to add BuddyPress info.
564
+ *
565
+ * @since 1.6.0
566
+ *
567
+ * @param string $user_agent User agent string, as generated by Akismet.
568
+ * @return string $user_agent Modified user agent string.
569
+ */
570
+ public function buddypress_ua( $user_agent ) {
571
+ $user_agent = 'BuddyPress/' . bp_get_version() . ' | Akismet/'. constant( 'AKISMET_VERSION' );
572
+ return $user_agent;
573
+ }
574
+
575
+ /**
576
+ * Adds a "History" meta box to the activity edit screen.
577
+ *
578
+ * @since 1.6.0
579
+ *
580
+ * @param string $screen_action The type of screen that has been requested.
581
+ */
582
+ function add_history_metabox( $screen_action ) {
583
+ // Only proceed if we're on the edit screen.
584
+ if ( 'edit' != $screen_action )
585
+ return;
586
+
587
+ // Display meta box with a low priority (low position on screen by default).
588
+ add_meta_box( 'bp_activity_history', __( 'Activity History', 'buddypress' ), array( $this, 'history_metabox' ), get_current_screen()->id, 'normal', 'low' );
589
+ }
590
+
591
+ /**
592
+ * History meta box for the Activity admin edit screen.
593
+ *
594
+ * @since 1.6.0
595
+ *
596
+ * @see https://buddypress.trac.wordpress.org/ticket/3907
597
+ * @todo Update activity meta to allow >1 record with the same key (iterate through $history).
598
+ *
599
+ * @param object $item Activity item.
600
+ */
601
+ function history_metabox( $item ) {
602
+ $history = BP_Akismet::get_activity_history( $item->id );
603
+
604
+ if ( empty( $history ) )
605
+ return;
606
+
607
+ echo '<div class="akismet-history"><div>';
608
+ printf( _x( '%1$s &mdash; %2$s', 'x hours ago - akismet cleared this item', 'buddypress' ), '<span>' . bp_core_time_since( $history[2] ) . '</span>', esc_html( $history[1] ) );
609
+ echo '</div></div>';
610
+ }
611
+
612
+ /**
613
+ * Update an activity item's Akismet history.
614
+ *
615
+ * @since 1.6.0
616
+ *
617
+ * @param int $activity_id Activity item ID.
618
+ * @param string $message Human-readable description of what's changed.
619
+ * @param string $event The type of check we were carrying out.
620
+ */
621
+ public function update_activity_history( $activity_id = 0, $message = '', $event = '' ) {
622
+ $event = array(
623
+ 'event' => $event,
624
+ 'message' => $message,
625
+ 'time' => Akismet::_get_microtime(),
626
+ 'user' => bp_loggedin_user_id(),
627
+ );
628
+
629
+ // Save the history data.
630
+ bp_activity_update_meta( $activity_id, '_bp_akismet_history', $event );
631
+ }
632
+
633
+ /**
634
+ * Get an activity item's Akismet history.
635
+ *
636
+ * @since 1.6.0
637
+ *
638
+ * @param int $activity_id Activity item ID.
639
+ * @return array The activity item's Akismet history.
640
+ */
641
+ public function get_activity_history( $activity_id = 0 ) {
642
+ $history = bp_activity_get_meta( $activity_id, '_bp_akismet_history' );
643
+ if ( $history === false )
644
+ $history = array();
645
+
646
+ // Sort it by the time recorded.
647
+ usort( $history, 'akismet_cmp_time' );
648
+
649
+ return $history;
650
+ }
651
+ }
bp-activity/css/mentions-rtl.css ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .atwho-view {
2
+ background: rgba(204, 204, 204, 0.8);
3
+ border-radius: 2px;
4
+ border: 1px solid rgb(204, 204, 204);
5
+ box-shadow: 0 0 5px rgba(204, 204, 204, 0.25), 0 0 1px #FFF;
6
+ color: #D84800;
7
+ display: none;
8
+ font-family: sans-serif;
9
+ margin-top: 18px;
10
+ position: absolute;
11
+ top: 0;
12
+ z-index: 1000; /* >999 for wp-admin */
13
+ }
14
+ .atwho-view {
15
+ left: 0;
16
+ }
17
+ .atwho-view ul {
18
+ background: #FFF;
19
+ list-style: none;
20
+ margin: auto;
21
+ padding: 0;
22
+ }
23
+ .atwho-view ul li {
24
+ border-bottom: 1px solid #EFEFEF;
25
+ box-sizing: content-box;
26
+ cursor: pointer;
27
+ display: block;
28
+ font-size: 14px;
29
+ height: 20px;
30
+ line-height: 20px;
31
+ margin: 0;
32
+ overflow: hidden;
33
+ padding: 5px 10px;
34
+ }
35
+ .atwho-view img {
36
+ border-radius: 2px;
37
+ float: left;
38
+ height: 20px;
39
+ margin-top:0;
40
+ width: 20px;
41
+ }
42
+ .atwho-view strong {
43
+ background: #EFEFEF;
44
+ font-weight: bold;
45
+ }
46
+ .atwho-view .username strong {
47
+ color: #D54E21;
48
+ }
49
+ .atwho-view small {
50
+ color: #AAA;
51
+ float: left;
52
+ font-size: smaller;
53
+ font-weight: normal;
54
+ margin: 0 40px 0 10px;
55
+ }
56
+ .atwho-view .cur {
57
+ background: rgba(239, 239, 239, 0.5);
58
+ }
59
+
60
+ @media (max-width: 900px) {
61
+ .atwho-view img {
62
+ float: right;
63
+ margin: 0 0 0 10px;
64
+ }
65
+ }
66
+ @media (max-width: 400px) {
67
+ .atwho-view ul li {
68
+ font-size: 16px;
69
+ line-height: 23px;
70
+ padding: 13px;
71
+ }
72
+ .atwho-view ul li img {
73
+ height: 30px;
74
+ margin-top: -5px;
75
+ width: 30px;
76
+ }
77
+ .atwho-view {
78
+ border-radius: 0;
79
+ height: 100%;
80
+ right: 0 !important;
81
+ width: 100%;
82
+ }
83
+ .atwho-view ul li .username {
84
+ display: inline-block;
85
+ margin: -10px 0 0 0;
86
+ padding: 10px 0;
87
+ }
88
+ .atwho-view ul li small {
89
+ display: inline-block;
90
+ margin-right: 20px;
91
+ }
92
+ }
bp-activity/css/mentions-rtl.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .atwho-view{background:rgba(204,204,204,.8);border-radius:2px;border:1px solid #ccc;box-shadow:0 0 5px rgba(204,204,204,.25),0 0 1px #FFF;color:#D84800;display:none;font-family:sans-serif;margin-top:18px;position:absolute;top:0;z-index:1000;left:0}.atwho-view ul{background:#FFF;list-style:none;margin:auto;padding:0}.atwho-view ul li{border-bottom:1px solid #EFEFEF;box-sizing:content-box;cursor:pointer;display:block;font-size:14px;height:20px;line-height:20px;margin:0;overflow:hidden;padding:5px 10px}.atwho-view img{border-radius:2px;float:left;height:20px;margin-top:0;width:20px}.atwho-view strong{background:#EFEFEF;font-weight:700}.atwho-view .username strong{color:#D54E21}.atwho-view small{color:#AAA;float:left;font-size:smaller;font-weight:400;margin:0 40px 0 10px}.atwho-view .cur{background:rgba(239,239,239,.5)}@media (max-width:900px){.atwho-view img{float:right;margin:0 0 0 10px}}@media (max-width:400px){.atwho-view ul li{font-size:16px;line-height:23px;padding:13px}.atwho-view ul li img{height:30px;margin-top:-5px;width:30px}.atwho-view{border-radius:0;height:100%;right:0!important;width:100%}.atwho-view ul li .username{display:inline-block;margin:-10px 0 0;padding:10px 0}.atwho-view ul li small{display:inline-block;margin-right:20px}}
bp-activity/css/mentions.css ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .atwho-view {
2
+ background: rgba(204, 204, 204, 0.8);
3
+ border-radius: 2px;
4
+ border: 1px solid rgb(204, 204, 204);
5
+ box-shadow: 0 0 5px rgba(204, 204, 204, 0.25), 0 0 1px #FFF;
6
+ color: #D84800;
7
+ display: none;
8
+ font-family: sans-serif;
9
+ margin-top: 18px;
10
+ position: absolute;
11
+ top: 0;
12
+ z-index: 1000; /* >999 for wp-admin */
13
+ }
14
+ /* rtl:ignore */
15
+ .atwho-view {
16
+ left: 0;
17
+ }
18
+ .atwho-view ul {
19
+ background: #FFF;
20
+ list-style: none;
21
+ margin: auto;
22
+ padding: 0;
23
+ }
24
+ .atwho-view ul li {
25
+ border-bottom: 1px solid #EFEFEF;
26
+ box-sizing: content-box;
27
+ cursor: pointer;
28
+ display: block;
29
+ font-size: 14px;
30
+ height: 20px;
31
+ line-height: 20px;
32
+ margin: 0;
33
+ overflow: hidden;
34
+ padding: 5px 10px;
35
+ }
36
+ .atwho-view img {
37
+ border-radius: 2px;
38
+ float: right;
39
+ height: 20px;
40
+ margin-top:0;
41
+ width: 20px;
42
+ }
43
+ .atwho-view strong {
44
+ background: #EFEFEF;
45
+ font-weight: bold;
46
+ }
47
+ .atwho-view .username strong {
48
+ color: #D54E21;
49
+ }
50
+ .atwho-view small {
51
+ color: #AAA;
52
+ float: right;
53
+ font-size: smaller;
54
+ font-weight: normal;
55
+ margin: 0 10px 0 40px;
56
+ }
57
+ .atwho-view .cur {
58
+ background: rgba(239, 239, 239, 0.5);
59
+ }
60
+
61
+ @media (max-width: 900px) {
62
+ .atwho-view img {
63
+ float: left;
64
+ margin: 0 10px 0 0;
65
+ }
66
+ }
67
+ @media (max-width: 400px) {
68
+ .atwho-view ul li {
69
+ font-size: 16px;
70
+ line-height: 23px;
71
+ padding: 13px;
72
+ }
73
+ .atwho-view ul li img {
74
+ height: 30px;
75
+ margin-top: -5px;
76
+ width: 30px;
77
+ }
78
+ .atwho-view {
79
+ border-radius: 0;
80
+ height: 100%;
81
+ left: 0 !important;
82
+ width: 100%;
83
+ }
84
+ .atwho-view ul li .username {
85
+ display: inline-block;
86
+ margin: -10px 0 0 0;
87
+ padding: 10px 0;
88
+ }
89
+ .atwho-view ul li small {
90
+ display: inline-block;
91
+ margin-left: 20px;
92
+ }
93
+ }
bp-activity/css/mentions.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .atwho-view{background:rgba(204,204,204,.8);border-radius:2px;border:1px solid #ccc;box-shadow:0 0 5px rgba(204,204,204,.25),0 0 1px #FFF;color:#D84800;display:none;font-family:sans-serif;margin-top:18px;position:absolute;top:0;z-index:1000;left:0}.atwho-view ul{background:#FFF;list-style:none;margin:auto;padding:0}.atwho-view ul li{border-bottom:1px solid #EFEFEF;box-sizing:content-box;cursor:pointer;display:block;font-size:14px;height:20px;line-height:20px;margin:0;overflow:hidden;padding:5px 10px}.atwho-view img{border-radius:2px;float:right;height:20px;margin-top:0;width:20px}.atwho-view strong{background:#EFEFEF;font-weight:700}.atwho-view .username strong{color:#D54E21}.atwho-view small{color:#AAA;float:right;font-size:smaller;font-weight:400;margin:0 10px 0 40px}.atwho-view .cur{background:rgba(239,239,239,.5)}@media (max-width:900px){.atwho-view img{float:left;margin:0 10px 0 0}}@media (max-width:400px){.atwho-view ul li{font-size:16px;line-height:23px;padding:13px}.atwho-view ul li img{height:30px;margin-top:-5px;width:30px}.atwho-view{border-radius:0;height:100%;left:0!important;width:100%}.atwho-view ul li .username{display:inline-block;margin:-10px 0 0;padding:10px 0}.atwho-view ul li small{display:inline-block;margin-left:20px}}
bp-activity/js/mentions.js ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global bp */
2
+
3
+ window.bp = window.bp || {};
4
+
5
+ ( function( bp, $, undefined ) {
6
+ var mentionsQueryCache = [],
7
+ mentionsItem;
8
+
9
+ bp.mentions = bp.mentions || {};
10
+ bp.mentions.users = window.bp.mentions.users || [];
11
+
12
+ if ( typeof window.BP_Suggestions === 'object' ) {
13
+ bp.mentions.users = window.BP_Suggestions.friends || bp.mentions.users;
14
+ }
15
+
16
+ /**
17
+ * Adds BuddyPress @mentions to form inputs.
18
+ *
19
+ * @param {array|object} options If array, becomes the suggestions' data source. If object, passed as config to $.atwho().
20
+ * @since 2.1.0
21
+ */
22
+ $.fn.bp_mentions = function( options ) {
23
+ if ( $.isArray( options ) ) {
24
+ options = { data: options };
25
+ }
26
+
27
+ /**
28
+ * Default options for at.js; see https://github.com/ichord/At.js/.
29
+ */
30
+ var suggestionsDefaults = {
31
+ delay: 200,
32
+ hide_without_suffix: true,
33
+ insert_tpl: '</>${atwho-data-value}</>', // For contentEditable, the fake tags make jQuery insert a textNode.
34
+ limit: 10,
35
+ start_with_space: false,
36
+ suffix: '',
37
+
38
+ callbacks: {
39
+ /**
40
+ * Custom filter to only match the start of spaced words.
41
+ * Based on the core/default one.
42
+ *
43
+ * @param {string} query
44
+ * @param {array} data
45
+ * @param {string} search_key
46
+ * @return {array}
47
+ * @since 2.1.0
48
+ */
49
+ filter: function( query, data, search_key ) {
50
+ var item, _i, _len, _results = [],
51
+ regxp = new RegExp( '^' + query + '| ' + query, 'ig' ); // start of string, or preceded by a space.
52
+
53
+ for ( _i = 0, _len = data.length; _i < _len; _i++ ) {
54
+ item = data[ _i ];
55
+ if ( item[ search_key ].toLowerCase().match( regxp ) ) {
56
+ _results.push( item );
57
+ }
58
+ }
59
+
60
+ return _results;
61
+ },
62
+
63
+ /**
64
+ * Removes some spaces around highlighted string and tweaks regex to allow spaces
65
+ * (to match display_name). Based on the core default.
66
+ *
67
+ * @param {unknown} li
68
+ * @param {string} query
69
+ * @return {string}
70
+ * @since 2.1.0
71
+ */
72
+ highlighter: function( li, query ) {
73
+ if ( ! query ) {
74
+ return li;
75
+ }
76
+
77
+ var regexp = new RegExp( '>(\\s*|[\\w\\s]*)(' + this.at.replace( '+', '\\+') + '?' + query.replace( '+', '\\+' ) + ')([\\w ]*)\\s*<', 'ig' );
78
+ return li.replace( regexp, function( str, $1, $2, $3 ) {
79
+ return '>' + $1 + '<strong>' + $2 + '</strong>' + $3 + '<';
80
+ });
81
+ },
82
+
83
+ /**
84
+ * Reposition the suggestion list dynamically.
85
+ *
86
+ * @param {unknown} offset
87
+ * @since 2.1.0
88
+ */
89
+ before_reposition: function( offset ) {
90
+ // get the iframe, if any, already applied with atwho
91
+ var caret,
92
+ line,
93
+ iframeOffset,
94
+ move,
95
+ $view = $( '#atwho-ground-' + this.id + ' .atwho-view' ),
96
+ $body = $( 'body' ),
97
+ atwhoDataValue = this.$inputor.data( 'atwho' );
98
+
99
+ if ( 'undefined' !== atwhoDataValue && 'undefined' !== atwhoDataValue.iframe && null !== atwhoDataValue.iframe ) {
100
+ caret = this.$inputor.caret( 'offset', { iframe: atwhoDataValue.iframe } );
101
+ // Caret.js no longer calculates iframe caret position from the window (it's now just within the iframe).
102
+ // We need to get the iframe offset from the window and merge that into our object.
103
+ iframeOffset = $( atwhoDataValue.iframe ).offset();
104
+ if ( 'undefined' !== iframeOffset ) {
105
+ caret.left += iframeOffset.left;
106
+ caret.top += iframeOffset.top;
107
+ }
108
+ } else {
109
+ caret = this.$inputor.caret( 'offset' );
110
+ }
111
+
112
+ // If the caret is past horizontal half, then flip it, yo
113
+ if ( caret.left > ( $body.width() / 2 ) ) {
114
+ $view.addClass( 'right' );
115
+ move = caret.left - offset.left - this.view.$el.width();
116
+ } else {
117
+ $view.removeClass( 'right' );
118
+ move = caret.left - offset.left + 1;
119
+ }
120
+
121
+ // If we're on a small screen, scroll to caret
122
+ if ( $body.width() <= 400 ) {
123
+ $( document ).scrollTop( caret.top - 6 );
124
+ }
125
+
126
+ // New position is under the caret (never above) and positioned to follow
127
+ // Dynamic sizing based on the input area (remove 'px' from end)
128
+ line = parseInt( this.$inputor.css( 'line-height' ).substr( 0, this.$inputor.css( 'line-height' ).length - 2 ), 10 );
129
+ if ( !line || line < 5 ) { // sanity check, and catch no line-height
130
+ line = 19;
131
+ }
132
+
133
+ offset.top = caret.top + line;
134
+ offset.left += move;
135
+ },
136
+
137
+ /**
138
+ * Override default behaviour which inserts junk tags in the WordPress Visual editor.
139
+ *
140
+ * @param {unknown} $inputor Element which we're inserting content into.
141
+ * @param {string) content The content that will be inserted.
142
+ * @param {string) suffix Applied to the end of the content string.
143
+ * @return {string}
144
+ * @since 2.1.0
145
+ */
146
+ inserting_wrapper: function( $inputor, content, suffix ) {
147
+ return '' + content + suffix;
148
+ }
149
+ }
150
+ },
151
+
152
+ /**
153
+ * Default options for our @mentions; see https://github.com/ichord/At.js/.
154
+ */
155
+ mentionsDefaults = {
156
+ callbacks: {
157
+ /**
158
+ * If there are no matches for the query in this.data, then query BuddyPress.
159
+ *
160
+ * @param {string} query Partial @mention to search for.
161
+ * @param {function} render_view Render page callback function.
162
+ * @since 2.1.0
163
+ */
164
+ remote_filter: function( query, render_view ) {
165
+ var self = $( this ),
166
+ params = {};
167
+
168
+ mentionsItem = mentionsQueryCache[ query ];
169
+ if ( typeof mentionsItem === 'object' ) {
170
+ render_view( mentionsItem );
171
+ return;
172
+ }
173
+
174
+ if ( self.xhr ) {
175
+ self.xhr.abort();
176
+ }
177
+
178
+ params = { 'action': 'bp_get_suggestions', 'term': query, 'type': 'members' };
179
+
180
+ if ( $.isNumeric( this.$inputor.data( 'suggestions-group-id' ) ) ) {
181
+ params['group-id'] = parseInt( this.$inputor.data( 'suggestions-group-id' ), 10 );
182
+ }
183
+
184
+ self.xhr = $.getJSON( ajaxurl, params )
185
+ /**
186
+ * Success callback for the @suggestions lookup.
187
+ *
188
+ * @param {object} response Details of users matching the query.
189
+ * @since 2.1.0
190
+ */
191
+ .done(function( response ) {
192
+ if ( ! response.success ) {
193
+ return;
194
+ }
195
+
196
+ var data = $.map( response.data,
197
+ /**
198
+ * Create a composite index to determine ordering of results;
199
+ * nicename matches will appear on top.
200
+ *
201
+ * @param {array} suggestion A suggestion's original data.
202
+ * @return {array} A suggestion's new data.
203
+ * @since 2.1.0
204
+ */
205
+ function( suggestion ) {
206
+ suggestion.search = suggestion.search || suggestion.ID + ' ' + suggestion.name;
207
+ return suggestion;
208
+ }
209
+ );
210
+
211
+ mentionsQueryCache[ query ] = data;
212
+ render_view( data );
213
+ });
214
+ }
215
+ },
216
+
217
+ data: $.map( options.data,
218
+ /**
219
+ * Create a composite index to search against of nicename + display name.
220
+ * This will also determine ordering of results, so nicename matches will appear on top.
221
+ *
222
+ * @param {array} suggestion A suggestion's original data.
223
+ * @return {array} A suggestion's new data.
224
+ * @since 2.1.0
225
+ */
226
+ function( suggestion ) {
227
+ suggestion.search = suggestion.search || suggestion.ID + ' ' + suggestion.name;
228
+ return suggestion;
229
+ }
230
+ ),
231
+
232
+ at: '@',
233
+ search_key: 'search',
234
+ tpl: '<li data-value="@${ID}"><img src="${image}" /><span class="username">@${ID}</span><small>${name}</small></li>'
235
+ },
236
+
237
+ opts = $.extend( true, {}, suggestionsDefaults, mentionsDefaults, options );
238
+ return $.fn.atwho.call( this, opts );
239
+ };
240
+
241
+ $( document ).ready(function() {
242
+ // Activity/reply, post comments, dashboard post 'text' editor.
243
+ $( '.bp-suggestions, #comments form textarea, .wp-editor-area' ).bp_mentions( bp.mentions.users );
244
+ });
245
+
246
+ bp.mentions.tinyMCEinit = function() {
247
+ if ( typeof window.tinyMCE === 'undefined' || window.tinyMCE.activeEditor === null || typeof window.tinyMCE.activeEditor === 'undefined' ) {
248
+ return;
249
+ } else {
250
+ $( window.tinyMCE.activeEditor.contentDocument.activeElement )
251
+ .atwho( 'setIframe', $( '.wp-editor-wrap iframe' )[0] )
252
+ .bp_mentions( bp.mentions.users );
253
+ }
254
+ };
255
+ })( bp, jQuery );
bp-activity/js/mentions.min.js ADDED
@@ -0,0 +1 @@
 
1
+ window.bp=window.bp||{},function(a,b,c){var d,e=[];a.mentions=a.mentions||{},a.mentions.users=window.bp.mentions.users||[],"object"==typeof window.BP_Suggestions&&(a.mentions.users=window.BP_Suggestions.friends||a.mentions.users),b.fn.bp_mentions=function(a){b.isArray(a)&&(a={data:a});var c={delay:200,hide_without_suffix:!0,insert_tpl:"</>${atwho-data-value}</>",limit:10,start_with_space:!1,suffix:"",callbacks:{filter:function(a,b,c){var d,e,f,g=[],h=new RegExp("^"+a+"| "+a,"ig");for(e=0,f=b.length;e<f;e++)d=b[e],d[c].toLowerCase().match(h)&&g.push(d);return g},highlighter:function(a,b){if(!b)return a;var c=new RegExp(">(\\s*|[\\w\\s]*)("+this.at.replace("+","\\+")+"?"+b.replace("+","\\+")+")([\\w ]*)\\s*<","ig");return a.replace(c,function(a,b,c,d){return">"+b+"<strong>"+c+"</strong>"+d+"<"})},before_reposition:function(a){var c,d,e,f,g=b("#atwho-ground-"+this.id+" .atwho-view"),h=b("body"),i=this.$inputor.data("atwho");"undefined"!==i&&"undefined"!==i.iframe&&null!==i.iframe?(c=this.$inputor.caret("offset",{iframe:i.iframe}),e=b(i.iframe).offset(),"undefined"!==e&&(c.left+=e.left,c.top+=e.top)):c=this.$inputor.caret("offset"),c.left>h.width()/2?(g.addClass("right"),f=c.left-a.left-this.view.$el.width()):(g.removeClass("right"),f=c.left-a.left+1),h.width()<=400&&b(document).scrollTop(c.top-6),d=parseInt(this.$inputor.css("line-height").substr(0,this.$inputor.css("line-height").length-2),10),(!d||d<5)&&(d=19),a.top=c.top+d,a.left+=f},inserting_wrapper:function(a,b,c){return""+b+c}}},f={callbacks:{remote_filter:function(a,c){var f=b(this),g={};return d=e[a],"object"==typeof d?void c(d):(f.xhr&&f.xhr.abort(),g={action:"bp_get_suggestions",term:a,type:"members"},b.isNumeric(this.$inputor.data("suggestions-group-id"))&&(g["group-id"]=parseInt(this.$inputor.data("suggestions-group-id"),10)),void(f.xhr=b.getJSON(ajaxurl,g).done(function(d){if(d.success){var f=b.map(d.data,function(a){return a.search=a.search||a.ID+" "+a.name,a});e[a]=f,c(f)}})))}},data:b.map(a.data,function(a){return a.search=a.search||a.ID+" "+a.name,a}),at:"@",search_key:"search",tpl:'<li data-value="@${ID}"><img src="${image}" /><span class="username">@${ID}</span><small>${name}</small></li>'},g=b.extend(!0,{},c,f,a);return b.fn.atwho.call(this,g)},b(document).ready(function(){b(".bp-suggestions, #comments form textarea, .wp-editor-area").bp_mentions(a.mentions.users)}),a.mentions.tinyMCEinit=function(){"undefined"!=typeof window.tinyMCE&&null!==window.tinyMCE.activeEditor&&"undefined"!=typeof window.tinyMCE.activeEditor&&b(window.tinyMCE.activeEditor.contentDocument.activeElement).atwho("setIframe",b(".wp-editor-wrap iframe")[0]).bp_mentions(a.mentions.users)}}(bp,jQuery);
bp-blogs/bp-blogs-actions.php CHANGED
@@ -1,32 +1,32 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Blogs Actions.
5
  *
6
  * @package BuddyPress
7
  * @subpackage BlogsActions
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
12
 
13
  /**
14
  * Redirect to a random blog in the multisite network.
15
  *
16
- * @since BuddyPress (1.0.0)
17
  */
18
  function bp_blogs_redirect_to_random_blog() {
19
 
20
- // Bail if not looking for a random blog
21
  if ( ! bp_is_blogs_component() || ! isset( $_GET['random-blog'] ) )
22
  return;
23
 
24
- // Multisite is active so find a random blog
25
  if ( is_multisite() ) {
26
  $blog = bp_blogs_get_random_blogs( 1, 1 );
27
  bp_core_redirect( get_home_url( $blog['blogs'][0]->blog_id ) );
28
 
29
- // No multisite and still called, always redirect to root
30
  } else {
31
  bp_core_redirect( bp_core_get_root_domain() );
32
  }
1
  <?php
 
2
  /**
3
  * BuddyPress Blogs Actions.
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsActions
7
+ * @since 1.5.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
 
13
  /**
14
  * Redirect to a random blog in the multisite network.
15
  *
16
+ * @since 1.0.0
17
  */
18
  function bp_blogs_redirect_to_random_blog() {
19
 
20
+ // Bail if not looking for a random blog.
21
  if ( ! bp_is_blogs_component() || ! isset( $_GET['random-blog'] ) )
22
  return;
23
 
24
+ // Multisite is active so find a random blog.
25
  if ( is_multisite() ) {
26
  $blog = bp_blogs_get_random_blogs( 1, 1 );
27
  bp_core_redirect( get_home_url( $blog['blogs'][0]->blog_id ) );
28
 
29
+ // No multisite and still called, always redirect to root.
30
  } else {
31
  bp_core_redirect( bp_core_get_root_domain() );
32
  }
bp-blogs/bp-blogs-activity.php CHANGED
@@ -1,66 +1,127 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Blogs Activity.
5
  *
6
  * @package BuddyPress
7
  * @subpackage BlogsActivity
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
12
 
13
  /**
14
  * Register activity actions for the blogs component.
15
  *
16
- * @since BuddyPress (1.0.0)
17
- *
18
- * @global object $bp The BuddyPress global settings object.
19
  *
20
  * @return bool|null Returns false if activity component is not active.
21
  */
22
  function bp_blogs_register_activity_actions() {
23
- global $bp;
24
-
25
- // Bail if activity is not active
26
- if ( ! bp_is_active( 'activity' ) ) {
27
- return false;
28
- }
29
-
30
  if ( is_multisite() ) {
31
  bp_activity_set_action(
32
- $bp->blogs->id,
33
  'new_blog',
34
  __( 'New site created', 'buddypress' ),
35
- 'bp_blogs_format_activity_action_new_blog'
 
 
 
36
  );
37
  }
38
 
39
- bp_activity_set_action(
40
- $bp->blogs->id,
41
- 'new_blog_post',
42
- __( 'New post published', 'buddypress' ),
43
- 'bp_blogs_format_activity_action_new_blog_post'
44
- );
45
-
46
- bp_activity_set_action(
47
- $bp->blogs->id,
48
- 'new_blog_comment',
49
- __( 'New post comment posted', 'buddypress' ),
50
- 'bp_blogs_format_activity_action_new_blog_comment'
51
- );
52
-
53
  do_action( 'bp_blogs_register_activity_actions' );
54
  }
55
  add_action( 'bp_register_activity_actions', 'bp_blogs_register_activity_actions' );
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  /**
58
  * Format 'new_blog' activity actions.
59
  *
60
- * @since BuddyPress (2.0.0)
61
  *
62
- * @param string $action Static activity action.
63
- * @param obj $activity Activity data object.
 
64
  */
65
  function bp_blogs_format_activity_action_new_blog( $action, $activity ) {
66
  $blog_url = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
@@ -68,7 +129,7 @@ function bp_blogs_format_activity_action_new_blog( $action, $activity ) {
68
 
69
  $action = sprintf( __( '%s created the site %s', 'buddypress' ), bp_core_get_userlink( $activity->user_id ), '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
70
 
71
- // Legacy filter - requires the BP_Blogs_Blog object
72
  if ( has_filter( 'bp_blogs_activity_created_blog_action' ) ) {
73
  $user_blog = BP_Blogs_Blog::get_user_blog( $activity->user_id, $activity->item_id );
74
  if ( $user_blog ) {
@@ -80,16 +141,25 @@ function bp_blogs_format_activity_action_new_blog( $action, $activity ) {
80
  }
81
  }
82
 
 
 
 
 
 
 
 
 
83
  return apply_filters( 'bp_blogs_format_activity_action_new_blog', $action, $activity );
84
  }
85
 
86
  /**
87
  * Format 'new_blog_post' activity actions.
88
  *
89
- * @since BuddyPress (2.0.0)
90
  *
91
- * @param string $action Static activity action.
92
- * @param obj $activity Activity data object.
 
93
  */
94
  function bp_blogs_format_activity_action_new_blog_post( $action, $activity ) {
95
  $blog_url = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
@@ -103,34 +173,75 @@ function bp_blogs_format_activity_action_new_blog_post( $action, $activity ) {
103
  bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
104
  }
105
 
106
- $post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
- $post_title = bp_activity_get_meta( $activity->id, 'post_title' );
 
 
109
 
110
- // Should only be empty at the time of post creation
 
 
 
 
 
 
 
 
111
  if ( empty( $post_title ) ) {
 
 
 
112
  switch_to_blog( $activity->item_id );
113
 
114
  $post = get_post( $activity->secondary_item_id );
115
  if ( is_a( $post, 'WP_Post' ) ) {
116
- $post_title = $post->post_title;
117
- bp_activity_update_meta( $activity->id, 'post_title', $post_title );
 
 
 
 
 
 
 
118
  }
119
 
120
  restore_current_blog();
121
  }
122
 
123
- $post_link = '<a href="' . $post_url . '">' . $post_title . '</a>';
 
124
 
125
  $user_link = bp_core_get_userlink( $activity->user_id );
126
 
 
127
  if ( is_multisite() ) {
128
  $action = sprintf( __( '%1$s wrote a new post, %2$s, on the site %3$s', 'buddypress' ), $user_link, $post_link, '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
129
  } else {
130
  $action = sprintf( __( '%1$s wrote a new post, %2$s', 'buddypress' ), $user_link, $post_link );
131
  }
132
 
133
- // Legacy filter - requires the post object
134
  if ( has_filter( 'bp_blogs_activity_new_post_action' ) ) {
135
  switch_to_blog( $activity->item_id );
136
  $post = get_post( $activity->secondary_item_id );
@@ -141,20 +252,56 @@ function bp_blogs_format_activity_action_new_blog_post( $action, $activity ) {
141
  }
142
  }
143
 
 
 
 
 
 
 
 
 
144
  return apply_filters( 'bp_blogs_format_activity_action_new_blog_post', $action, $activity );
145
  }
146
 
147
  /**
148
  * Format 'new_blog_comment' activity actions.
149
  *
150
- * @since BuddyPress (2.0.0)
151
  *
152
- * @param string $action Static activity action.
153
- * @param obj $activity Activity data object.
 
154
  */
155
  function bp_blogs_format_activity_action_new_blog_comment( $action, $activity ) {
156
- $blog_url = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
157
- $blog_name = bp_blogs_get_blogmeta( $activity->item_id, 'name' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  if ( empty( $blog_url ) || empty( $blog_name ) ) {
160
  $blog_url = get_home_url( $activity->item_id );
@@ -164,10 +311,33 @@ function bp_blogs_format_activity_action_new_blog_comment( $action, $activity )
164
  bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
165
  }
166
 
167
- $post_url = bp_activity_get_meta( $activity->id, 'post_url' );
168
- $post_title = bp_activity_get_meta( $activity->id, 'post_title' );
 
 
 
169
 
170
- // Should only be empty at the time of post creation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  if ( empty( $post_url ) || empty( $post_title ) ) {
172
  switch_to_blog( $activity->item_id );
173
 
@@ -188,7 +358,7 @@ function bp_blogs_format_activity_action_new_blog_comment( $action, $activity )
188
  restore_current_blog();
189
  }
190
 
191
- $post_link = '<a href="' . $post_url . '">' . $post_title . '</a>';
192
  $user_link = bp_core_get_userlink( $activity->user_id );
193
 
194
  if ( is_multisite() ) {
@@ -197,7 +367,7 @@ function bp_blogs_format_activity_action_new_blog_comment( $action, $activity )
197
  $action = sprintf( __( '%1$s commented on the post, %2$s', 'buddypress' ), $user_link, $post_link );
198
  }
199
 
200
- // Legacy filter - requires the comment object
201
  if ( has_filter( 'bp_blogs_activity_new_comment_action' ) ) {
202
  switch_to_blog( $activity->item_id );
203
  $comment = get_comment( $activity->secondary_item_id );
@@ -208,6 +378,14 @@ function bp_blogs_format_activity_action_new_blog_comment( $action, $activity )
208
  }
209
  }
210
 
 
 
 
 
 
 
 
 
211
  return apply_filters( 'bp_blogs_format_activity_action_new_blog_comment', $action, $activity );
212
  }
213
 
@@ -216,7 +394,7 @@ function bp_blogs_format_activity_action_new_blog_comment( $action, $activity )
216
  *
217
  * This reduces database overhead during the activity loop.
218
  *
219
- * @since BuddyPress (2.0.0)
220
  *
221
  * @param array $activities Array of activity items.
222
  * @return array
@@ -247,12 +425,11 @@ add_filter( 'bp_activity_prefetch_object_data', 'bp_blogs_prefetch_activity_obje
247
  /**
248
  * Record blog-related activity to the activity stream.
249
  *
250
- * @since BuddyPress (1.0.0)
251
  *
252
  * @see bp_activity_add() for description of parameters.
253
- * @global object $bp The BuddyPress global settings object.
254
  *
255
- * @param array $args {
256
  * See {@link bp_activity_add()} for complete description of arguments.
257
  * The arguments listed here have different default values from
258
  * bp_activity_add().
@@ -261,18 +438,12 @@ add_filter( 'bp_activity_prefetch_object_data', 'bp_blogs_prefetch_activity_obje
261
  * @return int|bool On success, returns the activity ID. False on failure.
262
  */
263
  function bp_blogs_record_activity( $args = '' ) {
264
- global $bp;
265
-
266
- // Bail if activity is not active
267
- if ( ! bp_is_active( 'activity' ) )
268
- return false;
269
-
270
  $defaults = array(
271
  'user_id' => bp_loggedin_user_id(),
272
  'action' => '',
273
  'content' => '',
274
  'primary_link' => '',
275
- 'component' => $bp->blogs->id,
276
  'type' => false,
277
  'item_id' => false,
278
  'secondary_item_id' => false,
@@ -281,39 +452,53 @@ function bp_blogs_record_activity( $args = '' ) {
281
  );
282
 
283
  $r = wp_parse_args( $args, $defaults );
284
- extract( $r, EXTR_SKIP );
285
 
286
- // Remove large images and replace them with just one image thumbnail
287
- if ( !empty( $content ) )
288
- $content = bp_activity_thumbnail_content_images( $content, $primary_link, $r );
289
 
290
- if ( !empty( $action ) )
291
- $action = apply_filters( 'bp_blogs_record_activity_action', $action );
 
 
 
 
 
 
 
292
 
293
- if ( !empty( $content ) )
294
- $content = apply_filters( 'bp_blogs_record_activity_content', bp_create_excerpt( $content ), $content );
 
 
 
 
 
 
 
 
 
 
 
295
 
296
  // Check for an existing entry and update if one exists.
297
  $id = bp_activity_get_activity_id( array(
298
- 'user_id' => $user_id,
299
- 'component' => $component,
300
- 'type' => $type,
301
- 'item_id' => $item_id,
302
- 'secondary_item_id' => $secondary_item_id
303
  ) );
304
 
305
- return bp_activity_add( array( 'id' => $id, 'user_id' => $user_id, 'action' => $action, 'content' => $content, 'primary_link' => $primary_link, 'component' => $component, 'type' => $type, 'item_id' => $item_id, 'secondary_item_id' => $secondary_item_id, 'recorded_time' => $recorded_time, 'hide_sitewide' => $hide_sitewide ) );
306
  }
307
 
308
  /**
309
  * Delete a blog-related activity stream item.
310
  *
311
- * @since BuddyPress (1.0.0)
312
  *
313
  * @see bp_activity_delete() for description of parameters.
314
- * @global object $bp The BuddyPress global settings object.
315
  *
316
- * @param array $args {
317
  * See {@link bp_activity_delete()} for complete description of arguments.
318
  * The arguments listed here have different default values from
319
  * bp_activity_add().
@@ -321,31 +506,16 @@ function bp_blogs_record_activity( $args = '' ) {
321
  * }
322
  * @return bool True on success, false on failure.
323
  */
324
- function bp_blogs_delete_activity( $args = true ) {
325
- global $bp;
326
-
327
- // Bail if activity is not active
328
- if ( ! bp_is_active( 'activity' ) )
329
- return false;
330
-
331
- $defaults = array(
332
  'item_id' => false,
333
- 'component' => $bp->blogs->id,
334
  'type' => false,
335
  'user_id' => false,
336
  'secondary_item_id' => false
337
- );
338
-
339
- $params = wp_parse_args( $args, $defaults );
340
- extract( $params, EXTR_SKIP );
341
-
342
- bp_activity_delete_by_item_id( array(
343
- 'item_id' => $item_id,
344
- 'component' => $component,
345
- 'type' => $type,
346
- 'user_id' => $user_id,
347
- 'secondary_item_id' => $secondary_item_id
348
  ) );
 
 
349
  }
350
 
351
  /**
@@ -359,9 +529,9 @@ function bp_blogs_delete_activity( $args = true ) {
359
  * to blogmeta and checks the values in blogmeta instead. This is to prevent
360
  * multiple {@link switch_to_blog()} calls in the activity stream.
361
  *
362
- * @since BuddyPress (2.0.0)
363
  *
364
- * @param object $activity The BP_Activity_Activity object
365
  * @return bool
366
  */
367
  function bp_blogs_comments_open( $activity ) {
@@ -369,24 +539,24 @@ function bp_blogs_comments_open( $activity ) {
369
 
370
  $blog_id = $activity->item_id;
371
 
372
- // see if we've mirrored the close comments option before
373
  $days_old = bp_blogs_get_blogmeta( $blog_id, 'close_comments_days_old' );
374
 
375
- // we've never cached these items before, so do it now
376
  if ( '' === $days_old ) {
377
  switch_to_blog( $blog_id );
378
 
379
- // use comments_open()
380
  remove_filter( 'comments_open', 'bp_comments_open', 10, 2 );
381
  $open = comments_open( $activity->secondary_item_id );
382
  add_filter( 'comments_open', 'bp_comments_open', 10, 2 );
383
 
384
- // might as well mirror values to blogmeta since we're here!
385
  $thread_depth = get_option( 'thread_comments' );
386
  if ( ! empty( $thread_depth ) ) {
387
  $thread_depth = get_option( 'thread_comments_depth' );
388
  } else {
389
- // perhaps filter this?
390
  $thread_depth = 1;
391
  }
392
 
@@ -396,11 +566,11 @@ function bp_blogs_comments_open( $activity ) {
396
 
397
  restore_current_blog();
398
 
399
- // check blogmeta and manually check activity item
400
- // basically a copy of _close_comments_for_old_post()
401
  } else {
402
 
403
- // comments are closed
404
  if ( 'closed' == bp_activity_get_meta( $activity->id, 'post_comment_status' ) ) {
405
  return false;
406
  }
@@ -414,7 +584,8 @@ function bp_blogs_comments_open( $activity ) {
414
  return $open;
415
  }
416
 
417
- /* commenting out for now - needs some more thought...
 
418
  should we add the post type to activity meta?
419
 
420
  $post = get_post($post_id);
@@ -435,6 +606,134 @@ function bp_blogs_comments_open( $activity ) {
435
  return $open;
436
  }
437
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  /** POST COMMENT SYNCHRONIZATION ****************************************/
439
 
440
  /**
@@ -442,93 +741,119 @@ function bp_blogs_comments_open( $activity ) {
442
  *
443
  * Note: This is only a one-way sync - activity comments -> blog comment.
444
  *
445
- * For blog post -> activity comment, see {@link bp_blogs_record_comment()}.
446
  *
447
- * @since BuddyPress (2.0.0)
 
448
  *
449
- * @param int $comment_id The activity ID for the posted activity comment.
450
- * @param array $params Parameters for the activity comment.
451
- * @param object Parameters of the parent activity item (in this case, the blog post).
452
  */
453
  function bp_blogs_sync_add_from_activity_comment( $comment_id, $params, $parent_activity ) {
454
- // if parent activity isn't a blog post, stop now!
455
- if ( $parent_activity->type != 'new_blog_post' ) {
456
  return;
457
  }
458
 
459
- // if activity comments are disabled for blog posts, stop now!
460
  if ( bp_disable_blogforum_comments() ) {
461
  return;
462
  }
463
 
464
- // get userdata
 
 
 
 
 
 
465
  if ( $params['user_id'] == bp_loggedin_user_id() ) {
466
  $user = buddypress()->loggedin_user->userdata;
467
  } else {
468
  $user = bp_core_get_core_userdata( $params['user_id'] );
469
  }
470
 
471
- // see if a parent WP comment ID exists
472
- if ( ! empty( $params['parent_id'] ) ) {
473
- $comment_parent = bp_activity_get_meta( $params['parent_id'], 'bp_blogs_post_comment_id' );
474
- } else {
475
- $comment_parent = 0;
 
 
476
  }
477
 
478
- // comment args
479
  $args = array(
480
  'comment_post_ID' => $parent_activity->secondary_item_id,
481
  'comment_author' => bp_core_get_user_displayname( $params['user_id'] ),
482
  'comment_author_email' => $user->user_email,
483
  'comment_author_url' => bp_core_get_user_domain( $params['user_id'], $user->user_nicename, $user->user_login ),
484
  'comment_content' => $params['content'],
485
- 'comment_type' => '', // could be interesting to add 'buddypress' here...
486
  'comment_parent' => (int) $comment_parent,
487
  'user_id' => $params['user_id'],
488
-
489
- // commenting these out for now
490
- //'comment_author_IP' => '127.0.0.1',
491
- //'comment_agent' => '',
492
-
493
  'comment_approved' => 1
494
  );
495
 
496
- // prevent separate activity entry being made
497
- remove_action( 'comment_post', 'bp_blogs_record_comment', 10, 2 );
498
 
499
- // handle multisite
500
  switch_to_blog( $parent_activity->item_id );
501
 
502
- // handle timestamps for the WP comment after we've switched to the blog
503
  $args['comment_date'] = current_time( 'mysql' );
504
  $args['comment_date_gmt'] = current_time( 'mysql', 1 );
505
 
506
- // post the comment
507
  $post_comment_id = wp_insert_comment( $args );
508
 
509
- // add meta to comment
510
  add_comment_meta( $post_comment_id, 'bp_activity_comment_id', $comment_id );
511
 
512
- // add meta to activity comment
513
- bp_activity_update_meta( $comment_id, 'bp_blogs_post_comment_id', $post_comment_id );
 
 
514
 
515
- // resave activity comment with WP comment permalink
516
  //
517
  // in bp_blogs_activity_comment_permalink(), we change activity comment
518
  // permalinks to use the post comment link
519
  //
520
  // @todo since this is done after AJAX posting, the activity comment permalink
521
- // doesn't change on the frontend until the next page refresh.
522
  $resave_activity = new BP_Activity_Activity( $comment_id );
523
  $resave_activity->primary_link = get_comment_link( $post_comment_id );
 
 
 
 
 
 
 
524
  $resave_activity->save();
525
 
526
- // multisite again!
527
- restore_current_blog();
528
 
529
- // add the comment hook back
530
- add_action( 'comment_post', 'bp_blogs_record_comment', 10, 2 );
531
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
  do_action( 'bp_blogs_sync_add_from_activity_comment', $comment_id, $args, $parent_activity, $user );
533
  }
534
  add_action( 'bp_activity_comment_posted', 'bp_blogs_sync_add_from_activity_comment', 10, 3 );
@@ -540,94 +865,124 @@ add_action( 'bp_activity_comment_posted', 'bp_blogs_sync_add_from_activity_comme
540
  * of the 'bp_activity_delete_comment' action because we need to fetch the
541
  * activity comment children before they are deleted.
542
  *
543
- * @since BuddyPress (2.0.0)
 
544
  *
545
- * @param bool $retval
546
- * @param int $parent_activity_id The parent activity ID for the activity comment.
547
- * @param int $activity_id The activity ID for the pending deleted activity comment.
 
 
548
  */
549
- function bp_blogs_sync_delete_from_activity_comment( $retval, $parent_activity_id, $activity_id ) {
550
- // check if parent activity is a blog post
551
  $parent_activity = new BP_Activity_Activity( $parent_activity_id );
552
- if ( 'new_blog_post' != $parent_activity->type ) {
 
 
553
  return $retval;
554
  }
555
 
556
- // fetch the activity comments for the activity item
557
  $activity = bp_activity_get( array(
558
  'in' => $activity_id,
559
  'display_comments' => 'stream',
 
560
  ) );
561
 
562
- // get all activity comment IDs for the pending deleted item
563
  $activity_ids = bp_activity_recurse_comments_activity_ids( $activity );
564
  $activity_ids[] = $activity_id;
565
 
566
- // handle multisite
567
- // switch to the blog where the comment was made
568
  switch_to_blog( $parent_activity->item_id );
569
 
570
- // remove associated blog comments
571
  bp_blogs_remove_associated_blog_comments( $activity_ids, current_user_can( 'moderate_comments' ) );
572
 
573
- // multisite again!
574
  restore_current_blog();
575
 
576
- // rebuild activity comment tree
577
- // emulate bp_activity_delete_comment()
578
  BP_Activity_Activity::rebuild_activity_comment_tree( $parent_activity_id );
579
 
580
- // we're overriding the default bp_activity_delete_comment() functionality
581
- // so we need to return false
 
 
 
582
  return false;
583
  }
584
- add_filter( 'bp_activity_delete_comment_pre', 'bp_blogs_sync_delete_from_activity_comment', 10, 3 );
585
 
586
  /**
587
  * Updates the blog comment when the associated activity comment is edited.
588
  *
589
- * @since BuddyPress (2.0.0)
590
  *
591
  * @param BP_Activity_Activity $activity The activity object.
592
  */
593
  function bp_blogs_sync_activity_edit_to_post_comment( BP_Activity_Activity $activity ) {
594
- // not an activity comment? stop now!
595
- if ( 'activity_comment' !== $activity->type ) {
 
596
  return;
597
  }
598
 
599
- // this is a new entry, so stop!
600
- // we only want edits!
601
- if ( empty( $activity->id ) ) {
 
 
602
  return;
603
  }
604
 
605
- // prevent recursion
606
- remove_action( 'bp_activity_before_save', 'bp_blogs_sync_activity_edit_to_post_comment', 20 );
607
 
608
- // Try to see if a corresponding blog comment exists
609
- $post_comment_id = bp_activity_get_meta( $activity->id, 'bp_blogs_post_comment_id' );
610
-
611
- if ( empty( $post_comment_id ) ) {
612
  return;
613
  }
614
 
615
- // fetch parent activity item
616
- $parent_activity = new BP_Activity_Activity( $activity->item_id );
617
 
618
- // sanity check
619
- if ( 'new_blog_post' !== $parent_activity->type ) {
620
  return;
621
  }
622
 
623
- // handle multisite
624
  switch_to_blog( $parent_activity->item_id );
625
 
626
- // update the blog post comment
627
- wp_update_comment( array(
628
- 'comment_ID' => $post_comment_id,
629
- 'comment_content' => $activity->content
630
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
631
 
632
  restore_current_blog();
633
  }
@@ -643,19 +998,111 @@ add_action( 'bp_activity_before_save', 'bp_blogs_sync_activity_edit_to_post_comm
643
  * Since these activity entries are deleted, we need to remove the deleted
644
  * activity comment IDs from each comment's meta when a post is trashed.
645
  *
646
- * @since BuddyPress (2.0.0)
647
  *
648
- * @param int $post_id The post ID
649
- * @param array $statuses Array of comment statuses. The key is comment ID, the
650
- * value is the $comment->comment_approved value.
651
  */
652
- function bp_blogs_remove_activity_meta_for_trashed_comments( $post_id, $statuses ) {
653
- foreach ( $statuses as $comment_id => $comment_approved ) {
654
- delete_comment_meta( $comment_id, 'bp_activity_comment_id' );
 
 
655
  }
656
  }
657
  add_action( 'trashed_post_comments', 'bp_blogs_remove_activity_meta_for_trashed_comments', 10, 2 );
658
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
659
  /**
660
  * Utility function to set up some variables for use in the activity loop.
661
  *
@@ -664,20 +1111,20 @@ add_action( 'trashed_post_comments', 'bp_blogs_remove_activity_meta_for_trashed_
664
  *
665
  * This is to prevent having to requery these items later on.
666
  *
667
- * @since BuddyPress (2.0.0)
668
  *
669
  * @see bp_blogs_disable_activity_commenting()
670
  * @see bp_blogs_setup_comment_loop_globals_on_ajax()
671
  *
672
- * @param object $activity The BP_Activity_Activity object
673
  */
674
  function bp_blogs_setup_activity_loop_globals( $activity ) {
675
  if ( ! is_object( $activity ) ) {
676
  return;
677
  }
678
 
679
- // parent not a blog post? stop now!
680
- if ( 'new_blog_post' !== $activity->type ) {
681
  return;
682
  }
683
 
@@ -685,7 +1132,7 @@ function bp_blogs_setup_activity_loop_globals( $activity ) {
685
  return;
686
  }
687
 
688
- // if we've already done this before, stop now!
689
  if ( isset( buddypress()->blogs->allow_comments[ $activity->id ] ) ) {
690
  return;
691
  }
@@ -693,8 +1140,8 @@ function bp_blogs_setup_activity_loop_globals( $activity ) {
693
  $allow_comments = bp_blogs_comments_open( $activity );
694
  $thread_depth = bp_blogs_get_blogmeta( $activity->item_id, 'thread_comments_depth' );
695
 
696
- // initialize a local object so we won't have to query this again in the
697
- // comment loop
698
  if ( empty( buddypress()->blogs->allow_comments ) ) {
699
  buddypress()->blogs->allow_comments = array();
700
  }
@@ -702,7 +1149,7 @@ function bp_blogs_setup_activity_loop_globals( $activity ) {
702
  buddypress()->blogs->thread_depth = array();
703
  }
704
 
705
- // cache comment settings in the buddypress() singleton to reference later in
706
  // the activity comment loop
707
  // @see bp_blogs_disable_activity_replies()
708
  //
@@ -716,12 +1163,12 @@ function bp_blogs_setup_activity_loop_globals( $activity ) {
716
  /**
717
  * Set up some globals used in the activity comment loop when AJAX is used.
718
  *
719
- * @since BuddyPress (2.0.0)
720
  *
721
  * @see bp_blogs_setup_activity_loop_globals()
722
  */
723
  function bp_blogs_setup_comment_loop_globals_on_ajax() {
724
- // not AJAX? stop now!
725
  if ( ! defined( 'DOING_AJAX' ) ) {
726
  return;
727
  }
@@ -729,11 +1176,11 @@ function bp_blogs_setup_comment_loop_globals_on_ajax() {
729
  return;
730
  }
731
 
732
- // get the parent activity item
733
  $comment = bp_activity_current_comment();
734
  $parent_activity = new BP_Activity_Activity( $comment->item_id );
735
 
736
- // setup the globals
737
  bp_blogs_setup_activity_loop_globals( $parent_activity );
738
  }
739
  add_action( 'bp_before_activity_comment', 'bp_blogs_setup_comment_loop_globals_on_ajax' );
@@ -748,47 +1195,78 @@ add_action( 'bp_before_activity_comment', 'bp_blogs_setup_comment_loop_globals_o
748
  * based on a certain age
749
  * - the activity entry is a 'new_blog_comment' type
750
  *
751
- * @since BuddyPress (2.0.0)
752
  *
753
- * @param bool $retval Is activity commenting enabled for this activity entry?
754
  * @return bool
755
  */
756
  function bp_blogs_disable_activity_commenting( $retval ) {
757
- // if activity commenting is disabled, return current value
758
- if ( bp_disable_blogforum_comments() ) {
 
 
759
  return $retval;
760
  }
761
 
762
- // activity commenting is enabled for blog posts
763
- switch ( bp_get_activity_action_name() ) {
764
 
765
- // we still have to disable activity commenting for 'new_blog_comment' items
766
- // commenting should only be done on the parent 'new_blog_post' item
767
- case 'new_blog_comment' :
 
 
 
 
 
 
 
 
 
 
 
768
  $retval = false;
 
 
769
 
770
- break;
 
 
771
 
772
- // check if commenting is disabled for the WP blog post
773
- // we should extrapolate this and automate this for plugins... or not
774
- case 'new_blog_post' :
775
- global $activities_template;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776
 
777
- // setup some globals we'll need to reference later
778
- bp_blogs_setup_activity_loop_globals( $activities_template->activity );
 
779
 
780
- // if comments are closed for the WP blog post, we should disable
781
- // activity comments for this activity entry
782
- if ( empty( buddypress()->blogs->allow_comments[bp_get_activity_id()] ) ) {
783
- $retval = false;
784
- }
785
 
786
- break;
 
787
  }
788
 
789
  return $retval;
790
  }
791
- add_filter( 'bp_activity_can_comment', 'bp_blogs_disable_activity_commenting' );
792
 
793
  /**
794
  * Check if an activity comment associated with a blog post can be replied to.
@@ -799,10 +1277,11 @@ add_filter( 'bp_activity_can_comment', 'bp_blogs_disable_activity_commenting' );
799
  * This check uses a locally-cached value set in {@link bp_blogs_disable_activity_commenting()}
800
  * via {@link bp_blogs_setup_activity_loop_globals()}.
801
  *
802
- * @since BuddyPress (2.0.0)
 
 
 
803
  *
804
- * @param bool $retval Are replies allowed for this activity reply?
805
- * @param object $comment The activity comment object
806
  * @return bool
807
  */
808
  function bp_blogs_can_comment_reply( $retval, $comment ) {
@@ -810,17 +1289,17 @@ function bp_blogs_can_comment_reply( $retval, $comment ) {
810
  $comment = (object) $comment;
811
  }
812
 
813
- // check comment depth and disable if depth is too large
814
  if ( isset( buddypress()->blogs->thread_depth[$comment->item_id] ) ){
815
- if ( $comment->mptt_left > buddypress()->blogs->thread_depth[$comment->item_id] ) {
816
  $retval = false;
817
  }
818
  }
819
 
820
- // check if we should disable activity replies based on the parent activity
821
  if ( isset( buddypress()->blogs->allow_comments[$comment->item_id] ) ){
822
- // the blog post has closed off commenting, so we should disable all activity
823
- // comments under the parent 'new_blog_post' activity entry
824
  if ( empty( buddypress()->blogs->allow_comments[$comment->item_id] ) ) {
825
  $retval = false;
826
  }
@@ -837,15 +1316,21 @@ add_filter( 'bp_activity_can_comment_reply', 'bp_blogs_can_comment_reply', 10, 2
837
  * This is only done if activity commenting is allowed and whether the parent
838
  * activity item is a 'new_blog_post' entry.
839
  *
840
- * @since BuddyPress (2.0.0)
841
  *
842
- * @param string $retval The activity comment permalink
843
  * @return string
844
  */
845
- function bp_blogs_activity_comment_permalink( $retval ) {
846
  global $activities_template;
847
 
848
- if ( isset( buddypress()->blogs->allow_comments[$activities_template->activity->current_comment->item_id] ) ){
 
 
 
 
 
 
849
  $retval = $activities_template->activity->current_comment->primary_link;
850
  }
851
 
@@ -858,10 +1343,10 @@ add_filter( 'bp_get_activity_comment_permalink', 'bp_blogs_activity_comment_perm
858
  *
859
  * This is only done if the activity comment is associated with a blog comment.
860
  *
861
- * @since BuddyPress (2.0.1)
862
  *
863
- * @param string $retval The activity permalink
864
- * @param BP_Activity_Activity $activity
865
  * @return string
866
  */
867
  function bp_blogs_activity_comment_single_permalink( $retval, $activity ) {
@@ -869,9 +1354,13 @@ function bp_blogs_activity_comment_single_permalink( $retval, $activity ) {
869
  return $retval;
870
  }
871
 
872
- $blog_comment_id = bp_activity_get_meta( $activity->id, 'bp_blogs_post_comment_id' );
 
 
873
 
874
- if ( ! empty( $blog_comment_id ) ) {
 
 
875
  $retval = $activity->primary_link;
876
  }
877
 
@@ -884,10 +1373,10 @@ add_filter( 'bp_activity_get_permalink', 'bp_blogs_activity_comment_single_perma
884
  *
885
  * This is only done if the activity comment is associated with a blog comment.
886
  *
887
- * @since BuddyPress (2.0.1)
888
  *
889
- * @param string $retval The activity action
890
- * @param BP_Activity_Activity $activity
891
  * @return string
892
  */
893
  function bp_blogs_activity_comment_single_action( $retval, $activity ) {
@@ -895,23 +1384,52 @@ function bp_blogs_activity_comment_single_action( $retval, $activity ) {
895
  return $retval;
896
  }
897
 
898
- $blog_comment_id = bp_activity_get_meta( $activity->id, 'bp_blogs_post_comment_id' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
899
 
900
  if ( ! empty( $blog_comment_id ) ) {
901
- // fetch the parent blog post activity item
902
- $parent_blog_post_activity = new BP_Activity_Activity( $activity->item_id );
 
 
 
 
 
 
 
903
 
904
- // fake a 'new_blog_comment' activity object
905
- $object = $activity;
906
 
907
- // override 'item_id' to use blog ID
908
- $object->item_id = $parent_blog_post_activity->item_id;
909
 
910
- // override 'secondary_item_id' to use comment ID
911
- $object->secondary_item_id = $blog_comment_id;
912
 
913
- // now format the activity action using the 'new_blog_comment' action callback
914
- $retval = bp_blogs_format_activity_action_new_blog_comment( '', $object );
 
 
 
 
 
 
915
  }
916
 
917
  return $retval;
1
  <?php
 
2
  /**
3
  * BuddyPress Blogs Activity.
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsActivity
7
+ * @since 1.5.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
 
13
  /**
14
  * Register activity actions for the blogs component.
15
  *
16
+ * @since 1.0.0
 
 
17
  *
18
  * @return bool|null Returns false if activity component is not active.
19
  */
20
  function bp_blogs_register_activity_actions() {
 
 
 
 
 
 
 
21
  if ( is_multisite() ) {
22
  bp_activity_set_action(
23
+ buddypress()->blogs->id,
24
  'new_blog',
25
  __( 'New site created', 'buddypress' ),
26
+ 'bp_blogs_format_activity_action_new_blog',
27
+ __( 'New Sites', 'buddypress' ),
28
+ array( 'activity', 'member' ),
29
+ 0
30
  );
31
  }
32
 
33
+ /**
34
+ * Fires after the registry of the default blog component activity actions.
35
+ *
36
+ * @since 1.1.0
37
+ */
 
 
 
 
 
 
 
 
 
38
  do_action( 'bp_blogs_register_activity_actions' );
39
  }
40
  add_action( 'bp_register_activity_actions', 'bp_blogs_register_activity_actions' );
41
 
42
+ /**
43
+ * Set up the tracking arguments for the 'post' post type.
44
+ *
45
+ * @since 2.5.0 This was moved out of the BP_Blogs_Component class.
46
+ *
47
+ * @see bp_activity_get_post_type_tracking_args() for information on parameters.
48
+ *
49
+ * @param object|null $params Tracking arguments.
50
+ * @param string|int $post_type Post type to track.
51
+ * @return object
52
+ */
53
+ function bp_blogs_register_post_tracking_args( $params = null, $post_type = 0 ) {
54
+
55
+ /**
56
+ * Filters the post types to track for the Blogs component.
57
+ *
58
+ * @since 1.5.0
59
+ * @deprecated 2.3.0
60
+ *
61
+ * Make sure plugins still using 'bp_blogs_record_post_post_types'
62
+ * to track their post types will generate new_blog_post activities
63
+ * See https://buddypress.trac.wordpress.org/ticket/6306
64
+ *
65
+ * @param array $value Array of post types to track.
66
+ */
67
+ $post_types = apply_filters( 'bp_blogs_record_post_post_types', array( 'post' ) );
68
+ $post_types_array = array_flip( $post_types );
69
+
70
+ if ( ! isset( $post_types_array[ $post_type ] ) ) {
71
+ return $params;
72
+ }
73
+
74
+ // Set specific params for the 'post' post type.
75
+ $params->component_id = buddypress()->blogs->id;
76
+ $params->action_id = 'new_blog_post';
77
+ $params->admin_filter = __( 'New post published', 'buddypress' );
78
+ $params->format_callback = 'bp_blogs_format_activity_action_new_blog_post';
79
+ $params->front_filter = __( 'Posts', 'buddypress' );
80
+ $params->contexts = array( 'activity', 'member' );
81
+ $params->position = 5;
82
+
83
+ if ( post_type_supports( $post_type, 'comments' ) ) {
84
+ $params->comment_action_id = 'new_blog_comment';
85
+
86
+ /**
87
+ * Filters the post types to track for the Blogs component.
88
+ *
89
+ * @since 1.5.0
90
+ * @deprecated 2.5.0
91
+ *
92
+ * Make sure plugins still using 'bp_blogs_record_comment_post_types'
93
+ * to track comment about their post types will generate new_blog_comment activities
94
+ * See https://buddypress.trac.wordpress.org/ticket/6306
95
+ *
96
+ * @param array $value Array of post types to track.
97
+ */
98
+ $comment_post_types = apply_filters( 'bp_blogs_record_comment_post_types', array( 'post' ) );
99
+ $comment_post_types_array = array_flip( $comment_post_types );
100
+
101
+ if ( isset( $comment_post_types_array[ $post_type ] ) ) {
102
+ $params->comments_tracking = new stdClass();
103
+ $params->comments_tracking->component_id = buddypress()->blogs->id;
104
+ $params->comments_tracking->action_id = 'new_blog_comment';
105
+ $params->comments_tracking->admin_filter = __( 'New post comment posted', 'buddypress' );
106
+ $params->comments_tracking->format_callback = 'bp_blogs_format_activity_action_new_blog_comment';
107
+ $params->comments_tracking->front_filter = __( 'Comments', 'buddypress' );
108
+ $params->comments_tracking->contexts = array( 'activity', 'member' );
109
+ $params->comments_tracking->position = 10;
110
+ }
111
+ }
112
+
113
+ return $params;
114
+ }
115
+ add_filter( 'bp_activity_get_post_type_tracking_args', 'bp_blogs_register_post_tracking_args', 10, 2 );
116
+
117
  /**
118
  * Format 'new_blog' activity actions.
119
  *
120
+ * @since 2.0.0
121
  *
122
+ * @param string $action Static activity action.
123
+ * @param object $activity Activity data object.
124
+ * @return string
125
  */
126
  function bp_blogs_format_activity_action_new_blog( $action, $activity ) {
127
  $blog_url = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
129
 
130
  $action = sprintf( __( '%s created the site %s', 'buddypress' ), bp_core_get_userlink( $activity->user_id ), '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
131
 
132
+ // Legacy filter - requires the BP_Blogs_Blog object.
133
  if ( has_filter( 'bp_blogs_activity_created_blog_action' ) ) {
134
  $user_blog = BP_Blogs_Blog::get_user_blog( $activity->user_id, $activity->item_id );
135
  if ( $user_blog ) {
141
  }
142
  }
143
 
144
+ /**
145
+ * Filters the new blog activity action for the new blog.
146
+ *
147
+ * @since 2.0.0
148
+ *
149
+ * @param string $action Constructed activity action.
150
+ * @param object $activity Activity data object.
151
+ */
152
  return apply_filters( 'bp_blogs_format_activity_action_new_blog', $action, $activity );
153
  }
154
 
155
  /**
156
  * Format 'new_blog_post' activity actions.
157
  *
158
+ * @since 2.0.0
159
  *
160
+ * @param string $action Static activity action.
161
+ * @param object $activity Activity data object.
162
+ * @return string Constructed activity action.
163
  */
164
  function bp_blogs_format_activity_action_new_blog_post( $action, $activity ) {
165
  $blog_url = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
173
  bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
174
  }
175
 
176
+ /**
177
+ * When the post is published we are faking an activity object
178
+ * to which we add 2 properties :
179
+ * - the post url
180
+ * - the post title
181
+ * This is done to build the 'post link' part of the activity
182
+ * action string.
183
+ * NB: in this case the activity has not yet been created.
184
+ */
185
+ if ( isset( $activity->post_url ) ) {
186
+ $post_url = $activity->post_url;
187
+
188
+ /**
189
+ * The post_url property is not set, we need to build the url
190
+ * thanks to the post id which is also saved as the secondary
191
+ * item id property of the activity object.
192
+ */
193
+ } else {
194
+ $post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) );
195
+ }
196
 
197
+ // Should be the case when the post has just been published.
198
+ if ( isset( $activity->post_title ) ) {
199
+ $post_title = $activity->post_title;
200
 
201
+ // If activity already exists try to get the post title from activity meta.
202
+ } else if ( ! empty( $activity->id ) ) {
203
+ $post_title = bp_activity_get_meta( $activity->id, 'post_title' );
204
+ }
205
+
206
+ /**
207
+ * In case the post was published without a title
208
+ * or the activity meta was not found.
209
+ */
210
  if ( empty( $post_title ) ) {
211
+ // Defaults to no title.
212
+ $post_title = esc_html__( '(no title)', 'buddypress' );
213
+
214
  switch_to_blog( $activity->item_id );
215
 
216
  $post = get_post( $activity->secondary_item_id );
217
  if ( is_a( $post, 'WP_Post' ) ) {
218
+ // Does the post have a title ?
219
+ if ( ! empty( $post->post_title ) ) {
220
+ $post_title = $post->post_title;
221
+ }
222
+
223
+ // Make sure the activity exists before saving the post title in activity meta.
224
+ if ( ! empty( $activity->id ) ) {
225
+ bp_activity_update_meta( $activity->id, 'post_title', $post_title );
226
+ }
227
  }
228
 
229
  restore_current_blog();
230
  }
231
 
232
+ // Build the 'post link' part of the activity action string.
233
+ $post_link = '<a href="' . esc_url( $post_url ) . '">' . $post_title . '</a>';
234
 
235
  $user_link = bp_core_get_userlink( $activity->user_id );
236
 
237
+ // Build the complete activity action string.
238
  if ( is_multisite() ) {
239
  $action = sprintf( __( '%1$s wrote a new post, %2$s, on the site %3$s', 'buddypress' ), $user_link, $post_link, '<a href="' . esc_url( $blog_url ) . '">' . esc_html( $blog_name ) . '</a>' );
240
  } else {
241
  $action = sprintf( __( '%1$s wrote a new post, %2$s', 'buddypress' ), $user_link, $post_link );
242
  }
243
 
244
+ // Legacy filter - requires the post object.
245
  if ( has_filter( 'bp_blogs_activity_new_post_action' ) ) {
246
  switch_to_blog( $activity->item_id );
247
  $post = get_post( $activity->secondary_item_id );
252
  }
253
  }
254
 
255
+ /**
256
+ * Filters the new blog post action for the new blog.
257
+ *
258
+ * @since 2.0.0
259
+ *
260
+ * @param string $action Constructed activity action.
261
+ * @param object $activity Activity data object.
262
+ */
263
  return apply_filters( 'bp_blogs_format_activity_action_new_blog_post', $action, $activity );
264
  }
265
 
266
  /**
267
  * Format 'new_blog_comment' activity actions.
268
  *
269
+ * @since 2.0.0
270
  *
271
+ * @param string $action Static activity action.
272
+ * @param object $activity Activity data object.
273
+ * @return string Constructed activity action.
274
  */
275
  function bp_blogs_format_activity_action_new_blog_comment( $action, $activity ) {
276
+ /**
277
+ * When the comment is published we are faking an activity object
278
+ * to which we add 4 properties :
279
+ * - the post url
280
+ * - the post title
281
+ * - the blog url
282
+ * - the blog name
283
+ * This is done to build the 'post link' part of the activity
284
+ * action string.
285
+ * NB: in this case the activity has not yet been created.
286
+ */
287
+
288
+ $blog_url = false;
289
+
290
+ // Try to get the blog url from the activity object
291
+ if ( isset( $activity->blog_url ) ) {
292
+ $blog_url = $activity->blog_url;
293
+ } else {
294
+ $blog_url = bp_blogs_get_blogmeta( $activity->item_id, 'url' );
295
+ }
296
+
297
+ $blog_name = false;
298
+
299
+ // Try to get the blog name from the activity object
300
+ if ( isset( $activity->blog_name ) ) {
301
+ $blog_name = $activity->blog_name;
302
+ } else {
303
+ $blog_name = bp_blogs_get_blogmeta( $activity->item_id, 'name' );
304
+ }
305
 
306
  if ( empty( $blog_url ) || empty( $blog_name ) ) {
307
  $blog_url = get_home_url( $activity->item_id );
311
  bp_blogs_update_blogmeta( $activity->item_id, 'name', $blog_name );
312
  }
313
 
314
+ $post_url = false;
315
+
316
+ // Try to get the post url from the activity object
317
+ if ( isset( $activity->post_url ) ) {
318
+ $post_url = $activity->post_url;
319
 
320
+ /**
321
+ * The post_url property is not set, we need to build the url
322
+ * thanks to the post id which is also saved as the secondary
323
+ * item id property of the activity object.
324
+ */
325
+ } elseif ( ! empty( $activity->id ) ) {
326
+ $post_url = bp_activity_get_meta( $activity->id, 'post_url' );
327
+ }
328
+
329
+ $post_title = false;
330
+
331
+ // Should be the case when the comment has just been published
332
+ if ( isset( $activity->post_title ) ) {
333
+ $post_title = $activity->post_title;
334
+
335
+ // If activity already exists try to get the post title from activity meta
336
+ } elseif ( ! empty( $activity->id ) ) {
337
+ $post_title = bp_activity_get_meta( $activity->id, 'post_title' );
338
+ }
339
+
340
+ // Should only be empty at the time of post creation.
341
  if ( empty( $post_url ) || empty( $post_title ) ) {
342
  switch_to_blog( $activity->item_id );
343
 
358
  restore_current_blog();
359
  }
360
 
361
+ $post_link = '<a href="' . esc_url( $post_url ) . '">' . $post_title . '</a>';
362
  $user_link = bp_core_get_userlink( $activity->user_id );
363
 
364
  if ( is_multisite() ) {
367
  $action = sprintf( __( '%1$s commented on the post, %2$s', 'buddypress' ), $user_link, $post_link );
368
  }
369
 
370
+ // Legacy filter - requires the comment object.
371
  if ( has_filter( 'bp_blogs_activity_new_comment_action' ) ) {
372
  switch_to_blog( $activity->item_id );
373
  $comment = get_comment( $activity->secondary_item_id );
378
  }
379
  }
380
 
381
+ /**
382
+ * Filters the new blog comment action for the new blog.
383
+ *
384
+ * @since 2.0.0
385
+ *
386
+ * @param string $action Constructed activity action.
387
+ * @param object $activity Activity data object.
388
+ */
389
  return apply_filters( 'bp_blogs_format_activity_action_new_blog_comment', $action, $activity );
390
  }
391
 
394
  *
395
  * This reduces database overhead during the activity loop.
396
  *
397
+ * @since 2.0.0
398
  *
399
  * @param array $activities Array of activity items.
400
  * @return array
425
  /**
426
  * Record blog-related activity to the activity stream.
427
  *
428
+ * @since 1.0.0
429
  *
430
  * @see bp_activity_add() for description of parameters.
 
431
  *
432
+ * @param array|string $args {
433
  * See {@link bp_activity_add()} for complete description of arguments.
434
  * The arguments listed here have different default values from
435
  * bp_activity_add().
438
  * @return int|bool On success, returns the activity ID. False on failure.
439
  */
440
  function bp_blogs_record_activity( $args = '' ) {
 
 
 
 
 
 
441
  $defaults = array(
442
  'user_id' => bp_loggedin_user_id(),
443
  'action' => '',
444
  'content' => '',
445
  'primary_link' => '',
446
+ 'component' => buddypress()->blogs->id,
447
  'type' => false,
448
  'item_id' => false,
449
  'secondary_item_id' => false,
452
  );
453
 
454
  $r = wp_parse_args( $args, $defaults );
 
455
 
456
+ if ( ! empty( $r['action'] ) ) {
 
 
457
 
458
+ /**
459
+ * Filters the action associated with activity for activity stream.
460
+ *
461
+ * @since 1.2.0
462
+ *
463
+ * @param string $value Action for the activity stream.
464
+ */
465
+ $r['action'] = apply_filters( 'bp_blogs_record_activity_action', $r['action'] );
466
+ }
467
 
468
+ if ( ! empty( $r['content'] ) ) {
469
+
470
+ /**
471
+ * Filters the content associated with activity for activity stream.
472
+ *
473
+ * @since 1.2.0
474
+ *
475
+ * @param string $value Generated summary from content for the activity stream.
476
+ * @param string $value Content for the activity stream.
477
+ * @param array $r Array of arguments used for the activity stream item.
478
+ */
479
+ $r['content'] = apply_filters( 'bp_blogs_record_activity_content', bp_activity_create_summary( $r['content'], $r ), $r['content'], $r );
480
+ }
481
 
482
  // Check for an existing entry and update if one exists.
483
  $id = bp_activity_get_activity_id( array(
484
+ 'user_id' => $r['user_id'],
485
+ 'component' => $r['component'],
486
+ 'type' => $r['type'],
487
+ 'item_id' => $r['item_id'],
488
+ 'secondary_item_id' => $r['secondary_item_id'],
489
  ) );
490
 
491
+ return bp_activity_add( array( 'id' => $id, 'user_id' => $r['user_id'], 'action' => $r['action'], 'content' => $r['content'], 'primary_link' => $r['primary_link'], 'component' => $r['component'], 'type' => $r['type'], 'item_id' => $r['item_id'], 'secondary_item_id' => $r['secondary_item_id'], 'recorded_time' => $r['recorded_time'], 'hide_sitewide' => $r['hide_sitewide'] ) );
492
  }
493
 
494
  /**
495
  * Delete a blog-related activity stream item.
496
  *
497
+ * @since 1.0.0
498
  *
499
  * @see bp_activity_delete() for description of parameters.
 
500
  *
501
+ * @param array|string $args {
502
  * See {@link bp_activity_delete()} for complete description of arguments.
503
  * The arguments listed here have different default values from
504
  * bp_activity_add().
506
  * }
507
  * @return bool True on success, false on failure.
508
  */
509
+ function bp_blogs_delete_activity( $args = '' ) {
510
+ $r = bp_parse_args( $args, array(
 
 
 
 
 
 
511
  'item_id' => false,
512
+ 'component' => buddypress()->blogs->id,
513
  'type' => false,
514
  'user_id' => false,
515
  'secondary_item_id' => false
 
 
 
 
 
 
 
 
 
 
 
516
  ) );
517
+
518
+ bp_activity_delete_by_item_id( $r );
519
  }
520
 
521
  /**
529
  * to blogmeta and checks the values in blogmeta instead. This is to prevent
530
  * multiple {@link switch_to_blog()} calls in the activity stream.
531
  *
532
+ * @since 2.0.0
533
  *
534
+ * @param object $activity The BP_Activity_Activity object.
535
  * @return bool
536
  */
537
  function bp_blogs_comments_open( $activity ) {
539
 
540
  $blog_id = $activity->item_id;
541
 
542
+ // See if we've mirrored the close comments option before.
543
  $days_old = bp_blogs_get_blogmeta( $blog_id, 'close_comments_days_old' );
544
 
545
+ // We've never cached these items before, so do it now.
546
  if ( '' === $days_old ) {
547
  switch_to_blog( $blog_id );
548
 
549
+ // Use comments_open().
550
  remove_filter( 'comments_open', 'bp_comments_open', 10, 2 );
551
  $open = comments_open( $activity->secondary_item_id );
552
  add_filter( 'comments_open', 'bp_comments_open', 10, 2 );
553
 
554
+ // Might as well mirror values to blogmeta since we're here!
555
  $thread_depth = get_option( 'thread_comments' );
556
  if ( ! empty( $thread_depth ) ) {
557
  $thread_depth = get_option( 'thread_comments_depth' );
558
  } else {
559
+ // Perhaps filter this?
560
  $thread_depth = 1;
561
  }
562
 
566
 
567
  restore_current_blog();
568
 
569
+ // Check blogmeta and manually check activity item.
570
+ // Basically a copy of _close_comments_for_old_post().
571
  } else {
572
 
573
+ // Comments are closed.
574
  if ( 'closed' == bp_activity_get_meta( $activity->id, 'post_comment_status' ) ) {
575
  return false;
576
  }
584
  return $open;
585
  }
586
 
587
+ /*
588
+ Commenting out for now - needs some more thought...
589
  should we add the post type to activity meta?
590
 
591
  $post = get_post($post_id);
606
  return $open;
607
  }
608
 
609
+ /** SITE TRACKING *******************************************************/
610
+
611
+ /**
612
+ * Add an activity entry for a newly-created site.
613
+ *
614
+ * Hooked to the 'bp_blogs_new_blog' action.
615
+ *
616
+ * @since 2.6.0
617
+ *
618
+ * @param BP_Blogs_Blog $recorded_blog Current site being recorded. Passed by reference.
619
+ * @param bool $is_private Whether the current site being recorded is private.
620
+ * @param bool $is_recorded Whether the current site was recorded.
621
+ */
622
+ function bp_blogs_record_activity_on_site_creation( $recorded_blog, $is_private, $is_recorded, $no_activity ) {
623
+ // Only record this activity if the blog is public.
624
+ if ( ! $is_private && ! $no_activity && bp_blogs_is_blog_trackable( $recorded_blog->blog_id, $recorded_blog->user_id ) ) {
625
+ bp_blogs_record_activity( array(
626
+ 'user_id' => $recorded_blog->user_id,
627
+ 'primary_link' => apply_filters( 'bp_blogs_activity_created_blog_primary_link', bp_blogs_get_blogmeta( $recorded_blog->blog_id, 'url' ), $recorded_blog->blog_id ),
628
+ 'type' => 'new_blog',
629
+ 'item_id' => $recorded_blog->blog_id
630
+ ) );
631
+ }
632
+ }
633
+ add_action( 'bp_blogs_new_blog', 'bp_blogs_record_activity_on_site_creation', 10, 4 );
634
+
635
+ /**
636
+ * Deletes the 'new_blog' activity entry when a site is deleted.
637
+ *
638
+ * @since 2.6.0
639
+ *
640
+ * @param int $blog_id Site ID.
641
+ */
642
+ function bp_blogs_delete_new_blog_activity_for_site( $blog_id, $user_id = 0 ) {
643
+ $args = array(
644
+ 'item_id' => $blog_id,
645
+ 'component' => buddypress()->blogs->id,
646
+ 'type' => 'new_blog'
647
+ );
648
+
649
+ /**
650
+ * In the case a user is removed, make sure he is the author of the 'new_blog' activity
651
+ * when trying to delete it.
652
+ */
653
+ if ( ! empty( $user_id ) ) {
654
+ $args['user_id'] = $user_id;
655
+ }
656
+
657
+ bp_blogs_delete_activity( $args );
658
+ }
659
+ add_action( 'bp_blogs_remove_blog', 'bp_blogs_delete_new_blog_activity_for_site', 10, 1 );
660
+ add_action( 'bp_blogs_remove_blog_for_user', 'bp_blogs_delete_new_blog_activity_for_site', 10, 2 );
661
+
662
+ /**
663
+ * Delete all 'blogs' activity items for a site when the site is deleted.
664
+ *
665
+ * @since 2.6.0
666
+ *
667
+ * @param int $blog_id Site ID.
668
+ */
669
+ function bp_blogs_delete_activity_for_site( $blog_id ) {
670
+ bp_blogs_delete_activity( array(
671
+ 'item_id' => $blog_id,
672
+ 'component' => buddypress()->blogs->id,
673
+ 'type' => false
674
+ ) );
675
+ }
676
+ add_action( 'bp_blogs_remove_data_for_blog', 'bp_blogs_delete_activity_for_site' );
677
+
678
+ /**
679
+ * Remove a blog post activity item from the activity stream.
680
+ *
681
+ * @since 1.0.0
682
+ *
683
+ * @param int $post_id ID of the post to be removed.
684
+ * @param int $blog_id Optional. Defaults to current blog ID.
685
+ * @param int $user_id Optional. Defaults to the logged-in user ID. This param
686
+ * is currently unused in the function (but is passed to hooks).
687
+ * @return bool
688
+ */
689
+ function bp_blogs_remove_post( $post_id, $blog_id = 0, $user_id = 0 ) {
690
+ global $wpdb;
691
+
692
+ if ( empty( $wpdb->blogid ) ) {
693
+ return false;
694
+ }
695
+
696
+ $post_id = (int) $post_id;
697
+
698
+ if ( ! $blog_id ) {
699
+ $blog_id = (int) $wpdb->blogid;
700
+ }
701
+
702
+ if ( ! $user_id ) {
703
+ $user_id = bp_loggedin_user_id();
704
+ }
705
+
706
+ /**
707
+ * Fires before removal of a blog post activity item from the activity stream.
708
+ *
709
+ * @since 1.5.0
710
+ *
711
+ * @param int $blog_id ID of the blog associated with the post that was removed.
712
+ * @param int $post_id ID of the post that was removed.
713
+ * @param int $user_id ID of the user having the blog removed for.
714
+ */
715
+ do_action( 'bp_blogs_before_remove_post', $blog_id, $post_id, $user_id );
716
+
717
+ bp_blogs_delete_activity( array(
718
+ 'item_id' => $blog_id,
719
+ 'secondary_item_id' => $post_id,
720
+ 'component' => buddypress()->blogs->id,
721
+ 'type' => 'new_blog_post'
722
+ ) );
723
+
724
+ /**
725
+ * Fires after removal of a blog post activity item from the activity stream.
726
+ *
727
+ * @since 1.0.0
728
+ *
729
+ * @param int $blog_id ID of the blog associated with the post that was removed.
730
+ * @param int $post_id ID of the post that was removed.
731
+ * @param int $user_id ID of the user having the blog removed for.
732
+ */
733
+ do_action( 'bp_blogs_remove_post', $blog_id, $post_id, $user_id );
734
+ }
735
+ add_action( 'delete_post', 'bp_blogs_remove_post' );
736
+
737
  /** POST COMMENT SYNCHRONIZATION ****************************************/
738
 
739
  /**
741
  *
742
  * Note: This is only a one-way sync - activity comments -> blog comment.
743
  *
744
+ * For blog post -> activity comment, see {@link bp_activity_post_type_comment()}.
745
  *
746
+ * @since 2.0.0
747
+ * @since 2.5.0 Allow custom post types to sync their comments with activity ones
748
  *
749
+ * @param int $comment_id The activity ID for the posted activity comment.
750
+ * @param array $params Parameters for the activity comment.
751
+ * @param object $parent_activity Parameters of the parent activity item (in this case, the blog post).
752
  */
753
  function bp_blogs_sync_add_from_activity_comment( $comment_id, $params, $parent_activity ) {
754
+ // if parent activity isn't a post type having the buddypress-activity support, stop now!
755
+ if ( ! bp_activity_type_supports( $parent_activity->type, 'post-type-comment-tracking' ) ) {
756
  return;
757
  }
758
 
759
+ // If activity comments are disabled for blog posts, stop now!
760
  if ( bp_disable_blogforum_comments() ) {
761
  return;
762
  }
763
 
764
+ // Do not sync if the activity comment was marked as spam.
765
+ $activity = new BP_Activity_Activity( $comment_id );
766
+ if ( $activity->is_spam ) {
767
+ return;
768
+ }
769
+
770
+ // Get userdata.
771
  if ( $params['user_id'] == bp_loggedin_user_id() ) {
772
  $user = buddypress()->loggedin_user->userdata;
773
  } else {
774
  $user = bp_core_get_core_userdata( $params['user_id'] );
775
  }
776
 
777
+ // Get associated post type and set default comment parent
778
+ $post_type = bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' );
779
+ $comment_parent = 0;
780
+
781
+ // See if a parent WP comment ID exists.
782
+ if ( ! empty( $params['parent_id'] ) && ! empty( $post_type ) ) {
783
+ $comment_parent = bp_activity_get_meta( $params['parent_id'], "bp_blogs_{$post_type}_comment_id" );
784
  }
785
 
786
+ // Comment args.
787
  $args = array(
788
  'comment_post_ID' => $parent_activity->secondary_item_id,
789
  'comment_author' => bp_core_get_user_displayname( $params['user_id'] ),
790
  'comment_author_email' => $user->user_email,
791
  'comment_author_url' => bp_core_get_user_domain( $params['user_id'], $user->user_nicename, $user->user_login ),
792
  'comment_content' => $params['content'],
793
+ 'comment_type' => '', // Could be interesting to add 'buddypress' here...
794
  'comment_parent' => (int) $comment_parent,
795
  'user_id' => $params['user_id'],
 
 
 
 
 
796
  'comment_approved' => 1
797
  );
798
 
799
+ // Prevent separate activity entry being made.
800
+ remove_action( 'comment_post', 'bp_activity_post_type_comment', 10, 2 );
801
 
802
+ // Handle multisite.
803
  switch_to_blog( $parent_activity->item_id );
804
 
805
+ // Handle timestamps for the WP comment after we've switched to the blog.
806
  $args['comment_date'] = current_time( 'mysql' );
807
  $args['comment_date_gmt'] = current_time( 'mysql', 1 );
808
 
809
+ // Post the comment.
810
  $post_comment_id = wp_insert_comment( $args );
811
 
812
+ // Add meta to comment.
813
  add_comment_meta( $post_comment_id, 'bp_activity_comment_id', $comment_id );
814
 
815
+ // Add meta to activity comment.
816
+ if ( ! empty( $post_type ) ) {
817
+ bp_activity_update_meta( $comment_id, "bp_blogs_{$post_type}_comment_id", $post_comment_id );
818
+ }
819
 
820
+ // Resave activity comment with WP comment permalink.
821
  //
822
  // in bp_blogs_activity_comment_permalink(), we change activity comment
823
  // permalinks to use the post comment link
824
  //
825
  // @todo since this is done after AJAX posting, the activity comment permalink
826
+ // doesn't change on the frontend until the next page refresh.
827
  $resave_activity = new BP_Activity_Activity( $comment_id );
828
  $resave_activity->primary_link = get_comment_link( $post_comment_id );
829
+
830
+ /**
831
+ * Now that the activity id exists and the post comment was created, we don't need to update
832
+ * the content of the comment as there are no chances it has evolved.
833
+ */
834
+ remove_action( 'bp_activity_before_save', 'bp_blogs_sync_activity_edit_to_post_comment', 20 );
835
+
836
  $resave_activity->save();
837
 
838
+ // Add the edit activity comment hook back.
839
+ add_action( 'bp_activity_before_save', 'bp_blogs_sync_activity_edit_to_post_comment', 20 );
840
 
841
+ // Multisite again!
842
+ restore_current_blog();
843
 
844
+ // Add the comment hook back.
845
+ add_action( 'comment_post', 'bp_activity_post_type_comment', 10, 2 );
846
+
847
+ /**
848
+ * Fires after activity comments have been synced and posted as blog comments.
849
+ *
850
+ * @since 2.0.0
851
+ *
852
+ * @param int $comment_id The activity ID for the posted activity comment.
853
+ * @param array $args Array of args used for the comment syncing.
854
+ * @param object $parent_activity Parameters of the blog post parent activity item.
855
+ * @param object $user User data object for the blog comment.
856
+ */
857
  do_action( 'bp_blogs_sync_add_from_activity_comment', $comment_id, $args, $parent_activity, $user );
858
  }
859
  add_action( 'bp_activity_comment_posted', 'bp_blogs_sync_add_from_activity_comment', 10, 3 );
865
  * of the 'bp_activity_delete_comment' action because we need to fetch the
866
  * activity comment children before they are deleted.
867
  *
868
+ * @since 2.0.0
869
+ * @since 2.5.0 Add the $delected parameter
870
  *
871
+ * @param bool $retval Whether BuddyPress should continue or not.
872
+ * @param int $parent_activity_id The parent activity ID for the activity comment.
873
+ * @param int $activity_id The activity ID for the pending deleted activity comment.
874
+ * @param bool $deleted Whether the comment was deleted or not.
875
+ * @return bool
876
  */
877
+ function bp_blogs_sync_delete_from_activity_comment( $retval, $parent_activity_id, $activity_id, &$deleted ) {
878
+ // Check if parent activity is a blog post.
879
  $parent_activity = new BP_Activity_Activity( $parent_activity_id );
880
+
881
+ // if parent activity isn't a post type having the buddypress-activity support, stop now!
882
+ if ( ! bp_activity_type_supports( $parent_activity->type, 'post-type-comment-tracking' ) ) {
883
  return $retval;
884
  }
885
 
886
+ // Fetch the activity comments for the activity item.
887
  $activity = bp_activity_get( array(
888
  'in' => $activity_id,
889
  'display_comments' => 'stream',
890
+ 'spam' => 'all',
891
  ) );
892
 
893
+ // Get all activity comment IDs for the pending deleted item.
894
  $activity_ids = bp_activity_recurse_comments_activity_ids( $activity );
895
  $activity_ids[] = $activity_id;
896
 
897
+ // Handle multisite
898
+ // switch to the blog where the comment was made.
899
  switch_to_blog( $parent_activity->item_id );
900
 
901
+ // Remove associated blog comments.
902
  bp_blogs_remove_associated_blog_comments( $activity_ids, current_user_can( 'moderate_comments' ) );
903
 
904
+ // Multisite again!
905
  restore_current_blog();
906
 
907
+ // Rebuild activity comment tree
908
+ // emulate bp_activity_delete_comment().
909
  BP_Activity_Activity::rebuild_activity_comment_tree( $parent_activity_id );
910
 
911
+ // Avoid the error message although the comments were successfully deleted
912
+ $deleted = true;
913
+
914
+ // We're overriding the default bp_activity_delete_comment() functionality
915
+ // so we need to return false.
916
  return false;
917
  }
918
+ add_filter( 'bp_activity_delete_comment_pre', 'bp_blogs_sync_delete_from_activity_comment', 10, 4 );
919
 
920
  /**
921
  * Updates the blog comment when the associated activity comment is edited.
922
  *
923
+ * @since 2.0.0
924
  *
925
  * @param BP_Activity_Activity $activity The activity object.
926
  */
927
  function bp_blogs_sync_activity_edit_to_post_comment( BP_Activity_Activity $activity ) {
928
+ // This is a new entry, so stop!
929
+ // We only want edits!
930
+ if ( empty( $activity->id ) || bp_disable_blogforum_comments() ) {
931
  return;
932
  }
933
 
934
+ // fetch parent activity item
935
+ $parent_activity = new BP_Activity_Activity( $activity->item_id );
936
+
937
+ // if parent activity isn't a post type having the buddypress-activity support for comments, stop now!
938
+ if ( ! bp_activity_type_supports( $parent_activity->type, 'post-type-comment-tracking' ) ) {
939
  return;
940
  }
941
 
942
+ $post_type = bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' );
 
943
 
944
+ // No associated post type for this activity comment, stop.
945
+ if ( ! $post_type ) {
 
 
946
  return;
947
  }
948
 
949
+ // Try to see if a corresponding blog comment exists.
950
+ $post_comment_id = bp_activity_get_meta( $activity->id, "bp_blogs_{$post_type}_comment_id" );
951
 
952
+ if ( empty( $post_comment_id ) ) {
 
953
  return;
954
  }
955
 
956
+ // Handle multisite.
957
  switch_to_blog( $parent_activity->item_id );
958
 
959
+ // Get the comment status
960
+ $post_comment_status = wp_get_comment_status( $post_comment_id );
961
+ $old_comment_status = $post_comment_status;
962
+
963
+ // No need to edit the activity, as it's the activity who's updating the comment
964
+ remove_action( 'transition_comment_status', 'bp_activity_transition_post_type_comment_status', 10, 3 );
965
+ remove_action( 'bp_activity_post_type_comment', 'bp_blogs_comment_sync_activity_comment', 10, 4 );
966
+
967
+ if ( 1 === $activity->is_spam && 'spam' !== $post_comment_status ) {
968
+ wp_spam_comment( $post_comment_id );
969
+ } elseif ( ! $activity->is_spam ) {
970
+ if ( 'spam' === $post_comment_status ) {
971
+ wp_unspam_comment( $post_comment_id );
972
+ } elseif ( 'trash' === $post_comment_status ) {
973
+ wp_untrash_comment( $post_comment_id );
974
+ } else {
975
+ // Update the blog post comment.
976
+ wp_update_comment( array(
977
+ 'comment_ID' => $post_comment_id,
978
+ 'comment_content' => $activity->content,
979
+ ) );
980
+ }
981
+ }
982
+
983
+ // Restore actions
984
+ add_action( 'transition_comment_status', 'bp_activity_transition_post_type_comment_status', 10, 3 );
985
+ add_action( 'bp_activity_post_type_comment', 'bp_blogs_comment_sync_activity_comment', 10, 4 );
986
 
987
  restore_current_blog();
988
  }
998
  * Since these activity entries are deleted, we need to remove the deleted
999
  * activity comment IDs from each comment's meta when a post is trashed.
1000
  *
1001
+ * @since 2.0.0
1002
  *
1003
+ * @param int $post_id The post ID.
1004
+ * @param array $comments Array of comment statuses. The key is comment ID, the
1005
+ * value is the $comment->comment_approved value.
1006
  */
1007
+ function bp_blogs_remove_activity_meta_for_trashed_comments( $post_id = 0, $comments = array() ) {
1008
+ if ( ! empty( $comments ) ) {
1009
+ foreach ( array_keys( $comments ) as $comment_id ) {
1010
+ delete_comment_meta( $comment_id, 'bp_activity_comment_id' );
1011
+ }
1012
  }
1013
  }
1014
  add_action( 'trashed_post_comments', 'bp_blogs_remove_activity_meta_for_trashed_comments', 10, 2 );
1015
 
1016
+ /**
1017
+ * Filter 'new_blog_comment' bp_has_activities() loop to include new- and old-style blog activity comment items.
1018
+ *
1019
+ * In BuddyPress 2.0, the schema for storing activity items related to blog
1020
+ * posts changed. Instead creating new top-level 'new_blog_comment' activity
1021
+ * items, blog comments are recorded in the activity stream as comments on the
1022
+ * 'new_blog_post' activity items corresponding to the parent post. This filter
1023
+ * ensures that the 'new_blog_comment' filter in bp_has_activities() (which
1024
+ * powers the 'Comments' filter in the activity directory dropdown) includes
1025
+ * both old-style and new-style activity comments.
1026
+ *
1027
+ * @since 2.1.0
1028
+ * @since 2.5.0 Used for any synced Post type comments, in wp-admin or front-end contexts.
1029
+ *
1030
+ * @param array $args Arguments passed from bp_parse_args() in bp_has_activities().
1031
+ * @return array $args
1032
+ */
1033
+ function bp_blogs_new_blog_comment_query_backpat( $args ) {
1034
+ global $wpdb;
1035
+ $bp = buddypress();
1036
+
1037
+ // If activity comments are disabled for blog posts, stop now!
1038
+ if ( bp_disable_blogforum_comments() ) {
1039
+ return $args;
1040
+ }
1041
+
1042
+ // Get the associated post type
1043
+ $post_type = bp_activity_post_type_get_tracking_arg( $args['action'], 'post_type' );
1044
+
1045
+ // Bail if this is not an activity associated with a post type
1046
+ if ( empty( $post_type ) ) {
1047
+ return $args;
1048
+ }
1049
+
1050
+ // Bail if this is an activity about posts and not comments
1051
+ if ( bp_activity_post_type_get_tracking_arg( $args['action'], 'comment_action_id' ) ) {
1052
+ return $args;
1053
+ }
1054
+
1055
+ // Comment synced ?
1056
+ $activity_ids = $wpdb->get_col( $wpdb->prepare( "SELECT activity_id FROM {$bp->activity->table_name_meta} WHERE meta_key = %s", "bp_blogs_{$post_type}_comment_id" ) );
1057
+
1058
+ if ( empty( $activity_ids ) ) {
1059
+ return $args;
1060
+ }
1061
+
1062
+ // Init the filter query.
1063
+ $filter_query = array();
1064
+
1065
+ if ( ! isset( $args['scope'] ) || 'null' === $args['scope'] ) {
1066
+ $args['scope'] = '';
1067
+ } elseif ( 'just-me' === $args['scope'] ) {
1068
+ $filter_query = array(
1069
+ 'relation' => 'AND',
1070
+ array(
1071
+ 'column' => 'user_id',
1072
+ 'value' => bp_displayed_user_id(),
1073
+ ),
1074
+ );
1075
+ $args['scope'] = '';
1076
+ }
1077
+
1078
+ $filter_query[] = array(
1079
+ 'relation' => 'OR',
1080
+ array(
1081
+ 'column' => 'type',
1082
+ 'value' => $args['action'],
1083
+ ),
1084
+ array(
1085
+ 'column' => 'id',
1086
+ 'value' => $activity_ids,
1087
+ 'compare' => 'IN'
1088
+ ),
1089
+ );
1090
+
1091
+ $args['filter_query'] = $filter_query;
1092
+
1093
+ // Make sure to have comment in stream mode && avoid duplicate content.
1094
+ $args['display_comments'] = 'stream';
1095
+
1096
+ // Finally reset the action.
1097
+ $args['action'] = '';
1098
+ $args['type'] = '';
1099
+
1100
+ // Return the original arguments.
1101
+ return $args;
1102
+ }
1103
+ add_filter( 'bp_after_has_activities_parse_args', 'bp_blogs_new_blog_comment_query_backpat' );
1104
+ add_filter( 'bp_activity_list_table_filter_activity_type_items', 'bp_blogs_new_blog_comment_query_backpat' );
1105
+
1106
  /**
1107
  * Utility function to set up some variables for use in the activity loop.
1108
  *
1111
  *
1112
  * This is to prevent having to requery these items later on.
1113
  *
1114
+ * @since 2.0.0
1115
  *
1116
  * @see bp_blogs_disable_activity_commenting()
1117
  * @see bp_blogs_setup_comment_loop_globals_on_ajax()
1118
  *
1119
+ * @param object $activity The BP_Activity_Activity object.
1120
  */
1121
  function bp_blogs_setup_activity_loop_globals( $activity ) {
1122
  if ( ! is_object( $activity ) ) {
1123
  return;
1124
  }
1125
 
1126
+ // The activity type does not support comments or replies ? stop now!
1127
+ if ( ! bp_activity_type_supports( $activity->type, 'post-type-comment-reply' ) ) {
1128
  return;
1129
  }
1130
 
1132
  return;
1133
  }
1134
 
1135
+ // If we've already done this before, stop now!
1136
  if ( isset( buddypress()->blogs->allow_comments[ $activity->id ] ) ) {
1137
  return;
1138
  }
1140
  $allow_comments = bp_blogs_comments_open( $activity );
1141
  $thread_depth = bp_blogs_get_blogmeta( $activity->item_id, 'thread_comments_depth' );
1142
 
1143
+ // Initialize a local object so we won't have to query this again in the
1144
+ // comment loop.
1145
  if ( empty( buddypress()->blogs->allow_comments ) ) {
1146
  buddypress()->blogs->allow_comments = array();
1147
  }
1149
  buddypress()->blogs->thread_depth = array();
1150
  }
1151
 
1152
+ // Cache comment settings in the buddypress() singleton to reference later in
1153
  // the activity comment loop
1154
  // @see bp_blogs_disable_activity_replies()
1155
  //
1163
  /**
1164
  * Set up some globals used in the activity comment loop when AJAX is used.
1165
  *
1166
+ * @since 2.0.0
1167
  *
1168
  * @see bp_blogs_setup_activity_loop_globals()
1169
  */
1170
  function bp_blogs_setup_comment_loop_globals_on_ajax() {
1171
+ // Not AJAX? stop now!
1172
  if ( ! defined( 'DOING_AJAX' ) ) {
1173
  return;
1174
  }
1176
  return;
1177
  }
1178
 
1179
+ // Get the parent activity item.
1180
  $comment = bp_activity_current_comment();
1181
  $parent_activity = new BP_Activity_Activity( $comment->item_id );
1182
 
1183
+ // Setup the globals.
1184
  bp_blogs_setup_activity_loop_globals( $parent_activity );
1185
  }
1186
  add_action( 'bp_before_activity_comment', 'bp_blogs_setup_comment_loop_globals_on_ajax' );
1195
  * based on a certain age
1196
  * - the activity entry is a 'new_blog_comment' type
1197
  *
1198
+ * @since 2.0.0
1199
  *
1200
+ * @param bool $retval Is activity commenting enabled for this activity entry.
1201
  * @return bool
1202
  */
1203
  function bp_blogs_disable_activity_commenting( $retval ) {
1204
+ global $activities_template;
1205
+
1206
+ // If activity commenting is disabled, return current value.
1207
+ if ( bp_disable_blogforum_comments() || ! isset( $activities_template->in_the_loop ) ) {
1208
  return $retval;
1209
  }
1210
 
1211
+ $type = bp_get_activity_type();
 
1212
 
1213
+ // It's a post type supporting comment tracking.
1214
+ if ( bp_activity_type_supports( $type, 'post-type-comment-tracking' ) ) {
1215
+ // The activity type is supporting comments or replies
1216
+ if ( bp_activity_type_supports( $type, 'post-type-comment-reply' ) ) {
1217
+ // Setup some globals we'll need to reference later.
1218
+ bp_blogs_setup_activity_loop_globals( $activities_template->activity );
1219
+
1220
+ // If comments are closed for the WP blog post, we should disable
1221
+ // activity comments for this activity entry.
1222
+ if ( empty( buddypress()->blogs->allow_comments[ bp_get_activity_id() ] ) ) {
1223
+ $retval = false;
1224
+ }
1225
+ // The activity type does not support comments or replies
1226
+ } else {
1227
  $retval = false;
1228
+ }
1229
+ }
1230
 
1231
+ return $retval;
1232
+ }
1233
+ add_filter( 'bp_activity_can_comment', 'bp_blogs_disable_activity_commenting' );
1234
 
1235
+ /**
1236
+ * Limit the display of post type synced comments.
1237
+ *
1238
+ * @since 2.5.0
1239
+ *
1240
+ * When viewing the synced comments in stream mode, this prevents comments to
1241
+ * be displayed twice, and avoids a Javascript error as the form to add replies
1242
+ * is not available.
1243
+ *
1244
+ * @param int $retval The comment count for the activity.
1245
+ * @return int The comment count, or 0 to hide activity comment replies.
1246
+ */
1247
+ function bp_blogs_post_type_comments_avoid_duplicates( $retval ) {
1248
+ /**
1249
+ * Only limit the display when Post type comments are synced with
1250
+ * activity comments.
1251
+ */
1252
+ if ( bp_disable_blogforum_comments() ) {
1253
+ return $retval;
1254
+ }
1255
 
1256
+ if ( 'activity_comment' !== bp_get_activity_type() ) {
1257
+ return $retval;
1258
+ }
1259
 
1260
+ // Check the parent activity
1261
+ $parent_activity = new BP_Activity_Activity( bp_get_activity_item_id() );
 
 
 
1262
 
1263
+ if ( isset( $parent_activity->type ) && bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' ) ) {
1264
+ $retval = 0;
1265
  }
1266
 
1267
  return $retval;
1268
  }
1269
+ add_filter( 'bp_activity_get_comment_count', 'bp_blogs_post_type_comments_avoid_duplicates' );
1270
 
1271
  /**
1272
  * Check if an activity comment associated with a blog post can be replied to.
1277
  * This check uses a locally-cached value set in {@link bp_blogs_disable_activity_commenting()}
1278
  * via {@link bp_blogs_setup_activity_loop_globals()}.
1279
  *
1280
+ * @since 2.0.0
1281
+ *
1282
+ * @param bool $retval Are replies allowed for this activity reply.
1283
+ * @param object|array $comment The activity comment object.
1284
  *
 
 
1285
  * @return bool
1286
  */
1287
  function bp_blogs_can_comment_reply( $retval, $comment ) {
1289
  $comment = (object) $comment;
1290
  }
1291
 
1292
+ // Check comment depth and disable if depth is too large.
1293
  if ( isset( buddypress()->blogs->thread_depth[$comment->item_id] ) ){
1294
+ if ( bp_activity_get_comment_depth() > buddypress()->blogs->thread_depth[$comment->item_id] ) {
1295
  $retval = false;
1296
  }
1297
  }
1298
 
1299
+ // Check if we should disable activity replies based on the parent activity.
1300
  if ( isset( buddypress()->blogs->allow_comments[$comment->item_id] ) ){
1301
+ // The blog post has closed off commenting, so we should disable all activity
1302
+ // comments under the parent 'new_blog_post' activity entry.
1303
  if ( empty( buddypress()->blogs->allow_comments[$comment->item_id] ) ) {
1304
  $retval = false;
1305
  }
1316
  * This is only done if activity commenting is allowed and whether the parent
1317
  * activity item is a 'new_blog_post' entry.
1318
  *
1319
+ * @since 2.0.0
1320
  *
1321
+ * @param string $retval The activity comment permalink.
1322
  * @return string
1323
  */
1324
+ function bp_blogs_activity_comment_permalink( $retval = '' ) {
1325
  global $activities_template;
1326
 
1327
+ // Get the current comment ID.
1328
+ $item_id = isset( $activities_template->activity->current_comment->item_id )
1329
+ ? $activities_template->activity->current_comment->item_id
1330
+ : false;
1331
+
1332
+ // Maybe adjust the link if item ID exists.
1333
+ if ( ( false !== $item_id ) && isset( buddypress()->blogs->allow_comments[ $item_id ] ) ) {
1334
  $retval = $activities_template->activity->current_comment->primary_link;
1335
  }
1336
 
1343
  *
1344
  * This is only done if the activity comment is associated with a blog comment.
1345
  *
1346
+ * @since 2.0.1
1347
  *
1348
+ * @param string $retval The activity permalink.
1349
+ * @param BP_Activity_Activity $activity Activity object.
1350
  * @return string
1351
  */
1352
  function bp_blogs_activity_comment_single_permalink( $retval, $activity ) {
1354
  return $retval;
1355
  }
1356
 
1357
+ if ( bp_disable_blogforum_comments() ) {
1358
+ return $retval;
1359
+ }
1360
 
1361
+ $parent_activity = new BP_Activity_Activity( $activity->item_id );
1362
+
1363
+ if ( isset( $parent_activity->type ) && bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' ) ) {
1364
  $retval = $activity->primary_link;
1365
  }
1366
 
1373
  *
1374
  * This is only done if the activity comment is associated with a blog comment.
1375
  *
1376
+ * @since 2.0.1
1377
  *
1378
+ * @param string $retval The activity action.
1379
+ * @param BP_Activity_Activity $activity Activity object.
1380
  * @return string
1381
  */
1382
  function bp_blogs_activity_comment_single_action( $retval, $activity ) {
1384
  return $retval;
1385
  }
1386
 
1387
+ if ( bp_disable_blogforum_comments() ) {
1388
+ return $retval;
1389
+ }
1390
+
1391
+ $parent_activity = new BP_Activity_Activity( $activity->item_id );
1392
+
1393
+ if ( ! isset( $parent_activity->type ) ) {
1394
+ return $retval;
1395
+ }
1396
+
1397
+ $post_type = bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'post_type' );
1398
+
1399
+ if ( ! $post_type ) {
1400
+ return $retval;
1401
+ }
1402
+
1403
+ $blog_comment_id = bp_activity_get_meta( $activity->id, "bp_blogs_{$post_type}_comment_id" );
1404
 
1405
  if ( ! empty( $blog_comment_id ) ) {
1406
+ $bp = buddypress();
1407
+
1408
+ // Check if a comment action id is set for the parent activity
1409
+ $comment_action_id = bp_activity_post_type_get_tracking_arg( $parent_activity->type, 'comment_action_id' );
1410
+
1411
+ // Use the action string callback for the activity type
1412
+ if ( ! empty( $comment_action_id ) ) {
1413
+ // Fake a 'new_{post_type}_comment' by cloning the activity object.
1414
+ $object = clone $activity;
1415
 
1416
+ // Set the type of the activity to be a comment about a post type
1417
+ $object->type = $comment_action_id;
1418
 
1419
+ // Use the blog ID as the item_id.
1420
+ $object->item_id = $parent_activity->item_id;
1421
 
1422
+ // Use comment ID as the secondary_item_id.
1423
+ $object->secondary_item_id = $blog_comment_id;
1424
 
1425
+ // Get the format callback for this activity comment
1426
+ $format_callback = bp_activity_post_type_get_tracking_arg( $comment_action_id, 'format_callback' );
1427
+
1428
+ // now format the activity action using the 'new_{post_type}_comment' action callback
1429
+ if ( is_callable( $format_callback ) ) {
1430
+ $retval = call_user_func_array( $format_callback, array( '', $object ) );
1431
+ }
1432
+ }
1433
  }
1434
 
1435
  return $retval;
bp-blogs/bp-blogs-buddybar.php DELETED
@@ -1,78 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * BuddyPress Blogs BuddyBar functions.
5
- *
6
- * @package BuddyPress
7
- * @subpackage BlogsBuddyBar
8
- */
9
-
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
12
-
13
- /**
14
- * Add a Sites menu to the BuddyBar.
15
- *
16
- * @since BuddyPress (1.0.0)
17
- *
18
- * @global object $bp The BuddyPress global settings object.
19
- *
20
- * @return bool|null Returns false on failure. Otherwise echoes the menu item.
21
- */
22
- function bp_adminbar_blogs_menu() {
23
- global $bp;
24
-
25
- if ( !is_user_logged_in() || !bp_is_active( 'blogs' ) )
26
- return false;
27
-
28
- if ( !is_multisite() )
29
- return false;
30
-
31
- $blogs = wp_cache_get( 'bp_blogs_of_user_' . bp_loggedin_user_id() . '_inc_hidden', 'bp' );
32
- if ( empty( $blogs ) ) {
33
- $blogs = bp_blogs_get_blogs_for_user( bp_loggedin_user_id(), true );
34
- wp_cache_set( 'bp_blogs_of_user_' . bp_loggedin_user_id() . '_inc_hidden', $blogs, 'bp' );
35
- }
36
-
37
- $counter = 0;
38
- if ( is_array( $blogs['blogs'] ) && (int) $blogs['count'] ) {
39
-
40
- echo '<li id="bp-adminbar-blogs-menu"><a href="' . trailingslashit( bp_loggedin_user_domain() . bp_get_blogs_slug() ) . '">';
41
-
42
- _e( 'My Sites', 'buddypress' );
43
-
44
- echo '</a>';
45
- echo '<ul>';
46
-
47
- foreach ( (array) $blogs['blogs'] as $blog ) {
48
- $alt = ( 0 == $counter % 2 ) ? ' class="alt"' : '';
49
- $site_url = esc_attr( $blog->siteurl );
50
-
51
- echo '<li' . $alt . '>';
52
- echo '<a href="' . $site_url . '">' . esc_html( $blog->name ) . '</a>';
53
- echo '<ul>';
54
- echo '<li class="alt"><a href="' . $site_url . 'wp-admin/">' . __( 'Dashboard', 'buddypress' ) . '</a></li>';
55
- echo '<li><a href="' . $site_url . 'wp-admin/post-new.php">' . __( 'New Post', 'buddypress' ) . '</a></li>';
56
- echo '<li class="alt"><a href="' . $site_url . 'wp-admin/edit.php">' . __( 'Manage Posts', 'buddypress' ) . '</a></li>';
57
- echo '<li><a href="' . $site_url . 'wp-admin/edit-comments.php">' . __( 'Manage Comments', 'buddypress' ) . '</a></li>';
58
- echo '</ul>';
59
-
60
- do_action( 'bp_adminbar_blog_items', $blog );
61
-
62
- echo '</li>';
63
- $counter++;
64
- }
65
-
66
- $alt = ( 0 == $counter % 2 ) ? ' class="alt"' : '';
67
-
68
- if ( bp_blog_signup_enabled() ) {
69
- echo '<li' . $alt . '>';
70
- echo '<a href="' . bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create/">' . __( 'Create a Site!', 'buddypress' ) . '</a>';
71
- echo '</li>';
72
- }
73
-
74
- echo '</ul>';
75
- echo '</li>';
76
- }
77
- }
78
- add_action( 'bp_adminbar_menus', 'bp_adminbar_blogs_menu', 6 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bp-blogs/bp-blogs-cache.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Blogs Caching.
5
  *
@@ -8,10 +7,11 @@
8
  *
9
  * @package BuddyPress
10
  * @subpackage BlogsCache
 
11
  */
12
 
13
- // Exit if accessed directly
14
- if ( !defined( 'ABSPATH' ) ) exit;
15
 
16
  /**
17
  * Slurp up blogmeta for a specified set of blogs.
@@ -20,16 +20,16 @@ if ( !defined( 'ABSPATH' ) ) exit;
20
  * in $blog_ids and adds it to the WP cache. This improves efficiency when
21
  * using querying blogmeta inline.
22
  *
23
- * @param int|str|array $blog_ids Accepts a single blog ID, or a comma-
24
- * separated list or array of blog IDs.
25
  */
26
  function bp_blogs_update_meta_cache( $blog_ids = false ) {
27
  $cache_args = array(
28
- 'object_ids' => $blog_ids,
29
- 'object_type' => buddypress()->blogs->id,
30
- 'object_column' => 'blog_id',
31
- 'cache_group' => 'blog_meta',
32
- 'meta_table' => buddypress()->blogs->table_name_blogmeta,
33
  );
34
 
35
  bp_update_meta_cache( $cache_args );
@@ -37,34 +37,26 @@ function bp_blogs_update_meta_cache( $blog_ids = false ) {
37
  /**
38
  * Clear the blog object cache.
39
  *
40
- * @since BuddyPress (1.0.0)
41
  *
42
  * @param int $blog_id ID of the current blog.
43
  * @param int $user_id ID of the user whose blog cache should be cleared.
44
  */
45
- function bp_blogs_clear_blog_object_cache( $blog_id, $user_id ) {
46
- wp_cache_delete( 'bp_blogs_of_user_' . $user_id, 'bp' );
47
- wp_cache_delete( 'bp_total_blogs_for_user_' . $user_id, 'bp' );
48
- }
 
49
 
50
- /**
51
- * Clear cache when a new blog is created.
52
- *
53
- * @since BuddyPress (1.0.0)
54
- *
55
- * @param BP_Blogs_Blog $recorded_blog_obj The recorded blog, passed by
56
- * 'bp_blogs_new_blog'.
57
- */
58
- function bp_blogs_format_clear_blog_cache( $recorded_blog_obj ) {
59
- bp_blogs_clear_blog_object_cache( false, $recorded_blog_obj->user_id );
60
  wp_cache_delete( 'bp_total_blogs', 'bp' );
61
  }
62
 
63
- // List actions to clear object caches on
64
  add_action( 'bp_blogs_remove_blog_for_user', 'bp_blogs_clear_blog_object_cache', 10, 2 );
65
- add_action( 'bp_blogs_new_blog', 'bp_blogs_format_clear_blog_cache', 10, 2 );
 
66
 
67
- // List actions to clear super cached pages on, if super cache is installed
68
  add_action( 'bp_blogs_remove_data_for_blog', 'bp_core_clear_cache' );
69
  add_action( 'bp_blogs_remove_comment', 'bp_core_clear_cache' );
70
  add_action( 'bp_blogs_remove_post', 'bp_core_clear_cache' );
1
  <?php
 
2
  /**
3
  * BuddyPress Blogs Caching.
4
  *
7
  *
8
  * @package BuddyPress
9
  * @subpackage BlogsCache
10
+ * @since 1.5.0
11
  */
12
 
13
+ // Exit if accessed directly.
14
+ defined( 'ABSPATH' ) || exit;
15
 
16
  /**
17
  * Slurp up blogmeta for a specified set of blogs.
20
  * in $blog_ids and adds it to the WP cache. This improves efficiency when
21
  * using querying blogmeta inline.
22
  *
23
+ * @param int|string|array|bool $blog_ids Accepts a single blog ID, or a comma-
24
+ * separated list or array of blog IDs.
25
  */
26
  function bp_blogs_update_meta_cache( $blog_ids = false ) {
27
  $cache_args = array(
28
+ 'object_ids' => $blog_ids,
29
+ 'object_type' => buddypress()->blogs->id,
30
+ 'object_column' => 'blog_id',
31
+ 'cache_group' => 'blog_meta',
32
+ 'meta_table' => buddypress()->blogs->table_name_blogmeta,
33
  );
34
 
35
  bp_update_meta_cache( $cache_args );
37
  /**
38
  * Clear the blog object cache.
39
  *
40
+ * @since 1.0.0
41
  *
42
  * @param int $blog_id ID of the current blog.
43
  * @param int $user_id ID of the user whose blog cache should be cleared.
44
  */
45
+ function bp_blogs_clear_blog_object_cache( $blog_id = 0, $user_id = 0 ) {
46
+ if ( ! empty( $user_id ) ) {
47
+ wp_cache_delete( 'bp_blogs_of_user_' . $user_id, 'bp' );
48
+ wp_cache_delete( 'bp_total_blogs_for_user_' . $user_id, 'bp' );
49
+ }
50
 
 
 
 
 
 
 
 
 
 
 
51
  wp_cache_delete( 'bp_total_blogs', 'bp' );
52
  }
53
 
54
+ // List actions to clear object caches on.
55
  add_action( 'bp_blogs_remove_blog_for_user', 'bp_blogs_clear_blog_object_cache', 10, 2 );
56
+ add_action( 'wpmu_new_blog', 'bp_blogs_clear_blog_object_cache', 10, 2 );
57
+ add_action( 'bp_blogs_remove_blog', 'bp_blogs_clear_blog_object_cache' );
58
 
59
+ // List actions to clear super cached pages on, if super cache is installed.
60
  add_action( 'bp_blogs_remove_data_for_blog', 'bp_core_clear_cache' );
61
  add_action( 'bp_blogs_remove_comment', 'bp_core_clear_cache' );
62
  add_action( 'bp_blogs_remove_post', 'bp_core_clear_cache' );
bp-blogs/bp-blogs-classes.php CHANGED
@@ -1,527 +1,13 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Blogs Classes.
5
  *
6
  * @package BuddyPress
7
  * @subpackage BlogsClasses
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
12
-
13
- /**
14
- * The main BuddyPress blog class.
15
- *
16
- * A BP_Blogs_Object represents a link between a specific WordPress blog on a
17
- * network and a specific user on that blog.
18
- *
19
- * @since BuddyPress (1.0.0)
20
- */
21
- class BP_Blogs_Blog {
22
- public $id;
23
- public $user_id;
24
- public $blog_id;
25
-
26
- /**
27
- * Constructor method.
28
- *
29
- * @param int $id Optional. The ID of the blog.
30
- */
31
- public function __construct( $id = null ) {
32
- if ( !empty( $id ) ) {
33
- $this->id = $id;
34
- $this->populate();
35
- }
36
- }
37
-
38
- /**
39
- * Populate the object with data about the specific activity item.
40
- */
41
- public function populate() {
42
- global $wpdb, $bp;
43
-
44
- $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->blogs->table_name} WHERE id = %d", $this->id ) );
45
-
46
- $this->user_id = $blog->user_id;
47
- $this->blog_id = $blog->blog_id;
48
- }
49
-
50
- /**
51
- * Save the BP blog data to the database.
52
- *
53
- * @return bool True on success, false on failure.
54
- */
55
- public function save() {
56
- global $wpdb, $bp;
57
-
58
- $this->user_id = apply_filters( 'bp_blogs_blog_user_id_before_save', $this->user_id, $this->id );
59
- $this->blog_id = apply_filters( 'bp_blogs_blog_id_before_save', $this->blog_id, $this->id );
60
-
61
- do_action_ref_array( 'bp_blogs_blog_before_save', array( &$this ) );
62
-
63
- // Don't try and save if there is no user ID or blog ID set.
64
- if ( !$this->user_id || !$this->blog_id )
65
- return false;
66
-
67
- // Don't save if this blog has already been recorded for the user.
68
- if ( !$this->id && $this->exists() )
69
- return false;
70
-
71
- if ( $this->id ) {
72
- // Update
73
- $sql = $wpdb->prepare( "UPDATE {$bp->blogs->table_name} SET user_id = %d, blog_id = %d WHERE id = %d", $this->user_id, $this->blog_id, $this->id );
74
- } else {
75
- // Save
76
- $sql = $wpdb->prepare( "INSERT INTO {$bp->blogs->table_name} ( user_id, blog_id ) VALUES ( %d, %d )", $this->user_id, $this->blog_id );
77
- }
78
-
79
- if ( !$wpdb->query($sql) )
80
- return false;
81
-
82
- do_action_ref_array( 'bp_blogs_blog_after_save', array( &$this ) );
83
-
84
- if ( $this->id )
85
- return $this->id;
86
- else
87
- return $wpdb->insert_id;
88
- }
89
-
90
- /**
91
- * Check whether an association between this user and this blog exists.
92
- *
93
- * @return int The number of associations between the user and blog
94
- * saved in the blog component tables.
95
- */
96
- public function exists() {
97
- global $bp, $wpdb;
98
-
99
- return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->blogs->table_name} WHERE user_id = %d AND blog_id = %d", $this->user_id, $this->blog_id ) );
100
- }
101
-
102
- /** Static Methods ***************************************************/
103
-
104
- /**
105
- * Retrieve a set of blog-user associations.
106
- *
107
- * @param string $type The order in which results should be returned.
108
- * 'active', 'alphabetical', 'newest', or 'random'.
109
- * @param int|bool $limit Optional. The maximum records to return.
110
- * Default: false.
111
- * @param int|bool $page Optional. The page of records to return.
112
- * Default: false (unlimited results).
113
- * @param int $user_id Optional. ID of the user whose blogs are being
114
- * retrieved. Default: 0.
115
- * @param string|bool $search_terms Optional. Search by text stored in
116
- * blogmeta (such as the blog name). Default: false.
117
- * @param bool $update_meta_cache Whether to pre-fetch metadata for
118
- * blogs. Default: true.
119
- * @param array $include_blog_ids Array of blog IDs to include.
120
- * @return array Multidimensional results array, structured as follows:
121
- * 'blogs' - Array of located blog objects
122
- * 'total' - A count of the total blogs matching the filter params
123
- */
124
- public static function get( $type, $limit = false, $page = false, $user_id = 0, $search_terms = false, $update_meta_cache = true, $include_blog_ids = false ) {
125
- global $bp, $wpdb;
126
-
127
- if ( !is_user_logged_in() || ( !bp_current_user_can( 'bp_moderate' ) && ( $user_id != bp_loggedin_user_id() ) ) )
128
- $hidden_sql = "AND wb.public = 1";
129
- else
130
- $hidden_sql = '';
131
-
132
- $pag_sql = ( $limit && $page ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
133
-
134
- $user_sql = !empty( $user_id ) ? $wpdb->prepare( " AND b.user_id = %d", $user_id ) : '';
135
-
136
- switch ( $type ) {
137
- case 'active': default:
138
- $order_sql = "ORDER BY bm.meta_value DESC";
139
- break;
140
- case 'alphabetical':
141
- $order_sql = "ORDER BY bm2.meta_value ASC";
142
- break;
143
- case 'newest':
144
- $order_sql = "ORDER BY wb.registered DESC";
145
- break;
146
- case 'random':
147
- $order_sql = "ORDER BY RAND()";
148
- break;
149
- }
150
-
151
- $include_sql = '';
152
- $include_blog_ids = array_filter( wp_parse_id_list( $include_blog_ids ) );
153
- if ( ! empty( $include_blog_ids ) ) {
154
- $blog_ids_sql = implode( ',', $include_blog_ids );
155
- $include_sql = " AND b.blog_id IN ({$blog_ids_sql})";
156
- }
157
-
158
- if ( !empty( $search_terms ) ) {
159
- $filter = esc_sql( like_escape( $search_terms ) );
160
- $paged_blogs = $wpdb->get_results( "SELECT b.blog_id, b.user_id as admin_user_id, u.user_email as admin_user_email, wb.domain, wb.path, bm.meta_value as last_activity, bm2.meta_value as name FROM {$bp->blogs->table_name} b, {$bp->blogs->table_name_blogmeta} bm, {$bp->blogs->table_name_blogmeta} bm2, {$wpdb->base_prefix}blogs wb, {$wpdb->users} u WHERE b.blog_id = wb.blog_id AND b.user_id = u.ID AND b.blog_id = bm.blog_id AND b.blog_id = bm2.blog_id AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql} AND bm.meta_key = 'last_activity' AND bm2.meta_key = 'name' AND bm2.meta_value LIKE '%%$filter%%' {$user_sql} {$include_sql} GROUP BY b.blog_id {$order_sql} {$pag_sql}" );
161
- $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb, {$bp->blogs->table_name_blogmeta} bm, {$bp->blogs->table_name_blogmeta} bm2 WHERE b.blog_id = wb.blog_id AND bm.blog_id = b.blog_id AND bm2.blog_id = b.blog_id AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql} AND bm.meta_key = 'name' AND bm2.meta_key = 'description' AND ( bm.meta_value LIKE '%%$filter%%' || bm2.meta_value LIKE '%%$filter%%' ) {$user_sql} {$include_sql}" );
162
- } else {
163
- $paged_blogs = $wpdb->get_results( "SELECT b.blog_id, b.user_id as admin_user_id, u.user_email as admin_user_email, wb.domain, wb.path, bm.meta_value as last_activity, bm2.meta_value as name FROM {$bp->blogs->table_name} b, {$bp->blogs->table_name_blogmeta} bm, {$bp->blogs->table_name_blogmeta} bm2, {$wpdb->base_prefix}blogs wb, {$wpdb->users} u WHERE b.blog_id = wb.blog_id AND b.user_id = u.ID AND b.blog_id = bm.blog_id AND b.blog_id = bm2.blog_id {$user_sql} AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql} AND bm.meta_key = 'last_activity' AND bm2.meta_key = 'name' {$include_sql} GROUP BY b.blog_id {$order_sql} {$pag_sql}" );
164
- $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb WHERE b.blog_id = wb.blog_id {$user_sql} AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$include_sql} {$hidden_sql}" );
165
- }
166
-
167
- $blog_ids = array();
168
- foreach ( (array) $paged_blogs as $blog ) {
169
- $blog_ids[] = (int) $blog->blog_id;
170
- }
171
-
172
- $paged_blogs = BP_Blogs_Blog::get_blog_extras( $paged_blogs, $blog_ids, $type );
173
-
174
- if ( $update_meta_cache ) {
175
- bp_blogs_update_meta_cache( $blog_ids );
176
- }
177
-
178
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
179
- }
180
-
181
- /**
182
- * Delete the record of a given blog for all users.
183
- *
184
- * @param int $blog_id The blog being removed from all users.
185
- * @return int|bool Number of rows deleted on success, false on failure.
186
- */
187
- public static function delete_blog_for_all( $blog_id ) {
188
- global $wpdb, $bp;
189
-
190
- bp_blogs_delete_blogmeta( $blog_id );
191
- return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name} WHERE blog_id = %d", $blog_id ) );
192
- }
193
-
194
- /**
195
- * Delete the record of a given blog for a specific user.
196
- *
197
- * @param int $blog_id The blog being removed.
198
- * @param int $user_id Optional. The ID of the user from whom the blog
199
- * is being removed. If absent, defaults to the logged-in user ID.
200
- * @return int|bool Number of rows deleted on success, false on failure.
201
- */
202
- public static function delete_blog_for_user( $blog_id, $user_id = null ) {
203
- global $wpdb, $bp;
204
-
205
- if ( !$user_id )
206
- $user_id = bp_loggedin_user_id();
207
-
208
- return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name} WHERE user_id = %d AND blog_id = %d", $user_id, $blog_id ) );
209
- }
210
-
211
- /**
212
- * Delete all of a user's blog associations in the BP tables.
213
- *
214
- * @param int $user_id Optional. The ID of the user whose blog
215
- * associations are being deleted. If absent, defaults to
216
- * logged-in user ID.
217
- * @return int|bool Number of rows deleted on success, false on failure.
218
- */
219
- public static function delete_blogs_for_user( $user_id = null ) {
220
- global $wpdb, $bp;
221
-
222
- if ( !$user_id )
223
- $user_id = bp_loggedin_user_id();
224
-
225
- return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name} WHERE user_id = %d", $user_id ) );
226
- }
227
-
228
- /**
229
- * Get all of a user's blogs, as tracked by BuddyPress.
230
- *
231
- * Note that this is different from the WordPress function
232
- * {@link get_blogs_of_user()}; the current method returns only those
233
- * blogs that have been recorded by BuddyPress, while the WP function
234
- * does a true query of a user's blog capabilities.
235
- *
236
- * @param int $user_id Optional. ID of the user whose blogs are being
237
- * queried. Defaults to logged-in user.
238
- * @param bool $show_hidden Optional. Whether to include blogs that are
239
- * not marked public. Defaults to true when viewing one's own
240
- * profile.
241
- * @return array Multidimensional results array, structured as follows:
242
- * 'blogs' - Array of located blog objects
243
- * 'total' - A count of the total blogs for the user.
244
- */
245
- public static function get_blogs_for_user( $user_id = 0, $show_hidden = false ) {
246
- global $bp, $wpdb;
247
-
248
- if ( !$user_id )
249
- $user_id = bp_displayed_user_id();
250
-
251
- // Show logged in users their hidden blogs.
252
- if ( !bp_is_my_profile() && !$show_hidden )
253
- $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT b.blog_id, b.id, bm1.meta_value as name, wb.domain, wb.path FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb, {$bp->blogs->table_name_blogmeta} bm1 WHERE b.blog_id = wb.blog_id AND b.blog_id = bm1.blog_id AND bm1.meta_key = 'name' AND wb.public = 1 AND wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND b.user_id = %d ORDER BY b.blog_id", $user_id ) );
254
- else
255
- $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT b.blog_id, b.id, bm1.meta_value as name, wb.domain, wb.path FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb, {$bp->blogs->table_name_blogmeta} bm1 WHERE b.blog_id = wb.blog_id AND b.blog_id = bm1.blog_id AND bm1.meta_key = 'name' AND wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND b.user_id = %d ORDER BY b.blog_id", $user_id ) );
256
-
257
- $total_blog_count = BP_Blogs_Blog::total_blog_count_for_user( $user_id );
258
-
259
- $user_blogs = array();
260
- foreach ( (array) $blogs as $blog ) {
261
- $user_blogs[$blog->blog_id] = new stdClass;
262
- $user_blogs[$blog->blog_id]->id = $blog->id;
263
- $user_blogs[$blog->blog_id]->blog_id = $blog->blog_id;
264
- $user_blogs[$blog->blog_id]->siteurl = ( is_ssl() ) ? 'https://' . $blog->domain . $blog->path : 'http://' . $blog->domain . $blog->path;
265
- $user_blogs[$blog->blog_id]->name = $blog->name;
266
- }
267
-
268
- return array( 'blogs' => $user_blogs, 'count' => $total_blog_count );
269
- }
270
-
271
- /**
272
- * Get IDs of all of a user's blogs, as tracked by BuddyPress.
273
- *
274
- * This method always includes hidden blogs.
275
- *
276
- * @param int $user_id Optional. ID of the user whose blogs are being
277
- * queried. Defaults to logged-in user.
278
- * @return int The number of blogs associated with the user.
279
- */
280
- public static function get_blog_ids_for_user( $user_id = 0 ) {
281
- global $bp, $wpdb;
282
-
283
- if ( !$user_id )
284
- $user_id = bp_displayed_user_id();
285
-
286
- return $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$bp->blogs->table_name} WHERE user_id = %d", $user_id ) );
287
- }
288
-
289
- /**
290
- * Check whether a blog has been recorded by BuddyPress.
291
- *
292
- * @param int $blog_id ID of the blog being queried.
293
- * @return int|null The ID of the first located entry in the BP table
294
- * on success, otherwise null.
295
- */
296
- public static function is_recorded( $blog_id ) {
297
- global $bp, $wpdb;
298
-
299
- return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->blogs->table_name} WHERE blog_id = %d", $blog_id ) );
300
- }
301
-
302
- /**
303
- * Return a count of associated blogs for a given user.
304
- *
305
- * Includes hidden blogs when the logged-in user is the same as the
306
- * $user_id parameter, or when the logged-in user has the bp_moderate
307
- * cap.
308
- *
309
- * @param int $user_id Optional. ID of the user whose blogs are being
310
- * queried. Defaults to logged-in user.
311
- * @return int Blog count for the user.
312
- */
313
- public static function total_blog_count_for_user( $user_id = null ) {
314
- global $bp, $wpdb;
315
-
316
- if ( !$user_id )
317
- $user_id = bp_displayed_user_id();
318
-
319
- // If the user is logged in return the blog count including their hidden blogs.
320
- if ( ( is_user_logged_in() && $user_id == bp_loggedin_user_id() ) || bp_current_user_can( 'bp_moderate' ) ) {
321
- return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND user_id = %d", $user_id ) );
322
- } else {
323
- return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.public = 1 AND wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND user_id = %d", $user_id ) );
324
- }
325
- }
326
-
327
- /**
328
- * Return a list of blogs matching a search term.
329
- *
330
- * Matches against blog names and descriptions, as stored in the BP
331
- * blogmeta table.
332
- *
333
- * @param string $filter The search term.
334
- * @param int $limit Optional. The maximum number of items to return.
335
- * Default: null (no limit).
336
- * @param int $page Optional. The page of results to return. Default:
337
- * null (no limit).
338
- * @return array Multidimensional results array, structured as follows:
339
- * 'blogs' - Array of located blog objects
340
- * 'total' - A count of the total blogs matching the query.
341
- */
342
- public static function search_blogs( $filter, $limit = null, $page = null ) {
343
- global $wpdb, $bp;
344
-
345
- $filter = esc_sql( like_escape( $filter ) );
346
-
347
- $hidden_sql = '';
348
- if ( !bp_current_user_can( 'bp_moderate' ) )
349
- $hidden_sql = "AND wb.public = 1";
350
-
351
- $pag_sql = '';
352
- if ( $limit && $page ) {
353
- $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
354
- }
355
-
356
- $paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND bm.meta_value LIKE '%%$filter%%' ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC{$pag_sql}" );
357
- $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND bm.meta_value LIKE '%%$filter%%' ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC" );
358
-
359
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
360
- }
361
-
362
- /**
363
- * Retrieve a list of all blogs.
364
- *
365
- * Query will include hidden blogs if the logged-in user has the
366
- * 'bp_moderate' cap.
367
- *
368
- * @param int $limit Optional. The maximum number of items to return.
369
- * Default: null (no limit).
370
- * @param int $page Optional. The page of results to return. Default:
371
- * null (no limit).
372
- * @return array Multidimensional results array, structured as follows:
373
- * 'blogs' - Array of located blog objects
374
- * 'total' - A count of the total blogs.
375
- */
376
- public static function get_all( $limit = null, $page = null ) {
377
- global $bp, $wpdb;
378
-
379
- $hidden_sql = !bp_current_user_can( 'bp_moderate' ) ? "AND wb.public = 1" : '';
380
- $pag_sql = ( $limit && $page ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
381
-
382
- $paged_blogs = $wpdb->get_results( "SELECT DISTINCT b.blog_id FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql} {$pag_sql}" );
383
- $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql}" );
384
-
385
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
386
- }
387
-
388
- /**
389
- * Retrieve a list of blogs whose names start with a given letter.
390
- *
391
- * Query will include hidden blogs if the logged-in user has the
392
- * 'bp_moderate' cap.
393
- *
394
- * @param string $letter. The letter you're looking for.
395
- * @param int $limit Optional. The maximum number of items to return.
396
- * Default: null (no limit).
397
- * @param int $page Optional. The page of results to return. Default:
398
- * null (no limit).
399
- * @return array Multidimensional results array, structured as follows:
400
- * 'blogs' - Array of located blog objects.
401
- * 'total' - A count of the total blogs matching the query.
402
- */
403
- public static function get_by_letter( $letter, $limit = null, $page = null ) {
404
- global $bp, $wpdb;
405
-
406
- $letter = esc_sql( like_escape( $letter ) );
407
-
408
- $hidden_sql = '';
409
- if ( !bp_current_user_can( 'bp_moderate' ) )
410
- $hidden_sql = "AND wb.public = 1";
411
-
412
- if ( $limit && $page )
413
- $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
414
-
415
- $paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND bm.meta_value LIKE '$letter%%' {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC{$pag_sql}" );
416
- $total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND bm.meta_value LIKE '$letter%%' {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC" );
417
-
418
- return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
419
- }
420
-
421
- /**
422
- * Fetch blog data not caught in the main query and append it to results array.
423
- *
424
- * Gets the following information, which is either unavailable at the
425
- * time of the original query, or is more efficient to look up in one
426
- * fell swoop:
427
- * - The latest post for each blog, include Featured Image data
428
- * - The blog description
429
- *
430
- * @param array $paged_blogs Array of results from the original query.
431
- * @param array $blog_ids Array of IDs returned from the original query.
432
- * @param string|bool $type Not currently used. Default: false.
433
- * @return array $paged_blogs The located blogs array, with the extras added.
434
- */
435
- public static function get_blog_extras( &$paged_blogs, &$blog_ids, $type = false ) {
436
- global $bp, $wpdb;
437
-
438
- if ( empty( $blog_ids ) )
439
- return $paged_blogs;
440
-
441
- $blog_ids = implode( ',', wp_parse_id_list( $blog_ids ) );
442
-
443
- for ( $i = 0, $count = count( $paged_blogs ); $i < $count; ++$i ) {
444
- $blog_prefix = $wpdb->get_blog_prefix( $paged_blogs[$i]->blog_id );
445
- $paged_blogs[$i]->latest_post = $wpdb->get_row( "SELECT ID, post_content, post_title, post_excerpt, guid FROM {$blog_prefix}posts WHERE post_status = 'publish' AND post_type = 'post' AND id != 1 ORDER BY id DESC LIMIT 1" );
446
- $images = array();
447
-
448
- // Add URLs to any Featured Image this post might have
449
- if ( ! empty( $paged_blogs[$i]->latest_post ) && has_post_thumbnail( $paged_blogs[$i]->latest_post->ID ) ) {
450
-
451
- // Grab 4 sizes of the image. Thumbnail.
452
- $image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'thumbnail', false );
453
- if ( ! empty( $image ) )
454
- $images['thumbnail'] = $image[0];
455
-
456
- // Medium
457
- $image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'medium', false );
458
- if ( ! empty( $image ) )
459
- $images['medium'] = $image[0];
460
-
461
- // Large
462
- $image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'large', false );
463
- if ( ! empty( $image ) )
464
- $images['large'] = $image[0];
465
-
466
- // Post thumbnail
467
- $image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'post-thumbnail', false );
468
- if ( ! empty( $image ) )
469
- $images['post-thumbnail'] = $image[0];
470
-
471
- // Add the images to the latest_post object
472
- $paged_blogs[$i]->latest_post->images = $images;
473
- }
474
- }
475
-
476
- /* Fetch the blog description for each blog (as it may be empty we can't fetch it in the main query). */
477
- $blog_descs = $wpdb->get_results( "SELECT blog_id, meta_value as description FROM {$bp->blogs->table_name_blogmeta} WHERE meta_key = 'description' AND blog_id IN ( {$blog_ids} )" );
478
-
479
- for ( $i = 0, $count = count( $paged_blogs ); $i < $count; ++$i ) {
480
- foreach ( (array) $blog_descs as $desc ) {
481
- if ( $desc->blog_id == $paged_blogs[$i]->blog_id )
482
- $paged_blogs[$i]->description = $desc->description;
483
- }
484
- }
485
-
486
- return $paged_blogs;
487
- }
488
-
489
- /**
490
- * Check whether a given blog is hidden.
491
- *
492
- * Checks the 'public' column in the wp_blogs table.
493
- *
494
- * @param int $blog_id The ID of the blog being checked.
495
- * @return bool True if hidden (public = 0), false otherwise.
496
- */
497
- public static function is_hidden( $blog_id ) {
498
- global $wpdb;
499
-
500
- if ( !(int) $wpdb->get_var( $wpdb->prepare( "SELECT public FROM {$wpdb->base_prefix}blogs WHERE blog_id = %d", $blog_id ) ) ) {
501
- return true;
502
- }
503
-
504
- return false;
505
- }
506
-
507
- /**
508
- * Get ID of user-blog link.
509
- *
510
- * @param int $user_id ID of user.
511
- * @param int $blog_id ID of blog.
512
- * @return int|bool ID of user-blog link, or false if not found.
513
- */
514
- public static function get_user_blog( $user_id, $blog_id ) {
515
- global $bp, $wpdb;
516
-
517
- $user_blog = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->blogs->table_name} WHERE user_id = %d AND blog_id = %d", $user_id, $blog_id ) );
518
-
519
- if ( empty( $user_blog ) ) {
520
- $user_blog = false;
521
- } else {
522
- $user_blog = intval( $user_blog );
523
- }
524
 
525
- return $user_blog;
526
- }
527
- }
1
  <?php
 
2
  /**
3
  * BuddyPress Blogs Classes.
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsClasses
7
+ * @since 1.0.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ require dirname( __FILE__ ) . '/classes/class-bp-blogs-blog.php';
 
 
bp-blogs/bp-blogs-filters.php CHANGED
@@ -1,11 +1,10 @@
1
  <?php
2
-
3
  /**
4
  * Filters related to the Blogs component.
5
  *
6
  * @package BuddyPress
7
- * @subpackage Blogs
8
- * @since BuddyPress (1.6.0)
9
  */
10
 
11
  /** Display Filters **********************************************************/
@@ -24,15 +23,115 @@ add_filter( 'bp_blog_latest_post_content', 'prepend_attachment' );
24
  /**
25
  * Ensure that the 'Create a new site' link at wp-admin/my-sites.php points to the BP blog signup.
26
  *
27
- * @since BuddyPress (1.6.0)
28
  *
29
- * @uses apply_filters() Filter 'bp_blogs_creation_location' to alter the
30
  * returned value.
31
  *
32
  * @param string $url The original URL (points to wp-signup.php by default).
33
  * @return string The new URL.
34
  */
35
  function bp_blogs_creation_location( $url ) {
36
- return apply_filters( 'bp_blogs_creation_location', trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create', $url ) );
 
 
 
 
 
 
 
 
37
  }
38
  add_filter( 'wp_signup_location', 'bp_blogs_creation_location' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  /**
3
  * Filters related to the Blogs component.
4
  *
5
  * @package BuddyPress
6
+ * @subpackage BlogFilters
7
+ * @since 1.6.0
8
  */
9
 
10
  /** Display Filters **********************************************************/
23
  /**
24
  * Ensure that the 'Create a new site' link at wp-admin/my-sites.php points to the BP blog signup.
25
  *
26
+ * @since 1.6.0
27
  *
 
28
  * returned value.
29
  *
30
  * @param string $url The original URL (points to wp-signup.php by default).
31
  * @return string The new URL.
32
  */
33
  function bp_blogs_creation_location( $url ) {
34
+
35
+ /**
36
+ * Filters the 'Create a new site' link URL.
37
+ *
38
+ * @since 1.6.0
39
+ *
40
+ * @param string $value URL for the 'Create a new site' signup page.
41
+ */
42
+ return apply_filters( 'bp_blogs_creation_location', trailingslashit( bp_get_blogs_directory_permalink() . 'create' ), $url );
43
  }
44
  add_filter( 'wp_signup_location', 'bp_blogs_creation_location' );
45
+
46
+ /**
47
+ * Only select comments by ID instead of all fields when using get_comments().
48
+ *
49
+ * @since 2.1.0
50
+ *
51
+ * @see bp_blogs_update_post_activity_meta()
52
+ *
53
+ * @param array $retval Current SQL clauses in array format.
54
+ * @return array
55
+ */
56
+ function bp_blogs_comments_clauses_select_by_id( $retval ) {
57
+ $retval['fields'] = 'comment_ID';
58
+
59
+ return $retval;
60
+ }
61
+
62
+ /**
63
+ * Check whether the current activity about a post or a comment can be published.
64
+ *
65
+ * Abstracted from the deprecated `bp_blogs_record_post()`.
66
+ *
67
+ * @since 2.2.0
68
+ *
69
+ * @param bool $return Whether the post should be published.
70
+ * @param int $blog_id ID of the blog.
71
+ * @param int $post_id ID of the post.
72
+ * @param int $user_id ID of the post author.
73
+ * @return bool True to authorize the post to be published, otherwise false.
74
+ */
75
+ function bp_blogs_post_pre_publish( $return = true, $blog_id = 0, $post_id = 0, $user_id = 0 ) {
76
+ $bp = buddypress();
77
+
78
+ // If blog is not trackable, do not record the activity.
79
+ if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) ) {
80
+ return false;
81
+ }
82
+
83
+ /*
84
+ * Stop infinite loops with WordPress MU Sitewide Tags.
85
+ * That plugin changed the way its settings were stored at some point. Thus the dual check.
86
+ */
87
+ $sitewide_tags_blog_settings = bp_core_get_root_option( 'sitewide_tags_blog' );
88
+ if ( ! empty( $sitewide_tags_blog_settings ) ) {
89
+ $st_options = maybe_unserialize( $sitewide_tags_blog_settings );
90
+ $tags_blog_id = isset( $st_options['tags_blog_id'] ) ? $st_options['tags_blog_id'] : 0;
91
+ } else {
92
+ $tags_blog_id = bp_core_get_root_option( 'sitewide_tags_blog' );
93
+ $tags_blog_id = intval( $tags_blog_id );
94
+ }
95
+
96
+ /**
97
+ * Filters whether or not BuddyPress should block sitewide tags activity.
98
+ *
99
+ * @since 2.2.0
100
+ *
101
+ * @param bool $value Current status of the sitewide tags activity.
102
+ */
103
+ if ( (int) $blog_id == $tags_blog_id && apply_filters( 'bp_blogs_block_sitewide_tags_activity', true ) ) {
104
+ return false;
105
+ }
106
+
107
+ /**
108
+ * Filters whether or not the current blog is public.
109
+ *
110
+ * @since 2.2.0
111
+ *
112
+ * @param int $value Value from the blog_public option for the current blog.
113
+ */
114
+ $is_blog_public = apply_filters( 'bp_is_blog_public', (int) get_blog_option( $blog_id, 'blog_public' ) );
115
+
116
+ if ( 0 === $is_blog_public && is_multisite() ) {
117
+ return false;
118
+ }
119
+
120
+ return $return;
121
+ }
122
+ add_filter( 'bp_activity_post_pre_publish', 'bp_blogs_post_pre_publish', 10, 4 );
123
+ add_filter( 'bp_activity_post_pre_comment', 'bp_blogs_post_pre_publish', 10, 4 );
124
+
125
+ /**
126
+ * Registers our custom thumb size with WP's Site Icon feature.
127
+ *
128
+ * @since 2.7.0
129
+ *
130
+ * @param array $sizes Current array of custom site icon sizes.
131
+ * @return array
132
+ */
133
+ function bp_blogs_register_custom_site_icon_size( $sizes ) {
134
+ $sizes[] = bp_core_avatar_thumb_width();
135
+ return $sizes;
136
+ }
137
+ add_filter( 'site_icon_image_sizes', 'bp_blogs_register_custom_site_icon_size' );
bp-blogs/bp-blogs-functions.php CHANGED
@@ -4,97 +4,232 @@
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsFunctions
 
7
  */
8
 
9
- // Exit if accessed directly
10
- if ( !defined( 'ABSPATH' ) ) exit;
11
 
12
  /**
13
  * Check whether the $bp global lists an activity directory page.
14
  *
15
- * @since BuddyPress (1.5.0)
16
- *
17
- * @global BuddyPress $bp The one true BuddyPress instance.
18
  *
19
  * @return bool True if set, false if empty.
20
  */
21
  function bp_blogs_has_directory() {
22
- global $bp;
23
 
24
  return (bool) !empty( $bp->pages->blogs->id );
25
  }
26
 
27
  /**
28
- * Retrieve a set of blogs
29
  *
30
  * @see BP_Blogs_Blog::get() for a description of arguments and return value.
31
  *
32
- * @param array $args {
33
  * Arguments are listed here with their default values. For more
34
  * information about the arguments, see {@link BP_Blogs_Blog::get()}.
35
- * @type string $type Default: 'active'.
36
- * @type int|bool $user_id Default: false.
37
- * @type array $include_blog_ids Default: false.
38
- * @type string|bool $search_terms Default: false.
39
- * @type int $per_page Default: 20.
40
- * @type int $page Default: 1.
41
- * @type bool $update_meta_cache Whether to pre-fetch blogmeta. Default: true.
42
  * }
43
  * @return array See {@link BP_Blogs_Blog::get()}.
44
  */
45
  function bp_blogs_get_blogs( $args = '' ) {
46
 
47
- $defaults = array(
48
- 'type' => 'active', // active, alphabetical, newest, or random
49
- 'user_id' => false, // Pass a user_id to limit to only blogs that this user has privilages higher than subscriber on
50
- 'include_blog_ids' => false,
51
- 'search_terms' => false, // Limit to blogs that match these search terms
 
52
  'per_page' => 20, // The number of results to return per page
53
  'page' => 1, // The page to return if limiting per page
54
- 'update_meta_cache' => true,
 
 
 
 
 
 
 
 
 
 
 
55
  );
56
 
57
- $params = wp_parse_args( $args, $defaults );
58
- extract( $params, EXTR_SKIP );
59
-
60
- return apply_filters( 'bp_blogs_get_blogs', BP_Blogs_Blog::get( $type, $per_page, $page, $user_id, $search_terms, $update_meta_cache, $include_blog_ids ), $params );
61
  }
62
 
63
  /**
64
  * Populate the BP blogs table with existing blogs.
65
  *
66
- * @global object $bp BuddyPress global settings
67
- * @global object $wpdb WordPress database object
68
- * @uses get_users()
69
- * @uses bp_blogs_record_blog()
 
 
 
 
 
 
 
 
 
 
 
70
  */
71
- function bp_blogs_record_existing_blogs() {
72
- global $bp, $wpdb;
73
 
74
- // Truncate user blogs table and re-record.
75
- $wpdb->query( "DELETE FROM {$bp->blogs->table_name} WHERE 1=1" );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
 
77
  if ( is_multisite() ) {
78
- $blog_ids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$wpdb->base_prefix}blogs WHERE mature = 0 AND spam = 0 AND deleted = 0 AND site_id = %d", $wpdb->siteid ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  } else {
80
- $blog_ids = 1;
 
 
 
 
 
 
 
81
  }
82
 
83
- if ( !empty( $blog_ids ) ) {
84
- foreach( (array) $blog_ids as $blog_id ) {
85
- $users = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ID' ) );
86
- $subscribers = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ID', 'role' => 'subscriber' ) );
 
 
87
 
88
- if ( !empty( $users ) ) {
89
- foreach ( (array) $users as $user ) {
90
- // Don't record blogs for subscribers
91
- if ( !in_array( $user, $subscribers ) ) {
92
- bp_blogs_record_blog( $blog_id, $user, true );
93
- }
94
- }
95
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
 
100
  /**
@@ -103,9 +238,7 @@ function bp_blogs_record_existing_blogs() {
103
  * If $user_id is provided, you can restrict site from being recordable
104
  * only to particular users.
105
  *
106
- * @since BuddyPress (1.7.0)
107
- *
108
- * @uses apply_filters()
109
  *
110
  * @param int $blog_id ID of the blog being checked.
111
  * @param int $user_id Optional. ID of the user for whom access is being checked.
@@ -134,10 +267,7 @@ function bp_blogs_is_blog_recordable( $blog_id, $user_id = 0 ) {
134
  * If $user_id is provided, the developer can restrict site from
135
  * being trackable only to particular users.
136
  *
137
- * @since BuddyPress (1.7.0)
138
- *
139
- * @uses bp_blogs_is_blog_recordable
140
- * @uses apply_filters()
141
  *
142
  * @param int $blog_id ID of the blog being checked.
143
  * @param int $user_id Optional. ID of the user for whom access is being checked.
@@ -163,14 +293,12 @@ function bp_blogs_is_blog_trackable( $blog_id, $user_id = 0 ) {
163
  /**
164
  * Make BuddyPress aware of a new site so that it can track its activity.
165
  *
166
- * @since BuddyPress (1.0.0)
167
- *
168
- * @uses BP_Blogs_Blog
169
  *
170
- * @param int $blog_id ID of the blog being recorded.
171
- * @param int $user_id ID of the user for whom the blog is being recorded.
172
  * @param bool $no_activity Optional. Whether to skip recording an activity
173
- * item about this blog creation. Default: false.
174
  * @return bool|null Returns false on failure.
175
  */
176
  function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
@@ -183,12 +311,12 @@ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
183
  return false;
184
 
185
  $name = get_blog_option( $blog_id, 'blogname' );
 
186
 
187
  if ( empty( $name ) ) {
188
- return false;
189
  }
190
 
191
- $url = get_home_url( $blog_id );
192
  $description = get_blog_option( $blog_id, 'blogdescription' );
193
  $close_old_posts = get_blog_option( $blog_id, 'close_comments_for_old_posts' );
194
  $close_days_old = get_blog_option( $blog_id, 'close_comments_days_old' );
@@ -197,7 +325,7 @@ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
197
  if ( ! empty( $thread_depth ) ) {
198
  $thread_depth = get_blog_option( $blog_id, 'thread_comments_depth' );
199
  } else {
200
- // perhaps filter this?
201
  $thread_depth = 1;
202
  }
203
 
@@ -218,19 +346,18 @@ function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
218
  $is_private = !empty( $_POST['blog_public'] ) && (int) $_POST['blog_public'] ? false : true;
219
  $is_private = !apply_filters( 'bp_is_new_blog_public', !$is_private );
220
 
221
- // Only record this activity if the blog is public
222
- if ( !$is_private && !$no_activity && bp_blogs_is_blog_trackable( $blog_id, $user_id ) ) {
223
-
224
- // Record this in activity streams
225
- bp_blogs_record_activity( array(
226
- 'user_id' => $recorded_blog->user_id,
227
- 'primary_link' => apply_filters( 'bp_blogs_activity_created_blog_primary_link', $url, $recorded_blog->blog_id ),
228
- 'type' => 'new_blog',
229
- 'item_id' => $recorded_blog->blog_id
230
- ) );
231
- }
232
-
233
- do_action_ref_array( 'bp_blogs_new_blog', array( &$recorded_blog, $is_private, $is_recorded ) );
234
  }
235
  add_action( 'wpmu_new_blog', 'bp_blogs_record_blog', 10, 2 );
236
 
@@ -240,7 +367,7 @@ add_action( 'wpmu_new_blog', 'bp_blogs_record_blog', 10, 2 );
240
  * @global object $wpdb DB Layer.
241
  *
242
  * @param string $oldvalue Value before save. Passed by do_action() but
243
- * unused here.
244
  * @param string $newvalue Value to change meta to.
245
  */
246
  function bp_blogs_update_option_blogname( $oldvalue, $newvalue ) {
@@ -251,12 +378,12 @@ function bp_blogs_update_option_blogname( $oldvalue, $newvalue ) {
251
  add_action( 'update_option_blogname', 'bp_blogs_update_option_blogname', 10, 2 );
252
 
253
  /**
254
- * Update blog description in BuddyPress blogmeta table
255
  *
256
  * @global object $wpdb DB Layer.
257
  *
258
  * @param string $oldvalue Value before save. Passed by do_action() but
259
- * unused here.
260
  * @param string $newvalue Value to change meta to.
261
  */
262
  function bp_blogs_update_option_blogdescription( $oldvalue, $newvalue ) {
@@ -269,12 +396,12 @@ add_action( 'update_option_blogdescription', 'bp_blogs_update_option_blogdescrip
269
  /**
270
  * Update "Close comments for old posts" option in BuddyPress blogmeta table.
271
  *
272
- * @since BuddyPress (2.0.0)
273
  *
274
  * @global object $wpdb DB Layer.
275
  *
276
  * @param string $oldvalue Value before save. Passed by do_action() but
277
- * unused here.
278
  * @param string $newvalue Value to change meta to.
279
  */
280
  function bp_blogs_update_option_close_comments_for_old_posts( $oldvalue, $newvalue ) {
@@ -287,15 +414,15 @@ add_action( 'update_option_close_comments_for_old_posts', 'bp_blogs_update_optio
287
  /**
288
  * Update "Close comments after days old" option in BuddyPress blogmeta table.
289
  *
290
- * @since BuddyPress (2.0.0)
291
  *
292
  * @global object $wpdb DB Layer.
293
  *
294
  * @param string $oldvalue Value before save. Passed by do_action() but
295
- * unused here.
296
  * @param string $newvalue Value to change meta to.
297
  */
298
- function bp_blogs_update_option_close_close_comments_days_old( $oldvalue, $newvalue ) {
299
  global $wpdb;
300
 
301
  bp_blogs_update_blogmeta( $wpdb->blogid, 'close_comments_days_old', $newvalue );
@@ -305,12 +432,12 @@ add_action( 'update_option_close_comments_days_old', 'bp_blogs_update_option_clo
305
  /**
306
  * When toggling threaded comments, update thread depth in blogmeta table.
307
  *
308
- * @since BuddyPress (2.0.0)
309
  *
310
  * @global object $wpdb DB Layer.
311
  *
312
  * @param string $oldvalue Value before save. Passed by do_action() but
313
- * unused here.
314
  * @param string $newvalue Value to change meta to.
315
  */
316
  function bp_blogs_update_option_thread_comments( $oldvalue, $newvalue ) {
@@ -329,12 +456,12 @@ add_action( 'update_option_thread_comments', 'bp_blogs_update_option_thread_comm
329
  /**
330
  * When updating comment depth, update thread depth in blogmeta table.
331
  *
332
- * @since BuddyPress (2.0.0)
333
  *
334
  * @global object $wpdb DB Layer.
335
  *
336
  * @param string $oldvalue Value before save. Passed by do_action() but
337
- * unused here.
338
  * @param string $newvalue Value to change meta to.
339
  */
340
  function bp_blogs_update_option_thread_comments_depth( $oldvalue, $newvalue ) {
@@ -349,354 +476,299 @@ function bp_blogs_update_option_thread_comments_depth( $oldvalue, $newvalue ) {
349
  add_action( 'update_option_thread_comments_depth', 'bp_blogs_update_option_thread_comments_depth', 10, 2 );
350
 
351
  /**
352
- * Detect a change in post status, and initiate an activity update if necessary.
353
  *
354
- * Posts get new activity updates when (a) they are being published, and (b)
355
- * they have not already been published. This enables proper posting for
356
- * regular posts as well as scheduled posts, while preventing post bumping.
357
  *
358
- * See #4090, #3746, #2546 for background.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  *
360
- * @since BuddyPress (2.0.0)
 
361
  *
362
- * @todo Support untrashing better
363
  *
364
- * @param string $new_status New status for the post.
365
- * @param string $old_status Old status for the post.
366
- * @param object $post Post data.
367
  */
368
- function bp_blogs_catch_transition_post_status( $new_status, $old_status, $post ) {
369
-
370
- // This is an edit
371
- if ( $new_status === $old_status ) {
372
- if ( $new_status == 'publish' ) {
373
- bp_blogs_update_post( $post );
374
- return;
375
- }
376
- }
377
-
378
- // Publishing a previously unpublished post
379
- if ( 'publish' === $new_status ) {
380
- // Untrashing the post
381
- // Nothing here yet
382
- if ( 'trash' == $old_status ) {}
383
-
384
- // Record the post
385
- bp_blogs_record_post( $post->ID, $post );
386
-
387
- // Unpublishing a previously published post
388
- } else if ( 'publish' === $old_status ) {
389
- // Some form of pending status
390
- // Only remove the activity entry
391
- bp_blogs_delete_activity( array(
392
- 'item_id' => get_current_blog_id(),
393
- 'secondary_item_id' => $post->ID,
394
- 'component' => buddypress()->blogs->id,
395
- 'type' => 'new_blog_post'
396
- ) );
397
- }
398
  }
399
- add_action( 'transition_post_status', 'bp_blogs_catch_transition_post_status', 10, 3 );
400
 
401
  /**
402
- * Record a new blog post in the BuddyPress activity stream.
403
  *
404
- * @param int $post_id ID of the post being recorded.
405
- * @param object $post The WP post object passed to the 'save_post' action.
406
- * @param int $user_id Optional. The user to whom the activity item will be
407
- * associated. Defaults to the post_author.
408
- * @return bool|null Returns false on failure.
409
  */
410
- function bp_blogs_record_post( $post_id, $post, $user_id = 0 ) {
411
- global $bp, $wpdb;
412
-
413
- $post_id = (int) $post_id;
414
- $blog_id = (int) $wpdb->blogid;
415
-
416
- // If blog is not trackable, do not record the activity.
417
- if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) )
418
- return false;
419
 
420
- if ( !$user_id )
421
- $user_id = (int) $post->post_author;
422
 
423
- // Stop infinite loops with WordPress MU Sitewide Tags.
424
- // That plugin changed the way its settings were stored at some point. Thus the dual check.
425
- if ( !empty( $bp->site_options['sitewide_tags_blog'] ) ) {
426
- $st_options = maybe_unserialize( $bp->site_options['sitewide_tags_blog'] );
427
- $tags_blog_id = isset( $st_options['tags_blog_id'] ) ? $st_options['tags_blog_id'] : 0;
428
  } else {
429
- $tags_blog_id = isset( $bp->site_options['tags_blog_id'] ) ? $bp->site_options['tags_blog_id'] : 0;
430
  }
431
 
432
- if ( (int) $blog_id == $tags_blog_id && apply_filters( 'bp_blogs_block_sitewide_tags_activity', true ) )
433
- return false;
434
 
435
- // Don't record this if it's not a post
436
- if ( !in_array( $post->post_type, apply_filters( 'bp_blogs_record_post_post_types', array( 'post' ) ) ) )
437
- return false;
438
 
439
- $is_blog_public = apply_filters( 'bp_is_blog_public', (int)get_blog_option( $blog_id, 'blog_public' ) );
440
-
441
- if ( 'publish' == $post->post_status && empty( $post->post_password ) ) {
442
- if ( $is_blog_public || !is_multisite() ) {
443
-
444
- // Record this in activity streams
445
- $post_permalink = add_query_arg(
446
- 'p',
447
- $post_id,
448
- trailingslashit( get_home_url( $blog_id ) )
449
- );
450
-
451
- if ( is_multisite() )
452
- $activity_action = sprintf( __( '%1$s wrote a new post, %2$s, on the site %3$s', 'buddypress' ), bp_core_get_userlink( (int) $post->post_author ), '<a href="' . $post_permalink . '">' . $post->post_title . '</a>', '<a href="' . get_blog_option( $blog_id, 'home' ) . '">' . get_blog_option( $blog_id, 'blogname' ) . '</a>' );
453
- else
454
- $activity_action = sprintf( __( '%1$s wrote a new post, %2$s', 'buddypress' ), bp_core_get_userlink( (int) $post->post_author ), '<a href="' . $post_permalink . '">' . $post->post_title . '</a>' );
455
-
456
- // Make sure there's not an existing entry for this post (prevent bumping)
457
- if ( bp_is_active( 'activity' ) ) {
458
- $existing = bp_activity_get( array(
459
- 'filter' => array(
460
- 'action' => 'new_blog_post',
461
- 'primary_id' => $blog_id,
462
- 'secondary_id' => $post_id,
463
- )
464
- ) );
465
-
466
- if ( !empty( $existing['activities'] ) ) {
467
- return;
468
- }
469
- }
470
-
471
- $activity_content = $post->post_content;
472
-
473
- bp_blogs_record_activity( array(
474
- 'user_id' => (int) $post->post_author,
475
- 'content' => apply_filters( 'bp_blogs_activity_new_post_content', $activity_content, $post, $post_permalink ),
476
- 'primary_link' => apply_filters( 'bp_blogs_activity_new_post_primary_link', $post_permalink, $post_id ),
477
- 'type' => 'new_blog_post',
478
- 'item_id' => $blog_id,
479
- 'secondary_item_id' => $post_id,
480
- 'recorded_time' => $post->post_date_gmt,
481
- ));
482
- }
483
-
484
- // Update the blogs last activity
485
- bp_blogs_update_blogmeta( $blog_id, 'last_activity', bp_core_current_time() );
486
- } else {
487
- bp_blogs_remove_post( $post_id, $blog_id, $user_id );
488
- }
489
-
490
- do_action( 'bp_blogs_new_blog_post', $post_id, $post, $user_id );
491
  }
 
492
 
493
  /**
494
- * Updates a blog post's corresponding activity entry during a post edit.
495
- *
496
- * @since BuddyPress (2.0.0)
497
  *
498
- * @see bp_blogs_catch_transition_post_status()
 
499
  *
500
- * @param WP_Post $post
 
 
501
  */
502
- function bp_blogs_update_post( $post ) {
503
- if ( ! bp_is_active( 'activity' ) ) {
504
  return;
505
  }
506
 
507
- $activity_id = bp_activity_get_activity_id( array(
508
- 'component' => buddypress()->blogs->id,
509
- 'item_id' => get_current_blog_id(),
510
- 'secondary_item_id' => $post->ID,
511
- 'type' => 'new_blog_post',
512
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
 
514
- // activity ID doesn't exist, so stop!
515
- if ( empty( $activity_id ) ) {
516
- return;
517
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
 
519
- // update the activity entry
520
- $activity = new BP_Activity_Activity( $activity_id );
521
- $activity->content = $post->post_content;
522
- $activity->save();
523
 
524
- // add post comment status to activity meta if closed
525
  if( 'closed' == $post->comment_status ) {
526
- bp_activity_update_meta( $activity_id, 'post_comment_status', $post->comment_status );
527
  } else {
528
- bp_activity_delete_meta( $activity_id, 'post_comment_status' );
529
  }
530
  }
 
531
 
532
  /**
533
- * Record a new blog comment in the BuddyPress activity stream.
534
  *
535
- * Only posts the item if blog is public and post is not password-protected.
536
  *
537
- * @param int $comment_id ID of the comment being recorded.
538
- * @param bool|string $is_approved Optional. The $is_approved value passed to
539
- * the 'comment_post' action. Default: true.
540
- * @return bool|object Returns false on failure, the comment object on success.
 
541
  */
542
- function bp_blogs_record_comment( $comment_id, $is_approved = true ) {
543
- // bail if activity component is not active
544
- if ( ! bp_is_active( 'activity' ) ) {
545
- return;
546
- }
547
-
548
- // Get the users comment
549
- $recorded_comment = get_comment( $comment_id );
550
-
551
- // Don't record activity if the comment hasn't been approved
552
- if ( empty( $is_approved ) )
553
  return false;
 
554
 
555
- // Don't record activity if no email address has been included
556
- if ( empty( $recorded_comment->comment_author_email ) )
557
- return false;
558
-
559
- // Don't record activity if the comment has already been marked as spam
560
- if ( 'spam' === $is_approved )
561
- return false;
562
-
563
- // Get the user by the comment author email.
564
- $user = get_user_by( 'email', $recorded_comment->comment_author_email );
565
-
566
- // If user isn't registered, don't record activity
567
- if ( empty( $user ) )
568
- return false;
569
-
570
- // Get the user_id
571
- $user_id = (int) $user->ID;
572
-
573
- // Get blog and post data
574
  $blog_id = get_current_blog_id();
575
 
576
- // If blog is not trackable, do not record the activity.
577
- if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) )
578
- return false;
579
-
580
- $recorded_comment->post = get_post( $recorded_comment->comment_post_ID );
581
-
582
- if ( empty( $recorded_comment->post ) || is_wp_error( $recorded_comment->post ) )
583
- return false;
584
 
585
- // If this is a password protected post, don't record the comment
586
- if ( !empty( $recorded_comment->post->post_password ) )
587
- return false;
588
 
589
- // Don't record activity if the comment's associated post isn't a WordPress Post
590
- if ( !in_array( $recorded_comment->post->post_type, apply_filters( 'bp_blogs_record_comment_post_types', array( 'post' ) ) ) )
591
- return false;
592
 
593
- $is_blog_public = apply_filters( 'bp_is_blog_public', (int)get_blog_option( $blog_id, 'blog_public' ) );
 
 
 
594
 
595
- // If blog is public allow activity to be posted
596
- if ( $is_blog_public ) {
 
597
 
598
- // Get activity related links
599
- $post_permalink = get_permalink( $recorded_comment->comment_post_ID );
600
- $comment_link = get_comment_link( $recorded_comment->comment_ID );
 
 
 
 
 
601
 
602
- // Setup activity args
603
- $args = array();
 
 
 
604
 
605
- $args['user_id'] = $user_id;
606
- $args['content'] = apply_filters_ref_array( 'bp_blogs_activity_new_comment_content', array( $recorded_comment->comment_content, &$recorded_comment, $comment_link ) );
607
- $args['primary_link'] = apply_filters_ref_array( 'bp_blogs_activity_new_comment_primary_link', array( $comment_link, &$recorded_comment ) );
608
- $args['recorded_time'] = $recorded_comment->comment_date_gmt;
 
609
 
610
- // Setup some different activity args depending if activity commenting is
611
- // enabled or not
 
 
 
612
 
613
- // if cannot comment, record separate activity entry
614
- // this is the old way of doing things
615
- if ( bp_disable_blogforum_comments() ) {
616
- $args['type'] = 'new_blog_comment';
617
- $args['item_id'] = $blog_id;
618
- $args['secondary_item_id'] = $comment_id;
619
 
620
- // record the activity entry
621
- bp_blogs_record_activity( $args );
622
 
623
- // record comment as BP activity comment under the parent 'new_blog_post'
624
- // activity item
625
  } else {
626
- // this is a comment edit
627
- // check to see if corresponding activity entry already exists
628
- if ( ! empty( $_REQUEST['action'] ) ) {
629
- $existing_activity_id = get_comment_meta( $comment_id, 'bp_activity_comment_id', true );
630
 
631
- if ( ! empty( $existing_activity_id ) ) {
632
- $args['id'] = $existing_activity_id;
633
- }
634
- }
635
 
636
- // find the parent 'new_blog_post' activity entry
637
- $parent_activity_id = bp_activity_get_activity_id( array(
638
- 'component' => 'blogs',
639
- 'type' => 'new_blog_post',
640
- 'item_id' => $blog_id,
641
- 'secondary_item_id' => $recorded_comment->comment_post_ID
642
- ) );
643
 
644
- // we found the parent activity entry
645
- // so let's go ahead and reconfigure some activity args
646
- if ( ! empty( $parent_activity_id ) ) {
647
- // set the 'item_id' with the parent activity entry ID
648
- $args['item_id'] = $parent_activity_id;
649
 
650
- // now see if the WP parent comment has a BP activity ID
651
- $comment_parent = 0;
652
- if ( ! empty( $recorded_comment->comment_parent ) ) {
653
- $comment_parent = get_comment_meta( $recorded_comment->comment_parent, 'bp_activity_comment_id', true );
654
  }
655
-
656
- // WP parent comment does not have a BP activity ID
657
- // so set to 'new_blog_post' activity ID
658
- if ( empty( $comment_parent ) ) {
659
- $comment_parent = $parent_activity_id;
660
- }
661
-
662
- $args['secondary_item_id'] = $comment_parent;
663
- $args['component'] = 'activity';
664
- $args['type'] = 'activity_comment';
665
-
666
- // could not find corresponding parent activity entry
667
- // so wipe out $args array
668
- } else {
669
- $args = array();
670
  }
671
 
672
- // Record in activity streams
673
- if ( ! empty( $args ) ) {
674
- // @todo should we use bp_activity_new_comment()? that function will also send
675
- // an email to people in the activity comment thread
676
- //
677
- // what if a site already has some comment email notification plugin setup?
678
- // this is why I decided to go with bp_activity_add() to avoid any conflict
679
- // with existing comment email notification plugins
680
- $comment_activity_id = bp_activity_add( $args );
681
-
682
- if ( empty( $args['id'] ) ) {
683
- // add meta to activity comment
684
- bp_activity_update_meta( $comment_activity_id, 'bp_blogs_post_comment_id', $comment_id );
685
-
686
- // add meta to comment
687
- add_comment_meta( $comment_id, 'bp_activity_comment_id', $comment_activity_id );
688
- }
689
- }
690
  }
 
691
 
692
- // Update the blogs last active date
693
- bp_blogs_update_blogmeta( $blog_id, 'last_activity', bp_core_current_time() );
 
 
 
 
 
 
 
 
 
 
 
 
694
  }
695
 
696
- return $recorded_comment;
697
  }
698
- add_action( 'comment_post', 'bp_blogs_record_comment', 10, 2 );
699
- add_action( 'edit_comment', 'bp_blogs_record_comment', 10 );
700
 
701
  /**
702
  * Record a user's association with a blog.
@@ -705,40 +777,76 @@ add_action( 'edit_comment', 'bp_blogs_record_comment', 10 );
705
  * set/changed ('add_user_to_blog', 'profile_update', 'user_register'). It
706
  * parses the changes, and records them as necessary in the BP blog tracker.
707
  *
708
- * BuddyPress does not track blogs for Subscribers.
 
 
709
  *
710
- * @param int $user_id The ID of the user.
711
- * @param string|bool $role The WP role being assigned to the user
712
- * ('subscriber', 'contributor', 'author', 'editor', 'administrator', or
713
- * a custom role). Defaults to false.
714
- * @param int $blog_id Default: the current blog ID.
715
  * @return bool|null False on failure.
716
  */
717
  function bp_blogs_add_user_to_blog( $user_id, $role = false, $blog_id = 0 ) {
718
  global $wpdb;
719
 
 
720
  if ( empty( $blog_id ) ) {
721
  $blog_id = isset( $wpdb->blogid ) ? $wpdb->blogid : bp_get_root_blog_id();
722
  }
723
 
 
724
  if ( empty( $role ) ) {
725
- $key = $wpdb->get_blog_prefix( $blog_id ). 'capabilities';
726
 
727
- $roles = bp_get_user_meta( $user_id, $key, true );
 
 
728
 
729
- if ( is_array( $roles ) )
730
- $role = array_search( 1, $roles );
731
- else
732
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
733
  }
734
 
735
- if ( $role != 'subscriber' )
736
- bp_blogs_record_blog( $blog_id, $user_id, true );
 
 
 
 
 
737
  }
738
  add_action( 'add_user_to_blog', 'bp_blogs_add_user_to_blog', 10, 3 );
739
  add_action( 'profile_update', 'bp_blogs_add_user_to_blog' );
740
  add_action( 'user_register', 'bp_blogs_add_user_to_blog' );
741
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
742
  /**
743
  * Remove a blog-user pair from BP's blog tracker.
744
  *
@@ -748,23 +856,23 @@ add_action( 'user_register', 'bp_blogs_add_user_to_blog' );
748
  function bp_blogs_remove_user_from_blog( $user_id, $blog_id = 0 ) {
749
  global $wpdb;
750
 
751
- if ( empty( $blog_id ) )
752
  $blog_id = $wpdb->blogid;
 
753
 
754
  bp_blogs_remove_blog_for_user( $user_id, $blog_id );
755
  }
756
  add_action( 'remove_user_from_blog', 'bp_blogs_remove_user_from_blog', 10, 2 );
757
 
758
  /**
759
- * Rehook WP's maybe_add_existing_user_to_blog with a later priority
760
  *
761
  * WordPress catches add-user-to-blog requests at init:10. In some cases, this
762
  * can precede BP's Blogs component. This function bumps the priority of the
763
  * core function, so that we can be sure that the Blogs component is loaded
764
- * first. See http://buddypress.trac.wordpress.org/ticket/3916.
765
  *
766
- * @since BuddyPress (1.6)
767
- * @access private
768
  */
769
  function bp_blogs_maybe_add_user_to_blog() {
770
  if ( ! is_multisite() )
@@ -781,16 +889,29 @@ add_action( 'init', 'bp_blogs_maybe_add_user_to_blog', 1 );
781
  * @param int $blog_id ID of the blog being removed.
782
  */
783
  function bp_blogs_remove_blog( $blog_id ) {
784
- global $bp;
785
 
786
  $blog_id = (int) $blog_id;
 
 
 
 
 
 
 
 
 
787
  do_action( 'bp_blogs_before_remove_blog', $blog_id );
788
 
789
  BP_Blogs_Blog::delete_blog_for_all( $blog_id );
790
 
791
- // Delete activity stream item
792
- bp_blogs_delete_activity( array( 'item_id' => $blog_id, 'component' => $bp->blogs->id, 'type' => 'new_blog' ) );
793
-
 
 
 
 
 
794
  do_action( 'bp_blogs_remove_blog', $blog_id );
795
  }
796
  add_action( 'delete_blog', 'bp_blogs_remove_blog' );
@@ -802,89 +923,62 @@ add_action( 'delete_blog', 'bp_blogs_remove_blog' );
802
  * @param int $blog_id ID of the blog being removed.
803
  */
804
  function bp_blogs_remove_blog_for_user( $user_id, $blog_id ) {
805
- global $bp;
806
 
807
  $blog_id = (int) $blog_id;
808
  $user_id = (int) $user_id;
809
 
 
 
 
 
 
 
 
 
810
  do_action( 'bp_blogs_before_remove_blog_for_user', $blog_id, $user_id );
811
 
812
  BP_Blogs_Blog::delete_blog_for_user( $blog_id, $user_id );
813
 
814
- // Delete activity stream item
815
- bp_blogs_delete_activity( array(
816
- 'item_id' => $blog_id,
817
- 'component' => $bp->blogs->id,
818
- 'type' => 'new_blog'
819
- ) );
820
-
 
821
  do_action( 'bp_blogs_remove_blog_for_user', $blog_id, $user_id );
822
  }
823
  add_action( 'remove_user_from_blog', 'bp_blogs_remove_blog_for_user', 10, 2 );
824
 
825
  /**
826
- * Remove a blog post activity item from the activity stream.
827
  *
828
- * @param int $post_id ID of the post to be removed.
829
- * @param int $blog_id Optional. Defaults to current blog ID.
830
- * @param int $user_id Optional. Defaults to the logged-in user ID. This param
831
- * is currently unused in the function (but is passed to hooks).
832
- */
833
- function bp_blogs_remove_post( $post_id, $blog_id = 0, $user_id = 0 ) {
834
- global $wpdb, $bp;
835
-
836
- if ( empty( $wpdb->blogid ) )
837
- return false;
838
-
839
- $post_id = (int) $post_id;
840
-
841
- if ( !$blog_id )
842
- $blog_id = (int) $wpdb->blogid;
843
-
844
- if ( !$user_id )
845
- $user_id = bp_loggedin_user_id();
846
-
847
- do_action( 'bp_blogs_before_remove_post', $blog_id, $post_id, $user_id );
848
-
849
- // Delete activity stream item
850
- bp_blogs_delete_activity( array( 'item_id' => $blog_id, 'secondary_item_id' => $post_id, 'component' => $bp->blogs->id, 'type' => 'new_blog_post' ) );
851
-
852
- do_action( 'bp_blogs_remove_post', $blog_id, $post_id, $user_id );
853
- }
854
- add_action( 'delete_post', 'bp_blogs_remove_post' );
855
-
856
- /**
857
- * Remove a blog comment activity item from the activity stream.
858
  *
859
- * @param int $comment_id ID of the comment to be removed.
860
  */
861
- function bp_blogs_remove_comment( $comment_id ) {
862
- global $wpdb;
863
-
864
- // activity comments are disabled for blog posts
865
- // which means that individual activity items exist for blog comments
866
- if ( bp_disable_blogforum_comments() ) {
867
- // Delete the individual activity stream item
868
- bp_blogs_delete_activity( array(
869
- 'item_id' => $wpdb->blogid,
870
- 'secondary_item_id' => $comment_id,
871
- 'type' => 'new_blog_comment'
872
- ) );
873
-
874
- // activity comments are enabled for blog posts
875
- // remove the associated activity item
876
- } else {
877
- // get associated activity ID from comment meta
878
  $activity_id = get_comment_meta( $comment_id, 'bp_activity_comment_id', true );
879
 
880
- // delete the associated activity comment
881
- //
882
- // also removes child post comments and associated activity comments
883
- if ( ! empty( $activity_id ) && bp_is_active( 'activity' ) ) {
 
884
  // fetch the activity comments for the activity item
885
  $activity = bp_activity_get( array(
886
  'in' => $activity_id,
887
  'display_comments' => 'stream',
 
888
  ) );
889
 
890
  // get all activity comment IDs for the pending deleted item
@@ -904,29 +998,46 @@ function bp_blogs_remove_comment( $comment_id ) {
904
 
905
  // rebuild activity comment tree
906
  BP_Activity_Activity::rebuild_activity_comment_tree( $activity['activities'][0]->item_id );
 
 
 
907
  }
908
  }
909
  }
910
 
911
- do_action( 'bp_blogs_remove_comment', $wpdb->blogid, $comment_id, bp_loggedin_user_id() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
912
  }
913
- add_action( 'delete_comment', 'bp_blogs_remove_comment' );
914
 
915
  /**
916
  * Removes blog comments that are associated with activity comments.
917
  *
918
- * @since BuddyPress (2.0.0)
919
  *
920
- * @see bp_blogs_remove_comment()
921
  * @see bp_blogs_sync_delete_from_activity_comment()
922
  *
923
  * @param array $activity_ids The activity IDs to check association with blog
924
- * comments.
925
- * @param bool $force_delete Whether to force delete the comments. If false,
926
- * comments are trashed instead.
927
  */
928
  function bp_blogs_remove_associated_blog_comments( $activity_ids = array(), $force_delete = true ) {
929
- // query args
930
  $query_args = array(
931
  'meta_query' => array(
932
  array(
@@ -937,109 +1048,31 @@ function bp_blogs_remove_associated_blog_comments( $activity_ids = array(), $for
937
  )
938
  );
939
 
940
- // get comment
941
  $comment_query = new WP_Comment_Query;
942
  $comments = $comment_query->query( $query_args );
943
 
944
- // found the corresponding comments
945
  // let's delete them!
946
  foreach ( $comments as $comment ) {
947
  wp_delete_comment( $comment->comment_ID, $force_delete );
948
 
949
- // if we're trashing the comment, remove the meta key as well
950
  if ( empty( $force_delete ) ) {
951
  delete_comment_meta( $comment->comment_ID, 'bp_activity_comment_id' );
952
  }
953
  }
954
  }
955
 
956
- /**
957
- * When a blog comment status transition occurs, update the relevant activity's status.
958
- *
959
- * @since BuddyPress (1.6.0)
960
- *
961
- * @global object $bp BuddyPress global settings.
962
- *
963
- * @param string $new_status New comment status.
964
- * @param string $old_status Previous comment status.
965
- * @param object $comment Comment data.
966
- */
967
- function bp_blogs_transition_activity_status( $new_status, $old_status, $comment ) {
968
- global $bp;
969
-
970
- // Check the Activity component is active
971
- if ( ! bp_is_active( 'activity' ) )
972
- return;
973
-
974
- /**
975
- * Activity currently doesn't have any concept of a trash, or an unapproved/approved state.
976
- *
977
- * If a blog comment transitions to a "delete" or "hold" status, delete the activity item.
978
- * If a blog comment transitions to trashed, or spammed, mark the activity as spam.
979
- * If a blog comment transitions to approved (and the activity exists), mark the activity as ham.
980
- * If a blog comment transitions to unapproved (and the activity exists), mark the activity as spam.
981
- * Otherwise, record the comment into the activity stream.
982
- */
983
-
984
- // This clause was moved in from bp_blogs_remove_comment() in BuddyPress 1.6. It handles delete/hold.
985
- if ( in_array( $new_status, array( 'delete', 'hold' ) ) ) {
986
- return bp_blogs_remove_comment( $comment->comment_ID );
987
-
988
- // These clauses handle trash, spam, and un-spams.
989
- } elseif ( in_array( $new_status, array( 'trash', 'spam', 'unapproved' ) ) ) {
990
- $action = 'spam_activity';
991
- } elseif ( 'approved' == $new_status ) {
992
- $action = 'ham_activity';
993
- }
994
-
995
- // Get the activity
996
- if ( bp_disable_blogforum_comments() ) {
997
- $activity_id = bp_activity_get_activity_id( array( 'component' => $bp->blogs->id, 'item_id' => get_current_blog_id(), 'secondary_item_id' => $comment->comment_ID, 'type' => 'new_blog_comment', ) );
998
- } else {
999
- $activity_id = get_comment_meta( $comment->comment_ID, 'bp_activity_comment_id', true );
1000
- }
1001
-
1002
- // Check activity item exists
1003
- if ( empty( $activity_id ) ) {
1004
- // If no activity exists, but the comment has been approved, record it into the activity table.
1005
- if ( 'approved' == $new_status ) {
1006
- return bp_blogs_record_comment( $comment->comment_ID, true );
1007
- }
1008
-
1009
- return;
1010
- }
1011
-
1012
- // Create an activity object
1013
- $activity = new BP_Activity_Activity( $activity_id );
1014
- if ( empty( $activity->component ) )
1015
- return;
1016
-
1017
- // Spam/ham the activity if it's not already in that state
1018
- if ( 'spam_activity' == $action && ! $activity->is_spam ) {
1019
- bp_activity_mark_as_spam( $activity );
1020
- } elseif ( 'ham_activity' == $action) {
1021
- bp_activity_mark_as_ham( $activity );
1022
- }
1023
-
1024
- // Add "new_blog_comment" to the whitelisted activity types, so that the activity's Akismet history is generated
1025
- $comment_akismet_history = create_function( '$t', '$t[] = "new_blog_comment"; return $t;' );
1026
- add_filter( 'bp_akismet_get_activity_types', $comment_akismet_history );
1027
-
1028
- // Save the updated activity
1029
- $activity->save();
1030
-
1031
- // Remove the "new_blog_comment" activity type whitelist so we don't break anything
1032
- remove_filter( 'bp_akismet_get_activity_types', $comment_akismet_history );
1033
- }
1034
- add_action( 'transition_comment_status', 'bp_blogs_transition_activity_status', 10, 3 );
1035
-
1036
  /**
1037
  * Get the total number of blogs being tracked by BuddyPress.
1038
  *
1039
  * @return int $count Total blog count.
1040
  */
1041
  function bp_blogs_total_blogs() {
1042
- if ( !$count = wp_cache_get( 'bp_total_blogs', 'bp' ) ) {
 
 
1043
  $blogs = BP_Blogs_Blog::get_all();
1044
  $count = $blogs['total'];
1045
  wp_cache_set( 'bp_total_blogs', $count, 'bp' );
@@ -1050,16 +1083,24 @@ function bp_blogs_total_blogs() {
1050
  /**
1051
  * Get the total number of blogs being tracked by BP for a specific user.
1052
  *
 
 
1053
  * @param int $user_id ID of the user being queried. Default: on a user page,
1054
- * the displayed user. Otherwise, the logged-in user.
1055
  * @return int $count Total blog count for the user.
1056
  */
1057
  function bp_blogs_total_blogs_for_user( $user_id = 0 ) {
1058
-
1059
- if ( empty( $user_id ) )
1060
  $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
 
1061
 
1062
- if ( !$count = wp_cache_get( 'bp_total_blogs_for_user_' . $user_id, 'bp' ) ) {
 
 
 
 
 
 
1063
  $count = BP_Blogs_Blog::total_blog_count_for_user( $user_id );
1064
  wp_cache_set( 'bp_total_blogs_for_user_' . $user_id, $count, 'bp' );
1065
  }
@@ -1073,16 +1114,28 @@ function bp_blogs_total_blogs_for_user( $user_id = 0 ) {
1073
  * @param int $blog_id The ID of the blog to expunge.
1074
  */
1075
  function bp_blogs_remove_data_for_blog( $blog_id ) {
1076
- global $bp;
1077
 
 
 
 
 
 
 
 
 
1078
  do_action( 'bp_blogs_before_remove_data_for_blog', $blog_id );
1079
 
1080
  // If this is regular blog, delete all data for that blog.
1081
  BP_Blogs_Blog::delete_blog_for_all( $blog_id );
1082
 
1083
- // Delete activity stream item
1084
- bp_blogs_delete_activity( array( 'item_id' => $blog_id, 'component' => $bp->blogs->id, 'type' => false ) );
1085
-
 
 
 
 
 
1086
  do_action( 'bp_blogs_remove_data_for_blog', $blog_id );
1087
  }
1088
  add_action( 'delete_blog', 'bp_blogs_remove_data_for_blog', 1 );
@@ -1093,7 +1146,7 @@ add_action( 'delete_blog', 'bp_blogs_remove_data_for_blog', 1 );
1093
  * @see BP_Blogs_Blog::get_blogs_for_user() for a description of parameters
1094
  * and return values.
1095
  *
1096
- * @param int $user_id See {@BP_Blogs_Blog::get_blogs_for_user()}.
1097
  * @param bool $show_hidden See {@BP_Blogs_Blog::get_blogs_for_user()}.
1098
  * @return array See {@BP_Blogs_Blog::get_blogs_for_user()}.
1099
  */
@@ -1106,8 +1159,8 @@ function bp_blogs_get_blogs_for_user( $user_id, $show_hidden = false ) {
1106
  *
1107
  * @see BP_Blogs_Blog::get_all() for a description of parameters and return values.
1108
  *
1109
- * @param int $limit See {@BP_Blogs_Blog::get_all()}.
1110
- * @param int $page See {@BP_Blogs_Blog::get_all()}.
1111
  * @return array See {@BP_Blogs_Blog::get_all()}.
1112
  */
1113
  function bp_blogs_get_all_blogs( $limit = null, $page = null ) {
@@ -1119,8 +1172,8 @@ function bp_blogs_get_all_blogs( $limit = null, $page = null ) {
1119
  *
1120
  * @see BP_Blogs_Blog::get() for a description of parameters and return values.
1121
  *
1122
- * @param int $limit See {@BP_Blogs_Blog::get()}.
1123
- * @param int $page See {@BP_Blogs_Blog::get()}.
1124
  * @return array See {@BP_Blogs_Blog::get()}.
1125
  */
1126
  function bp_blogs_get_random_blogs( $limit = null, $page = null ) {
@@ -1139,7 +1192,7 @@ function bp_blogs_is_blog_hidden( $blog_id ) {
1139
  return BP_Blogs_Blog::is_hidden( $blog_id );
1140
  }
1141
 
1142
- /*******************************************************************************
1143
  * Blog meta functions
1144
  *
1145
  * These functions are used to store specific blogmeta in one global table,
@@ -1149,26 +1202,26 @@ function bp_blogs_is_blog_hidden( $blog_id ) {
1149
  */
1150
 
1151
  /**
1152
- * Delete a metadta from the DB for a blog.
1153
  *
1154
  * @global object $wpdb WordPress database access object.
1155
- * @global object $bp BuddyPress global settings.
1156
- *
1157
- * @param int $blog_id ID of the blog whose metadata is being deleted.
1158
- * @param string $meta_key Optional. The key of the metadata being deleted. If
1159
- * omitted, all BP metadata associated with the blog will be deleted.
1160
- * @param string $meta_value Optional. If present, the metadata will only be
1161
- * deleted if the meta_value matches this parameter.
1162
- * @param bool $delete_all Optional. If true, delete matching metadata entries
1163
- * for all objects, ignoring the specified blog_id. Otherwise, only
1164
- * delete matching metadata entries for the specified blog.
1165
- * Default: false.
1166
  * @return bool True on success, false on failure.
1167
  */
1168
  function bp_blogs_delete_blogmeta( $blog_id, $meta_key = false, $meta_value = false, $delete_all = false ) {
1169
- global $wpdb, $bp;
1170
 
1171
- // Legacy - if no meta_key is passed, delete all for the blog_id
1172
  if ( empty( $meta_key ) ) {
1173
  $keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->blogmeta} WHERE blog_id = %d", $blog_id ) );
1174
  $delete_all = false;
@@ -1191,18 +1244,17 @@ function bp_blogs_delete_blogmeta( $blog_id, $meta_key = false, $meta_value = fa
1191
  /**
1192
  * Get metadata for a given blog.
1193
  *
1194
- * @since BuddyPress (1.2.0)
1195
  *
1196
  * @global object $wpdb WordPress database access object.
1197
- * @global object $bp BuddyPress global settings.
1198
  *
1199
- * @param int $blog_id ID of the blog whose metadata is being requested.
1200
  * @param string $meta_key Optional. If present, only the metadata matching
1201
- * that meta key will be returned. Otherwise, all metadata for the
1202
- * blog will be fetched.
1203
- * @param bool $single Optional. If true, return only the first value of the
1204
- * specified meta_key. This parameter has no effect if meta_key is not
1205
- * specified. Default: true.
1206
  * @return mixed The meta value(s) being requested.
1207
  */
1208
  function bp_blogs_get_blogmeta( $blog_id, $meta_key = '', $single = true ) {
@@ -1217,17 +1269,16 @@ function bp_blogs_get_blogmeta( $blog_id, $meta_key = '', $single = true ) {
1217
  * Update a piece of blog meta.
1218
  *
1219
  * @global object $wpdb WordPress database access object.
1220
- * @global object $bp BuddyPress global settings.
1221
- *
1222
- * @param int $blog_id ID of the blog whose metadata is being updated.
1223
- * @param string $meta_key Key of the metadata being updated.
1224
- * @param mixed $meta_value Value to be set.
1225
- * @param mixed $prev_value Optional. If specified, only update existing
1226
- * metadata entries with the specified value. Otherwise, update all
1227
- * entries.
1228
  * @return bool|int Returns false on failure. On successful update of existing
1229
- * metadata, returns true. On successful creation of new metadata,
1230
- * returns the integer ID of the new metadata row.
1231
  */
1232
  function bp_blogs_update_blogmeta( $blog_id, $meta_key, $meta_value, $prev_value = '' ) {
1233
  add_filter( 'query', 'bp_filter_metaid_column_name' );
@@ -1240,14 +1291,14 @@ function bp_blogs_update_blogmeta( $blog_id, $meta_key, $meta_value, $prev_value
1240
  /**
1241
  * Add a piece of blog metadata.
1242
  *
1243
- * @since BuddyPress (2.0.0)
1244
  *
1245
- * @param int $blog_id ID of the blog.
1246
- * @param string $meta_key Metadata key.
1247
- * @param mixed $meta_value Metadata value.
1248
- * @param bool $unique. Optional. Whether to enforce a single metadata value
1249
- * for the given key. If true, and the object already has a value for
1250
- * the key, no change will be made. Default: false.
1251
  * @return int|bool The meta ID on successful update, false on failure.
1252
  */
1253
  function bp_blogs_add_blogmeta( $blog_id, $meta_key, $meta_value, $unique = false ) {
@@ -1261,19 +1312,59 @@ function bp_blogs_add_blogmeta( $blog_id, $meta_key, $meta_value, $unique = fals
1261
  * Remove all blog associations for a given user.
1262
  *
1263
  * @param int $user_id ID whose blog data should be removed.
1264
- * @return bool|null Returns false on failure.
1265
  */
1266
  function bp_blogs_remove_data( $user_id ) {
1267
  if ( !is_multisite() )
1268
  return false;
1269
 
 
 
 
 
 
 
 
1270
  do_action( 'bp_blogs_before_remove_data', $user_id );
1271
 
1272
  // If this is regular blog, delete all data for that blog.
1273
  BP_Blogs_Blog::delete_blogs_for_user( $user_id );
1274
 
 
 
 
 
 
 
 
1275
  do_action( 'bp_blogs_remove_data', $user_id );
1276
  }
1277
  add_action( 'wpmu_delete_user', 'bp_blogs_remove_data' );
1278
  add_action( 'delete_user', 'bp_blogs_remove_data' );
1279
  add_action( 'bp_make_spam_user', 'bp_blogs_remove_data' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsFunctions
7
+ * @since 1.5.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
 
13
  /**
14
  * Check whether the $bp global lists an activity directory page.
15
  *
16
+ * @since 1.5.0
 
 
17
  *
18
  * @return bool True if set, false if empty.
19
  */
20
  function bp_blogs_has_directory() {
21
+ $bp = buddypress();
22
 
23
  return (bool) !empty( $bp->pages->blogs->id );
24
  }
25
 
26
  /**
27
+ * Retrieve a set of blogs.
28
  *
29
  * @see BP_Blogs_Blog::get() for a description of arguments and return value.
30
  *
31
+ * @param array|string $args {
32
  * Arguments are listed here with their default values. For more
33
  * information about the arguments, see {@link BP_Blogs_Blog::get()}.
34
+ * @type string $type Default: 'active'.
35
+ * @type int|bool $user_id Default: false.
36
+ * @type array $include_blog_ids Default: false.
37
+ * @type string|bool $search_terms Default: false.
38
+ * @type int $per_page Default: 20.
39
+ * @type int $page Default: 1.
40
+ * @type bool $update_meta_cache Whether to pre-fetch blogmeta. Default: true.
41
  * }
42
  * @return array See {@link BP_Blogs_Blog::get()}.
43
  */
44
  function bp_blogs_get_blogs( $args = '' ) {
45
 
46
+ // Parse query arguments.
47
+ $r = bp_parse_args( $args, array(
48
+ 'type' => 'active', // 'active', 'alphabetical', 'newest', or 'random'
49
+ 'include_blog_ids' => false, // Array of blog IDs to include
50
+ 'user_id' => false, // Limit to blogs this user can post to
51
+ 'search_terms' => false, // Limit to blogs matching these search terms
52
  'per_page' => 20, // The number of results to return per page
53
  'page' => 1, // The page to return if limiting per page
54
+ 'update_meta_cache' => true // Whether to pre-fetch blogmeta
55
+ ), 'blogs_get_blogs' );
56
+
57
+ // Get the blogs.
58
+ $blogs = BP_Blogs_Blog::get(
59
+ $r['type'],
60
+ $r['per_page'],
61
+ $r['page'],
62
+ $r['user_id'],
63
+ $r['search_terms'],
64
+ $r['update_meta_cache'],
65
+ $r['include_blog_ids']
66
  );
67
 
68
+ // Filter and return.
69
+ return apply_filters( 'bp_blogs_get_blogs', $blogs, $r );
 
 
70
  }
71
 
72
  /**
73
  * Populate the BP blogs table with existing blogs.
74
  *
75
+ * Warning: By default, this will remove all existing records from the BP
76
+ * blogs and blogmeta tables before re-populating the tables.
77
+ *
78
+ * @since 1.0.0
79
+ * @since 2.6.0 Accepts $args as a parameter.
80
+ *
81
+ * @param array $args {
82
+ * Array of arguments.
83
+ * @type int $offset The offset to use.
84
+ * @type int $limit The number of blogs to record at one time.
85
+ * @type array $blog_ids Blog IDs to record. If empty, all blogs will be recorded.
86
+ * @type array $site_id The network site ID to use.
87
+ * }
88
+ *
89
+ * @return bool
90
  */
91
+ function bp_blogs_record_existing_blogs( $args = array() ) {
92
+ global $wpdb;
93
 
94
+ // Query for all sites in network.
95
+ $r = bp_parse_args( $args, array(
96
+ 'offset' => false === bp_get_option( '_bp_record_blogs_offset' ) ? 0 : bp_get_option( '_bp_record_blogs_offset' ),
97
+ 'limit' => 50,
98
+ 'blog_ids' => array(),
99
+ 'site_id' => $wpdb->siteid
100
+ ), 'record_existing_blogs' );
101
+
102
+ // Truncate all BP blogs tables if starting fresh
103
+ if ( empty( $r['offset'] ) && empty( $r['blog_ids'] ) ) {
104
+ $bp = buddypress();
105
+
106
+ // Truncate user blogs table
107
+ $truncate = $wpdb->query( "TRUNCATE {$bp->blogs->table_name}" );
108
+ if ( is_wp_error( $truncate ) ) {
109
+ return false;
110
+ }
111
+
112
+ // Truncate user blogmeta table
113
+ $truncate = $wpdb->query( "TRUNCATE {$bp->blogs->table_name_blogmeta}" );
114
+ if ( is_wp_error( $truncate ) ) {
115
+ return false;
116
+ }
117
+ }
118
 
119
+ // Multisite
120
  if ( is_multisite() ) {
121
+ $sql = array();
122
+ $sql['select'] = $wpdb->prepare( "SELECT blog_id, last_updated FROM {$wpdb->base_prefix}blogs WHERE mature = 0 AND spam = 0 AND deleted = 0 AND site_id = %d", $r['site_id'] );
123
+
124
+ // Omit root blog if large network
125
+ if ( wp_is_large_network( 'users' ) ) {
126
+ $sql['omit_root_blog'] = $wpdb->prepare( "AND blog_id != %d", bp_get_root_blog_id() );
127
+ }
128
+
129
+ // Filter by selected blog IDs
130
+ if ( ! empty( $r['blog_ids'] ) ) {
131
+ $in = implode( ',', wp_parse_id_list( $r['blog_ids'] ) );
132
+ $sql['in'] = "AND blog_id IN ({$in})";
133
+ }
134
+
135
+ $sql['orderby'] = 'ORDER BY blog_id ASC';
136
+
137
+ $sql['limit'] = $wpdb->prepare( "LIMIT %d", $r['limit'] );
138
+
139
+ if ( ! empty( $r['offset'] ) ) {
140
+ $sql['offset'] = $wpdb->prepare( "OFFSET %d", $r['offset'] );
141
+ }
142
+
143
+ $blogs = $wpdb->get_results( implode( ' ', $sql ) );
144
+
145
+ // Record a single site.
146
  } else {
147
+ // Just record blog for the current user only.
148
+ $record = bp_blogs_record_blog( $wpdb->blogid, get_current_user_id(), true );
149
+
150
+ if ( false === $record ) {
151
+ return false;
152
+ } else {
153
+ return true;
154
+ }
155
  }
156
 
157
+ // Bail if there are no blogs
158
+ if ( empty( $blogs ) ) {
159
+ // Make sure we remove our offset marker
160
+ if ( is_multisite() ) {
161
+ bp_delete_option( '_bp_record_blogs_offset' );
162
+ }
163
 
164
+ return false;
165
+ }
166
+
167
+ // Loop through users of blogs and record the relationship.
168
+ foreach ( (array) $blogs as $blog ) {
169
+
170
+ // Ensure that the cache is clear after the table TRUNCATE above.
171
+ wp_cache_delete( $blog->blog_id, 'blog_meta' );
172
+
173
+ // Get all users.
174
+ $users = get_users( array(
175
+ 'blog_id' => $blog->blog_id,
176
+ 'fields' => 'ID'
177
+ ) );
178
+
179
+ // Continue on if no users exist for this site (how did this happen?).
180
+ if ( empty( $users ) ) {
181
+ continue;
182
+ }
183
+
184
+ // Loop through users and record their relationship to this blog.
185
+ foreach ( (array) $users as $user_id ) {
186
+ bp_blogs_add_user_to_blog( $user_id, false, $blog->blog_id );
187
+
188
+ // Clear cache
189
+ bp_blogs_clear_blog_object_cache( $blog->blog_id, $user_id );
190
+ }
191
+
192
+ // Update blog last activity timestamp
193
+ if ( ! empty( $blog->last_updated ) && false !== strtotime( $blog->last_updated ) ) {
194
+ bp_blogs_update_blogmeta( $blog->blog_id, 'last_activity', $blog->last_updated );
195
  }
196
  }
197
+
198
+ // See if we need to do this again
199
+ if ( is_multisite() && empty( $r['blog_ids'] ) ) {
200
+ $sql['offset'] = $wpdb->prepare( " OFFSET %d", $r['limit'] + $r['offset'] );
201
+
202
+ // Check if there are more blogs to record
203
+ $blog_ids = $wpdb->get_results( implode( ' ', $sql ) );
204
+
205
+ // We have more blogs; record offset and re-run function
206
+ if ( ! empty( $blog_ids ) ) {
207
+ bp_update_option( '_bp_record_blogs_offset', $r['limit'] + $r['offset'] );
208
+ bp_blogs_record_existing_blogs( array(
209
+ 'offset' => $r['limit'] + $r['offset'],
210
+ 'limit' => $r['limit'],
211
+ 'blog_ids' => $r['blog_ids'],
212
+ 'site_id' => $r['site_id']
213
+ ) );
214
+
215
+ // Bail since we have more blogs to record.
216
+ return;
217
+
218
+ // No more blogs; delete offset marker
219
+ } else {
220
+ bp_delete_option( '_bp_record_blogs_offset' );
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Fires after the BP blogs tables have been populated with existing blogs.
226
+ *
227
+ * @since 2.4.0
228
+ */
229
+ do_action( 'bp_blogs_recorded_existing_blogs' );
230
+
231
+ // No errors.
232
+ return true;
233
  }
234
 
235
  /**
238
  * If $user_id is provided, you can restrict site from being recordable
239
  * only to particular users.
240
  *
241
+ * @since 1.7.0
 
 
242
  *
243
  * @param int $blog_id ID of the blog being checked.
244
  * @param int $user_id Optional. ID of the user for whom access is being checked.
267
  * If $user_id is provided, the developer can restrict site from
268
  * being trackable only to particular users.
269
  *
270
+ * @since 1.7.0
 
 
 
271
  *
272
  * @param int $blog_id ID of the blog being checked.
273
  * @param int $user_id Optional. ID of the user for whom access is being checked.
293
  /**
294
  * Make BuddyPress aware of a new site so that it can track its activity.
295
  *
296
+ * @since 1.0.0
 
 
297
  *
298
+ * @param int $blog_id ID of the blog being recorded.
299
+ * @param int $user_id ID of the user for whom the blog is being recorded.
300
  * @param bool $no_activity Optional. Whether to skip recording an activity
301
+ * item about this blog creation. Default: false.
302
  * @return bool|null Returns false on failure.
303
  */
304
  function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
311
  return false;
312
 
313
  $name = get_blog_option( $blog_id, 'blogname' );
314
+ $url = get_home_url( $blog_id );
315
 
316
  if ( empty( $name ) ) {
317
+ $name = $url;
318
  }
319
 
 
320
  $description = get_blog_option( $blog_id, 'blogdescription' );
321
  $close_old_posts = get_blog_option( $blog_id, 'close_comments_for_old_posts' );
322
  $close_days_old = get_blog_option( $blog_id, 'close_comments_days_old' );
325
  if ( ! empty( $thread_depth ) ) {
326
  $thread_depth = get_blog_option( $blog_id, 'thread_comments_depth' );
327
  } else {
328
+ // Perhaps filter this?
329
  $thread_depth = 1;
330
  }
331
 
346
  $is_private = !empty( $_POST['blog_public'] ) && (int) $_POST['blog_public'] ? false : true;
347
  $is_private = !apply_filters( 'bp_is_new_blog_public', !$is_private );
348
 
349
+ /**
350
+ * Fires after BuddyPress has been made aware of a new site for activity tracking.
351
+ *
352
+ * @since 1.0.0
353
+ * @since 2.6.0 Added $no_activity as a parameter.
354
+ *
355
+ * @param BP_Blogs_Blog $recorded_blog Current blog being recorded. Passed by reference.
356
+ * @param bool $is_private Whether or not the current blog being recorded is private.
357
+ * @param bool $is_recorded Whether or not the current blog was recorded.
358
+ * @param bool $no_activity Whether to skip recording an activity item for this blog creation.
359
+ */
360
+ do_action_ref_array( 'bp_blogs_new_blog', array( &$recorded_blog, $is_private, $is_recorded, $no_activity ) );
 
361
  }
362
  add_action( 'wpmu_new_blog', 'bp_blogs_record_blog', 10, 2 );
363
 
367
  * @global object $wpdb DB Layer.
368
  *
369
  * @param string $oldvalue Value before save. Passed by do_action() but
370
+ * unused here.
371
  * @param string $newvalue Value to change meta to.
372
  */
373
  function bp_blogs_update_option_blogname( $oldvalue, $newvalue ) {
378
  add_action( 'update_option_blogname', 'bp_blogs_update_option_blogname', 10, 2 );
379
 
380
  /**
381
+ * Update blog description in BuddyPress blogmeta table.
382
  *
383
  * @global object $wpdb DB Layer.
384
  *
385
  * @param string $oldvalue Value before save. Passed by do_action() but
386
+ * unused here.
387
  * @param string $newvalue Value to change meta to.
388
  */
389
  function bp_blogs_update_option_blogdescription( $oldvalue, $newvalue ) {
396
  /**
397
  * Update "Close comments for old posts" option in BuddyPress blogmeta table.
398
  *
399
+ * @since 2.0.0
400
  *
401
  * @global object $wpdb DB Layer.
402
  *
403
  * @param string $oldvalue Value before save. Passed by do_action() but
404
+ * unused here.
405
  * @param string $newvalue Value to change meta to.
406
  */
407
  function bp_blogs_update_option_close_comments_for_old_posts( $oldvalue, $newvalue ) {
414
  /**
415
  * Update "Close comments after days old" option in BuddyPress blogmeta table.
416
  *
417
+ * @since 2.0.0
418
  *
419
  * @global object $wpdb DB Layer.
420
  *
421
  * @param string $oldvalue Value before save. Passed by do_action() but
422
+ * unused here.
423
  * @param string $newvalue Value to change meta to.
424
  */
425
+ function bp_blogs_update_option_close_comments_days_old( $oldvalue, $newvalue ) {
426
  global $wpdb;
427
 
428
  bp_blogs_update_blogmeta( $wpdb->blogid, 'close_comments_days_old', $newvalue );
432
  /**
433
  * When toggling threaded comments, update thread depth in blogmeta table.
434
  *
435
+ * @since 2.0.0
436
  *
437
  * @global object $wpdb DB Layer.
438
  *
439
  * @param string $oldvalue Value before save. Passed by do_action() but
440
+ * unused here.
441
  * @param string $newvalue Value to change meta to.
442
  */
443
  function bp_blogs_update_option_thread_comments( $oldvalue, $newvalue ) {
456
  /**
457
  * When updating comment depth, update thread depth in blogmeta table.
458
  *
459
+ * @since 2.0.0
460
  *
461
  * @global object $wpdb DB Layer.
462
  *
463
  * @param string $oldvalue Value before save. Passed by do_action() but
464
+ * unused here.
465
  * @param string $newvalue Value to change meta to.
466
  */
467
  function bp_blogs_update_option_thread_comments_depth( $oldvalue, $newvalue ) {
476
  add_action( 'update_option_thread_comments_depth', 'bp_blogs_update_option_thread_comments_depth', 10, 2 );
477
 
478
  /**
479
+ * Syncs site icon URLs to blogmeta.
480
  *
481
+ * @since 2.7.0
 
 
482
  *
483
+ * @param int|string $old_value Old value
484
+ * @param int|string $new_value New value
485
+ */
486
+ function bp_blogs_update_option_site_icon( $old_value, $new_value ) {
487
+ if ( 0 === $new_value ) {
488
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_thumb', 0 );
489
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_full', 0 );
490
+ } else {
491
+ // Save site icon URL as blogmeta.
492
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_thumb', get_site_icon_url( bp_core_avatar_thumb_width() ) );
493
+ bp_blogs_update_blogmeta( get_current_blog_id(), 'site_icon_url_full', get_site_icon_url( bp_core_avatar_full_width() ) );
494
+ }
495
+ }
496
+ add_action( 'update_option_site_icon', 'bp_blogs_update_option_site_icon', 10, 2 );
497
+
498
+ /**
499
+ * Deletes the 'url' blogmeta for a site.
500
  *
501
+ * Hooked to 'refresh_blog_details', which is notably used when editing a site
502
+ * under "Network Admin > Sites".
503
  *
504
+ * @since 2.3.0
505
  *
506
+ * @param int $site_id The site ID.
 
 
507
  */
508
+ function bp_blogs_delete_url_blogmeta( $site_id = 0 ) {
509
+ bp_blogs_delete_blogmeta( (int) $site_id, 'url' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  }
511
+ add_action( 'refresh_blog_details', 'bp_blogs_delete_url_blogmeta' );
512
 
513
  /**
514
+ * Record activity metadata about a published blog post.
515
  *
516
+ * @since 2.2.0
517
+ *
518
+ * @param int $activity_id ID of the activity item.
519
+ * @param WP_Post $post Post object.
520
+ * @param array $args Array of arguments.
521
  */
522
+ function bp_blogs_publish_post_activity_meta( $activity_id, $post, $args ) {
523
+ if ( empty( $activity_id ) || 'post' != $post->post_type ) {
524
+ return;
525
+ }
 
 
 
 
 
526
 
527
+ bp_activity_update_meta( $activity_id, 'post_title', $post->post_title );
 
528
 
529
+ if ( ! empty( $args['post_url'] ) ) {
530
+ $post_permalink = $args['post_url'];
 
 
 
531
  } else {
532
+ $post_permalink = $post->guid;
533
  }
534
 
535
+ bp_activity_update_meta( $activity_id, 'post_url', $post_permalink );
 
536
 
537
+ // Update the blog's last activity.
538
+ bp_blogs_update_blogmeta( $args['item_id'], 'last_activity', bp_core_current_time() );
 
539
 
540
+ /**
541
+ * Fires after BuddyPress has recorded metadata about a published blog post.
542
+ *
543
+ * @since 1.0.0
544
+ *
545
+ * @param int $ID ID of the blog post being recorded.
546
+ * @param WP_Post $post WP_Post object for the current blog post.
547
+ * @param string $value ID of the user associated with the current blog post.
548
+ */
549
+ do_action( 'bp_blogs_new_blog_post', $post->ID, $post, $args['user_id'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
  }
551
+ add_action( 'bp_activity_post_type_published', 'bp_blogs_publish_post_activity_meta', 10, 3 );
552
 
553
  /**
554
+ * Updates a blog post's activity meta entry during a post edit.
 
 
555
  *
556
+ * @since 2.2.0
557
+ * @since 2.5.0 Add the post type tracking args object parameter
558
  *
559
+ * @param WP_Post $post Post object.
560
+ * @param BP_Activity_Activity $activity Activity object.
561
+ * @param object $activity_post_object The post type tracking args object.
562
  */
563
+ function bp_blogs_update_post_activity_meta( $post, $activity, $activity_post_object ) {
564
+ if ( empty( $activity->id ) || empty( $activity_post_object->action_id ) ) {
565
  return;
566
  }
567
 
568
+ // Update post title in activity meta.
569
+ $existing_title = bp_activity_get_meta( $activity->id, 'post_title' );
570
+ if ( $post->post_title !== $existing_title ) {
571
+ bp_activity_update_meta( $activity->id, 'post_title', $post->post_title );
572
+
573
+ if ( ! empty( $activity_post_object->comments_tracking->action_id ) ) {
574
+ // Now update activity meta for post comments... sigh.
575
+ add_filter( 'comments_clauses', 'bp_blogs_comments_clauses_select_by_id' );
576
+ $comments = get_comments( array( 'post_id' => $post->ID ) );
577
+ remove_filter( 'comments_clauses', 'bp_blogs_comments_clauses_select_by_id' );
578
+
579
+ if ( ! empty( $comments ) ) {
580
+ $activity_ids = array();
581
+ $comment_ids = wp_list_pluck( $comments, 'comment_ID' );
582
+
583
+ // Set up activity args.
584
+ $args = array(
585
+ 'update_meta_cache' => false,
586
+ 'show_hidden' => true,
587
+ 'per_page' => 99999,
588
+ );
589
+
590
+ // Query for old-style "new_blog_comment" activity items.
591
+ $args['filter'] = array(
592
+ 'object' => $activity_post_object->comments_tracking->component_id,
593
+ 'action' => $activity_post_object->comments_tracking->action_id,
594
+ 'secondary_id' => implode( ',', $comment_ids ),
595
+ );
596
+
597
+ $activities = bp_activity_get( $args );
598
+ if ( ! empty( $activities['activities'] ) ) {
599
+ $activity_ids = (array) wp_list_pluck( $activities['activities'], 'id' );
600
+ }
601
 
602
+ // Query for activity comments connected to a blog post.
603
+ unset( $args['filter'] );
604
+ $args['meta_query'] = array( array(
605
+ 'key' => 'bp_blogs_' . $post->post_type . '_comment_id',
606
+ 'value' => $comment_ids,
607
+ 'compare' => 'IN',
608
+ ) );
609
+ $args['type'] = 'activity_comment';
610
+ $args['display_comments'] = 'stream';
611
+
612
+ $activities = bp_activity_get( $args );
613
+ if ( ! empty( $activities['activities'] ) ) {
614
+ $activity_ids = array_merge( $activity_ids, (array) wp_list_pluck( $activities['activities'], 'id' ) );
615
+ }
616
+
617
+ // Update activity meta for all found activity items.
618
+ if ( ! empty( $activity_ids ) ) {
619
+ foreach ( $activity_ids as $aid ) {
620
+ bp_activity_update_meta( $aid, 'post_title', $post->post_title );
621
+ }
622
+ }
623
 
624
+ unset( $activities, $activity_ids, $comment_ids, $comments );
625
+ }
626
+ }
627
+ }
628
 
629
+ // Add post comment status to activity meta if closed.
630
  if( 'closed' == $post->comment_status ) {
631
+ bp_activity_update_meta( $activity->id, 'post_comment_status', $post->comment_status );
632
  } else {
633
+ bp_activity_delete_meta( $activity->id, 'post_comment_status' );
634
  }
635
  }
636
+ add_action( 'bp_activity_post_type_updated', 'bp_blogs_update_post_activity_meta', 10, 3 );
637
 
638
  /**
639
+ * Update Activity and blogs meta and eventually sync comment with activity comment
640
  *
641
+ * @since 2.5.0
642
  *
643
+ * @param int|bool $activity_id ID of recorded activity, or false if sync is active.
644
+ * @param WP_Comment|null $comment The comment object.
645
+ * @param array $activity_args Array of activity arguments.
646
+ * @param object|null $activity_post_object The post type tracking args object.
647
+ * @return int|bool Returns false if no activity, the activity id otherwise.
648
  */
649
+ function bp_blogs_comment_sync_activity_comment( &$activity_id, $comment = null, $activity_args = array(), $activity_post_object = null ) {
650
+ if ( empty( $activity_args ) || empty( $comment->post->ID ) || empty( $activity_post_object->comment_action_id ) ) {
 
 
 
 
 
 
 
 
 
651
  return false;
652
+ }
653
 
654
+ // Set the current blog id.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  $blog_id = get_current_blog_id();
656
 
657
+ // These activity metadatas are used to build the new_blog_comment action string
658
+ if ( ! empty( $activity_id ) && ! empty( $activity_args['item_id'] ) && 'new_blog_comment' === $activity_post_object->comment_action_id ) {
659
+ // add some post info in activity meta
660
+ bp_activity_update_meta( $activity_id, 'post_title', $comment->post->post_title );
661
+ bp_activity_update_meta( $activity_id, 'post_url', esc_url_raw( add_query_arg( 'p', $comment->post->ID, home_url( '/' ) ) ) );
662
+ }
 
 
663
 
664
+ // Sync comment - activity comment
665
+ if ( ! bp_disable_blogforum_comments() ) {
 
666
 
667
+ if ( ! empty( $_REQUEST['action'] ) ) {
668
+ $existing_activity_id = get_comment_meta( $comment->comment_ID, 'bp_activity_comment_id', true );
 
669
 
670
+ if ( ! empty( $existing_activity_id ) ) {
671
+ $activity_args['id'] = $existing_activity_id;
672
+ }
673
+ }
674
 
675
+ if ( empty( $activity_post_object ) ) {
676
+ $activity_post_object = bp_activity_get_post_type_tracking_args( $comment->post->post_type );
677
+ }
678
 
679
+ if ( isset( $activity_post_object->action_id ) && isset( $activity_post_object->component_id ) ) {
680
+ // find the parent 'new_post_type' activity entry
681
+ $parent_activity_id = bp_activity_get_activity_id( array(
682
+ 'component' => $activity_post_object->component_id,
683
+ 'type' => $activity_post_object->action_id,
684
+ 'item_id' => $blog_id,
685
+ 'secondary_item_id' => $comment->comment_post_ID
686
+ ) );
687
 
688
+ // Try to create a new activity item for the parent blog post.
689
+ if ( empty( $parent_activity_id ) ) {
690
+ $parent_activity_id = bp_activity_post_type_publish( $comment->post->ID, $comment->post );
691
+ }
692
+ }
693
 
694
+ // we found the parent activity entry
695
+ // so let's go ahead and reconfigure some activity args
696
+ if ( ! empty( $parent_activity_id ) ) {
697
+ // set the parent activity entry ID
698
+ $activity_args['activity_id'] = $parent_activity_id;
699
 
700
+ // now see if the WP parent comment has a BP activity ID
701
+ $comment_parent = 0;
702
+ if ( ! empty( $comment->comment_parent ) ) {
703
+ $comment_parent = get_comment_meta( $comment->comment_parent, 'bp_activity_comment_id', true );
704
+ }
705
 
706
+ // WP parent comment does not have a BP activity ID
707
+ // so set to 'new_' . post_type activity ID
708
+ if ( empty( $comment_parent ) ) {
709
+ $comment_parent = $parent_activity_id;
710
+ }
 
711
 
712
+ $activity_args['parent_id'] = $comment_parent;
713
+ $activity_args['skip_notification'] = true;
714
 
715
+ // could not find corresponding parent activity entry
716
+ // so wipe out $args array
717
  } else {
718
+ $activity_args = array();
719
+ }
 
 
720
 
721
+ // Record in activity streams
722
+ if ( ! empty( $activity_args ) ) {
723
+ $activity_id = bp_activity_new_comment( $activity_args );
 
724
 
725
+ if ( empty( $activity_args['id'] ) ) {
726
+ // The activity metadata to inform about the corresponding comment ID
727
+ bp_activity_update_meta( $activity_id, "bp_blogs_{$comment->post->post_type}_comment_id", $comment->comment_ID );
 
 
 
 
728
 
729
+ // The comment metadata to inform about the corresponding activity ID
730
+ add_comment_meta( $comment->comment_ID, 'bp_activity_comment_id', $activity_id );
 
 
 
731
 
732
+ // These activity metadatas are used to build the new_blog_comment action string
733
+ if ( 'new_blog_comment' === $activity_post_object->comment_action_id ) {
734
+ bp_activity_update_meta( $activity_id, 'post_title', $comment->post->post_title );
735
+ bp_activity_update_meta( $activity_id, 'post_url', esc_url_raw( add_query_arg( 'p', $comment->post->ID, home_url( '/' ) ) ) );
736
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
  }
738
 
739
+ /**
740
+ * Fires after an activity comment is added from a WP post comment.
741
+ *
742
+ * @since 2.6.0
743
+ *
744
+ * @param int $activity_id The activity comment ID.
745
+ * @param WP_Comment $post_type_comment WP Comment object.
746
+ * @param array $activity_args Activity comment arguments.
747
+ * @param object $activity_post_object The post type tracking args object.
748
+ */
749
+ do_action( 'bp_blogs_comment_sync_activity_comment', $activity_id, $comment, $activity_args, $activity_post_object );
 
 
 
 
 
 
 
750
  }
751
+ }
752
 
753
+ // Update the blogs last active date
754
+ bp_blogs_update_blogmeta( $blog_id, 'last_activity', bp_core_current_time() );
755
+
756
+ if ( 'new_blog_comment' === $activity_post_object->comment_action_id ) {
757
+ /**
758
+ * Fires after BuddyPress has recorded metadata about a published blog post comment.
759
+ *
760
+ * @since 2.5.0
761
+ *
762
+ * @param int $value Comment ID of the blog post comment being recorded.
763
+ * @param WP_Post $post WP_Comment object for the current blog post.
764
+ * @param string $value ID of the user associated with the current blog post comment.
765
+ */
766
+ do_action( 'bp_blogs_new_blog_comment', $comment->comment_ID, $comment, bp_loggedin_user_id() );
767
  }
768
 
769
+ return $activity_id;
770
  }
771
+ add_action( 'bp_activity_post_type_comment', 'bp_blogs_comment_sync_activity_comment', 10, 4 );
 
772
 
773
  /**
774
  * Record a user's association with a blog.
777
  * set/changed ('add_user_to_blog', 'profile_update', 'user_register'). It
778
  * parses the changes, and records them as necessary in the BP blog tracker.
779
  *
780
+ * BuddyPress does not track blogs for users with the 'subscriber' role by
781
+ * default, though as of 2.1.0 you can filter 'bp_blogs_get_allowed_roles' to
782
+ * modify this behavior.
783
  *
784
+ * @param int $user_id The ID of the user.
785
+ * @param string|bool $role User's WordPress role for this blog ID.
786
+ * @param int $blog_id Blog ID user is being added to.
 
 
787
  * @return bool|null False on failure.
788
  */
789
  function bp_blogs_add_user_to_blog( $user_id, $role = false, $blog_id = 0 ) {
790
  global $wpdb;
791
 
792
+ // If no blog ID was passed, use the root blog ID.
793
  if ( empty( $blog_id ) ) {
794
  $blog_id = isset( $wpdb->blogid ) ? $wpdb->blogid : bp_get_root_blog_id();
795
  }
796
 
797
+ // If no role was passed, try to find the blog role.
798
  if ( empty( $role ) ) {
 
799
 
800
+ // Get user capabilities.
801
+ $key = $wpdb->get_blog_prefix( $blog_id ). 'capabilities';
802
+ $user_roles = array_keys( (array) bp_get_user_meta( $user_id, $key, true ) );
803
 
804
+ // User has roles so lets.
805
+ if ( ! empty( $user_roles ) ) {
806
+
807
+ // Get blog roles.
808
+ $blog_roles = array_keys( bp_get_current_blog_roles() );
809
+
810
+ // Look for blog only roles of the user.
811
+ $intersect_roles = array_intersect( $user_roles, $blog_roles );
812
+
813
+ // If there's a role in the array, use the first one. This isn't
814
+ // very smart, but since roles aren't exactly hierarchical, and
815
+ // WordPress does not yet have a UI for multiple user roles, it's
816
+ // fine for now.
817
+ if ( ! empty( $intersect_roles ) ) {
818
+ $role = array_shift( $intersect_roles );
819
+ }
820
+ }
821
  }
822
 
823
+ // Bail if no role was found or role is not in the allowed roles array.
824
+ if ( empty( $role ) || ! in_array( $role, bp_blogs_get_allowed_roles() ) ) {
825
+ return false;
826
+ }
827
+
828
+ // Record the blog activity for this user being added to this blog.
829
+ bp_blogs_record_blog( $blog_id, $user_id, true );
830
  }
831
  add_action( 'add_user_to_blog', 'bp_blogs_add_user_to_blog', 10, 3 );
832
  add_action( 'profile_update', 'bp_blogs_add_user_to_blog' );
833
  add_action( 'user_register', 'bp_blogs_add_user_to_blog' );
834
 
835
+ /**
836
+ * The allowed blog roles a member must have to be recorded into the
837
+ * `bp_user_blogs` pointer table.
838
+ *
839
+ * This added and was made filterable in BuddyPress 2.1.0 to make it easier
840
+ * to extend the functionality of the Blogs component.
841
+ *
842
+ * @since 2.1.0
843
+ *
844
+ * @return string
845
+ */
846
+ function bp_blogs_get_allowed_roles() {
847
+ return apply_filters( 'bp_blogs_get_allowed_roles', array( 'contributor', 'author', 'editor', 'administrator' ) );
848
+ }
849
+
850
  /**
851
  * Remove a blog-user pair from BP's blog tracker.
852
  *
856
  function bp_blogs_remove_user_from_blog( $user_id, $blog_id = 0 ) {
857
  global $wpdb;
858
 
859
+ if ( empty( $blog_id ) ) {
860
  $blog_id = $wpdb->blogid;
861
+ }
862
 
863
  bp_blogs_remove_blog_for_user( $user_id, $blog_id );
864
  }
865
  add_action( 'remove_user_from_blog', 'bp_blogs_remove_user_from_blog', 10, 2 );
866
 
867
  /**
868
+ * Rehook WP's maybe_add_existing_user_to_blog with a later priority.
869
  *
870
  * WordPress catches add-user-to-blog requests at init:10. In some cases, this
871
  * can precede BP's Blogs component. This function bumps the priority of the
872
  * core function, so that we can be sure that the Blogs component is loaded
873
+ * first. See https://buddypress.trac.wordpress.org/ticket/3916.
874
  *
875
+ * @since 1.6.0
 
876
  */
877
  function bp_blogs_maybe_add_user_to_blog() {
878
  if ( ! is_multisite() )
889
  * @param int $blog_id ID of the blog being removed.
890
  */
891
  function bp_blogs_remove_blog( $blog_id ) {
 
892
 
893
  $blog_id = (int) $blog_id;
894
+
895
+ /**
896
+ * Fires before a "blog created" item is removed from blogs
897
+ * tracker and activity stream.
898
+ *
899
+ * @since 1.5.0
900
+ *
901
+ * @param int $blog_id ID of the blog having its item removed.
902
+ */
903
  do_action( 'bp_blogs_before_remove_blog', $blog_id );
904
 
905
  BP_Blogs_Blog::delete_blog_for_all( $blog_id );
906
 
907
+ /**
908
+ * Fires after a "blog created" item has been removed from blogs
909
+ * tracker and activity stream.
910
+ *
911
+ * @since 1.0.0
912
+ *
913
+ * @param int $blog_id ID of the blog who had its item removed.
914
+ */
915
  do_action( 'bp_blogs_remove_blog', $blog_id );
916
  }
917
  add_action( 'delete_blog', 'bp_blogs_remove_blog' );
923
  * @param int $blog_id ID of the blog being removed.
924
  */
925
  function bp_blogs_remove_blog_for_user( $user_id, $blog_id ) {
 
926
 
927
  $blog_id = (int) $blog_id;
928
  $user_id = (int) $user_id;
929
 
930
+ /**
931
+ * Fires before a blog is removed from the tracker for a specific user.
932
+ *
933
+ * @since 1.5.0
934
+ *
935
+ * @param int $blog_id ID of the blog being removed.
936
+ * @param int $user_id ID of the user having the blog removed for.
937
+ */
938
  do_action( 'bp_blogs_before_remove_blog_for_user', $blog_id, $user_id );
939
 
940
  BP_Blogs_Blog::delete_blog_for_user( $blog_id, $user_id );
941
 
942
+ /**
943
+ * Fires after a blog has been removed from the tracker for a specific user.
944
+ *
945
+ * @since 1.0.0
946
+ *
947
+ * @param int $blog_id ID of the blog that was removed.
948
+ * @param int $user_id ID of the user having the blog removed for.
949
+ */
950
  do_action( 'bp_blogs_remove_blog_for_user', $blog_id, $user_id );
951
  }
952
  add_action( 'remove_user_from_blog', 'bp_blogs_remove_blog_for_user', 10, 2 );
953
 
954
  /**
955
+ * Remove a synced activity comment from the activity stream.
956
  *
957
+ * @since 2.5.0
958
+ *
959
+ * @param bool $deleted True when a comment post type activity was successfully removed.
960
+ * @param int $comment_id ID of the comment to be removed.
961
+ * @param object $activity_post_object The post type tracking args object.
962
+ * @param string $activity_type The post type comment activity type.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963
  *
964
+ * @return bool True on success. False on error.
965
  */
966
+ function bp_blogs_post_type_remove_comment( $deleted, $comment_id, $activity_post_object, $activity_type = '' ) {
967
+ // Remove synced activity comments, if needed.
968
+ if ( ! bp_disable_blogforum_comments() ) {
969
+ // Get associated activity ID from comment meta
 
 
 
 
 
 
 
 
 
 
 
 
 
970
  $activity_id = get_comment_meta( $comment_id, 'bp_activity_comment_id', true );
971
 
972
+ /**
973
+ * Delete the associated activity comment & also remove
974
+ * child post comments and associated activity comments.
975
+ */
976
+ if ( ! empty( $activity_id ) ) {
977
  // fetch the activity comments for the activity item
978
  $activity = bp_activity_get( array(
979
  'in' => $activity_id,
980
  'display_comments' => 'stream',
981
+ 'spam' => 'all',
982
  ) );
983
 
984
  // get all activity comment IDs for the pending deleted item
998
 
999
  // rebuild activity comment tree
1000
  BP_Activity_Activity::rebuild_activity_comment_tree( $activity['activities'][0]->item_id );
1001
+
1002
+ // Set the result
1003
+ $deleted = true;
1004
  }
1005
  }
1006
  }
1007
 
1008
+ // Backcompat for comments about the 'post' post type.
1009
+ if ( 'new_blog_comment' === $activity_type ) {
1010
+ /**
1011
+ * Fires after a blog comment activity item was removed from activity stream.
1012
+ *
1013
+ * @since 1.0.0
1014
+ *
1015
+ * @param int $value ID for the blog associated with the removed comment.
1016
+ * @param int $comment_id ID of the comment being removed.
1017
+ * @param int $value ID of the current logged in user.
1018
+ */
1019
+ do_action( 'bp_blogs_remove_comment', get_current_blog_id(), $comment_id, bp_loggedin_user_id() );
1020
+ }
1021
+
1022
+ return $deleted;
1023
  }
1024
+ add_action( 'bp_activity_post_type_remove_comment', 'bp_blogs_post_type_remove_comment', 10, 4 );
1025
 
1026
  /**
1027
  * Removes blog comments that are associated with activity comments.
1028
  *
1029
+ * @since 2.0.0
1030
  *
1031
+ * @see bp_blogs_remove_synced_comment()
1032
  * @see bp_blogs_sync_delete_from_activity_comment()
1033
  *
1034
  * @param array $activity_ids The activity IDs to check association with blog
1035
+ * comments.
1036
+ * @param bool $force_delete Whether to force delete the comments. If false,
1037
+ * comments are trashed instead.
1038
  */
1039
  function bp_blogs_remove_associated_blog_comments( $activity_ids = array(), $force_delete = true ) {
1040
+ // Query args.
1041
  $query_args = array(
1042
  'meta_query' => array(
1043
  array(
1048
  )
1049
  );
1050
 
1051
+ // Get comment.
1052
  $comment_query = new WP_Comment_Query;
1053
  $comments = $comment_query->query( $query_args );
1054
 
1055
+ // Found the corresponding comments
1056
  // let's delete them!
1057
  foreach ( $comments as $comment ) {
1058
  wp_delete_comment( $comment->comment_ID, $force_delete );
1059
 
1060
+ // If we're trashing the comment, remove the meta key as well.
1061
  if ( empty( $force_delete ) ) {
1062
  delete_comment_meta( $comment->comment_ID, 'bp_activity_comment_id' );
1063
  }
1064
  }
1065
  }
1066
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1067
  /**
1068
  * Get the total number of blogs being tracked by BuddyPress.
1069
  *
1070
  * @return int $count Total blog count.
1071
  */
1072
  function bp_blogs_total_blogs() {
1073
+ $count = wp_cache_get( 'bp_total_blogs', 'bp' );
1074
+
1075
+ if ( false === $count ) {
1076
  $blogs = BP_Blogs_Blog::get_all();
1077
  $count = $blogs['total'];
1078
  wp_cache_set( 'bp_total_blogs', $count, 'bp' );
1083
  /**
1084
  * Get the total number of blogs being tracked by BP for a specific user.
1085
  *
1086
+ * @since 1.2.0
1087
+ *
1088
  * @param int $user_id ID of the user being queried. Default: on a user page,
1089
+ * the displayed user. Otherwise, the logged-in user.
1090
  * @return int $count Total blog count for the user.
1091
  */
1092
  function bp_blogs_total_blogs_for_user( $user_id = 0 ) {
1093
+ if ( empty( $user_id ) ) {
 
1094
  $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
1095
+ }
1096
 
1097
+ // No user ID? do not attempt to look at cache.
1098
+ if ( empty( $user_id ) ) {
1099
+ return 0;
1100
+ }
1101
+
1102
+ $count = wp_cache_get( 'bp_total_blogs_for_user_' . $user_id, 'bp' );
1103
+ if ( false === $count ) {
1104
  $count = BP_Blogs_Blog::total_blog_count_for_user( $user_id );
1105
  wp_cache_set( 'bp_total_blogs_for_user_' . $user_id, $count, 'bp' );
1106
  }
1114
  * @param int $blog_id The ID of the blog to expunge.
1115
  */
1116
  function bp_blogs_remove_data_for_blog( $blog_id ) {
 
1117
 
1118
+ /**
1119
+ * Fires before all data related to a given blog is removed from blogs tracker
1120
+ * and activity stream.
1121
+ *
1122
+ * @since 1.5.0
1123
+ *
1124
+ * @param int $blog_id ID of the blog whose data is being removed.
1125
+ */
1126
  do_action( 'bp_blogs_before_remove_data_for_blog', $blog_id );
1127
 
1128
  // If this is regular blog, delete all data for that blog.
1129
  BP_Blogs_Blog::delete_blog_for_all( $blog_id );
1130
 
1131
+ /**
1132
+ * Fires after all data related to a given blog has been removed from blogs tracker
1133
+ * and activity stream.
1134
+ *
1135
+ * @since 1.0.0
1136
+ *
1137
+ * @param int $blog_id ID of the blog whose data is being removed.
1138
+ */
1139
  do_action( 'bp_blogs_remove_data_for_blog', $blog_id );
1140
  }
1141
  add_action( 'delete_blog', 'bp_blogs_remove_data_for_blog', 1 );
1146
  * @see BP_Blogs_Blog::get_blogs_for_user() for a description of parameters
1147
  * and return values.
1148
  *
1149
+ * @param int $user_id See {@BP_Blogs_Blog::get_blogs_for_user()}.
1150
  * @param bool $show_hidden See {@BP_Blogs_Blog::get_blogs_for_user()}.
1151
  * @return array See {@BP_Blogs_Blog::get_blogs_for_user()}.
1152
  */
1159
  *
1160
  * @see BP_Blogs_Blog::get_all() for a description of parameters and return values.
1161
  *
1162
+ * @param int|null $limit See {@BP_Blogs_Blog::get_all()}.
1163
+ * @param int|null $page See {@BP_Blogs_Blog::get_all()}.
1164
  * @return array See {@BP_Blogs_Blog::get_all()}.
1165
  */
1166
  function bp_blogs_get_all_blogs( $limit = null, $page = null ) {
1172
  *
1173
  * @see BP_Blogs_Blog::get() for a description of parameters and return values.
1174
  *
1175
+ * @param int|null $limit See {@BP_Blogs_Blog::get()}.
1176
+ * @param int|null $page See {@BP_Blogs_Blog::get()}.
1177
  * @return array See {@BP_Blogs_Blog::get()}.
1178
  */
1179
  function bp_blogs_get_random_blogs( $limit = null, $page = null ) {
1192
  return BP_Blogs_Blog::is_hidden( $blog_id );
1193
  }
1194
 
1195
+ /*
1196
  * Blog meta functions
1197
  *
1198
  * These functions are used to store specific blogmeta in one global table,
1202
  */
1203
 
1204
  /**
1205
+ * Delete a metadata from the DB for a blog.
1206
  *
1207
  * @global object $wpdb WordPress database access object.
1208
+ *
1209
+ * @param int $blog_id ID of the blog whose metadata is being deleted.
1210
+ * @param string|bool $meta_key Optional. The key of the metadata being deleted. If
1211
+ * omitted, all BP metadata associated with the blog will
1212
+ * be deleted.
1213
+ * @param string|bool $meta_value Optional. If present, the metadata will only be
1214
+ * deleted if the meta_value matches this parameter.
1215
+ * @param bool $delete_all Optional. If true, delete matching metadata entries for
1216
+ * all objects, ignoring the specified blog_id. Otherwise, only
1217
+ * delete matching metadata entries for the specified blog.
1218
+ * Default: false.
1219
  * @return bool True on success, false on failure.
1220
  */
1221
  function bp_blogs_delete_blogmeta( $blog_id, $meta_key = false, $meta_value = false, $delete_all = false ) {
1222
+ global $wpdb;
1223
 
1224
+ // Legacy - if no meta_key is passed, delete all for the blog_id.
1225
  if ( empty( $meta_key ) ) {
1226
  $keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->blogmeta} WHERE blog_id = %d", $blog_id ) );
1227
  $delete_all = false;
1244
  /**
1245
  * Get metadata for a given blog.
1246
  *
1247
+ * @since 1.2.0
1248
  *
1249
  * @global object $wpdb WordPress database access object.
 
1250
  *
1251
+ * @param int $blog_id ID of the blog whose metadata is being requested.
1252
  * @param string $meta_key Optional. If present, only the metadata matching
1253
+ * that meta key will be returned. Otherwise, all
1254
+ * metadata for the blog will be fetched.
1255
+ * @param bool $single Optional. If true, return only the first value of the
1256
+ * specified meta_key. This parameter has no effect if
1257
+ * meta_key is not specified. Default: true.
1258
  * @return mixed The meta value(s) being requested.
1259
  */
1260
  function bp_blogs_get_blogmeta( $blog_id, $meta_key = '', $single = true ) {
1269
  * Update a piece of blog meta.
1270
  *
1271
  * @global object $wpdb WordPress database access object.
1272
+ *
1273
+ * @param int $blog_id ID of the blog whose metadata is being updated.
1274
+ * @param string $meta_key Key of the metadata being updated.
1275
+ * @param mixed $meta_value Value to be set.
1276
+ * @param mixed $prev_value Optional. If specified, only update existing
1277
+ * metadata entries with the specified value.
1278
+ * Otherwise, update all entries.
 
1279
  * @return bool|int Returns false on failure. On successful update of existing
1280
+ * metadata, returns true. On successful creation of new metadata,
1281
+ * returns the integer ID of the new metadata row.
1282
  */
1283
  function bp_blogs_update_blogmeta( $blog_id, $meta_key, $meta_value, $prev_value = '' ) {
1284
  add_filter( 'query', 'bp_filter_metaid_column_name' );
1291
  /**
1292
  * Add a piece of blog metadata.
1293
  *
1294
+ * @since 2.0.0
1295
  *
1296
+ * @param int $blog_id ID of the blog.
1297
+ * @param string $meta_key Metadata key.
1298
+ * @param mixed $meta_value Metadata value.
1299
+ * @param bool $unique Optional. Whether to enforce a single metadata value
1300
+ * for the given key. If true, and the object already has a value for
1301
+ * the key, no change will be made. Default: false.
1302
  * @return int|bool The meta ID on successful update, false on failure.
1303
  */
1304
  function bp_blogs_add_blogmeta( $blog_id, $meta_key, $meta_value, $unique = false ) {
1312
  * Remove all blog associations for a given user.
1313
  *
1314
  * @param int $user_id ID whose blog data should be removed.
1315
+ * @return bool Returns false on failure.
1316
  */
1317
  function bp_blogs_remove_data( $user_id ) {
1318
  if ( !is_multisite() )
1319
  return false;
1320
 
1321
+ /**
1322
+ * Fires before all blog associations are removed for a given user.
1323
+ *
1324
+ * @since 1.5.0
1325
+ *
1326
+ * @param int $user_id ID of the user whose blog associations are being removed.
1327
+ */
1328
  do_action( 'bp_blogs_before_remove_data', $user_id );
1329
 
1330
  // If this is regular blog, delete all data for that blog.
1331
  BP_Blogs_Blog::delete_blogs_for_user( $user_id );
1332
 
1333
+ /**
1334
+ * Fires after all blog associations are removed for a given user.
1335
+ *
1336
+ * @since 1.0.0
1337
+ *
1338
+ * @param int $user_id ID of the user whose blog associations were removed.
1339
+ */
1340
  do_action( 'bp_blogs_remove_data', $user_id );
1341
  }
1342
  add_action( 'wpmu_delete_user', 'bp_blogs_remove_data' );
1343
  add_action( 'delete_user', 'bp_blogs_remove_data' );
1344
  add_action( 'bp_make_spam_user', 'bp_blogs_remove_data' );
1345
+
1346
+ /**
1347
+ * Restore all blog associations for a given user.
1348
+ *
1349
+ * @since 2.2.0
1350
+ *
1351
+ * @param int $user_id ID whose blog data should be restored.
1352
+ */
1353
+ function bp_blogs_restore_data( $user_id = 0 ) {
1354
+ if ( ! is_multisite() ) {
1355
+ return;
1356
+ }
1357
+
1358
+ // Get the user's blogs.
1359
+ $user_blogs = get_blogs_of_user( $user_id );
1360
+ if ( empty( $user_blogs ) ) {
1361
+ return;
1362
+ }
1363
+
1364
+ $blogs = array_keys( $user_blogs );
1365
+
1366
+ foreach ( $blogs as $blog_id ) {
1367
+ bp_blogs_add_user_to_blog( $user_id, false, $blog_id );
1368
+ }
1369
+ }
1370
+ add_action( 'bp_make_ham_user', 'bp_blogs_restore_data', 10, 1 );
bp-blogs/bp-blogs-loader.php CHANGED
@@ -1,250 +1,27 @@
1
  <?php
2
-
3
  /**
4
- * BuddyPress Blogs Streams Loader
5
  *
6
- * An blogs stream component, for users, groups, and blog tracking.
 
 
7
  *
8
  * @package BuddyPress
9
- * @subpackage Blogs Core
 
10
  */
11
 
12
- // Exit if accessed directly
13
- if ( !defined( 'ABSPATH' ) ) exit;
14
-
15
- class BP_Blogs_Component extends BP_Component {
16
-
17
- /**
18
- * Start the blogs component creation process.
19
- *
20
- * @since BuddyPress (1.5.0)
21
- */
22
- public function __construct() {
23
- parent::start(
24
- 'blogs',
25
- __( 'Site Tracking', 'buddypress' ),
26
- buddypress()->plugin_dir,
27
- array(
28
- 'adminbar_myaccount_order' => 30
29
- )
30
- );
31
- }
32
-
33
- /**
34
- * Set up global settings for the blogs component.
35
- *
36
- * The BP_BLOGS_SLUG constant is deprecated, and only used here for
37
- * backwards compatibility.
38
- *
39
- * @since BuddyPress (1.5.0)
40
- *
41
- * @see BP_Component::setup_globals() for description of parameters.
42
- *
43
- * @param array $args See {@link BP_Component::setup_globals()}.
44
- */
45
- public function setup_globals( $args = array() ) {
46
- $bp = buddypress();
47
-
48
- if ( !defined( 'BP_BLOGS_SLUG' ) )
49
- define ( 'BP_BLOGS_SLUG', $this->id );
50
-
51
- // Global tables for messaging component
52
- $global_tables = array(
53
- 'table_name' => $bp->table_prefix . 'bp_user_blogs',
54
- 'table_name_blogmeta' => $bp->table_prefix . 'bp_user_blogs_blogmeta',
55
- );
56
-
57
- $meta_tables = array(
58
- 'blog' => $bp->table_prefix . 'bp_user_blogs_blogmeta',
59
- );
60
-
61
- // All globals for messaging component.
62
- // Note that global_tables is included in this array.
63
- $args = array(
64
- 'slug' => BP_BLOGS_SLUG,
65
- 'root_slug' => isset( $bp->pages->blogs->slug ) ? $bp->pages->blogs->slug : BP_BLOGS_SLUG,
66
- 'has_directory' => is_multisite(), // Non-multisite installs don't need a top-level Sites directory, since there's only one site
67
- 'notification_callback' => 'bp_blogs_format_notifications',
68
- 'search_string' => __( 'Search sites...', 'buddypress' ),
69
- 'autocomplete_all' => defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' ),
70
- 'global_tables' => $global_tables,
71
- 'meta_tables' => $meta_tables,
72
- );
73
-
74
- // Setup the globals
75
- parent::setup_globals( $args );
76
- }
77
-
78
- /**
79
- * Include bp-blogs files.
80
- *
81
- * @see BP_Component::includes() for description of parameters.
82
- *
83
- * @param array $includes See {@link BP_Component::includes()}.
84
- */
85
- public function includes( $includes = array() ) {
86
- // Files to include
87
- $includes = array(
88
- 'cache',
89
- 'actions',
90
- 'screens',
91
- 'classes',
92
- 'template',
93
- 'filters',
94
- 'activity',
95
- 'functions',
96
- 'buddybar'
97
- );
98
-
99
- if ( is_multisite() )
100
- $includes[] = 'widgets';
101
-
102
- // Include the files
103
- parent::includes( $includes );
104
- }
105
-
106
- /**
107
- * Set up component navigation for bp-blogs.
108
- *
109
- * @see BP_Component::setup_nav() for a description of arguments.
110
- *
111
- * @param array $main_nav Optional. See BP_Component::setup_nav() for
112
- * description.
113
- * @param array $sub_nav Optional. See BP_Component::setup_nav() for
114
- * description.
115
- */
116
- public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
117
- $bp = buddypress();
118
-
119
- /**
120
- * Blog/post/comment menus should not appear on single WordPress setups.
121
- * Although comments and posts made by users will still show on their
122
- * activity stream.
123
- */
124
- if ( !is_multisite() )
125
- return false;
126
-
127
- // Add 'Sites' to the main navigation
128
- $main_nav = array(
129
- 'name' => sprintf( __( 'Sites <span>%d</span>', 'buddypress' ), bp_blogs_total_blogs_for_user() ),
130
- 'slug' => $this->slug,
131
- 'position' => 30,
132
- 'screen_function' => 'bp_blogs_screen_my_blogs',
133
- 'default_subnav_slug' => 'my-sites',
134
- 'item_css_id' => $this->id
135
- );
136
-
137
- // Determine user to use
138
- if ( bp_displayed_user_domain() ) {
139
- $user_domain = bp_displayed_user_domain();
140
- } elseif ( bp_loggedin_user_domain() ) {
141
- $user_domain = bp_loggedin_user_domain();
142
- } else {
143
- return;
144
- }
145
 
146
- $parent_url = trailingslashit( $user_domain . bp_get_blogs_slug() );
147
-
148
- $sub_nav[] = array(
149
- 'name' => __( 'My Sites', 'buddypress' ),
150
- 'slug' => 'my-sites',
151
- 'parent_url' => $parent_url,
152
- 'parent_slug' => $bp->blogs->slug,
153
- 'screen_function' => 'bp_blogs_screen_my_blogs',
154
- 'position' => 10
155
- );
156
-
157
- // Setup navigation
158
- parent::setup_nav( $main_nav, $sub_nav );
159
- }
160
-
161
- /**
162
- * Set up bp-blogs integration with the WordPress admin bar.
163
- *
164
- * @since BuddyPress (1.5.0)
165
- *
166
- * @see BP_Component::setup_admin_bar() for a description of arguments.
167
- *
168
- * @param array $wp_admin_nav See BP_Component::setup_admin_bar()
169
- * for description.
170
- */
171
- public function setup_admin_bar( $wp_admin_nav = array() ) {
172
- $bp = buddypress();
173
-
174
- /**
175
- * Site/post/comment menus should not appear on single WordPress setups.
176
- * Although comments and posts made by users will still show on their
177
- * activity stream.
178
- */
179
- if ( !is_multisite() )
180
- return false;
181
-
182
- // Menus for logged in user
183
- if ( is_user_logged_in() ) {
184
-
185
- $blogs_link = trailingslashit( bp_loggedin_user_domain() . $this->slug );
186
-
187
- // Add the "Sites" sub menu
188
- $wp_admin_nav[] = array(
189
- 'parent' => $bp->my_account_menu_id,
190
- 'id' => 'my-account-' . $this->id,
191
- 'title' => __( 'Sites', 'buddypress' ),
192
- 'href' => trailingslashit( $blogs_link )
193
- );
194
-
195
- // My Sites
196
- $wp_admin_nav[] = array(
197
- 'parent' => 'my-account-' . $this->id,
198
- 'id' => 'my-account-' . $this->id . '-my-sites',
199
- 'title' => __( 'My Sites', 'buddypress' ),
200
- 'href' => trailingslashit( $blogs_link )
201
- );
202
-
203
- // Create a Site
204
- if ( bp_blog_signup_enabled() ) {
205
- $wp_admin_nav[] = array(
206
- 'parent' => 'my-account-' . $this->id,
207
- 'id' => 'my-account-' . $this->id . '-create',
208
- 'title' => __( 'Create a Site', 'buddypress' ),
209
- 'href' => trailingslashit( bp_get_blogs_directory_permalink() . 'create' )
210
- );
211
- }
212
- }
213
-
214
- parent::setup_admin_bar( $wp_admin_nav );
215
- }
216
-
217
- /**
218
- * Set up the title for pages and <title>
219
- */
220
- public function setup_title() {
221
- $bp = buddypress();
222
-
223
- // Set up the component options navigation for Site
224
- if ( bp_is_blogs_component() ) {
225
- if ( bp_is_my_profile() ) {
226
- if ( bp_is_active( 'xprofile' ) ) {
227
- $bp->bp_options_title = __( 'My Sites', 'buddypress' );
228
- }
229
-
230
- // If we are not viewing the logged in user, set up the current
231
- // users avatar and name
232
- } else {
233
- $bp->bp_options_avatar = bp_core_fetch_avatar( array(
234
- 'item_id' => bp_displayed_user_id(),
235
- 'type' => 'thumb',
236
- 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
237
- ) );
238
- $bp->bp_options_title = bp_get_displayed_user_fullname();
239
- }
240
- }
241
-
242
- parent::setup_title();
243
- }
244
  }
245
 
246
  /**
247
  * Set up the bp-blogs component.
 
 
248
  */
249
  function bp_setup_blogs() {
250
  buddypress()->blogs = new BP_Blogs_Component();
1
  <?php
 
2
  /**
3
+ * BuddyPress Blogs Loader
4
  *
5
+ * The blogs component tracks posts and comments to member activity streams,
6
+ * shows blogs the member can post to in their profiles, and caches useful
7
+ * information from those blogs to make querying blogs in bulk more performant.
8
  *
9
  * @package BuddyPress
10
+ * @subpackage BlogsCore
11
+ * @since 1.5.0
12
  */
13
 
14
+ // Exit if accessed directly.
15
+ defined( 'ABSPATH' ) || exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ if ( ! buddypress()->do_autoload ) {
18
+ require dirname( __FILE__ ) . '/classes/class-bp-blogs-component.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  }
20
 
21
  /**
22
  * Set up the bp-blogs component.
23
+ *
24
+ * @since 1.5.0
25
  */
26
  function bp_setup_blogs() {
27
  buddypress()->blogs = new BP_Blogs_Component();
bp-blogs/bp-blogs-screens.php CHANGED
@@ -1,14 +1,18 @@
1
  <?php
2
-
3
  /**
4
- * BuddyPress Blogs Screens
5
  *
6
  * @package BuddyPress
7
  * @subpackage BlogsScreens
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
 
 
 
 
12
 
13
  /**
14
  * Load the "My Blogs" screen.
@@ -17,6 +21,11 @@ function bp_blogs_screen_my_blogs() {
17
  if ( !is_multisite() )
18
  return false;
19
 
 
 
 
 
 
20
  do_action( 'bp_blogs_screen_my_blogs' );
21
 
22
  bp_core_load_template( apply_filters( 'bp_blogs_template_my_blogs', 'members/single/home' ) );
@@ -33,6 +42,11 @@ function bp_blogs_screen_create_a_blog() {
33
  if ( !is_user_logged_in() || !bp_blog_signup_enabled() )
34
  return false;
35
 
 
 
 
 
 
36
  do_action( 'bp_blogs_screen_create_a_blog' );
37
 
38
  bp_core_load_template( apply_filters( 'bp_blogs_template_create_a_blog', 'blogs/create' ) );
@@ -46,6 +60,11 @@ function bp_blogs_screen_index() {
46
  if ( bp_is_blogs_directory() ) {
47
  bp_update_is_directory( true, 'blogs' );
48
 
 
 
 
 
 
49
  do_action( 'bp_blogs_screen_index' );
50
 
51
  bp_core_load_template( apply_filters( 'bp_blogs_screen_index', 'blogs/index' ) );
@@ -53,179 +72,6 @@ function bp_blogs_screen_index() {
53
  }
54
  add_action( 'bp_screens', 'bp_blogs_screen_index', 2 );
55
 
56
- /** Theme Compatability *******************************************************/
57
-
58
- /**
59
- * The main theme compat class for BuddyPress Blogs
60
- *
61
- * This class sets up the necessary theme compatability actions to safely output
62
- * group template parts to the_title and the_content areas of a theme.
63
- *
64
- * @since BuddyPress (1.7.0)
65
- */
66
- class BP_Blogs_Theme_Compat {
67
-
68
- /**
69
- * Set up theme compatibility for the Blogs component.
70
- *
71
- * @since BuddyPress (1.7.0)
72
- */
73
- public function __construct() {
74
- add_action( 'bp_setup_theme_compat', array( $this, 'is_blogs' ) );
75
- }
76
-
77
- /**
78
- * Are we looking at something that needs Blogs theme compatability?
79
- *
80
- * @since BuddyPress (1.7.0)
81
- */
82
- public function is_blogs() {
83
-
84
- // Bail if not looking at a group
85
- if ( ! bp_is_blogs_component() )
86
- return;
87
-
88
- // Bail if looking at a users sites
89
- if ( bp_is_user() )
90
- return;
91
-
92
- // Blog Directory
93
- if ( is_multisite() && ! bp_current_action() ) {
94
- bp_update_is_directory( true, 'blogs' );
95
-
96
- do_action( 'bp_blogs_screen_index' );
97
-
98
- add_filter( 'bp_get_buddypress_template', array( $this, 'directory_template_hierarchy' ) );
99
- add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
100
- add_filter( 'bp_replace_the_content', array( $this, 'directory_content' ) );
101
-
102
- // Create blog
103
- } elseif ( is_user_logged_in() && bp_blog_signup_enabled() ) {
104
- add_filter( 'bp_get_buddypress_template', array( $this, 'create_template_hierarchy' ) );
105
- add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'create_dummy_post' ) );
106
- add_filter( 'bp_replace_the_content', array( $this, 'create_content' ) );
107
- }
108
- }
109
-
110
- /** Directory *************************************************************/
111
-
112
- /**
113
- * Add template hierarchy to theme compat for the blog directory page.
114
- *
115
- * This is to mirror how WordPress has
116
- * {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
117
- *
118
- * @since BuddyPress (1.8.0)
119
- *
120
- * @param string $templates The templates from
121
- * bp_get_theme_compat_templates().
122
- * @return array $templates Array of custom templates to look for.
123
- */
124
- public function directory_template_hierarchy( $templates ) {
125
- // Setup our templates based on priority
126
- $new_templates = apply_filters( 'bp_template_hierarchy_blogs_create', array(
127
- 'blogs/index-directory.php'
128
- ) );
129
-
130
- // Merge new templates with existing stack
131
- // @see bp_get_theme_compat_templates()
132
- $templates = array_merge( (array) $new_templates, $templates );
133
-
134
- return $templates;
135
- }
136
-
137
- /**
138
- * Update the global $post with directory data.
139
- *
140
- * @since BuddyPress (1.7.0)
141
- */
142
- public function directory_dummy_post() {
143
-
144
- $title = apply_filters( 'bp_blogs_directory_header', __( 'Sites', 'buddypress' ) );
145
-
146
- bp_theme_compat_reset_post( array(
147
- 'ID' => 0,
148
- 'post_title' => $title,
149
- 'post_author' => 0,
150
- 'post_date' => 0,
151
- 'post_content' => '',
152
- 'post_type' => 'bp_blogs',
153
- 'post_status' => 'publish',
154
- 'is_page' => true,
155
- 'comment_status' => 'closed'
156
- ) );
157
- }
158
 
159
- /**
160
- * Filter the_content with the groups index template part.
161
- *
162
- * @since BuddyPress (1.7.0)
163
- */
164
- public function directory_content() {
165
- return bp_buffer_template_part( 'blogs/index', null, false );
166
- }
167
-
168
- /** Create ****************************************************************/
169
-
170
- /**
171
- * Add custom template hierarchy to theme compat for the blog create page.
172
- *
173
- * This is to mirror how WordPress has
174
- * {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
175
- *
176
- * @since BuddyPress (1.8.0)
177
- *
178
- * @param string $templates The templates from
179
- * bp_get_theme_compat_templates().
180
- * @return array $templates Array of custom templates to look for.
181
- */
182
- public function create_template_hierarchy( $templates ) {
183
- // Setup our templates based on priority
184
- $new_templates = apply_filters( 'bp_template_hierarchy_blogs_create', array(
185
- 'blogs/index-create.php'
186
- ) );
187
-
188
- // Merge new templates with existing stack
189
- // @see bp_get_theme_compat_templates()
190
- $templates = array_merge( (array) $new_templates, $templates );
191
-
192
- return $templates;
193
- }
194
-
195
- /**
196
- * Update the global $post with create screen data.
197
- *
198
- * @since BuddyPress (1.7.0)
199
- */
200
- public function create_dummy_post() {
201
-
202
- // Title based on ability to create blogs
203
- if ( is_user_logged_in() && bp_blog_signup_enabled() ) {
204
- $title = '<a class="button bp-title-button" href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ) . '">' . __( 'Sites', 'buddypress' ) . '</a>&nbsp;' . __( 'Create a Site', 'buddypress' );
205
- } else {
206
- $title = __( 'Sites', 'buddypress' );
207
- }
208
-
209
- bp_theme_compat_reset_post( array(
210
- 'ID' => 0,
211
- 'post_title' => $title,
212
- 'post_author' => 0,
213
- 'post_date' => 0,
214
- 'post_content' => '',
215
- 'post_type' => 'bp_group',
216
- 'post_status' => 'publish',
217
- 'is_page' => true,
218
- 'comment_status' => 'closed'
219
- ) );
220
- }
221
-
222
- /**
223
- * Filter the_content with the create screen template part.
224
- *
225
- * @since BuddyPress (1.7.0)
226
- */
227
- public function create_content() {
228
- return bp_buffer_template_part( 'blogs/create', null, false );
229
- }
230
- }
231
  new BP_Blogs_Theme_Compat();
1
  <?php
 
2
  /**
3
+ * BuddyPress Blogs Screens.
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsScreens
7
+ * @since 1.5.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ if ( ! buddypress()->do_autoload ) {
14
+ require dirname( __FILE__ ) . '/classes/class-bp-blogs-theme-compat.php';
15
+ }
16
 
17
  /**
18
  * Load the "My Blogs" screen.
21
  if ( !is_multisite() )
22
  return false;
23
 
24
+ /**
25
+ * Fires right before the loading of the My Blogs screen template file.
26
+ *
27
+ * @since 1.0.0
28
+ */
29
  do_action( 'bp_blogs_screen_my_blogs' );
30
 
31
  bp_core_load_template( apply_filters( 'bp_blogs_template_my_blogs', 'members/single/home' ) );
42
  if ( !is_user_logged_in() || !bp_blog_signup_enabled() )
43
  return false;
44
 
45
+ /**
46
+ * Fires right before the loading of the Create A Blog screen template file.
47
+ *
48
+ * @since 1.0.0
49
+ */
50
  do_action( 'bp_blogs_screen_create_a_blog' );
51
 
52
  bp_core_load_template( apply_filters( 'bp_blogs_template_create_a_blog', 'blogs/create' ) );
60
  if ( bp_is_blogs_directory() ) {
61
  bp_update_is_directory( true, 'blogs' );
62
 
63
+ /**
64
+ * Fires right before the loading of the top-level Blogs screen template file.
65
+ *
66
+ * @since 1.0.0
67
+ */
68
  do_action( 'bp_blogs_screen_index' );
69
 
70
  bp_core_load_template( apply_filters( 'bp_blogs_screen_index', 'blogs/index' ) );
72
  }
73
  add_action( 'bp_screens', 'bp_blogs_screen_index', 2 );
74
 
75
+ /** Theme Compatibility *******************************************************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  new BP_Blogs_Theme_Compat();
bp-blogs/bp-blogs-template.php CHANGED
@@ -1,21 +1,24 @@
1
  <?php
2
-
3
  /**
4
  * BuddyPress Blogs Template Tags.
5
  *
6
  * @package BuddyPress
7
  * @subpackage BlogsTemplate
 
8
  */
9
 
10
- // Exit if accessed directly
11
- if ( !defined( 'ABSPATH' ) ) exit;
 
 
 
 
12
 
13
  /**
14
  * Output the blogs component slug.
15
  *
16
- * @since BuddyPress (1.5.0)
17
  *
18
- * @uses bp_get_blogs_slug()
19
  */
20
  function bp_blogs_slug() {
21
  echo bp_get_blogs_slug();
@@ -23,20 +26,27 @@ function bp_blogs_slug() {
23
  /**
24
  * Return the blogs component slug.
25
  *
26
- * @since BuddyPress (1.5.0)
27
  *
28
  * @return string The 'blogs' slug.
29
  */
30
  function bp_get_blogs_slug() {
 
 
 
 
 
 
 
 
31
  return apply_filters( 'bp_get_blogs_slug', buddypress()->blogs->slug );
32
  }
33
 
34
  /**
35
  * Output the blogs component root slug.
36
  *
37
- * @since BuddyPress (1.5.0)
38
  *
39
- * @uses bp_get_blogs_root_slug()
40
  */
41
  function bp_blogs_root_slug() {
42
  echo bp_get_blogs_root_slug();
@@ -44,262 +54,50 @@ function bp_blogs_root_slug() {
44
  /**
45
  * Return the blogs component root slug.
46
  *
47
- * @since BuddyPress (1.5.0)
48
  *
49
  * @return string The 'blogs' root slug.
50
  */
51
  function bp_get_blogs_root_slug() {
 
 
 
 
 
 
 
 
52
  return apply_filters( 'bp_get_blogs_root_slug', buddypress()->blogs->root_slug );
53
  }
54
 
55
  /**
56
  * Output blog directory permalink.
57
  *
58
- * @since BuddyPress (1.5.0)
59
  *
60
- * @uses bp_get_blogs_directory_permalink()
61
  */
62
  function bp_blogs_directory_permalink() {
63
- echo bp_get_blogs_directory_permalink();
64
  }
65
  /**
66
  * Return blog directory permalink.
67
  *
68
- * @since BuddyPress (1.5.0)
 
69
  *
70
- * @uses apply_filters()
71
- * @uses trailingslashit()
72
- * @uses bp_get_root_domain()
73
- * @uses bp_get_blogs_root_slug()
74
  * @return string The URL of the Blogs directory.
75
  */
76
  function bp_get_blogs_directory_permalink() {
77
- return apply_filters( 'bp_get_blogs_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ) );
78
- }
79
-
80
- /**
81
- * The main blog template loop class.
82
- *
83
- * Responsible for loading a group of blogs into a loop for display.
84
- */
85
- class BP_Blogs_Template {
86
-
87
- /**
88
- * The loop iterator.
89
- *
90
- * @access public
91
- * @var int
92
- */
93
- var $current_blog = -1;
94
-
95
- /**
96
- * The number of blogs returned by the paged query.
97
- *
98
- * @access public
99
- * @var int
100
- */
101
- var $blog_count;
102
-
103
- /**
104
- * Array of blogs located by the query..
105
- *
106
- * @access public
107
- * @var array
108
- */
109
- var $blogs;
110
-
111
- /**
112
- * The blog object currently being iterated on.
113
- *
114
- * @access public
115
- * @var object
116
- */
117
- var $blog;
118
-
119
- /**
120
- * A flag for whether the loop is currently being iterated.
121
- *
122
- * @access public
123
- * @var bool
124
- */
125
- var $in_the_loop;
126
-
127
- /**
128
- * The page number being requested.
129
- *
130
- * @access public
131
- * @var public
132
- */
133
- var $pag_page;
134
-
135
- /**
136
- * The number of items being requested per page.
137
- *
138
- * @access public
139
- * @var public
140
- */
141
- var $pag_num;
142
-
143
- /**
144
- * An HTML string containing pagination links.
145
- *
146
- * @access public
147
- * @var string
148
- */
149
- var $pag_links;
150
-
151
- /**
152
- * The total number of blogs matching the query parameters.
153
- *
154
- * @access public
155
- * @var int
156
- */
157
- var $total_blog_count;
158
-
159
- /**
160
- * Constructor method.
161
- *
162
- * @see BP_Blogs_Blog::get() for a description of parameters.
163
- *
164
- * @param string $type See {@link BP_Blogs_Blog::get()}.
165
- * @param string $page See {@link BP_Blogs_Blog::get()}.
166
- * @param string $per_page See {@link BP_Blogs_Blog::get()}.
167
- * @param string $max See {@link BP_Blogs_Blog::get()}.
168
- * @param string $user_id See {@link BP_Blogs_Blog::get()}.
169
- * @param string $search_terms See {@link BP_Blogs_Blog::get()}.
170
- * @param string $page_arg The string used as a query parameter in
171
- * pagination links. Default: 'bpage'.
172
- * @param bool $update_meta_cache Whether to pre-fetch metadata for
173
- * queried blogs.
174
- * @param array $include_blog_ids Array of blog IDs to include.
175
- */
176
- function __construct( $type, $page, $per_page, $max, $user_id, $search_terms, $page_arg = 'bpage', $update_meta_cache = true, $include_blog_ids = false ) {
177
-
178
- $this->pag_page = isset( $_REQUEST[$page_arg] ) ? intval( $_REQUEST[$page_arg] ) : $page;
179
- $this->pag_num = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
180
-
181
- if ( isset( $_REQUEST['letter'] ) && '' != $_REQUEST['letter'] ) {
182
- $this->blogs = BP_Blogs_Blog::get_by_letter( $_REQUEST['letter'], $this->pag_num, $this->pag_page );
183
- } else {
184
- $this->blogs = bp_blogs_get_blogs( array(
185
- 'type' => $type,
186
- 'per_page' => $this->pag_num,
187
- 'page' => $this->pag_page,
188
- 'user_id' => $user_id,
189
- 'search_terms' => $search_terms,
190
- 'update_meta_cache' => $update_meta_cache,
191
- 'include_blog_ids' => $include_blog_ids,
192
- ) );
193
- }
194
-
195
- if ( !$max || $max >= (int) $this->blogs['total'] )
196
- $this->total_blog_count = (int) $this->blogs['total'];
197
- else
198
- $this->total_blog_count = (int) $max;
199
-
200
- $this->blogs = $this->blogs['blogs'];
201
-
202
- if ( $max ) {
203
- if ( $max >= count($this->blogs) ) {
204
- $this->blog_count = count( $this->blogs );
205
- } else {
206
- $this->blog_count = (int) $max;
207
- }
208
- } else {
209
- $this->blog_count = count( $this->blogs );
210
- }
211
-
212
- if ( (int) $this->total_blog_count && (int) $this->pag_num ) {
213
- $this->pag_links = paginate_links( array(
214
- 'base' => add_query_arg( $page_arg, '%#%' ),
215
- 'format' => '',
216
- 'total' => ceil( (int) $this->total_blog_count / (int) $this->pag_num ),
217
- 'current' => (int) $this->pag_page,
218
- 'prev_text' => _x( '&larr;', 'Blog pagination previous text', 'buddypress' ),
219
- 'next_text' => _x( '&rarr;', 'Blog pagination next text', 'buddypress' ),
220
- 'mid_size' => 1
221
- ) );
222
- }
223
- }
224
-
225
- /**
226
- * Whether there are blogs available in the loop.
227
- *
228
- * @see bp_has_blogs()
229
- *
230
- * @return bool True if there are items in the loop, otherwise false.
231
- */
232
- function has_blogs() {
233
- if ( $this->blog_count )
234
- return true;
235
-
236
- return false;
237
- }
238
 
239
- /**
240
- * Set up the next blog and iterate index.
241
- *
242
- * @return object The next blog to iterate over.
243
- */
244
- function next_blog() {
245
- $this->current_blog++;
246
- $this->blog = $this->blogs[$this->current_blog];
247
-
248
- return $this->blog;
249
- }
250
-
251
- /**
252
- * Rewind the blogs and reset blog index.
253
- */
254
- function rewind_blogs() {
255
- $this->current_blog = -1;
256
- if ( $this->blog_count > 0 ) {
257
- $this->blog = $this->blogs[0];
258
- }
259
- }
260
-
261
- /**
262
- * Whether there are blogs left in the loop to iterate over.
263
- *
264
- * This method is used by {@link bp_blogs()} as part of the while loop
265
- * that controls iteration inside the blogs loop, eg:
266
- * while ( bp_blogs() ) { ...
267
- *
268
- * @see bp_blogs()
269
- *
270
- * @return bool True if there are more blogs to show, otherwise false.
271
- */
272
- function blogs() {
273
- if ( $this->current_blog + 1 < $this->blog_count ) {
274
- return true;
275
- } elseif ( $this->current_blog + 1 == $this->blog_count ) {
276
- do_action('blog_loop_end');
277
- // Do some cleaning up after the loop
278
- $this->rewind_blogs();
279
- }
280
-
281
- $this->in_the_loop = false;
282
- return false;
283
- }
284
-
285
- /**
286
- * Set up the current blog inside the loop.
287
- *
288
- * Used by {@link bp_the_blog()} to set up the current blog data while
289
- * looping, so that template tags used during that iteration make
290
- * reference to the current blog.
291
- *
292
- * @see bp_the_blog()
293
- */
294
- function the_blog() {
295
-
296
- $this->in_the_loop = true;
297
- $this->blog = $this->next_blog();
298
-
299
- if ( 0 == $this->current_blog ) // loop has just started
300
- do_action('blog_loop_start');
301
  }
302
- }
303
 
304
  /**
305
  * Rewind the blogs and reset blog index.
@@ -319,7 +117,7 @@ function bp_rewind_blogs() {
319
  *
320
  * @global object $blogs_template {@link BP_Blogs_Template}
321
  *
322
- * @param array $args {
323
  * Arguments for limiting the contents of the blogs loop. Most arguments
324
  * are in the same format as {@link BP_Blogs_Blog::get()}. However, because
325
  * the format of the arguments accepted here differs in a number of ways,
@@ -329,72 +127,68 @@ function bp_rewind_blogs() {
329
  * Arguments can be passed as an associative array, or as a URL query
330
  * string (eg, 'user_id=4&per_page=3').
331
  *
332
- * @type int $page Which page of results to fetch. Using page=1 without
333
- * per_page will result in no pagination. Default: 1.
334
- * @type int|bool $per_page Number of results per page. Default: 20.
335
- * @type string $page_arg The string used as a query parameter in
336
- * pagination links. Default: 'bpage'.
337
- * @type int|bool $max Maximum number of results to return.
338
- * Default: false (unlimited).
339
- * @type string $type The order in which results should be fetched.
340
- * 'active', 'alphabetical', 'newest', or 'random'.
341
- * @type array $include_blog_ids Array of blog IDs to limit results to.
342
- * @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.
343
- * @type string $search_terms Limit results by a search term. Default: null.
344
- * @type int $user_id The ID of the user whose blogs should be retrieved.
345
- * When viewing a user profile page, 'user_id' defaults to the ID of
346
- * the displayed user. Otherwise the default is false.
 
347
  * }
348
  * @return bool Returns true when blogs are found, otherwise false.
349
  */
350
  function bp_has_blogs( $args = '' ) {
351
  global $blogs_template;
352
 
353
- /***
354
- * Set the defaults based on the current page. Any of these will be overridden
355
- * if arguments are directly passed into the loop. Custom plugins should always
356
- * pass their parameters directly to the loop.
357
- */
358
- $type = 'active';
359
- $user_id = 0;
360
- $search_terms = null;
361
-
362
- // User filtering
363
- if ( bp_displayed_user_id() )
364
- $user_id = bp_displayed_user_id();
365
 
366
- $defaults = array(
367
- 'type' => $type,
 
 
368
  'page' => 1,
369
  'per_page' => 20,
370
  'max' => false,
371
-
372
- 'page_arg' => 'bpage', // See https://buddypress.trac.wordpress.org/ticket/3679
373
-
374
- 'user_id' => $user_id, // Pass a user_id to limit to only blogs this user has higher than subscriber access to
375
  'include_blog_ids' => false,
376
- 'search_terms' => $search_terms, // Pass search terms to filter on the blog title or description.
377
- 'update_meta_cache' => true,
378
- );
379
-
380
- $r = bp_parse_args( $args, $defaults, 'has_blogs' );
381
- extract( $r );
382
-
383
- if ( is_null( $search_terms ) ) {
384
- if ( isset( $_REQUEST['s'] ) && !empty( $_REQUEST['s'] ) )
385
- $search_terms = $_REQUEST['s'];
386
- else
387
- $search_terms = false;
388
- }
389
 
390
- if ( $max ) {
391
- if ( $per_page > $max ) {
392
- $per_page = $max;
393
- }
394
  }
395
 
396
- $blogs_template = new BP_Blogs_Template( $type, $page, $per_page, $max, $user_id, $search_terms, $page_arg, $update_meta_cache, $include_blog_ids );
397
- return apply_filters( 'bp_has_blogs', $blogs_template->has_blogs(), $blogs_template );
 
 
 
 
 
 
 
 
 
 
 
398
  }
399
 
400
  /**
@@ -426,9 +220,20 @@ function bp_the_blog() {
426
  /**
427
  * Output the blogs pagination count.
428
  *
429
- * @global object $blogs_template {@link BP_Blogs_Template}
430
  */
431
  function bp_blogs_pagination_count() {
 
 
 
 
 
 
 
 
 
 
 
432
  global $blogs_template;
433
 
434
  $start_num = intval( ( $blogs_template->pag_page - 1 ) * $blogs_template->pag_num ) + 1;
@@ -436,7 +241,23 @@ function bp_blogs_pagination_count() {
436
  $to_num = bp_core_number_format( ( $start_num + ( $blogs_template->pag_num - 1 ) > $blogs_template->total_blog_count ) ? $blogs_template->total_blog_count : $start_num + ( $blogs_template->pag_num - 1 ) );
437
  $total = bp_core_number_format( $blogs_template->total_blog_count );
438
 
439
- echo sprintf( _n( 'Viewing site %1$s to %2$s (of %3$s site)', 'Viewing site %1$s to %2$s (of %3$s sites)', $total, 'buddypress' ), $from_num, $to_num, $total );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  }
441
 
442
  /**
@@ -455,6 +276,13 @@ function bp_blogs_pagination_links() {
455
  function bp_get_blogs_pagination_links() {
456
  global $blogs_template;
457
 
 
 
 
 
 
 
 
458
  return apply_filters( 'bp_get_blogs_pagination_links', $blogs_template->pag_links );
459
  }
460
 
@@ -463,7 +291,7 @@ function bp_blogs_pagination_links() {
463
  *
464
  * @see bp_get_blog_avatar() for description of arguments.
465
  *
466
- * @param array $args See {@link bp_get_blog_avatar()}.
467
  */
468
  function bp_blog_avatar( $args = '' ) {
469
  echo bp_get_blog_avatar( $args );
@@ -474,41 +302,122 @@ function bp_blog_avatar( $args = '' ) {
474
  * At the moment, blog avatars are simply the user avatars of the blog
475
  * admin. Filter 'bp_get_blog_avatar_' . $blog_id to customize.
476
  *
 
 
477
  * @see bp_core_fetch_avatar() For a description of arguments and
478
  * return values.
479
  *
480
- * @param array $args {
481
  * Arguments are listed here with an explanation of their defaults.
482
  * For more information about the arguments, see
483
  * {@link bp_core_fetch_avatar()}.
484
- * @type string $alt Default: 'Profile picture of site author
485
- * [user name]'.
486
- * @type string $class Default: 'avatar'.
487
- * @type string $type Default: 'full'.
488
- * @type int|bool $width Default: false.
489
- * @type int|bool $height Default: false.
490
- * @type bool $id Currently unused.
491
- * @type bool $no_grav Default: false.
492
  * }
493
  * @return string User avatar string.
494
  */
495
  function bp_get_blog_avatar( $args = '' ) {
496
  global $blogs_template;
497
 
498
- $defaults = array(
 
 
 
 
 
 
 
 
 
499
  'type' => 'full',
500
  'width' => false,
501
  'height' => false,
502
  'class' => 'avatar',
 
503
  'id' => false,
504
- 'alt' => sprintf( __( 'Profile picture of site author %s', 'buddypress' ), bp_core_get_user_displayname( $blogs_template->blog->a
1
  <?php
 
2
  /**
3
  * BuddyPress Blogs Template Tags.
4
  *
5
  * @package BuddyPress
6
  * @subpackage BlogsTemplate
7
+ * @since 1.5.0
8
  */
9
 
10
+ // Exit if accessed directly.
11
+ defined( 'ABSPATH' ) || exit;
12
+
13
+ if ( ! buddypress()->do_autoload ) {
14
+ require dirname( __FILE__ ) . '/classes/class-bp-blogs-template.php';
15
+ }
16
 
17
  /**
18
  * Output the blogs component slug.
19
  *
20
+ * @since 1.5.0
21
  *
 
22
  */
23
  function bp_blogs_slug() {
24
  echo bp_get_blogs_slug();
26
  /**
27
  * Return the blogs component slug.
28
  *
29
+ * @since 1.5.0
30
  *
31
  * @return string The 'blogs' slug.
32
  */
33
  function bp_get_blogs_slug() {
34
+
35
+ /**
36
+ * Filters the blogs component slug.
37
+ *
38
+ * @since 1.5.0
39
+ *
40
+ * @param string $slug Slug for the blogs component.
41
+ */
42
  return apply_filters( 'bp_get_blogs_slug', buddypress()->blogs->slug );
43
  }
44
 
45
  /**
46
  * Output the blogs component root slug.
47
  *
48
+ * @since 1.5.0
49
  *
 
50
  */
51
  function bp_blogs_root_slug() {
52
  echo bp_get_blogs_root_slug();
54
  /**
55
  * Return the blogs component root slug.
56
  *
57
+ * @since 1.5.0
58
  *
59
  * @return string The 'blogs' root slug.
60
  */
61
  function bp_get_blogs_root_slug() {
62
+
63
+ /**
64
+ * Filters the blogs component root slug.
65
+ *
66
+ * @since 1.5.0
67
+ *
68
+ * @param string $root_slug Root slug for the blogs component.
69
+ */
70
  return apply_filters( 'bp_get_blogs_root_slug', buddypress()->blogs->root_slug );
71
  }
72
 
73
  /**
74
  * Output blog directory permalink.
75
  *
76
+ * @since 1.5.0
77
  *
 
78
  */
79
  function bp_blogs_directory_permalink() {
80
+ echo esc_url( bp_get_blogs_directory_permalink() );
81
  }
82
  /**
83
  * Return blog directory permalink.
84
  *
85
+ * @since 1.5.0
86
+ *
87
  *
 
 
 
 
88
  * @return string The URL of the Blogs directory.
89
  */
90
  function bp_get_blogs_directory_permalink() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
+ /**
93
+ * Filters the blog directory permalink.
94
+ *
95
+ * @since 1.5.0
96
+ *
97
+ * @param string $value Permalink URL for the blog directory.
98
+ */
99
+ return apply_filters( 'bp_get_blogs_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  }
 
101
 
102
  /**
103
  * Rewind the blogs and reset blog index.
117
  *
118
  * @global object $blogs_template {@link BP_Blogs_Template}
119
  *
120
+ * @param array|string $args {
121
  * Arguments for limiting the contents of the blogs loop. Most arguments
122
  * are in the same format as {@link BP_Blogs_Blog::get()}. However, because
123
  * the format of the arguments accepted here differs in a number of ways,
127
  * Arguments can be passed as an associative array, or as a URL query
128
  * string (eg, 'user_id=4&per_page=3').
129
  *
130
+ * @type int $page Which page of results to fetch. Using page=1 without
131
+ * per_page will result in no pagination. Default: 1.
132
+ * @type int|bool $per_page Number of results per page. Default: 20.
133
+ * @type string $page_arg The string used as a query parameter in
134
+ * pagination links. Default: 'bpage'.
135
+ * @type int|bool $max Maximum number of results to return.
136
+ * Default: false (unlimited).
137
+ * @type string $type The order in which results should be fetched.
138
+ * 'active', 'alphabetical', 'newest', or 'random'.
139
+ * @type array $include_blog_ids Array of blog IDs to limit results to.
140
+ * @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.
141
+ * @type string $search_terms Limit results by a search term. Default: the value of `$_REQUEST['s']` or
142
+ * `$_REQUEST['sites_search']`, if present.
143
+ * @type int $user_id The ID of the user whose blogs should be retrieved.
144
+ * When viewing a user profile page, 'user_id' defaults to the
145
+ * ID of the displayed user. Otherwise the default is false.
146
  * }
147
  * @return bool Returns true when blogs are found, otherwise false.
148
  */
149
  function bp_has_blogs( $args = '' ) {
150
  global $blogs_template;
151
 
152
+ // Check for and use search terms.
153
+ $search_terms_default = false;
154
+ $search_query_arg = bp_core_get_component_search_query_arg( 'blogs' );
155
+ if ( ! empty( $_REQUEST[ $search_query_arg ] ) ) {
156
+ $search_terms_default = stripslashes( $_REQUEST[ $search_query_arg ] );
157
+ } elseif ( ! empty( $_REQUEST['s'] ) ) {
158
+ $search_terms_default = stripslashes( $_REQUEST['s'] );
159
+ }
 
 
 
 
160
 
161
+ // Parse arguments.
162
+ $r = bp_parse_args( $args, array(
163
+ 'type' => 'active',
164
+ 'page_arg' => 'bpage', // See https://buddypress.trac.wordpress.org/ticket/3679.
165
  'page' => 1,
166
  'per_page' => 20,
167
  'max' => false,
168
+ 'user_id' => bp_displayed_user_id(), // Pass a user_id to limit to only blogs this user is a member of.
 
 
 
169
  'include_blog_ids' => false,
170
+ 'search_terms' => $search_terms_default,
171
+ 'update_meta_cache' => true
172
+ ), 'has_blogs' );
 
 
 
 
 
 
 
 
 
 
173
 
174
+ // Set per_page to maximum if max is enforced.
175
+ if ( ! empty( $r['max'] ) && ( (int) $r['per_page'] > (int) $r['max'] ) ) {
176
+ $r['per_page'] = (int) $r['max'];
 
177
  }
178
 
179
+ // Get the blogs.
180
+ $blogs_template = new BP_Blogs_Template( $r['type'], $r['page'], $r['per_page'], $r['max'], $r['user_id'], $r['search_terms'], $r['page_arg'], $r['update_meta_cache'], $r['include_blog_ids'] );
181
+
182
+ /**
183
+ * Filters whether or not there are blogs to list.
184
+ *
185
+ * @since 1.1.0
186
+ *
187
+ * @param bool $value Whether or not there are blogs to list.
188
+ * @param BP_Blogs_Template $blogs_template Current blogs template object.
189
+ * @param array $r Parsed arguments used in blogs template query.
190
+ */
191
+ return apply_filters( 'bp_has_blogs', $blogs_template->has_blogs(), $blogs_template, $r );
192
  }
193
 
194
  /**
220
  /**
221
  * Output the blogs pagination count.
222
  *
223
+ * @since 1.0.0
224
  */
225
  function bp_blogs_pagination_count() {
226
+ echo bp_get_blogs_pagination_count();
227
+ }
228
+
229
+ /**
230
+ * Get the blogs pagination count.
231
+ *
232
+ * @since 2.7.0
233
+ *
234
+ * @global object $blogs_template {@link BP_Blogs_Template}
235
+ */
236
+ function bp_get_blogs_pagination_count() {
237
  global $blogs_template;
238
 
239
  $start_num = intval( ( $blogs_template->pag_page - 1 ) * $blogs_template->pag_num ) + 1;
241
  $to_num = bp_core_number_format( ( $start_num + ( $blogs_template->pag_num - 1 ) > $blogs_template->total_blog_count ) ? $blogs_template->total_blog_count : $start_num + ( $blogs_template->pag_num - 1 ) );
242
  $total = bp_core_number_format( $blogs_template->total_blog_count );
243
 
244
+ if ( 1 == $blogs_template->total_blog_count ) {
245
+ $message = __( 'Viewing 1 site', 'buddypress' );
246
+ } else {
247
+ $message = sprintf( _n( 'Viewing %1$s - %2$s of %3$s site', 'Viewing %1$s - %2$s of %3$s sites', $blogs_template->total_blog_count, 'buddypress' ), $from_num, $to_num, $total );
248
+ }
249
+
250
+ /**
251
+ * Filters the "Viewing x-y of z blogs" pagination message.
252
+ *
253
+ * @since 2.7.0
254
+ *
255
+ * @param string $message "Viewing x-y of z blogs" text.
256
+ * @param string $from_num Total amount for the low value in the range.
257
+ * @param string $to_num Total amount for the high value in the range.
258
+ * @param string $total Total amount of blogs found.
259
+ */
260
+ return apply_filters( 'bp_get_blogs_pagination_count', $message, $from_num, $to_num, $total );
261
  }
262
 
263
  /**
276
  function bp_get_blogs_pagination_links() {
277
  global $blogs_template;
278
 
279
+ /**
280
+ * Filters the blogs pagination links.
281
+ *
282
+ * @since 1.0.0
283
+ *
284
+ * @param string $pag_links HTML pagination links.
285
+ */
286
  return apply_filters( 'bp_get_blogs_pagination_links', $blogs_template->pag_links );
287
  }
288
 
291
  *
292
  * @see bp_get_blog_avatar() for description of arguments.
293
  *
294
+ * @param array|string $args See {@link bp_get_blog_avatar()}.
295
  */
296
  function bp_blog_avatar( $args = '' ) {
297
  echo bp_get_blog_avatar( $args );
302
  * At the moment, blog avatars are simply the user avatars of the blog
303
  * admin. Filter 'bp_get_blog_avatar_' . $blog_id to customize.
304
  *
305
+ * @since 2.4.0 Introduced `$title` argument.
306
+ *
307
  * @see bp_core_fetch_avatar() For a description of arguments and
308
  * return values.
309
  *
310
+ * @param array|string $args {
311
  * Arguments are listed here with an explanation of their defaults.
312
  * For more information about the arguments, see
313
  * {@link bp_core_fetch_avatar()}.
314
+ * @type string $alt Default: 'Profile picture of site author [user name]'.
315
+ * @type string $class Default: 'avatar'.
316
+ * @type string $title Default: 'Profile picture of site author [user name]'.
317
+ * @type string $type Default: 'full'.
318
+ * @type int|bool $width Default: false.
319
+ * @type int|bool $height Default: false.
320
+ * @type bool $id Currently unused.
321
+ * @type bool $no_grav Default: true.
322
  * }
323
  * @return string User avatar string.
324
  */
325
  function bp_get_blog_avatar( $args = '' ) {
326
  global $blogs_template;
327
 
328
+ // Bail if avatars are turned off
329
+ // @todo Should we maybe still filter this?
330
+ if ( ! buddypress()->avatar->show_avatars ) {
331
+ return false;
332
+ }
333
+
334
+ $author_displayname = bp_core_get_user_displayname( $blogs_template->blog->admin_user_id );
335
+
336
+ // Parse the arguments.
337
+ $r = bp_parse_args( $args, array(
338
  'type' => 'full',
339
  'width' => false,
340
  'height' => false,
341
  'class' => 'avatar',
342
+ 'title' => sprintf( __( 'Profile picture of site author %s', 'buddypress' ), esc_attr( $author_displayname ) ),
343
  'id' => false,