From e015da7f8f258d193ce1950e14be3123a44aee5a Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 01:42:15 +0100 Subject: [PATCH 01/26] optimize publishing --- includes/class-activity-dispatcher.php | 78 +++++++++----------------- includes/class-activitypub.php | 2 +- includes/functions.php | 5 +- includes/model/class-activity.php | 17 +++++- includes/model/class-post.php | 2 +- 5 files changed, 48 insertions(+), 56 deletions(-) diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index f8abd38..09fca79 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -13,7 +13,10 @@ class Activity_Dispatcher { * Initialize the class, registering WordPress hooks. */ public static function init() { - \add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_post_activity' ) ); + // legacy + \add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_create_activity' ) ); + + \add_action( 'activitypub_send_create_activity', array( '\Activitypub\Activity_Dispatcher', 'send_create_activity' ) ); \add_action( 'activitypub_send_update_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_activity' ) ); \add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity' ) ); } @@ -23,38 +26,8 @@ class Activity_Dispatcher { * * @param \Activitypub\Model\Post $activitypub_post */ - public static function send_post_activity( Model\Post $activitypub_post ) { - // get latest version of post - $user_id = $activitypub_post->get_post_author(); - - $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); - $activitypub_activity->from_post( $activitypub_post ); - - $inboxes = \Activitypub\get_follower_inboxes( $user_id ); - - $followers_url = \get_rest_url( null, '/activitypub/1.0/users/' . intval( $user_id ) . '/followers' ); - foreach ( $activitypub_activity->get_cc() as $cc ) { - if ( $cc === $followers_url ) { - continue; - } - $inbox = \Activitypub\get_inbox_by_actor( $cc ); - if ( ! $inbox || \is_wp_error( $inbox ) ) { - continue; - } - // init array if empty - if ( ! isset( $inboxes[ $inbox ] ) ) { - $inboxes[ $inbox ] = array(); - } - $inboxes[ $inbox ][] = $cc; - } - - foreach ( $inboxes as $inbox => $to ) { - $to = array_values( array_unique( $to ) ); - $activitypub_activity->set_to( $to ); - $activity = $activitypub_activity->to_json(); - - \Activitypub\safe_remote_post( $inbox, $activity, $user_id ); - } + public static function send_create_activity( Model\Post $activitypub_post ) { + self::send_activity( $activitypub_post, 'Create' ); } /** @@ -62,19 +35,8 @@ class Activity_Dispatcher { * * @param \Activitypub\Model\Post $activitypub_post */ - public static function send_update_activity( $activitypub_post ) { - // get latest version of post - $user_id = $activitypub_post->get_post_author(); - - $activitypub_activity = new \Activitypub\Model\Activity( 'Update', \Activitypub\Model\Activity::TYPE_FULL ); - $activitypub_activity->from_post( $activitypub_post ); - - foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { - $activitypub_activity->set_to( $to ); - $activity = $activitypub_activity->to_json(); // phpcs:ignore - - \Activitypub\safe_remote_post( $inbox, $activity, $user_id ); - } + public static function send_update_activity( Model\Post $activitypub_post ) { + self::send_activity( $activitypub_post, 'Update' ); } /** @@ -82,16 +44,30 @@ class Activity_Dispatcher { * * @param \Activitypub\Model\Post $activitypub_post */ - public static function send_delete_activity( $activitypub_post ) { + public static function send_delete_activity( Model\Post $activitypub_post ) { + self::send_activity( $activitypub_post, 'Delete' ); + } + + /** + * Undocumented function + * + * @param [type] $activitypub_post + * @param [type] $activity_type + * @return void + */ + public function send_activity( Model\Post $activitypub_post, $activity_type ) { // get latest version of post $user_id = $activitypub_post->get_post_author(); - $activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL ); + $activitypub_activity = new \Activitypub\Model\Activity( $activity_type, \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity->from_post( $activitypub_post ); - foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { - $activitypub_activity->set_to( $to ); - $activity = $activitypub_activity->to_json(); // phpcs:ignore + $inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() ); + + foreach ( $inboxes as $inbox => $cc ) { + $cc = array_values( array_unique( $cc ) ); + $activitypub_activity->add_cc( $cc ); + $activity = $activitypub_activity->to_json(); \Activitypub\safe_remote_post( $inbox, $activity, $user_id ); } diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index c04aedc..4a60915 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -117,7 +117,7 @@ class Activitypub { $activitypub_post = new \Activitypub\Model\Post( $post ); if ( 'publish' === $new_status && 'publish' !== $old_status ) { - \wp_schedule_single_event( \time(), 'activitypub_send_post_activity', array( $activitypub_post ) ); + \wp_schedule_single_event( \time(), 'activitypub_send_create_activity', array( $activitypub_post ) ); } elseif ( 'publish' === $new_status ) { \wp_schedule_single_event( \time(), 'activitypub_send_update_activity', array( $activitypub_post ) ); } elseif ( 'trash' === $new_status ) { diff --git a/includes/functions.php b/includes/functions.php index 8f2e5d9..77508c5 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -219,8 +219,11 @@ function get_publickey_by_actor( $actor, $key_id ) { return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata ); } -function get_follower_inboxes( $user_id ) { +function get_follower_inboxes( $user_id, $cc = array() ) { $followers = \Activitypub\Peer\Followers::get_followers( $user_id ); + $followers = array_merge( $followers, $cc ); + $followers = array_unique( $followers ); + $inboxes = array(); foreach ( $followers as $follower ) { diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index f865d6d..c95e6ff 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -43,6 +43,18 @@ class Activity { if ( \strncasecmp( $method, 'set', 3 ) === 0 ) { $this->$var = $params[0]; } + + if ( \strncasecmp( $method, 'add', 3 ) === 0 ) { + if ( ! is_array( $this->$var ) ) { + $this->$var = $params[0]; + } + + if ( is_array( $params[0] ) ) { + $this->$var = array_merge( $this->$var, $params[0] ); + } else { + array_push( $this->$var, $params[0] ); + } + } } public function from_post( Post $post ) { @@ -51,7 +63,8 @@ class Activity { if ( isset( $object['published'] ) ) { $this->published = $object['published']; } - $this->cc = array( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) ); + + $this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) ); if ( isset( $this->object['attributedTo'] ) ) { $this->actor = $this->object['attributedTo']; @@ -59,7 +72,7 @@ class Activity { foreach ( $post->get_tags() as $tag ) { if ( 'Mention' === $tag['type'] ) { - $this->cc[] = $tag['href']; + $this->add_cc( $tag['href'] ); } } diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 543a890..5d2ac48 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -386,7 +386,7 @@ class Post { $filtered_content = \apply_filters( 'activitypub_the_content', $content, $post ); $decoded_content = \html_entity_decode( $filtered_content, \ENT_QUOTES, 'UTF-8' ); - $content = \trim( \preg_replace( '/[\n\r]/', '', $content ) ); + $content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) ); $this->content = $content; From 472ee27849c561b241caac44cb04bdb827768abf Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 01:47:12 +0100 Subject: [PATCH 02/26] fix unit tests --- tests/test-class-activitypub-activity-dispatcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-class-activitypub-activity-dispatcher.php b/tests/test-class-activitypub-activity-dispatcher.php index 6693ba1..ec62b2d 100644 --- a/tests/test-class-activitypub-activity-dispatcher.php +++ b/tests/test-class-activitypub-activity-dispatcher.php @@ -28,7 +28,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); $activitypub_post = new \Activitypub\Model\Post( $post ); - \Activitypub\Activity_Dispatcher::send_post_activity( $activitypub_post ); + \Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post ); $this->assertSame( 2, $pre_http_request->get_call_count() ); $all_args = $pre_http_request->get_args(); @@ -67,7 +67,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); $activitypub_post = new \Activitypub\Model\Post( $post ); - \Activitypub\Activity_Dispatcher::send_post_activity( $activitypub_post ); + \Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post ); $this->assertSame( 1, $pre_http_request->get_call_count() ); $all_args = $pre_http_request->get_args(); From 3c84be1691b7388e57d942911c0973671a0309c4 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 01:50:20 +0100 Subject: [PATCH 03/26] fix unit tests --- includes/class-activity-dispatcher.php | 2 +- tests/test-class-activitypub-activity.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index 09fca79..221e2b0 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -55,7 +55,7 @@ class Activity_Dispatcher { * @param [type] $activity_type * @return void */ - public function send_activity( Model\Post $activitypub_post, $activity_type ) { + public static function send_activity( Model\Post $activitypub_post, $activity_type ) { // get latest version of post $user_id = $activitypub_post->get_post_author(); diff --git a/tests/test-class-activitypub-activity.php b/tests/test-class-activitypub-activity.php index 254d860..74d0727 100644 --- a/tests/test-class-activitypub-activity.php +++ b/tests/test-class-activitypub-activity.php @@ -22,7 +22,7 @@ class Test_Activitypub_Activity extends WP_UnitTestCase { $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity->from_post( $activitypub_post ); - $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_cc() ); + $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_to() ); $this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() ); remove_all_filters( 'activitypub_extract_mentions' ); From e52181fd3733b6b9b126f5ce046bbe10207ea312 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 02:04:06 +0100 Subject: [PATCH 04/26] fix tests --- includes/model/class-activity.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index c95e6ff..220541e 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -15,7 +15,7 @@ class Activity { private $type = 'Create'; private $actor = ''; private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); - private $cc = array( 'https://www.w3.org/ns/activitystreams#Public' ); + private $cc = array(); private $object = null; const TYPE_SIMPLE = 'simple'; @@ -54,6 +54,8 @@ class Activity { } else { array_push( $this->$var, $params[0] ); } + + $this->$var = array_unique( $this->$var ); } } From 365d5dd4997c22d7e6c2ef14a8e68e5a0bd36f7d Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 02:35:57 +0100 Subject: [PATCH 05/26] fix outbox --- includes/rest/class-outbox.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/rest/class-outbox.php b/includes/rest/class-outbox.php index 7eec5ac..677e2ff 100644 --- a/includes/rest/class-outbox.php +++ b/includes/rest/class-outbox.php @@ -102,8 +102,8 @@ class Outbox { foreach ( $posts as $post ) { $activitypub_post = new \Activitypub\Model\Post( $post ); - $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_NONE ); - $activitypub_activity->from_post( $activitypub_post->to_array() ); + $activitypub_activity = new \Activitypub\Model\Activity( 'Create', false ); + $activitypub_activity->from_post( $activitypub_post ); $json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore } } From de32cb7b7320bfa6fac5603ea7978059c1e83579 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 02:36:29 +0100 Subject: [PATCH 06/26] add changes also to the object --- includes/class-activity-dispatcher.php | 2 +- includes/model/class-activity.php | 32 ++++++++++++++++------- includes/model/class-post.php | 22 ++++++++++++++-- includes/rest/class-inbox.php | 2 +- tests/test-class-activitypub-activity.php | 2 +- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index 221e2b0..6df83e7 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -59,7 +59,7 @@ class Activity_Dispatcher { // get latest version of post $user_id = $activitypub_post->get_post_author(); - $activitypub_activity = new \Activitypub\Model\Activity( $activity_type, \Activitypub\Model\Activity::TYPE_FULL ); + $activitypub_activity = new \Activitypub\Model\Activity( $activity_type ); $activitypub_activity->from_post( $activitypub_post ); $inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() ); diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index 220541e..34f6146 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -9,7 +9,27 @@ namespace Activitypub\Model; * @see https://www.w3.org/TR/activitypub/ */ class Activity { - private $context = array( 'https://www.w3.org/ns/activitystreams' ); + private $context = array( + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + array( + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + 'PropertyValue' => 'schema:PropertyValue', + 'schema' => 'http://schema.org#', + 'pt' => 'https://joinpeertube.org/ns#', + 'toot' => 'http://joinmastodon.org/ns#', + 'value' => 'schema:value', + 'Hashtag' => 'as:Hashtag', + 'featured' => array( + '@id' => 'toot:featured', + '@type' => '@id', + ), + 'featuredTags' => array( + '@id' => 'toot:featuredTags', + '@type' => '@id', + ), + ), + ); private $published = ''; private $id = ''; private $type = 'Create'; @@ -18,15 +38,9 @@ class Activity { private $cc = array(); private $object = null; - const TYPE_SIMPLE = 'simple'; - const TYPE_FULL = 'full'; - const TYPE_NONE = 'none'; - - public function __construct( $type = 'Create', $context = self::TYPE_SIMPLE ) { - if ( 'none' === $context ) { + public function __construct( $type = 'Create', $context = true ) { + if ( true !== $context ) { $this->context = null; - } elseif ( 'full' === $context ) { - $this->context = \Activitypub\get_context(); } $this->type = \ucfirst( $type ); diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 5d2ac48..90f19ef 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -87,6 +87,9 @@ class Post { ), ); + private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); + private $cc = array(); + /** * Constructor * @@ -94,6 +97,7 @@ class Post { */ public function __construct( $post ) { $this->post = \get_post( $post ); + $this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $this->get_post_author() ) . '/followers' ) ); } /** @@ -117,6 +121,20 @@ class Post { if ( \strncasecmp( $method, 'set', 3 ) === 0 ) { $this->$var = $params[0]; } + + if ( \strncasecmp( $method, 'add', 3 ) === 0 ) { + if ( ! is_array( $this->$var ) ) { + $this->$var = $params[0]; + } + + if ( is_array( $params[0] ) ) { + $this->$var = array_merge( $this->$var, $params[0] ); + } else { + array_push( $this->$var, $params[0] ); + } + + $this->$var = array_unique( $this->$var ); + } } /** @@ -138,8 +156,8 @@ class Post { 'contentMap' => array( \strstr( \get_locale(), '_', true ) => $this->get_content(), ), - 'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ), - 'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ), + 'to' => $this->get_to(), + 'cc' => $this->get_cc(), 'attachment' => $this->get_attachments(), 'tag' => $this->get_tags(), ); diff --git a/includes/rest/class-inbox.php b/includes/rest/class-inbox.php index 5c21f43..1eab8a5 100644 --- a/includes/rest/class-inbox.php +++ b/includes/rest/class-inbox.php @@ -356,7 +356,7 @@ class Inbox { $inbox = \Activitypub\get_inbox_by_actor( $object['actor'] ); // send "Accept" activity - $activity = new \Activitypub\Model\Activity( 'Accept', \Activitypub\Model\Activity::TYPE_SIMPLE ); + $activity = new \Activitypub\Model\Activity( 'Accept' ); $activity->set_object( $object ); $activity->set_actor( \get_author_posts_url( $user_id ) ); $activity->set_to( $object['actor'] ); diff --git a/tests/test-class-activitypub-activity.php b/tests/test-class-activitypub-activity.php index 74d0727..7fe6551 100644 --- a/tests/test-class-activitypub-activity.php +++ b/tests/test-class-activitypub-activity.php @@ -19,7 +19,7 @@ class Test_Activitypub_Activity extends WP_UnitTestCase { $activitypub_post = new \Activitypub\Model\Post( $post ); - $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); + $activitypub_activity = new \Activitypub\Model\Activity( 'Create' ); $activitypub_activity->from_post( $activitypub_post ); $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_to() ); From 73ae47e37729047088bb34dbff618ca76468b3c8 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 07:24:27 +0100 Subject: [PATCH 07/26] PHPDoc --- includes/model/class-post.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 90f19ef..0929277 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -87,7 +87,22 @@ class Post { ), ); + /** + * List of audience + * + * Also used for visibility + * + * @var array + */ private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); + + /** + * List of audience + * + * Also used for visibility + * + * @var array + */ private $cc = array(); /** From 3c367f8eb19b421b61799217b1aa2db97a6857f7 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Wed, 15 Mar 2023 17:50:22 +0100 Subject: [PATCH 08/26] remove shortcodes that might confuse people --- templates/settings.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/settings.php b/templates/settings.php index 97e7e4d..2bfaed4 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -65,8 +65,6 @@
  • [ap_permalink] -
  • [ap_shortlink] - Hum.', 'activitypub' ), 'default' ); ?>
  • [ap_hashtags] -
  • -
  • [ap_hashcats] -
  • -
  • [ap_image] -
  • From becef59452405424db02af0e56579e9fce39f0c5 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Sat, 18 Mar 2023 21:59:09 +0100 Subject: [PATCH 09/26] improve readme thanks a lot @cavalierlife --- README.md | 62 ++++++++++++++++++++++++++++++++++++++---------------- readme.txt | 62 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 88 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 969f562..7b394c1 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ The ActivityPub protocol is a decentralized social networking protocol based upo ## Description ## -This is **BETA** software, see the FAQ to see the current feature set or rather what is still planned. +This is BETA software, see the FAQ to see the current feature set or rather what is still planned. -The plugin implements the ActivityPub protocol for your blog. Your readers will be able to follow your blogposts on Mastodon and other federated platforms that support ActivityPub. +The plugin implements the ActivityPub protocol for your blog, which means that your readers will be able to follow your blog posts on Mastodon and other federated platforms that support ActivityPub. In addition, replies to your posts on Mastodon and related platforms will automatically become comments on your blog post. -The plugin works with the following federated platforms: +The plugin works with the following tested federated platforms, but there may be more that it works with as well: * [Mastodon](https://joinmastodon.org/) * [Pleroma](https://pleroma.social/) @@ -26,8 +26,44 @@ The plugin works with the following federated platforms: * [SocialHome](https://socialhome.network/) * [Misskey](https://join.misskey.page/) +Here’s what that means and what you can expect. + +Once the ActivityPub plugin is installed, each author’s page on your WordPress blog will become its own federated instance. In other words, if you have two authors, Jane and Bob, on your website, `example.com`, then your authors would have their own author pages at `example.com/author/jane` and `example.com/author/bob`. Each of those author pages would now be available to Mastodon users (and all other federated platform users) as a profile that can be followed. Let’s break that down further. Let’s say you have a friend on Mastodon who tells you to follow them and they give you their profile name `@janelivesheresomeofthetime@mastodon.social`. You search for her name, see her profile, and click the follow button, right? From then on, everything Jane posts on her profile shows up in your Home feed. Okay, similarly, now that Jane has installed the ActivityPub plugin on her `example.com` site, her friends can also follow her on Mastodon by searching for `@jane@example.com` and clicking the Follow button on that profile. + +From now on, every blog post Jane publishes on example.com will show up on your Home feed because you follow her `@jane@example.com` profile. +Of course, if no one follows your author instance, then no one will ever see the posts - including you! So the easiest way to even know if the plugin is working is to follow your new profile yourself. If you already have a Mastodon profile, just follow your new one from there. + +Some things to note: + + 1. Many single-author blogs have chosen to turn off or redirect their author profile pages, usually via an SEO plugin like Yoast or Rank Math. This is usually done to avoid duplicate content with your blog’s home page. If your author page has been deactivated in this way, then ActivityPub won’t work for you. Instead, you can turn your author profile page back on, and then use the option in your SEO plugin to noindex the author page. This will enable the page to be live and ActivityPub will now work, but the live page won’t cause any duplicate content issues with search engines. + 2. Once ActivityPub is installed, only new posts going forward will be available in the fediverse. Likewise, even if you’ve been using ActivityPub for a while, anyone who follows your site, will only see new posts you publish from that moment on. They will never see previously-published posts in their Home feed. This process is very similar to subscribing to a newsletter. If you subscribe to a newsletter, you will only receive future emails, but not the old archived ones. With ActivityPub, if someone follows your site, they will only receive new blog posts you publish from then on. + +So what’s the process? + + 1. Install the ActivityPub plugin. + 2. Go to the plugin’s settings page and adjust the settings to your liking. Click the Save button when ready. + 3. Make sure your blog’s author profile page is active. + 4. Go to Mastodon or any other federated platform, search for your author’s new federated profile, and follow it. Your new profile will be in the form of @yourauthorname@yourwebsite.com, so that is what you’ll search for. + 5. On your blog, publish a new post. + 6. From Mastodon, check to see if the new post appears in your Home feed. + +Please note that it may take up to 15 minutes or so for the new post to show up in your federated feed. This is because the messages are sent to the federated platforms using a delayed cron. This avoids breaking the publishing process for those cases where users might have lots of followers. So please don’t assume that just because you didn’t see it show up right away that something is broken. Give it some time. In most cases, it will show up within a few minutes, and you’ll know everything is working as expected. + ## Frequently Asked Questions ## +### tl;dr ### + +This plugin connects your WordPress blog to popular social platforms like Mastodon, making your posts more accessible to a wider audience. Once installed, your blog's author pages can be followed by users on these platforms, allowing them to receive your new posts in their feeds. + +Here's how it works: + + 1. Install the plugin and adjust settings as needed. + 2. Ensure your blog's author profile page is active. + 3. On Mastodon or other supported platforms, search for and follow your author's new profile (e.g., `@yourauthorname@yourwebsite.com`). + 4. Publish a new post on your blog and check if it appears in your Mastodon feed. + +Please note that it may take up to 15 minutes for a new post to appear in your feed, as messages are sent on a delay to avoid overwhelming your followers. Be patient and give it some time. + ### What is the status of this plugin? ### Implemented: @@ -50,16 +86,6 @@ To implement: *ActivityPub for WordPress* extends WordPress with some Fediverse features, but it does not compete with platforms like Friendica or Mastodon. If you want to run a **decentralized social network**, please use [Mastodon](https://joinmastodon.org/) or [GNU social](https://gnusocial.network/). -### What are the differences between this plugin and Pterotype? ### - -**Compatibility** - -*ActivityPub for WordPress* is compatible with OStatus and IndieWeb plugin suites. *Pterotype* is incompatible with the standalone [WebFinger plugin](https://wordpress.org/plugins/webfinger/), so it can't be run together with OStatus. - -**Custom tables** - -*Pterotype* creates/uses a bunch of custom tables, *ActivityPub for WordPress* only uses the native tables and adds as little meta data as possible. - ### What if you are running your blog in a subdirectory? ### In order for webfinger to work, it must be mapped to the root directory of the URL on which your blog resides. @@ -356,12 +382,12 @@ Follow the normal instructions for [installing WordPress plugins](https://wordpr To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). -1. Type "`activitypub`" into the **Search Plugins** box. -1. Find the WordPress Plugin you wish to install. +2. Type "`activitypub`" into the **Search Plugins** box. +3. Find the WordPress Plugin you wish to install. 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. - 1. Click **Install Now** to install the WordPress Plugin. -1. The resulting installation screen will list the installation as successful or note any problems during the install. -1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. + 2. Click **Install Now** to install the WordPress Plugin. +4. The resulting installation screen will list the installation as successful or note any problems during the install. +5. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. ### Manual Plugin Installation ### diff --git a/readme.txt b/readme.txt index 63e1f6a..d47f644 100644 --- a/readme.txt +++ b/readme.txt @@ -12,11 +12,11 @@ The ActivityPub protocol is a decentralized social networking protocol based upo == Description == -This is **BETA** software, see the FAQ to see the current feature set or rather what is still planned. +This is BETA software, see the FAQ to see the current feature set or rather what is still planned. -The plugin implements the ActivityPub protocol for your blog. Your readers will be able to follow your blogposts on Mastodon and other federated platforms that support ActivityPub. +The plugin implements the ActivityPub protocol for your blog, which means that your readers will be able to follow your blog posts on Mastodon and other federated platforms that support ActivityPub. In addition, replies to your posts on Mastodon and related platforms will automatically become comments on your blog post. -The plugin works with the following federated platforms: +The plugin works with the following tested federated platforms, but there may be more that it works with as well: * [Mastodon](https://joinmastodon.org/) * [Pleroma](https://pleroma.social/) @@ -26,8 +26,44 @@ The plugin works with the following federated platforms: * [SocialHome](https://socialhome.network/) * [Misskey](https://join.misskey.page/) +Here’s what that means and what you can expect. + +Once the ActivityPub plugin is installed, each author’s page on your WordPress blog will become its own federated instance. In other words, if you have two authors, Jane and Bob, on your website, `example.com`, then your authors would have their own author pages at `example.com/author/jane` and `example.com/author/bob`. Each of those author pages would now be available to Mastodon users (and all other federated platform users) as a profile that can be followed. Let’s break that down further. Let’s say you have a friend on Mastodon who tells you to follow them and they give you their profile name `@janelivesheresomeofthetime@mastodon.social`. You search for her name, see her profile, and click the follow button, right? From then on, everything Jane posts on her profile shows up in your Home feed. Okay, similarly, now that Jane has installed the ActivityPub plugin on her `example.com` site, her friends can also follow her on Mastodon by searching for `@jane@example.com` and clicking the Follow button on that profile. + +From now on, every blog post Jane publishes on example.com will show up on your Home feed because you follow her `@jane@example.com` profile. +Of course, if no one follows your author instance, then no one will ever see the posts - including you! So the easiest way to even know if the plugin is working is to follow your new profile yourself. If you already have a Mastodon profile, just follow your new one from there. + +Some things to note: + + 1. Many single-author blogs have chosen to turn off or redirect their author profile pages, usually via an SEO plugin like Yoast or Rank Math. This is usually done to avoid duplicate content with your blog’s home page. If your author page has been deactivated in this way, then ActivityPub won’t work for you. Instead, you can turn your author profile page back on, and then use the option in your SEO plugin to noindex the author page. This will enable the page to be live and ActivityPub will now work, but the live page won’t cause any duplicate content issues with search engines. + 2. Once ActivityPub is installed, only new posts going forward will be available in the fediverse. Likewise, even if you’ve been using ActivityPub for a while, anyone who follows your site, will only see new posts you publish from that moment on. They will never see previously-published posts in their Home feed. This process is very similar to subscribing to a newsletter. If you subscribe to a newsletter, you will only receive future emails, but not the old archived ones. With ActivityPub, if someone follows your site, they will only receive new blog posts you publish from then on. + +So what’s the process? + + 1. Install the ActivityPub plugin. + 2. Go to the plugin’s settings page and adjust the settings to your liking. Click the Save button when ready. + 3. Make sure your blog’s author profile page is active. + 4. Go to Mastodon or any other federated platform, search for your author’s new federated profile, and follow it. Your new profile will be in the form of @yourauthorname@yourwebsite.com, so that is what you’ll search for. + 5. On your blog, publish a new post. + 6. From Mastodon, check to see if the new post appears in your Home feed. + +Please note that it may take up to 15 minutes or so for the new post to show up in your federated feed. This is because the messages are sent to the federated platforms using a delayed cron. This avoids breaking the publishing process for those cases where users might have lots of followers. So please don’t assume that just because you didn’t see it show up right away that something is broken. Give it some time. In most cases, it will show up within a few minutes, and you’ll know everything is working as expected. + == Frequently Asked Questions == += tl;dr = + +This plugin connects your WordPress blog to popular social platforms like Mastodon, making your posts more accessible to a wider audience. Once installed, your blog's author pages can be followed by users on these platforms, allowing them to receive your new posts in their feeds. + +Here's how it works: + + 1. Install the plugin and adjust settings as needed. + 2. Ensure your blog's author profile page is active. + 3. On Mastodon or other supported platforms, search for and follow your author's new profile (e.g., `@yourauthorname@yourwebsite.com`). + 4. Publish a new post on your blog and check if it appears in your Mastodon feed. + +Please note that it may take up to 15 minutes for a new post to appear in your feed, as messages are sent on a delay to avoid overwhelming your followers. Be patient and give it some time. + = What is the status of this plugin? = Implemented: @@ -50,16 +86,6 @@ To implement: *ActivityPub for WordPress* extends WordPress with some Fediverse features, but it does not compete with platforms like Friendica or Mastodon. If you want to run a **decentralized social network**, please use [Mastodon](https://joinmastodon.org/) or [GNU social](https://gnusocial.network/). -= What are the differences between this plugin and Pterotype? = - -**Compatibility** - -*ActivityPub for WordPress* is compatible with OStatus and IndieWeb plugin suites. *Pterotype* is incompatible with the standalone [WebFinger plugin](https://wordpress.org/plugins/webfinger/), so it can't be run together with OStatus. - -**Custom tables** - -*Pterotype* creates/uses a bunch of custom tables, *ActivityPub for WordPress* only uses the native tables and adds as little meta data as possible. - = What if you are running your blog in a subdirectory? = In order for webfinger to work, it must be mapped to the root directory of the URL on which your blog resides. @@ -356,12 +382,12 @@ Follow the normal instructions for [installing WordPress plugins](https://wordpr To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). -1. Type "`activitypub`" into the **Search Plugins** box. -1. Find the WordPress Plugin you wish to install. +2. Type "`activitypub`" into the **Search Plugins** box. +3. Find the WordPress Plugin you wish to install. 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. - 1. Click **Install Now** to install the WordPress Plugin. -1. The resulting installation screen will list the installation as successful or note any problems during the install. -1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. + 2. Click **Install Now** to install the WordPress Plugin. +4. The resulting installation screen will list the installation as successful or note any problems during the install. +5. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. = Manual Plugin Installation = From 70fe654c95624ec6fd0c50ad1c63116ac4597f67 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Sun, 19 Mar 2023 08:42:33 +0100 Subject: [PATCH 10/26] fix ordered lists --- README.md | 34 +++++++++++++++++----------------- readme.txt | 34 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 7b394c1..d1b4461 100644 --- a/README.md +++ b/README.md @@ -35,17 +35,17 @@ Of course, if no one follows your author instance, then no one will ever see the Some things to note: - 1. Many single-author blogs have chosen to turn off or redirect their author profile pages, usually via an SEO plugin like Yoast or Rank Math. This is usually done to avoid duplicate content with your blog’s home page. If your author page has been deactivated in this way, then ActivityPub won’t work for you. Instead, you can turn your author profile page back on, and then use the option in your SEO plugin to noindex the author page. This will enable the page to be live and ActivityPub will now work, but the live page won’t cause any duplicate content issues with search engines. - 2. Once ActivityPub is installed, only new posts going forward will be available in the fediverse. Likewise, even if you’ve been using ActivityPub for a while, anyone who follows your site, will only see new posts you publish from that moment on. They will never see previously-published posts in their Home feed. This process is very similar to subscribing to a newsletter. If you subscribe to a newsletter, you will only receive future emails, but not the old archived ones. With ActivityPub, if someone follows your site, they will only receive new blog posts you publish from then on. +1. Many single-author blogs have chosen to turn off or redirect their author profile pages, usually via an SEO plugin like Yoast or Rank Math. This is usually done to avoid duplicate content with your blog’s home page. If your author page has been deactivated in this way, then ActivityPub won’t work for you. Instead, you can turn your author profile page back on, and then use the option in your SEO plugin to noindex the author page. This will enable the page to be live and ActivityPub will now work, but the live page won’t cause any duplicate content issues with search engines. +1. Once ActivityPub is installed, only new posts going forward will be available in the fediverse. Likewise, even if you’ve been using ActivityPub for a while, anyone who follows your site, will only see new posts you publish from that moment on. They will never see previously-published posts in their Home feed. This process is very similar to subscribing to a newsletter. If you subscribe to a newsletter, you will only receive future emails, but not the old archived ones. With ActivityPub, if someone follows your site, they will only receive new blog posts you publish from then on. So what’s the process? - 1. Install the ActivityPub plugin. - 2. Go to the plugin’s settings page and adjust the settings to your liking. Click the Save button when ready. - 3. Make sure your blog’s author profile page is active. - 4. Go to Mastodon or any other federated platform, search for your author’s new federated profile, and follow it. Your new profile will be in the form of @yourauthorname@yourwebsite.com, so that is what you’ll search for. - 5. On your blog, publish a new post. - 6. From Mastodon, check to see if the new post appears in your Home feed. +1. Install the ActivityPub plugin. +1. Go to the plugin’s settings page and adjust the settings to your liking. Click the Save button when ready. +1. Make sure your blog’s author profile page is active. +1. Go to Mastodon or any other federated platform, search for your author’s new federated profile, and follow it. Your new profile will be in the form of @yourauthorname@yourwebsite.com, so that is what you’ll search for. +1. On your blog, publish a new post. +1. From Mastodon, check to see if the new post appears in your Home feed. Please note that it may take up to 15 minutes or so for the new post to show up in your federated feed. This is because the messages are sent to the federated platforms using a delayed cron. This avoids breaking the publishing process for those cases where users might have lots of followers. So please don’t assume that just because you didn’t see it show up right away that something is broken. Give it some time. In most cases, it will show up within a few minutes, and you’ll know everything is working as expected. @@ -57,10 +57,10 @@ This plugin connects your WordPress blog to popular social platforms like Mastod Here's how it works: - 1. Install the plugin and adjust settings as needed. - 2. Ensure your blog's author profile page is active. - 3. On Mastodon or other supported platforms, search for and follow your author's new profile (e.g., `@yourauthorname@yourwebsite.com`). - 4. Publish a new post on your blog and check if it appears in your Mastodon feed. +1. Install the plugin and adjust settings as needed. +1. Ensure your blog's author profile page is active. +1. On Mastodon or other supported platforms, search for and follow your author's new profile (e.g., `@yourauthorname@yourwebsite.com`). +1. Publish a new post on your blog and check if it appears in your Mastodon feed. Please note that it may take up to 15 minutes for a new post to appear in your feed, as messages are sent on a delay to avoid overwhelming your followers. Be patient and give it some time. @@ -382,12 +382,12 @@ Follow the normal instructions for [installing WordPress plugins](https://wordpr To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). -2. Type "`activitypub`" into the **Search Plugins** box. -3. Find the WordPress Plugin you wish to install. +1. Type "`activitypub`" into the **Search Plugins** box. +1. Find the WordPress Plugin you wish to install. 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. - 2. Click **Install Now** to install the WordPress Plugin. -4. The resulting installation screen will list the installation as successful or note any problems during the install. -5. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. + 1. Click **Install Now** to install the WordPress Plugin. +1. The resulting installation screen will list the installation as successful or note any problems during the install. +1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. ### Manual Plugin Installation ### diff --git a/readme.txt b/readme.txt index d47f644..9c7661d 100644 --- a/readme.txt +++ b/readme.txt @@ -35,17 +35,17 @@ Of course, if no one follows your author instance, then no one will ever see the Some things to note: - 1. Many single-author blogs have chosen to turn off or redirect their author profile pages, usually via an SEO plugin like Yoast or Rank Math. This is usually done to avoid duplicate content with your blog’s home page. If your author page has been deactivated in this way, then ActivityPub won’t work for you. Instead, you can turn your author profile page back on, and then use the option in your SEO plugin to noindex the author page. This will enable the page to be live and ActivityPub will now work, but the live page won’t cause any duplicate content issues with search engines. - 2. Once ActivityPub is installed, only new posts going forward will be available in the fediverse. Likewise, even if you’ve been using ActivityPub for a while, anyone who follows your site, will only see new posts you publish from that moment on. They will never see previously-published posts in their Home feed. This process is very similar to subscribing to a newsletter. If you subscribe to a newsletter, you will only receive future emails, but not the old archived ones. With ActivityPub, if someone follows your site, they will only receive new blog posts you publish from then on. +1. Many single-author blogs have chosen to turn off or redirect their author profile pages, usually via an SEO plugin like Yoast or Rank Math. This is usually done to avoid duplicate content with your blog’s home page. If your author page has been deactivated in this way, then ActivityPub won’t work for you. Instead, you can turn your author profile page back on, and then use the option in your SEO plugin to noindex the author page. This will enable the page to be live and ActivityPub will now work, but the live page won’t cause any duplicate content issues with search engines. +1. Once ActivityPub is installed, only new posts going forward will be available in the fediverse. Likewise, even if you’ve been using ActivityPub for a while, anyone who follows your site, will only see new posts you publish from that moment on. They will never see previously-published posts in their Home feed. This process is very similar to subscribing to a newsletter. If you subscribe to a newsletter, you will only receive future emails, but not the old archived ones. With ActivityPub, if someone follows your site, they will only receive new blog posts you publish from then on. So what’s the process? - 1. Install the ActivityPub plugin. - 2. Go to the plugin’s settings page and adjust the settings to your liking. Click the Save button when ready. - 3. Make sure your blog’s author profile page is active. - 4. Go to Mastodon or any other federated platform, search for your author’s new federated profile, and follow it. Your new profile will be in the form of @yourauthorname@yourwebsite.com, so that is what you’ll search for. - 5. On your blog, publish a new post. - 6. From Mastodon, check to see if the new post appears in your Home feed. +1. Install the ActivityPub plugin. +1. Go to the plugin’s settings page and adjust the settings to your liking. Click the Save button when ready. +1. Make sure your blog’s author profile page is active. +1. Go to Mastodon or any other federated platform, search for your author’s new federated profile, and follow it. Your new profile will be in the form of @yourauthorname@yourwebsite.com, so that is what you’ll search for. +1. On your blog, publish a new post. +1. From Mastodon, check to see if the new post appears in your Home feed. Please note that it may take up to 15 minutes or so for the new post to show up in your federated feed. This is because the messages are sent to the federated platforms using a delayed cron. This avoids breaking the publishing process for those cases where users might have lots of followers. So please don’t assume that just because you didn’t see it show up right away that something is broken. Give it some time. In most cases, it will show up within a few minutes, and you’ll know everything is working as expected. @@ -57,10 +57,10 @@ This plugin connects your WordPress blog to popular social platforms like Mastod Here's how it works: - 1. Install the plugin and adjust settings as needed. - 2. Ensure your blog's author profile page is active. - 3. On Mastodon or other supported platforms, search for and follow your author's new profile (e.g., `@yourauthorname@yourwebsite.com`). - 4. Publish a new post on your blog and check if it appears in your Mastodon feed. +1. Install the plugin and adjust settings as needed. +1. Ensure your blog's author profile page is active. +1. On Mastodon or other supported platforms, search for and follow your author's new profile (e.g., `@yourauthorname@yourwebsite.com`). +1. Publish a new post on your blog and check if it appears in your Mastodon feed. Please note that it may take up to 15 minutes for a new post to appear in your feed, as messages are sent on a delay to avoid overwhelming your followers. Be patient and give it some time. @@ -382,12 +382,12 @@ Follow the normal instructions for [installing WordPress plugins](https://wordpr To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). -2. Type "`activitypub`" into the **Search Plugins** box. -3. Find the WordPress Plugin you wish to install. +1. Type "`activitypub`" into the **Search Plugins** box. +1. Find the WordPress Plugin you wish to install. 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. - 2. Click **Install Now** to install the WordPress Plugin. -4. The resulting installation screen will list the installation as successful or note any problems during the install. -5. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. + 1. Click **Install Now** to install the WordPress Plugin. +1. The resulting installation screen will list the installation as successful or note any problems during the install. +1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. = Manual Plugin Installation = From 7d11d3e2089d49c4e1626e4a73ca192aa5881eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Thu, 23 Mar 2023 08:35:26 +0100 Subject: [PATCH 11/26] Fix documentation and typos. --- includes/class-health-check.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/includes/class-health-check.php b/includes/class-health-check.php index 26bc808..248d260 100644 --- a/includes/class-health-check.php +++ b/includes/class-health-check.php @@ -35,7 +35,7 @@ class Health_Check { /** * Author URL tests * - * @return void + * @return array */ public static function test_author_url() { $result = array( @@ -73,7 +73,7 @@ class Health_Check { /** * WebFinger tests * - * @return void + * @return array */ public static function test_webfinger() { $result = array( @@ -85,7 +85,7 @@ class Health_Check { ), 'description' => \sprintf( '

    %s

    ', - \__( 'Your WebFinger endpoint is accessible and returns the correct informations.', 'activitypub' ) + \__( 'Your WebFinger endpoint is accessible and returns the correct information.', 'activitypub' ) ), 'actions' => '', 'test' => 'test_webfinger', @@ -109,9 +109,9 @@ class Health_Check { } /** - * Check if `author_posts_url` is accessible and that requerst returns correct JSON + * Check if `author_posts_url` is accessible and that request returns correct JSON * - * @return boolean|WP_Error + * @return boolean|\WP_Error */ public static function is_author_url_accessible() { $user = \wp_get_current_user(); @@ -194,9 +194,9 @@ class Health_Check { } /** - * Check if WebFinger endoint is accessible and profile requerst returns correct JSON + * Check if WebFinger endpoint is accessible and profile request returns correct JSON * - * @return boolean|WP_Error + * @return boolean|\WP_Error */ public static function is_webfinger_endpoint_accessible() { $user = \wp_get_current_user(); @@ -272,7 +272,7 @@ class Health_Check { * Static function for generating site debug data when required. * * @param array $info The debug information to be added to the core information page. - * @return array The filtered informations + * @return array The filtered information */ public static function debug_information( $info ) { $info['activitypub'] = array( From 643c47dcb7644af10d6687e4a119a4c7c6fa7454 Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Mon, 10 Apr 2023 13:10:46 +0200 Subject: [PATCH 12/26] Webfinger info: avoid PHP warning when user isn't defined This should avoid warnings like this one: ``` PHP Warning: Attempt to read property "user_login" on bool in /var/www/html/wp-content/plugins/activitypub/includes/class-webfinger.php on line 27 ``` --- includes/class-webfinger.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/class-webfinger.php b/includes/class-webfinger.php index ab33411..c7d2cba 100644 --- a/includes/class-webfinger.php +++ b/includes/class-webfinger.php @@ -23,6 +23,9 @@ class Webfinger { } $user = \get_user_by( 'id', $user_id ); + if ( ! $user ) { + return ''; + } return $user->user_login . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST ); } From c32eec2390328fb37b320fc31f8a74c6b1ac1f4d Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 20 Apr 2023 15:22:11 +0200 Subject: [PATCH 13/26] some code cleanup --- activitypub.php | 30 +++++++++++++------------- includes/class-activity-dispatcher.php | 30 +++++++++++++++----------- includes/class-activitypub.php | 12 +++++------ includes/class-admin.php | 16 +++++++------- includes/class-debug.php | 5 ++++- includes/class-hashtag.php | 4 ++-- includes/class-health-check.php | 8 +++---- includes/class-mention.php | 6 +++--- includes/class-webfinger.php | 10 +++++---- includes/model/class-activity.php | 2 ++ includes/rest/class-followers.php | 4 ++-- includes/rest/class-following.php | 4 ++-- includes/rest/class-inbox.php | 24 +++++++++++---------- includes/rest/class-nodeinfo.php | 12 +++++------ includes/rest/class-outbox.php | 4 ++-- includes/rest/class-webfinger.php | 17 +++++++++------ 16 files changed, 102 insertions(+), 86 deletions(-) diff --git a/activitypub.php b/activitypub.php index 7320f0c..35e6de8 100644 --- a/activitypub.php +++ b/activitypub.php @@ -39,50 +39,50 @@ function init() { require_once \dirname( __FILE__ ) . '/includes/model/class-post.php'; require_once \dirname( __FILE__ ) . '/includes/class-activity-dispatcher.php'; - \Activitypub\Activity_Dispatcher::init(); + Activity_Dispatcher::init(); require_once \dirname( __FILE__ ) . '/includes/class-activitypub.php'; - \Activitypub\Activitypub::init(); + Activitypub::init(); // Configure the REST API route require_once \dirname( __FILE__ ) . '/includes/rest/class-outbox.php'; - \Activitypub\Rest\Outbox::init(); + Rest\Outbox::init(); require_once \dirname( __FILE__ ) . '/includes/rest/class-inbox.php'; - \Activitypub\Rest\Inbox::init(); + Rest\Inbox::init(); require_once \dirname( __FILE__ ) . '/includes/rest/class-followers.php'; - \Activitypub\Rest\Followers::init(); + Rest\Followers::init(); require_once \dirname( __FILE__ ) . '/includes/rest/class-following.php'; - \Activitypub\Rest\Following::init(); + Rest\Following::init(); require_once \dirname( __FILE__ ) . '/includes/rest/class-webfinger.php'; - \Activitypub\Rest\Webfinger::init(); + Rest\Webfinger::init(); // load NodeInfo endpoints only if blog is public if ( true === (bool) \get_option( 'blog_public', 1 ) ) { require_once \dirname( __FILE__ ) . '/includes/rest/class-nodeinfo.php'; - \Activitypub\Rest\NodeInfo::init(); + Rest\NodeInfo::init(); } require_once \dirname( __FILE__ ) . '/includes/class-admin.php'; - \Activitypub\Admin::init(); + Admin::init(); require_once \dirname( __FILE__ ) . '/includes/class-hashtag.php'; - \Activitypub\Hashtag::init(); + Hashtag::init(); require_once \dirname( __FILE__ ) . '/includes/class-shortcodes.php'; - \Activitypub\Shortcodes::init(); + Shortcodes::init(); require_once \dirname( __FILE__ ) . '/includes/class-mention.php'; - \Activitypub\Mention::init(); + Mention::init(); require_once \dirname( __FILE__ ) . '/includes/class-debug.php'; - \Activitypub\Debug::init(); + Debug::init(); require_once \dirname( __FILE__ ) . '/includes/class-health-check.php'; - \Activitypub\Health_Check::init(); + Health_Check::init(); if ( \WP_DEBUG ) { require_once \dirname( __FILE__ ) . '/includes/debug.php'; @@ -136,6 +136,6 @@ function flush_rewrite_rules() { */ function enable_buddypress_features() { require_once \dirname( __FILE__ ) . '/integration/class-buddypress.php'; - \Activitypub\Integration\Buddypress::init(); + Integration\Buddypress::init(); } add_action( 'bp_include', '\Activitypub\enable_buddypress_features' ); diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index 6df83e7..57fee1a 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -1,6 +1,9 @@ get_post_author(); - $activitypub_activity = new \Activitypub\Model\Activity( $activity_type ); + $activitypub_activity = new Activity( $activity_type ); $activitypub_activity->from_post( $activitypub_post ); $inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() ); diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index 4a60915..4730515 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -11,9 +11,9 @@ class Activitypub { * Initialize the class, registering WordPress hooks. */ public static function init() { - \add_filter( 'template_include', array( '\Activitypub\Activitypub', 'render_json_template' ), 99 ); - \add_filter( 'query_vars', array( '\Activitypub\Activitypub', 'add_query_vars' ) ); - \add_filter( 'pre_get_avatar_data', array( '\Activitypub\Activitypub', 'pre_get_avatar_data' ), 11, 2 ); + \add_filter( 'template_include', array( self::class, 'render_json_template' ), 99 ); + \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 support for ActivityPub to custom post types $post_types = \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) ) ? \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) ) : array(); @@ -22,9 +22,9 @@ class Activitypub { \add_post_type_support( $post_type, 'activitypub' ); } - \add_action( 'transition_post_status', array( '\Activitypub\Activitypub', 'schedule_post_activity' ), 33, 3 ); - \add_action( 'wp_trash_post', array( '\Activitypub\Activitypub', 'trash_post' ), 1 ); - \add_action( 'untrash_post', array( '\Activitypub\Activitypub', 'untrash_post' ), 1 ); + \add_action( 'transition_post_status', array( self::class, 'schedule_post_activity' ), 33, 3 ); + \add_action( 'wp_trash_post', array( self::class, 'trash_post' ), 1 ); + \add_action( 'untrash_post', array( self::class, 'untrash_post' ), 1 ); } /** diff --git a/includes/class-admin.php b/includes/class-admin.php index e98d547..220ed9b 100644 --- a/includes/class-admin.php +++ b/includes/class-admin.php @@ -11,10 +11,10 @@ class Admin { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_action( 'admin_menu', array( '\Activitypub\Admin', 'admin_menu' ) ); - \add_action( 'admin_init', array( '\Activitypub\Admin', 'register_settings' ) ); - \add_action( 'show_user_profile', array( '\Activitypub\Admin', 'add_fediverse_profile' ) ); - \add_action( 'admin_enqueue_scripts', array( '\Activitypub\Admin', 'enqueue_scripts' ) ); + \add_action( 'admin_menu', array( self::class, 'admin_menu' ) ); + \add_action( 'admin_init', array( self::class, 'register_settings' ) ); + \add_action( 'show_user_profile', array( self::class, 'add_fediverse_profile' ) ); + \add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_scripts' ) ); } /** @@ -26,14 +26,14 @@ class Admin { 'ActivityPub', 'manage_options', 'activitypub', - array( '\Activitypub\Admin', 'settings_page' ) + array( self::class, 'settings_page' ) ); - \add_action( 'load-' . $settings_page, array( '\Activitypub\Admin', 'add_settings_help_tab' ) ); + \add_action( 'load-' . $settings_page, array( self::class, 'add_settings_help_tab' ) ); - $followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers (Fediverse)', 'activitypub' ), 'read', 'activitypub-followers-list', array( '\Activitypub\Admin', 'followers_list_page' ) ); + $followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers (Fediverse)', 'activitypub' ), 'read', 'activitypub-followers-list', array( self::class, 'followers_list_page' ) ); - \add_action( 'load-' . $followers_list_page, array( '\Activitypub\Admin', 'add_followers_list_help_tab' ) ); + \add_action( 'load-' . $followers_list_page, array( self::class, 'add_followers_list_help_tab' ) ); } /** diff --git a/includes/class-debug.php b/includes/class-debug.php index 767d4a9..36f8bda 100644 --- a/includes/class-debug.php +++ b/includes/class-debug.php @@ -1,6 +1,9 @@ \__( 'Author URL test', 'activitypub' ), - 'test' => array( '\Activitypub\Health_Check', 'test_author_url' ), + 'test' => array( self::class, 'test_author_url' ), ); $tests['direct']['activitypub_test_webfinger'] = array( 'label' => __( 'WebFinger Test', 'activitypub' ), - 'test' => array( '\Activitypub\Health_Check', 'test_webfinger' ), + 'test' => array( self::class, 'test_webfinger' ), ); return $tests; diff --git a/includes/class-mention.php b/includes/class-mention.php index 7c8672a..e0930cc 100644 --- a/includes/class-mention.php +++ b/includes/class-mention.php @@ -11,8 +11,8 @@ class Mention { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_filter( 'the_content', array( '\Activitypub\Mention', 'the_content' ), 99, 2 ); - \add_filter( 'activitypub_extract_mentions', array( '\Activitypub\Mention', 'extract_mentions' ), 99, 2 ); + \add_filter( 'the_content', array( self::class, 'the_content' ), 99, 2 ); + \add_filter( 'activitypub_extract_mentions', array( self::class, 'extract_mentions' ), 99, 2 ); } /** @@ -46,7 +46,7 @@ class Mention { $the_content ); - $the_content = \preg_replace_callback( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/', array( '\Activitypub\Mention', 'replace_with_links' ), $the_content ); + $the_content = \preg_replace_callback( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/', array( self::class, 'replace_with_links' ), $the_content ); $the_content = str_replace( array_reverse( array_keys( $protected_tags ) ), array_reverse( array_values( $protected_tags ) ), $the_content ); diff --git a/includes/class-webfinger.php b/includes/class-webfinger.php index c7d2cba..1581853 100644 --- a/includes/class-webfinger.php +++ b/includes/class-webfinger.php @@ -1,6 +1,8 @@ \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Followers', 'get' ), + 'callback' => array( self::class, 'get' ), 'args' => self::request_parameters(), 'permission_callback' => '__return_true', ), diff --git a/includes/rest/class-following.php b/includes/rest/class-following.php index d7caff4..52a95e7 100644 --- a/includes/rest/class-following.php +++ b/includes/rest/class-following.php @@ -13,7 +13,7 @@ class Following { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_action( 'rest_api_init', array( '\Activitypub\Rest\Following', 'register_routes' ) ); + \add_action( 'rest_api_init', array( self::class, 'register_routes' ) ); } /** @@ -26,7 +26,7 @@ class Following { array( array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Following', 'get' ), + 'callback' => array( self::class, 'get' ), 'args' => self::request_parameters(), 'permission_callback' => '__return_true', ), diff --git a/includes/rest/class-inbox.php b/includes/rest/class-inbox.php index 86aefd4..1a63108 100644 --- a/includes/rest/class-inbox.php +++ b/includes/rest/class-inbox.php @@ -1,6 +1,8 @@ \WP_REST_Server::EDITABLE, - 'callback' => array( '\Activitypub\Rest\Inbox', 'shared_inbox_post' ), + 'callback' => array( self::class, 'shared_inbox_post' ), 'args' => self::shared_inbox_post_parameters(), 'permission_callback' => '__return_true', ), @@ -45,13 +47,13 @@ class Inbox { array( array( 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox_post' ), + 'callback' => array( self::class, 'user_inbox_post' ), 'args' => self::user_inbox_post_parameters(), 'permission_callback' => '__return_true', ), array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Inbox', 'user_inbox_get' ), + 'callback' => array( self::class, 'user_inbox_get' ), 'args' => self::user_inbox_get_parameters(), 'permission_callback' => '__return_true', ), @@ -356,7 +358,7 @@ class Inbox { $inbox = \Activitypub\get_inbox_by_actor( $object['actor'] ); // send "Accept" activity - $activity = new \Activitypub\Model\Activity( 'Accept' ); + $activity = new Activity( 'Accept' ); $activity->set_object( $object ); $activity->set_actor( \get_author_posts_url( $user_id ) ); $activity->set_to( $object['actor'] ); diff --git a/includes/rest/class-nodeinfo.php b/includes/rest/class-nodeinfo.php index 3106c5e..100fdd3 100644 --- a/includes/rest/class-nodeinfo.php +++ b/includes/rest/class-nodeinfo.php @@ -13,9 +13,9 @@ class Nodeinfo { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_action( 'rest_api_init', array( '\Activitypub\Rest\Nodeinfo', 'register_routes' ) ); - \add_filter( 'nodeinfo_data', array( '\Activitypub\Rest\Nodeinfo', 'add_nodeinfo_discovery' ), 10, 2 ); - \add_filter( 'nodeinfo2_data', array( '\Activitypub\Rest\Nodeinfo', 'add_nodeinfo2_discovery' ), 10 ); + \add_action( 'rest_api_init', array( self::class, 'register_routes' ) ); + \add_filter( 'nodeinfo_data', array( self::class, 'add_nodeinfo_discovery' ), 10, 2 ); + \add_filter( 'nodeinfo2_data', array( self::class, 'add_nodeinfo2_discovery' ), 10 ); } /** @@ -28,7 +28,7 @@ class Nodeinfo { array( array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Nodeinfo', 'discovery' ), + 'callback' => array( self::class, 'discovery' ), 'permission_callback' => '__return_true', ), ) @@ -40,7 +40,7 @@ class Nodeinfo { array( array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Nodeinfo', 'nodeinfo' ), + 'callback' => array( self::class, 'nodeinfo' ), 'permission_callback' => '__return_true', ), ) @@ -52,7 +52,7 @@ class Nodeinfo { array( array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Nodeinfo', 'nodeinfo2' ), + 'callback' => array( self::class, 'nodeinfo2' ), 'permission_callback' => '__return_true', ), ) diff --git a/includes/rest/class-outbox.php b/includes/rest/class-outbox.php index 8749d11..905dfd5 100644 --- a/includes/rest/class-outbox.php +++ b/includes/rest/class-outbox.php @@ -13,7 +13,7 @@ class Outbox { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_action( 'rest_api_init', array( '\Activitypub\Rest\Outbox', 'register_routes' ) ); + \add_action( 'rest_api_init', array( self::class, 'register_routes' ) ); } /** @@ -26,7 +26,7 @@ class Outbox { array( array( 'methods' => \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Outbox', 'user_outbox_get' ), + 'callback' => array( self::class, 'user_outbox_get' ), 'args' => self::request_parameters(), 'permission_callback' => '__return_true', ), diff --git a/includes/rest/class-webfinger.php b/includes/rest/class-webfinger.php index 0c6d5f1..d41cf25 100644 --- a/includes/rest/class-webfinger.php +++ b/includes/rest/class-webfinger.php @@ -1,6 +1,9 @@ \WP_REST_Server::READABLE, - 'callback' => array( '\Activitypub\Rest\Webfinger', 'webfinger' ), + 'callback' => array( self::class, 'webfinger' ), 'args' => self::request_parameters(), 'permission_callback' => '__return_true', ), @@ -45,7 +48,7 @@ class Webfinger { $resource = $request->get_param( 'resource' ); if ( \strpos( $resource, '@' ) === false ) { - return new \WP_Error( 'activitypub_unsupported_resource', \__( 'Resource is invalid', 'activitypub' ), array( 'status' => 400 ) ); + return new WP_Error( 'activitypub_unsupported_resource', \__( 'Resource is invalid', 'activitypub' ), array( 'status' => 400 ) ); } $resource = \str_replace( 'acct:', '', $resource ); @@ -54,13 +57,13 @@ class Webfinger { $resource_host = \substr( \strrchr( $resource, '@' ), 1 ); if ( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) !== $resource_host ) { - return new \WP_Error( 'activitypub_wrong_host', \__( 'Resource host does not match blog host', 'activitypub' ), array( 'status' => 404 ) ); + return new WP_Error( 'activitypub_wrong_host', \__( 'Resource host does not match blog host', 'activitypub' ), array( 'status' => 404 ) ); } $user = \get_user_by( 'login', \esc_sql( $resource_identifier ) ); if ( ! $user || ! user_can( $user, 'publish_posts' ) ) { - return new \WP_Error( 'activitypub_user_not_found', \__( 'User not found', 'activitypub' ), array( 'status' => 404 ) ); + return new WP_Error( 'activitypub_user_not_found', \__( 'User not found', 'activitypub' ), array( 'status' => 404 ) ); } $json = array( @@ -82,7 +85,7 @@ class Webfinger { ), ); - return new \WP_REST_Response( $json, 200 ); + return new WP_REST_Response( $json, 200 ); } /** From eeb3ba295274f43b1776ad4e7953525327fa80f5 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 20 Apr 2023 15:32:38 +0200 Subject: [PATCH 14/26] remove unused "use function" --- includes/model/class-activity.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index cfbb431..34f6146 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -1,8 +1,6 @@ Date: Fri, 21 Apr 2023 08:42:51 +0200 Subject: [PATCH 15/26] count only users that can `publish_posts` --- includes/rest/class-nodeinfo.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/includes/rest/class-nodeinfo.php b/includes/rest/class-nodeinfo.php index 100fdd3..980c24b 100644 --- a/includes/rest/class-nodeinfo.php +++ b/includes/rest/class-nodeinfo.php @@ -75,13 +75,24 @@ class Nodeinfo { 'version' => \get_bloginfo( 'version' ), ); - $users = \count_users(); + $users = \get_users( + array( + 'capability__in' => array( 'publish_posts' ), + ) + ); + + if ( is_array( $users ) ) { + $users = count( $users ); + } else { + $users = 1; + } + $posts = \wp_count_posts(); $comments = \wp_count_comments(); $nodeinfo['usage'] = array( 'users' => array( - 'total' => (int) $users['total_users'], + 'total' => $users, ), 'localPosts' => (int) $posts->publish, 'localComments' => (int) $comments->approved, From 45ae73bb0660ed6062751ff1ca452e10e7a868eb Mon Sep 17 00:00:00 2001 From: Alex Kirk Date: Fri, 21 Apr 2023 17:20:48 +0200 Subject: [PATCH 16/26] Add Vary header --- includes/class-activitypub.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index 4730515..b20eb71 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -39,6 +39,8 @@ class Activitypub { return $template; } + header( 'Vary: Accept' ); + // check if user can publish posts if ( \is_author() && ! user_can( \get_the_author_meta( 'ID' ), 'publish_posts' ) ) { return $template; From 4ed4d06fd5f651377551fa6860d2b5028cec00ca Mon Sep 17 00:00:00 2001 From: Alex Kirk Date: Fri, 21 Apr 2023 17:41:04 +0200 Subject: [PATCH 17/26] Add comment --- includes/class-activitypub.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index b20eb71..16a1f22 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -39,6 +39,7 @@ class Activitypub { return $template; } + // Ensure that edge caches know that this page can deliver both HTML and JSON. header( 'Vary: Accept' ); // check if user can publish posts From 28c077e422645d84ea4fc8ff41157e5555fe59a2 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Sun, 23 Apr 2023 22:56:45 +0200 Subject: [PATCH 18/26] Add URL --- includes/model/class-post.php | 43 +++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/includes/model/class-post.php b/includes/model/class-post.php index cfe49b6..76d4d03 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -28,6 +28,13 @@ class Post { */ private $id; + /** + * The Object URL. + * + * @var string + */ + private $url; + /** * The Object Summary. * @@ -179,6 +186,7 @@ class Post { $array = array( 'id' => $this->get_id(), + 'url' => $this->get_url(), 'type' => $this->get_object_type(), 'published' => \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_date_gmt ) ), 'attributedTo' => \get_author_posts_url( $post->post_author ), @@ -206,6 +214,29 @@ class Post { return \wp_json_encode( $this->to_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT ); } + /** + * Returns the URL of an Activity Object + * + * @return string + */ + public function get_url() { + if ( $this->url ) { + return $this->url; + } + + $post = $this->post; + + if ( 'trash' === get_post_status( $post ) ) { + $permalink = \get_post_meta( $post->url, 'activitypub_canonical_url', true ); + } else { + $permalink = \get_permalink( $post ); + } + + $this->url = $permalink; + + return $permalink; + } + /** * Returns the ID of an Activity Object * @@ -216,17 +247,9 @@ class Post { return $this->id; } - $post = $this->post; + $this->id = $this->get_url(); - if ( 'trash' === get_post_status( $post ) ) { - $permalink = \get_post_meta( $post->ID, 'activitypub_canonical_url', true ); - } else { - $permalink = \get_permalink( $post ); - } - - $this->id = $permalink; - - return $permalink; + return $this->id; } /** From 77415ef510a1ebea33d567c354e87e02cf0df824 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Sun, 23 Apr 2023 22:57:03 +0200 Subject: [PATCH 19/26] Remove "(Fediverse)" --- includes/class-admin.php | 2 +- templates/followers-list.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/class-admin.php b/includes/class-admin.php index 220ed9b..fbb953a 100644 --- a/includes/class-admin.php +++ b/includes/class-admin.php @@ -31,7 +31,7 @@ class Admin { \add_action( 'load-' . $settings_page, array( self::class, 'add_settings_help_tab' ) ); - $followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers (Fediverse)', 'activitypub' ), 'read', 'activitypub-followers-list', array( self::class, 'followers_list_page' ) ); + $followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers', 'activitypub' ), 'read', 'activitypub-followers-list', array( self::class, 'followers_list_page' ) ); \add_action( 'load-' . $followers_list_page, array( self::class, 'add_followers_list_help_tab' ) ); } diff --git a/templates/followers-list.php b/templates/followers-list.php index 057f498..a7136ce 100644 --- a/templates/followers-list.php +++ b/templates/followers-list.php @@ -1,5 +1,5 @@
    -

    +

    From 47dc2f72d1095eb02fe0975c95936c82a139ddc5 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Mon, 24 Apr 2023 09:49:06 +0200 Subject: [PATCH 20/26] fix "bulk replace" issue --- includes/model/class-post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 76d4d03..470ad70 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -227,7 +227,7 @@ class Post { $post = $this->post; if ( 'trash' === get_post_status( $post ) ) { - $permalink = \get_post_meta( $post->url, 'activitypub_canonical_url', true ); + $permalink = \get_post_meta( $post->ID, 'activitypub_canonical_url', true ); } else { $permalink = \get_permalink( $post ); } From 3f4c44db05e7a6b8df24f7891a177b865972e4d8 Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Mon, 24 Apr 2023 09:15:48 +0200 Subject: [PATCH 21/26] Compatibility: do not serve images with Jetpack CDN when active When Jetpack's image CDN is active, core calls to retrieve images return an image served by the CDN. Since Fediverse instances usually fetch and cache the data themselves, we do not need to use the CDN for those images when returned by the ActivityPub plugin. In fact, we really do not want that to happen, as Fediverse instances may get errors when trying to fetch images from the CDN (they may get blocked / rate-limited / ...). Let's hook into Jetpack's CDN to avoid that. --- includes/model/class-post.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 470ad70..6f33cc3 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -306,7 +306,24 @@ class Post { // get URLs for each image foreach ( $image_ids as $id ) { $alt = \get_post_meta( $id, '_wp_attachment_image_alt', true ); + + /** + * If you use the Jetpack plugin and its Image CDN, aka Photon, + * the image strings returned will use the Photon URL. + * We don't want that since Fediverse instances already do caching on their end. + * Let the CDN only be used for visitors of the site. + */ + if ( class_exists( 'Jetpack_Photon' ) ) { + \remove_filter( 'image_downsize', array( \Jetpack_Photon::instance(), 'filter_image_downsize' ) ); + } + $thumbnail = \wp_get_attachment_image_src( $id, 'full' ); + + // Re-enable Photon now that the image URL has been built. + if ( class_exists( 'Jetpack_Photon' ) ) { + \add_filter( 'image_downsize', array( \Jetpack_Photon::instance(), 'filter_image_downsize' ), 10, 3 ); + } + $mimetype = \get_post_mime_type( $id ); if ( $thumbnail ) { From 56d2b7e8be6b6765138dbd6a4170a056c7e95794 Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Mon, 24 Apr 2023 09:49:05 +0200 Subject: [PATCH 22/26] Update to handle both old and new versions of Jetpack See https://github.com/Automattic/jetpack/pull/30050/ --- includes/model/class-post.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 6f33cc3..a69e139 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -312,15 +312,23 @@ class Post { * the image strings returned will use the Photon URL. * We don't want that since Fediverse instances already do caching on their end. * Let the CDN only be used for visitors of the site. + * + * Old versions of Jetpack used the Jetpack_Photon class to do this. + * New versions use the Image_CDN class. + * Let's handle both. */ - if ( class_exists( 'Jetpack_Photon' ) ) { + if ( \class_exists( '\Automattic\Jetpack\Image_CDN\Image_CDN' ) ) { + \remove_filter( 'image_downsize', array( \Automattic\Jetpack\Image_CDN\Image_CDN::instance(), 'filter_image_downsize' ) ); + } elseif ( \class_exists( 'Jetpack_Photon' ) ) { \remove_filter( 'image_downsize', array( \Jetpack_Photon::instance(), 'filter_image_downsize' ) ); } $thumbnail = \wp_get_attachment_image_src( $id, 'full' ); // Re-enable Photon now that the image URL has been built. - if ( class_exists( 'Jetpack_Photon' ) ) { + if ( \class_exists( '\Automattic\Jetpack\Image_CDN\Image_CDN' ) ) { + \add_filter( 'image_downsize', array( \Automattic\Jetpack\Image_CDN\Image_CDN::instance(), 'filter_image_downsize' ), 10, 3 ); + } elseif ( \class_exists( 'Jetpack_Photon' ) ) { \add_filter( 'image_downsize', array( \Jetpack_Photon::instance(), 'filter_image_downsize' ), 10, 3 ); } From 2afe74b29bf49e5d3745a5f21f10db09892c3001 Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Tue, 25 Apr 2023 11:03:33 +0200 Subject: [PATCH 23/26] Compatibility: the plugin is compatible with WP 6.2. --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 9c7661d..6fe6189 100644 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: pfefferle, mediaformat, akirk, automattic Tags: OStatus, fediverse, activitypub, activitystream Requires at least: 4.7 -Tested up to: 6.1 +Tested up to: 6.2 Stable tag: 0.17.0 Requires PHP: 5.6 License: MIT From 6ee59d2a10e5e1d53b3cc93b30850d98a1403145 Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Tue, 25 Apr 2023 11:04:32 +0200 Subject: [PATCH 24/26] Add changelog --- readme.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.txt b/readme.txt index 6fe6189..e89c768 100644 --- a/readme.txt +++ b/readme.txt @@ -113,6 +113,10 @@ Where 'blog' is the path to the subdirectory at which your blog resides. Project maintained on GitHub at [pfefferle/wordpress-activitypub](https://github.com/pfefferle/wordpress-activitypub). += Next = + +* Compatibility: indicate that the plugin is compatible and has been tested with the latest version of WordPress, 6.2. + = 0.17.0 = * Fix type-selector From ca646588d2b64af1621221b4a862b9275b02f4c6 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Tue, 25 Apr 2023 20:44:54 +0200 Subject: [PATCH 25/26] ignore `www` subdomain when comparing hosts fix #290 --- includes/rest/class-webfinger.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/includes/rest/class-webfinger.php b/includes/rest/class-webfinger.php index d41cf25..10dcfa4 100644 --- a/includes/rest/class-webfinger.php +++ b/includes/rest/class-webfinger.php @@ -54,15 +54,16 @@ class Webfinger { $resource = \str_replace( 'acct:', '', $resource ); $resource_identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) ); - $resource_host = \substr( \strrchr( $resource, '@' ), 1 ); + $resource_host = \str_replace( 'www.', '', \substr( \strrchr( $resource, '@' ), 1 ) ); + $blog_host = \str_replace( 'www.', '', \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) ); - if ( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) !== $resource_host ) { + if ( $blog_host !== $resource_host ) { return new WP_Error( 'activitypub_wrong_host', \__( 'Resource host does not match blog host', 'activitypub' ), array( 'status' => 404 ) ); } $user = \get_user_by( 'login', \esc_sql( $resource_identifier ) ); - if ( ! $user || ! user_can( $user, 'publish_posts' ) ) { + if ( ! $user || ! \user_can( $user, 'publish_posts' ) ) { return new WP_Error( 'activitypub_user_not_found', \__( 'User not found', 'activitypub' ), array( 'status' => 404 ) ); } From 98619dc3198181ad44736afdb82cf74ae31a296d Mon Sep 17 00:00:00 2001 From: Alex Kirk Date: Wed, 26 Apr 2023 10:08:22 +0200 Subject: [PATCH 26/26] Protect img tags from replacing mentions --- includes/class-mention.php | 6 ++++++ tests/test-class-activitypub-mention.php | 1 + 2 files changed, 7 insertions(+) diff --git a/includes/class-mention.php b/includes/class-mention.php index e0930cc..9c93d80 100644 --- a/includes/class-mention.php +++ b/includes/class-mention.php @@ -46,6 +46,12 @@ class Mention { $the_content ); + $the_content = preg_replace_callback( + '#]+>#i', + $protect, + $the_content + ); + $the_content = \preg_replace_callback( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/', array( self::class, 'replace_with_links' ), $the_content ); $the_content = str_replace( array_reverse( array_keys( $protected_tags ) ), array_reverse( array_values( $protected_tags ) ), $the_content ); diff --git a/tests/test-class-activitypub-mention.php b/tests/test-class-activitypub-mention.php index 6f6b9ff..ca7395f 100644 --- a/tests/test-class-activitypub-mention.php +++ b/tests/test-class-activitypub-mention.php @@ -31,6 +31,7 @@ ENDPRE; array( 'hallo @pfefferle@notiz.blog test', 'hallo @pfefferle@notiz.blog test' ), array( 'hallo @pfefferle@notiz.blog test', 'hallo @pfefferle@notiz.blog test' ), array( 'hallo @pfefferle@notiz.blog test', 'hallo @pfefferle@notiz.blog test' ), + array( 'hallo https://notiz.blog/@pfefferle/ test', 'hallo https://notiz.blog/@pfefferle/ test' ), array( $code, $code ), array( $pre, $pre ), );