Skip to content

Commit

Permalink
improve federated comments (Automattic#645)
Browse files Browse the repository at this point in the history
* fix some times broken reply context

* revert changes

* add a filter to finally verify if an activity should be send or not

* better local comment handling

do not federate local only comments (fix Automattic#652) and hide "reply" link for federated comments

* show JSON only for comments that should be federated!

* fix parent_comment handling

* show external id if exists

* disable "edit comments" for federated comments

* some more doc

* added tests

* fix Automattic#658

* allow custom reply link!

* some restructurings

* this will be only a minor release

* version bump

* mark WordPress object as federated

* fix content filter issue!

fixes https://wordpress.org/support/topic/yasr-ratings-appear-on-comments-on-mastodon/

* add custom filter

thanks @janboddez for the idea Automattic#645 (comment)

* optimize code a bit

* consts to enable/disable incoming/outgoing interactions

see https://wordpress.org/support/topic/how-to-suppress-user-comments-from-feed/

* rename state

* cleanup federation check

* fix markdown

* better handling of Create/Update/Delete

* update check
  • Loading branch information
pfefferle authored Feb 1, 2024
1 parent 484cc56 commit 1fc6869
Show file tree
Hide file tree
Showing 13 changed files with 767 additions and 138 deletions.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
**Tags:** OStatus, fediverse, activitypub, activitystream
**Requires at least:** 5.5
**Tested up to:** 6.4
**Stable tag:** 2.0.1
**Stable tag:** 2.0.2
**Requires PHP:** 5.6
**License:** MIT
**License URI:** http://opensource.org/licenses/MIT
Expand Down Expand Up @@ -105,6 +105,23 @@ Where 'blog' is the path to the subdirectory at which your blog resides.

In that case you don't need the redirect, because the index.php will take care of that.

### Constants ###

The plugin uses PHP Constants to enable, disable or change its default behaviour. Please use them with caution and only if you know what you are doing.

* `ACTIVITYPUB_REST_NAMESPACE` - Change the default Namespace of the REST endpoint. Default: `activitypub/1.0`.
* `ACTIVITYPUB_EXCERPT_LENGTH` - Change the length of the Excerpt. Default: `400`.
* `ACTIVITYPUB_SHOW_PLUGIN_RECOMMENDATIONS` - show plugin recommendations in the ActivityPub settings. Default: `true`.
* `ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS` - Change the number of attachments, that should be federated. Default: `3`.
* `ACTIVITYPUB_HASHTAGS_REGEXP` - Change the default regex to detect hashtext in a text. Default: `(?:(?<=\s)|(?<=<p>)|(?<=<br>)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))`.
* `ACTIVITYPUB_USERNAME_REGEXP` - Change the default regex to detect @-replies in a text. Default: `(?:([A-Za-z0-9\._-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))`.
* `ACTIVITYPUB_CUSTOM_POST_CONTENT` - Change the default template for Activities. Default: `<strong>[ap_title]</strong>\n\n[ap_content]\n\n[ap_hashtags]\n\n[ap_shortlink]`.
* `ACTIVITYPUB_AUTHORIZED_FETCH` - Enable AUTHORIZED_FETCH. Default: `false`.
* `ACTIVITYPUB_DISABLE_REWRITES` - Disable auto generation of `mod_rewrite` rules. Default: `false`.
* `ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS` - Block incoming replies/comments/likes. Default: `false`.
* `ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS` - Disable outgoing replies/comments/likes. Default: `false`.
* `ACTIVITYPUB_SHARED_INBOX_FEATURE` - Enable the shared inbox. Default: `false`.

### Where can you manage your followers? ###

If you have activated the blog user, you will find the list of his followers in the settings under `/wp-admin/options-general.php?page=activitypub&tab=followers`.
Expand All @@ -117,6 +134,11 @@ For reasons of data protection, it is not possible to see the followers of other

Project maintained on GitHub at [automattic/wordpress-activitypub](https://github.com/automattic/wordpress-activitypub).

### 2.0.2 ###

* Fixed: Some Federated Comment improvements
* Fixed: Remove old/abandoned Crons

### 2.0.1 ###

* Fixed: Comment `Update` Federation
Expand Down
5 changes: 4 additions & 1 deletion activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: ActivityPub
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
* Version: 2.0.1
* Version: 2.0.2
* Author: Matthias Pfefferle & Automattic
* Author URI: https://automattic.com/
* License: MIT
Expand Down Expand Up @@ -33,6 +33,8 @@
\defined( 'ACTIVITYPUB_CUSTOM_POST_CONTENT' ) || \define( 'ACTIVITYPUB_CUSTOM_POST_CONTENT', "<strong>[ap_title]</strong>\n\n[ap_content]\n\n[ap_hashtags]\n\n[ap_shortlink]" );
\defined( 'ACTIVITYPUB_AUTHORIZED_FETCH' ) || \define( 'ACTIVITYPUB_AUTHORIZED_FETCH', false );
\defined( 'ACTIVITYPUB_DISABLE_REWRITES' ) || \define( 'ACTIVITYPUB_DISABLE_REWRITES', false );
\defined( 'ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS' ) || \define( 'ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS', false );
\defined( 'ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS' ) || \define( 'ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS', false );
\defined( 'ACTIVITYPUB_SHARED_INBOX_FEATURE' ) || \define( 'ACTIVITYPUB_SHARED_INBOX_FEATURE', false );

\define( 'ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
Expand Down Expand Up @@ -73,6 +75,7 @@ function plugin_init() {
\add_action( 'init', array( __NAMESPACE__ . '\Mention', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Health_Check', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Scheduler', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Comment', 'init' ) );

if ( site_supports_blocks() ) {
\add_action( 'init', array( __NAMESPACE__ . '\Blocks', 'init' ) );
Expand Down
21 changes: 15 additions & 6 deletions includes/class-activity-dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use function Activitypub\is_single_user;
use function Activitypub\is_user_disabled;
use function Activitypub\safe_remote_post;
use function Activitypub\mark_wp_object_as_federated;

/**
* ActivityPub Activity_Dispatcher Class
Expand Down Expand Up @@ -77,7 +78,7 @@ public static function send_activity( $wp_object, $type, $user_id = null ) {

$activity = $transformer->to_activity( $type );

self::send_activity_to_inboxes( $activity, $user_id );
self::send_activity_to_followers( $activity, $user_id, $wp_object );
}

/**
Expand All @@ -103,7 +104,7 @@ public static function send_announce( $wp_object, $type ) {
$user_id = $transformer->get_wp_user_id();
$activity = $transformer->to_activity( 'Announce' );

self::send_activity_to_inboxes( $activity, $user_id );
self::send_activity_to_followers( $activity, $user_id, $wp_object );
}

/**
Expand All @@ -130,18 +131,24 @@ public static function send_profile_update( $user_id ) {
$activity->set_to( 'https://www.w3.org/ns/activitystreams#Public' );

// send the update
self::send_activity_to_inboxes( $activity, $user_id );
self::send_activity_to_followers( $activity, $user_id, $user );
}

/**
* Send an Activity to all followers and mentioned users.
*
* @param Activity $activity The ActivityPub Activity.
* @param int $user_id The user ID.
* @param Activity $activity The ActivityPub Activity.
* @param int $user_id The user ID.
* @param WP_User|WP_Post|WP_Comment $wp_object The WordPress object.
*
* @return void
*/
private static function send_activity_to_inboxes( $activity, $user_id ) {
private static function send_activity_to_followers( $activity, $user_id, $wp_object ) {
// check if the Activity should be send to the followers
if ( ! apply_filters( 'activitypub_send_activity_to_followers', true, $activity, $user_id, $wp_object ) ) {
return;
}

$follower_inboxes = Followers::get_inboxes( $user_id );

$mentioned_inboxes = array();
Expand All @@ -162,5 +169,7 @@ private static function send_activity_to_inboxes( $activity, $user_id ) {
foreach ( $inboxes as $inbox ) {
safe_remote_post( $inbox, $json, $user_id );
}

mark_wp_object_as_federated( $wp_object );
}
}
51 changes: 4 additions & 47 deletions includes/class-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
use Activitypub\Collection\Users;
use Activitypub\Collection\Followers;

use function Activitypub\sanitize_url;
use function Activitypub\is_comment;
use function Activitypub\sanitize_url;
use function Activitypub\is_local_comment;
use function Activitypub\is_activitypub_request;
use function Activitypub\should_comment_be_federated;

/**
* ActivityPub Class
Expand All @@ -24,7 +26,6 @@ public static function init() {
\add_action( 'template_redirect', array( self::class, 'template_redirect' ) );
\add_filter( 'query_vars', array( self::class, 'add_query_vars' ) );
\add_filter( 'pre_get_avatar_data', array( self::class, 'pre_get_avatar_data' ), 11, 2 );
\add_filter( 'get_comment_link', array( self::class, 'remote_comment_link' ), 11, 3 );

// Add support for ActivityPub to custom post types
$post_types = \get_option( 'activitypub_support_post_types', array( 'post' ) ) ? \get_option( 'activitypub_support_post_types', array( 'post' ) ) : array();
Expand All @@ -42,8 +43,6 @@ public static function init() {

\add_action( 'in_plugin_update_message-' . ACTIVITYPUB_PLUGIN_BASENAME, array( self::class, 'plugin_update_message' ) );

\add_filter( 'comment_class', array( self::class, 'comment_class' ), 10, 3 );

// register several post_types
self::register_post_types();
}
Expand Down Expand Up @@ -149,7 +148,7 @@ public static function template_redirect() {
}

// stop if it's not an ActivityPub comment
if ( is_activitypub_request() && $comment->user_id ) {
if ( is_activitypub_request() && ! is_local_comment( $comment ) ) {
return;
}

Expand Down Expand Up @@ -230,30 +229,6 @@ public static function get_avatar_url( $comment ) {
return \get_comment_meta( $comment->comment_ID, 'avatar_url', true );
}

/**
* Link remote comments to source url.
*
* @param string $comment_link
* @param object|WP_Comment $comment
*
* @return string $url
*/
public static function remote_comment_link( $comment_link, $comment ) {
if ( ! $comment || is_admin() ) {
return $comment_link;
}

$comment_meta = \get_comment_meta( $comment->comment_ID );

if ( ! empty( $comment_meta['source_url'][0] ) ) {
return $comment_meta['source_url'][0];
} elseif ( ! empty( $comment_meta['source_id'][0] ) ) {
return $comment_meta['source_id'][0];
}

return $comment_link;
}

/**
* Store permalink in meta, to send delete Activity.
*
Expand Down Expand Up @@ -462,22 +437,4 @@ private static function register_post_types() {

\do_action( 'activitypub_after_register_post_type' );
}

/**
* Filters the CSS classes to add an ActivityPub class.
*
* @param string[] $classes An array of comment classes.
* @param string[] $css_class An array of additional classes added to the list.
* @param string $comment_id The comment ID as a numeric string.
*
* @return string[] An array of classes.
*/
public static function comment_class( $classes, $css_class, $comment_id ) {
// check if ActivityPub comment
if ( 'activitypub' === get_comment_meta( $comment_id, 'protocol', true ) ) {
$classes[] = 'activitypub-comment';
}

return $classes;
}
}
43 changes: 43 additions & 0 deletions includes/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
use WP_User_Query;
use Activitypub\Model\Blog_User;

use function Activitypub\is_user_disabled;
use function Activitypub\was_comment_received;
use function Activitypub\is_comment_federatable;

/**
* ActivityPub Admin Class
*
Expand All @@ -16,9 +20,11 @@ class Admin {
public static function init() {
\add_action( 'admin_menu', array( self::class, 'admin_menu' ) );
\add_action( 'admin_init', array( self::class, 'register_settings' ) );
\add_action( 'load-comment.php', array( self::class, 'edit_comment' ) );
\add_action( 'personal_options_update', array( self::class, 'save_user_description' ) );
\add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_scripts' ) );
\add_action( 'admin_notices', array( self::class, 'admin_notices' ) );
\add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 );

if ( ! is_user_disabled( get_current_user_id() ) ) {
\add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
Expand Down Expand Up @@ -304,4 +310,41 @@ public static function enqueue_scripts( $hook_suffix ) {
wp_enqueue_script( 'activitypub-admin-styles', plugins_url( 'assets/js/activitypub-admin.js', ACTIVITYPUB_PLUGIN_FILE ), array( 'jquery' ), '1.0.0', false );
}
}

/**
* Hook into the edit_comment functionality
*
* * Disable the edit_comment capability for federated comments.
*
* @return void
*/
public static function edit_comment() {
// Disable the edit_comment capability for federated comments.
\add_filter(
'user_has_cap',
function ( $allcaps, $caps, $arg ) {
if ( 'edit_comment' !== $arg[0] ) {
return $allcaps;
}

if ( was_comment_received( $arg[2] ) ) {
return false;
}

return $allcaps;
},
1,
3
);
}

public static function comment_row_actions( $actions, $comment ) {
if ( was_comment_received( $comment ) ) {
unset( $actions['edit'] );
unset( $actions['reply'] );
unset( $actions['quickedit'] );
}

return $actions;
}
}
Loading

0 comments on commit 1fc6869

Please sign in to comment.