diff --git a/FEDERATION.md b/FEDERATION.md index 078fef4..831d5af 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -14,6 +14,7 @@ The WordPress plugin largely follows ActivityPub's server-to-server specificatio - [FEP-f1d5: NodeInfo in Fediverse Software](https://codeberg.org/fediverse/fep/src/branch/main/fep/f1d5/fep-f1d5.md) - [FEP-67ff: FEDERATION.md](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) - [FEP-5feb: Search indexing consent for actors](https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md) +- [FEP-2677: Identifying the Application Actor](https://codeberg.org/fediverse/fep/src/branch/main/fep/2677/fep-2677.md) Partially supported FEPs diff --git a/README.md b/README.md index e83f274..7947c21 100644 --- a/README.md +++ b/README.md @@ -68,10 +68,10 @@ Implemented: * share posts * receive comments/reactions * signature verification +* threaded comments support To implement: -* threaded comments support * replace shortcodes with blocks for layout ### What is "ActivityPub for WordPress" ### @@ -111,7 +111,9 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu * Fixed: Normalize attributes that can have mixed value types * Added: URL support for WebFinger * Added: Make Post-Template filterable -* Addes: CSS class for ActivityPub comments to allow custom designs +* Added: CSS class for ActivityPub comments to allow custom designs +* Added: FEP-2677: Identifying the Application Actor +* Improved: WebFinger endpoints ### 1.3.0 ### diff --git a/includes/activity/class-activity.php b/includes/activity/class-activity.php index 96ee095..68caa34 100644 --- a/includes/activity/class-activity.php +++ b/includes/activity/class-activity.php @@ -196,7 +196,7 @@ class Activity extends Base_Object { public function set_object( $object ) { // convert array to object if ( is_array( $object ) ) { - $object = Base_Object::init_from_array( $object ); + $object = self::init_from_array( $object ); } // set object diff --git a/includes/class-health-check.php b/includes/class-health-check.php index 74a6f9e..22d95f2 100644 --- a/includes/class-health-check.php +++ b/includes/class-health-check.php @@ -39,11 +39,6 @@ class Health_Check { 'test' => array( self::class, 'test_webfinger' ), ); - $tests['direct']['activitypub_test_system_cron'] = array( - 'label' => __( 'System Cron Test', 'activitypub' ), - 'test' => array( self::class, 'test_system_cron' ), - ); - return $tests; } diff --git a/includes/class-shortcodes.php b/includes/class-shortcodes.php index 491a6ad..922c10d 100644 --- a/includes/class-shortcodes.php +++ b/includes/class-shortcodes.php @@ -127,8 +127,7 @@ class Shortcodes { // Strip out any remaining tags. $excerpt = \wp_strip_all_tags( $excerpt ); - /** This filter is documented in wp-includes/formatting.php */ - $excerpt_more = \apply_filters( 'excerpt_more', ' [...]' ); + $excerpt_more = \apply_filters( 'activitypub_excerpt_more', ' […]' ); $excerpt_more_len = strlen( $excerpt_more ); // We now have a excerpt, but we need to check it's length, it may be longer than we want for two reasons: diff --git a/includes/model/class-application-user.php b/includes/model/class-application-user.php index cf4d9cc..8fb4ee6 100644 --- a/includes/model/class-application-user.php +++ b/includes/model/class-application-user.php @@ -38,6 +38,15 @@ class Application_User extends Blog_User { return get_rest_url_by_path( 'application' ); } + /** + * Returns the User-URL with @-Prefix for the username. + * + * @return string The User-URL with @-Prefix for the username. + */ + public function get_alternate_url() { + return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_preferred_username() ); + } + public function get_name() { return 'application'; } @@ -69,4 +78,8 @@ class Application_User extends Blog_User { public function get_indexable() { return false; } + + public function get_type() { + return $this->type; + } } diff --git a/includes/model/class-blog-user.php b/includes/model/class-blog-user.php index bee52f3..5026684 100644 --- a/includes/model/class-blog-user.php +++ b/includes/model/class-blog-user.php @@ -100,12 +100,12 @@ class Blog_User extends User { } /** - * Returns the User-URL with @-Prefix for the username. + * Get blog's homepage URL. * - * @return string The User-URL with @-Prefix for the username. + * @return string The User-Url. */ - public function get_at_url() { - return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_preferred_username() ); + public function get_alternate_url() { + return \esc_url( \trailingslashit( get_home_url() ) ); } /** diff --git a/includes/model/class-user.php b/includes/model/class-user.php index 018c70e..54f88b5 100644 --- a/includes/model/class-user.php +++ b/includes/model/class-user.php @@ -135,8 +135,8 @@ class User extends Actor { * * @return string The User-URL with @-Prefix for the username. */ - public function get_at_url() { - return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_username() ); + public function get_alternate_url() { + return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_preferred_username() ); } public function get_preferred_username() { diff --git a/includes/rest/class-nodeinfo.php b/includes/rest/class-nodeinfo.php index e9f346c..7537310 100644 --- a/includes/rest/class-nodeinfo.php +++ b/includes/rest/class-nodeinfo.php @@ -108,6 +108,12 @@ class Nodeinfo { 'outbound' => array(), ); + $nodeinfo['metadata'] = array( + 'nodeName' => \get_bloginfo( 'name' ), + 'nodeDescription' => \get_bloginfo( 'description' ), + 'nodeIcon' => \get_site_icon_url(), + ); + return new WP_REST_Response( $nodeinfo, 200 ); } @@ -174,7 +180,7 @@ class Nodeinfo { ), array( 'rel' => 'https://www.w3.org/ns/activitystreams#Application', - 'href' => Application_User::from_wp_user( Users::APPLICATION_USER_ID )->get_url(), + 'href' => get_rest_url_by_path( 'application' ), ), ); diff --git a/includes/rest/class-webfinger.php b/includes/rest/class-webfinger.php index 52abd9f..fac408e 100644 --- a/includes/rest/class-webfinger.php +++ b/includes/rest/class-webfinger.php @@ -94,10 +94,13 @@ class Webfinger { $aliases = array( $user->get_url(), + $user->get_alternate_url(), ); + $aliases = array_unique( $aliases ); + $profile = array( - 'subject' => $resource, + 'subject' => sprintf( 'acct:%s', $user->get_resource() ), 'aliases' => array_values( array_unique( $aliases ) ), 'links' => array( array( @@ -113,9 +116,9 @@ class Webfinger { ), ); - if ( 'Group' === $user->get_type() ) { + if ( 'Person' !== $user->get_type() ) { $profile['links'][0]['properties'] = array( - 'https://www.w3.org/ns/activitystreams#type' => 'Group', + 'https://www.w3.org/ns/activitystreams#type' => $user->get_type(), ); } diff --git a/integration/class-nodeinfo.php b/integration/class-nodeinfo.php index dea6c67..02f3a64 100644 --- a/integration/class-nodeinfo.php +++ b/integration/class-nodeinfo.php @@ -3,6 +3,7 @@ namespace Activitypub\Integration; use function Activitypub\get_total_users; use function Activitypub\get_active_users; +use function Activitypub\get_rest_url_by_path; /** * Compatibility with the NodeInfo plugin @@ -14,8 +15,10 @@ class Nodeinfo { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_filter( 'nodeinfo_data', array( self::class, 'add_nodeinfo_discovery' ), 10, 2 ); - \add_filter( 'nodeinfo2_data', array( self::class, 'add_nodeinfo2_discovery' ), 10 ); + \add_filter( 'nodeinfo_data', array( self::class, 'add_nodeinfo_data' ), 10, 2 ); + \add_filter( 'nodeinfo2_data', array( self::class, 'add_nodeinfo2_data' ), 10 ); + + \add_filter( 'wellknown_nodeinfo_data', array( self::class, 'add_wellknown_nodeinfo_data' ), 10, 2 ); } /** @@ -26,7 +29,7 @@ class Nodeinfo { * * @return array The extended array */ - public static function add_nodeinfo_discovery( $nodeinfo, $version ) { + public static function add_nodeinfo_data( $nodeinfo, $version ) { if ( $version >= '2.0' ) { $nodeinfo['protocols'][] = 'activitypub'; } else { @@ -50,7 +53,7 @@ class Nodeinfo { * * @return array The extended array */ - public static function add_nodeinfo2_discovery( $nodeinfo ) { + public static function add_nodeinfo2_data( $nodeinfo ) { $nodeinfo['protocols'][] = 'activitypub'; $nodeinfo['usage']['users'] = array( @@ -61,4 +64,20 @@ class Nodeinfo { return $nodeinfo; } + + /** + * Extend the well-known nodeinfo data + * + * @param array $data The well-known nodeinfo data + * + * @return array The extended array + */ + public static function add_wellknown_nodeinfo_data( $data ) { + $data['links'][] = array( + 'rel' => 'https://www.w3.org/ns/activitystreams#Application', + 'href' => get_rest_url_by_path( 'application' ), + ); + + return $data; + } } diff --git a/integration/class-webfinger.php b/integration/class-webfinger.php index 6b3b6dd..e5fdd5d 100644 --- a/integration/class-webfinger.php +++ b/integration/class-webfinger.php @@ -14,8 +14,8 @@ class Webfinger { * Initialize the class, registering WordPress hooks */ public static function init() { - \add_filter( 'webfinger_user_data', array( self::class, 'add_user_discovery' ), 10, 3 ); - \add_filter( 'webfinger_data', array( self::class, 'add_pseudo_user_discovery' ), 99, 2 ); + \add_filter( 'webfinger_user_data', array( self::class, 'add_user_discovery' ), 1, 3 ); + \add_filter( 'webfinger_data', array( self::class, 'add_pseudo_user_discovery' ), 1, 2 ); } /** @@ -34,6 +34,11 @@ class Webfinger { return $array; } + $array['subject'] = sprintf( 'acct:%s', $user->get_resource() ); + + $array['aliases'][] = $user->get_url(); + $array['aliases'][] = $user->get_alternate_url(); + $array['links'][] = array( 'rel' => 'self', 'type' => 'application/activity+json', diff --git a/readme.txt b/readme.txt index 40f210a..c15b43f 100644 --- a/readme.txt +++ b/readme.txt @@ -68,10 +68,10 @@ Implemented: * share posts * receive comments/reactions * signature verification +* threaded comments support To implement: -* threaded comments support * replace shortcodes with blocks for layout = What is "ActivityPub for WordPress" = @@ -111,7 +111,9 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu * Fixed: Normalize attributes that can have mixed value types * Added: URL support for WebFinger * Added: Make Post-Template filterable -* Addes: CSS class for ActivityPub comments to allow custom designs +* Added: CSS class for ActivityPub comments to allow custom designs +* Added: FEP-2677: Identifying the Application Actor +* Improved: WebFinger endpoints = 1.3.0 = diff --git a/tests/test-class-activitypub-shortcodes.php b/tests/test-class-activitypub-shortcodes.php index b1413e8..7b592e0 100644 --- a/tests/test-class-activitypub-shortcodes.php +++ b/tests/test-class-activitypub-shortcodes.php @@ -62,4 +62,34 @@ class Test_Activitypub_Shortcodes extends WP_UnitTestCase { $this->assertEquals( '', $content ); Shortcodes::unregister(); } + + public function test_excerpt() { + Shortcodes::register(); + global $post; + + $post_id = -97; // negative ID, to avoid clash with a valid post + $post = new stdClass(); + $post->ID = $post_id; + $post->post_author = 1; + $post->post_date = current_time( 'mysql' ); + $post->post_date_gmt = current_time( 'mysql', 1 ); + $post->post_title = 'Some title or other'; + $post->post_content = 'Lorem ipsum dolor sit amet, consectetur.'; + $post->post_status = 'publish'; + $post->comment_status = 'closed'; + $post->ping_status = 'closed'; + $post->post_name = 'fake-page-' . rand( 1, 99999 ); // append random number to avoid clash + $post->post_type = 'page'; + $post->filter = 'raw'; // important! + + $content = '[ap_excerpt length="25"]'; + + // Fill in the shortcodes. + setup_postdata( $post ); + $content = do_shortcode( $content ); + wp_reset_postdata(); + + $this->assertEquals( "

Lorem ipsum […]

\n", $content ); + Shortcodes::unregister(); + } }