diff --git a/README.md b/README.md index 93f3e85..dcc91f2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **Tags:** OStatus, fediverse, activitypub, activitystream **Requires at least:** 4.7 **Tested up to:** 6.3 -**Stable tag:** 1.0.7 +**Stable tag:** 1.0.10 **Requires PHP:** 5.6 **License:** MIT **License URI:** http://opensource.org/licenses/MIT @@ -105,6 +105,26 @@ Where 'blog' is the path to the subdirectory at which your blog resides. Project maintained on GitHub at [automattic/wordpress-activitypub](https://github.com/automattic/wordpress-activitypub). +### 1.0.10 ### + +* Improved: better error messages if remote profile is not accessible + +### 1.0.9 ### + +* Fixed: broken following endpoint + +### 1.0.8 ### + +* Fixed: blocking of HEAD requests +* Fixed: PHP fatal error +* Fixed: several typos +* Fixed: error codes +* Improved: loading of shortcodes +* Updated: caching of followers +* Updated: Application-User is no longer "indexable" +* Updated: more consistent usage of the `application/activity+json` Content-Type +* Removed: featured tags endpoint + ### 1.0.7 ### * Fixed: broken function call diff --git a/activitypub.php b/activitypub.php index 521a379..97f6067 100644 --- a/activitypub.php +++ b/activitypub.php @@ -3,7 +3,7 @@ * Plugin Name: ActivityPub * Plugin URI: https://github.com/pfefferle/wordpress-activitypub/ * Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format. - * Version: 1.0.7 + * Version: 1.0.10 * Author: Matthias Pfefferle & Automattic * Author URI: https://automattic.com/ * License: MIT @@ -69,7 +69,6 @@ function plugin_init() { \add_action( 'init', array( __NAMESPACE__ . '\Collection\Followers', 'init' ) ); \add_action( 'init', array( __NAMESPACE__ . '\Admin', 'init' ) ); \add_action( 'init', array( __NAMESPACE__ . '\Hashtag', 'init' ) ); - \add_action( 'init', array( __NAMESPACE__ . '\Shortcodes', 'init' ) ); \add_action( 'init', array( __NAMESPACE__ . '\Mention', 'init' ) ); \add_action( 'init', array( __NAMESPACE__ . '\Health_Check', 'init' ) ); \add_action( 'init', array( __NAMESPACE__ . '\Scheduler', 'init' ) ); diff --git a/includes/class-shortcodes.php b/includes/class-shortcodes.php index 43be17b..708aa61 100644 --- a/includes/class-shortcodes.php +++ b/includes/class-shortcodes.php @@ -5,14 +5,9 @@ use function Activitypub\esc_hashtag; class Shortcodes { /** - * Class constructor, registering WordPress then Shortcodes + * Register the shortcodes */ - public static function init() { - // do not load on admin pages - if ( is_admin() ) { - return; - } - + public static function register() { foreach ( get_class_methods( self::class ) as $shortcode ) { if ( 'init' !== $shortcode ) { add_shortcode( 'ap_' . $shortcode, array( self::class, $shortcode ) ); @@ -20,6 +15,17 @@ class Shortcodes { } } + /** + * Unregister the shortcodes + */ + public static function unregister() { + foreach ( get_class_methods( self::class ) as $shortcode ) { + if ( 'init' !== $shortcode ) { + remove_shortcode( 'ap_' . $shortcode ); + } + } + } + /** * Generates output for the 'ap_hashtags' shortcode * diff --git a/includes/class-signature.php b/includes/class-signature.php index 1789dd6..d021cf0 100644 --- a/includes/class-signature.php +++ b/includes/class-signature.php @@ -4,6 +4,7 @@ namespace Activitypub; use WP_Error; use DateTime; use DateTimeZone; +use WP_REST_Request; use Activitypub\Collection\Users; /** @@ -226,7 +227,7 @@ class Signature { /** * Verifies the http signatures * - * @param WP_REQUEST|array $request The request object or $_SERVER array. + * @param WP_REST_Request|array $request The request object or $_SERVER array. * * @return mixed A boolean or WP_Error. */ @@ -259,7 +260,7 @@ class Signature { } if ( ! isset( $headers['signature'] ) ) { - return new WP_Error( 'activitypub_signature', __( 'Request not signed', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( 'activitypub_signature', __( 'Request not signed', 'activitypub' ), array( 'status' => 401 ) ); } if ( array_key_exists( 'signature', $headers ) ) { @@ -269,7 +270,7 @@ class Signature { } if ( ! isset( $signature_block ) || ! $signature_block ) { - return new WP_Error( 'activitypub_signature', __( 'Incompatible request signature. keyId and signature are required', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( 'activitypub_signature', __( 'Incompatible request signature. keyId and signature are required', 'activitypub' ), array( 'status' => 401 ) ); } $signed_headers = $signature_block['headers']; @@ -279,12 +280,12 @@ class Signature { $signed_data = self::get_signed_data( $signed_headers, $signature_block, $headers ); if ( ! $signed_data ) { - return new WP_Error( 'activitypub_signature', __( 'Signed request date outside acceptable time window', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( 'activitypub_signature', __( 'Signed request date outside acceptable time window', 'activitypub' ), array( 'status' => 401 ) ); } $algorithm = self::get_signature_algorithm( $signature_block ); if ( ! $algorithm ) { - return new WP_Error( 'activitypub_signature', __( 'Unsupported signature algorithm (only rsa-sha256 and hs2019 are supported)', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( 'activitypub_signature', __( 'Unsupported signature algorithm (only rsa-sha256 and hs2019 are supported)', 'activitypub' ), array( 'status' => 401 ) ); } if ( \in_array( 'digest', $signed_headers, true ) && isset( $body ) ) { @@ -300,7 +301,7 @@ class Signature { } if ( \base64_encode( \hash( $hashalg, $body, true ) ) !== $digest[1] ) { // phpcs:ignore - return new WP_Error( 'activitypub_signature', __( 'Invalid Digest header', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( 'activitypub_signature', __( 'Invalid Digest header', 'activitypub' ), array( 'status' => 401 ) ); } } @@ -313,7 +314,7 @@ class Signature { $verified = \openssl_verify( $signed_data, $signature_block['signature'], $public_key, $algorithm ) > 0; if ( ! $verified ) { - return new WP_Error( 'activitypub_signature', __( 'Invalid signature', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( 'activitypub_signature', __( 'Invalid signature', 'activitypub' ), array( 'status' => 401 ) ); } return $verified; } @@ -323,17 +324,25 @@ class Signature { * * @param string $key_id The URL to the public key. * - * @return WP_Error|string The public key. + * @return WP_Error|string The public key or WP_Error. */ public static function get_remote_key( $key_id ) { // phpcs:ignore $actor = get_remote_metadata_by_actor( strip_fragment_from_url( $key_id ) ); // phpcs:ignore if ( \is_wp_error( $actor ) ) { - return $actor; + return new WP_Error( + 'activitypub_no_remote_profile_found', + __( 'No Profile found or Profile not accessible', 'activitypub' ), + array( 'status' => 401 ) + ); } if ( isset( $actor['publicKey']['publicKeyPem'] ) ) { return \rtrim( $actor['publicKey']['publicKeyPem'] ); // phpcs:ignore } - return new WP_Error( 'activitypub_no_remote_key_found', __( 'No Public-Key found', 'activitypub' ), array( 'status' => 403 ) ); + return new WP_Error( + 'activitypub_no_remote_key_found', + __( 'No Public-Key found', 'activitypub' ), + array( 'status' => 401 ) + ); } /** diff --git a/includes/collection/class-followers.php b/includes/collection/class-followers.php index a9fe298..c2ad01f 100644 --- a/includes/collection/class-followers.php +++ b/includes/collection/class-followers.php @@ -173,8 +173,6 @@ class Followers { return new WP_Error( 'activitypub_invalid_follower', __( 'Invalid Follower', 'activitypub' ), array( 'status' => 400 ) ); } - $error = null; - $follower = new Follower(); $follower->from_array( $meta ); @@ -184,14 +182,10 @@ class Followers { return $id; } - $meta = get_post_meta( $id, 'activitypub_user_id' ); - - if ( $error ) { - self::add_error( $id, $error ); - } + $post_meta = get_post_meta( $id, 'activitypub_user_id' ); // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict - if ( is_array( $meta ) && ! in_array( $user_id, $meta ) ) { + if ( is_array( $post_meta ) && ! in_array( $user_id, $post_meta ) ) { add_post_meta( $id, 'activitypub_user_id', $user_id ); wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' ); } diff --git a/includes/compat.php b/includes/compat.php index 4bee640..3dd405c 100644 --- a/includes/compat.php +++ b/includes/compat.php @@ -35,3 +35,15 @@ if ( ! function_exists( 'get_self_link' ) ) { return esc_url( apply_filters( 'self_link', set_url_scheme( 'http://' . $host['host'] . $path ) ) ); } } + +if ( ! function_exists( 'is_countable' ) ) { + /** + * Polyfill for `is_countable()` function added in PHP 7.3. + * + * @param mixed $value The value to check. + * @return bool True if `$value` is countable, otherwise false. + */ + function is_countable( $value ) { + return is_array( $value ) || $value instanceof \Countable; + } +} diff --git a/includes/functions.php b/includes/functions.php index afb9d51..2e87a98 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -42,7 +42,7 @@ function get_webfinger_resource( $user_id ) { * @param string $actor The Actor URL. * @param bool $cached If the result should be cached. * - * @return array The Actor profile as array + * @return array|WP_Error The Actor profile as array or WP_Error on failure. */ function get_remote_metadata_by_actor( $actor, $cached = true ) { $pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor ); @@ -74,32 +74,25 @@ function get_remote_metadata_by_actor( $actor, $cached = true ) { if ( ! \wp_http_validate_url( $actor ) ) { $metadata = new WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), array( 'status' => 400, 'actor' => $actor ) ); - \set_transient( $transient_key, $metadata, HOUR_IN_SECONDS ); // Cache the error for a shorter period. return $metadata; } - $short_timeout = function() { - return 10; - }; - add_filter( 'activitypub_remote_get_timeout', $short_timeout ); $response = Http::get( $actor ); - remove_filter( 'activitypub_remote_get_timeout', $short_timeout ); + if ( \is_wp_error( $response ) ) { - \set_transient( $transient_key, $response, HOUR_IN_SECONDS ); // Cache the error for a shorter period. return $response; } $metadata = \wp_remote_retrieve_body( $response ); $metadata = \json_decode( $metadata, true ); - \set_transient( $transient_key, $metadata, WEEK_IN_SECONDS ); - if ( ! $metadata ) { $metadata = new WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), array( 'status' => 400, 'actor' => $actor ) ); - \set_transient( $transient_key, $metadata, HOUR_IN_SECONDS ); // Cache the error for a shorter period. return $metadata; } + \set_transient( $transient_key, $metadata, WEEK_IN_SECONDS ); + return $metadata; } diff --git a/includes/model/class-application-user.php b/includes/model/class-application-user.php index 1cfcec0..cf4d9cc 100644 --- a/includes/model/class-application-user.php +++ b/includes/model/class-application-user.php @@ -58,10 +58,6 @@ class Application_User extends Blog_User { return null; } - public function get_featured_tags() { - return null; - } - public function get_featured() { return null; } @@ -69,4 +65,8 @@ class Application_User extends Blog_User { public function get_moderators() { return null; } + + public function get_indexable() { + return false; + } } diff --git a/includes/model/class-user.php b/includes/model/class-user.php index f62772d..95c83d7 100644 --- a/includes/model/class-user.php +++ b/includes/model/class-user.php @@ -18,15 +18,6 @@ class User extends Actor { */ protected $_id; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore - /** - * The Featured-Tags. - * - * @see https://docs.joinmastodon.org/spec/activitypub/#featuredTags - * - * @var string - */ - protected $featured_tags; - /** * The Featured-Posts. * @@ -235,15 +226,6 @@ class User extends Actor { return get_rest_url_by_path( sprintf( 'users/%d/collections/featured', $this->get__id() ) ); } - /** - * Returns the Featured-Tags-API-Endpoint. - * - * @return string The Featured-Tags-Endpoint. - */ - public function get_featured_tags() { - return get_rest_url_by_path( sprintf( 'users/%d/collections/tags', $this->get__id() ) ); - } - /** * Extend the User-Output with Attachments. * diff --git a/includes/rest/class-collection.php b/includes/rest/class-collection.php index 5fa585d..365641c 100644 --- a/includes/rest/class-collection.php +++ b/includes/rest/class-collection.php @@ -105,7 +105,7 @@ class Collection { '@context' => Activity::CONTEXT, 'id' => get_rest_url_by_path( sprintf( 'users/%d/collections/tags', $user->get__id() ) ), 'type' => 'Collection', - 'totalItems' => count( $tags ), + 'totalItems' => is_countable( $tags ) ? count( $tags ) : 0, 'items' => array(), ); @@ -117,7 +117,10 @@ class Collection { ); } - return new WP_REST_Response( $response, 200 ); + $rest_response = new WP_REST_Response( $response, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); + + return $rest_response; } /** @@ -160,7 +163,7 @@ class Collection { '@context' => Activity::CONTEXT, 'id' => get_rest_url_by_path( sprintf( 'users/%d/collections/featured', $user_id ) ), 'type' => 'OrderedCollection', - 'totalItems' => count( $posts ), + 'totalItems' => is_countable( $posts ) ? count( $posts ) : 0, 'orderedItems' => array(), ); @@ -168,7 +171,10 @@ class Collection { $response['orderedItems'][] = Post::transform( $post )->to_object()->to_array(); } - return new WP_REST_Response( $response, 200 ); + $rest_response = new WP_REST_Response( $response, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); + + return $rest_response; } /** @@ -192,7 +198,10 @@ class Collection { $response['orderedItems'][] = $user->get_url(); } - return new WP_REST_Response( $response, 200 ); + $rest_response = new WP_REST_Response( $response, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); + + return $rest_response; } /** diff --git a/includes/rest/class-followers.php b/includes/rest/class-followers.php index b7be9d0..71e4840 100644 --- a/includes/rest/class-followers.php +++ b/includes/rest/class-followers.php @@ -103,10 +103,10 @@ class Followers { $data['followers'] ); - $response = new WP_REST_Response( $json, 200 ); - $response->header( 'Content-Type', 'application/activity+json' ); + $rest_response = new WP_REST_Response( $json, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); - return $response; + return $rest_response; } /** diff --git a/includes/rest/class-following.php b/includes/rest/class-following.php index 33bdf65..58e4375 100644 --- a/includes/rest/class-following.php +++ b/includes/rest/class-following.php @@ -1,6 +1,7 @@ totalItems = count( $items ); // phpcs:ignore + $json->totalItems = is_countable( $items ) ? count( $items ) : 0; // phpcs:ignore $json->orderedItems = $items; // phpcs:ignore $json->first = $json->partOf; // phpcs:ignore - $response = new \WP_REST_Response( $json, 200 ); - $response->header( 'Content-Type', 'application/activity+json' ); + $rest_response = new WP_REST_Response( $json, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); - return $response; + return $rest_response; } /** diff --git a/includes/rest/class-inbox.php b/includes/rest/class-inbox.php index 7901c78..525509c 100644 --- a/includes/rest/class-inbox.php +++ b/includes/rest/class-inbox.php @@ -109,11 +109,10 @@ class Inbox { */ \do_action( 'activitypub_inbox_post' ); - $response = new WP_REST_Response( $json, 200 ); + $rest_response = new WP_REST_Response( $json, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); - $response->header( 'Content-Type', 'application/activity+json' ); - - return $response; + return $rest_response; } /** @@ -138,7 +137,10 @@ class Inbox { \do_action( 'activitypub_inbox', $data, $user->get__id(), $type ); \do_action( "activitypub_inbox_{$type}", $data, $user->get__id() ); - return new WP_REST_Response( array(), 202 ); + $rest_response = new WP_REST_Response( array(), 202 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); + + return $rest_response; } /** @@ -158,7 +160,7 @@ class Inbox { 'rest_invalid_param', \__( 'No recipients found', 'activitypub' ), array( - 'status' => 404, + 'status' => 400, 'params' => array( 'to' => \__( 'Please check/validate "to" field', 'activitypub' ), 'bto' => \__( 'Please check/validate "bto" field', 'activitypub' ), @@ -183,7 +185,10 @@ class Inbox { \do_action( "activitypub_inbox_{$type}", $data, $user->ID ); } - return new WP_REST_Response( array(), 202 ); + $rest_response = new WP_REST_Response( array(), 202 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); + + return $rest_response; } /** @@ -523,7 +528,7 @@ class Inbox { $recipient_items = array_merge( $recipient_items, $recipient ); } - if ( array_key_exists( $i, $data['object'] ) ) { + if ( is_array( $data['object'] ) && array_key_exists( $i, $data['object'] ) ) { if ( is_array( $data['object'][ $i ] ) ) { $recipient = $data['object'][ $i ]; } else { diff --git a/includes/rest/class-nodeinfo.php b/includes/rest/class-nodeinfo.php index 1f6277a..4829e75 100644 --- a/includes/rest/class-nodeinfo.php +++ b/includes/rest/class-nodeinfo.php @@ -88,7 +88,7 @@ class Nodeinfo { ) ); - if ( is_array( $users ) ) { + if ( is_countable( $users ) ) { $users = count( $users ); } else { $users = 1; @@ -145,7 +145,7 @@ class Nodeinfo { ) ); - if ( is_array( $users ) ) { + if ( is_countable( $users ) ) { $users = count( $users ); } else { $users = 1; diff --git a/includes/rest/class-outbox.php b/includes/rest/class-outbox.php index eb35e86..d640d17 100644 --- a/includes/rest/class-outbox.php +++ b/includes/rest/class-outbox.php @@ -123,11 +123,10 @@ class Outbox { */ \do_action( 'activitypub_outbox_post' ); - $response = new WP_REST_Response( $json, 200 ); + $rest_response = new WP_REST_Response( $json, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); - $response->header( 'Content-Type', 'application/activity+json' ); - - return $response; + return $rest_response; } /** diff --git a/includes/rest/class-server.php b/includes/rest/class-server.php index e1a1037..0e6e4cc 100644 --- a/includes/rest/class-server.php +++ b/includes/rest/class-server.php @@ -2,6 +2,7 @@ namespace Activitypub\Rest; use stdClass; +use WP_Error; use WP_REST_Response; use Activitypub\Signature; use Activitypub\Model\Application_User; @@ -54,11 +55,10 @@ class Server { $json = $user->to_array(); - $response = new WP_REST_Response( $json, 200 ); + $rest_response = new WP_REST_Response( $json, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); - $response->header( 'Content-Type', 'application/activity+json' ); - - return $response; + return $rest_response; } /** @@ -74,6 +74,10 @@ class Server { * @return mixed|WP_Error The response, error, or modified response. */ public static function authorize_activitypub_requests( $response, $handler, $request ) { + if ( 'HEAD' === $request->get_method() ) { + return $response; + } + $route = $request->get_route(); // check if it is an activitypub request and exclude webfinger and nodeinfo endpoints @@ -86,16 +90,16 @@ class Server { } // POST-Requets are always signed - if ( 'get' !== \strtolower( $request->get_method() ) ) { + if ( 'GET' !== $request->get_method() ) { $verified_request = Signature::verify_http_signature( $request ); if ( \is_wp_error( $verified_request ) ) { - return $verified_request; + return new WP_Error( 'activitypub_signature_verification', $verified_request->get_error_message(), array( 'status' => 401 ) ); } - } elseif ( 'get' === \strtolower( $request->get_method() ) ) { // GET-Requests are only signed in secure mode + } elseif ( 'GET' === $request->get_method() ) { // GET-Requests are only signed in secure mode if ( ACTIVITYPUB_AUTHORIZED_FETCH ) { $verified_request = Signature::verify_http_signature( $request ); if ( \is_wp_error( $verified_request ) ) { - return $verified_request; + return new WP_Error( 'activitypub_signature_verification', $verified_request->get_error_message(), array( 'status' => 401 ) ); } } } diff --git a/includes/rest/class-users.php b/includes/rest/class-users.php index 31a92dd..9fb10ba 100644 --- a/includes/rest/class-users.php +++ b/includes/rest/class-users.php @@ -95,10 +95,10 @@ class Users { $json = $user->to_array(); - $response = new WP_REST_Response( $json, 200 ); - $response->header( 'Content-Type', 'application/activity+json' ); + $rest_response = new WP_REST_Response( $json, 200 ); + $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) ); - return $response; + return $rest_response; } diff --git a/includes/transformer/class-post.php b/includes/transformer/class-post.php index eb2bd5a..28e40a4 100644 --- a/includes/transformer/class-post.php +++ b/includes/transformer/class-post.php @@ -5,6 +5,7 @@ use WP_Post; use Activitypub\Collection\Users; use Activitypub\Model\Blog_User; use Activitypub\Activity\Base_Object; +use Activitypub\Shortcodes; use function Activitypub\esc_hashtag; use function Activitypub\is_single_user; @@ -334,6 +335,8 @@ class Post { return \ucfirst( \get_option( 'activitypub_object_type', 'note' ) ); } + // Default to Article. + $object_type = 'Article'; $post_type = \get_post_type( $this->wp_post ); switch ( $post_type ) { case 'post': @@ -466,6 +469,8 @@ class Post { $post = $this->wp_post; $content = $this->get_post_content_template(); + // Register our shortcodes just in time. + Shortcodes::register(); // Fill in the shortcodes. setup_postdata( $post ); $content = do_shortcode( $content ); @@ -477,6 +482,9 @@ class Post { $content = \apply_filters( 'activitypub_the_content', $content, $post ); + // Don't need these any more, should never appear in a post. + Shortcodes::unregister(); + return $content; } diff --git a/readme.txt b/readme.txt index 03e9b39..7e48fc1 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: automattic, pfefferle, mediaformat, mattwiebe, akirk, jeherve, nur Tags: OStatus, fediverse, activitypub, activitystream Requires at least: 4.7 Tested up to: 6.3 -Stable tag: 1.0.7 +Stable tag: 1.0.10 Requires PHP: 5.6 License: MIT License URI: http://opensource.org/licenses/MIT @@ -105,6 +105,26 @@ Where 'blog' is the path to the subdirectory at which your blog resides. Project maintained on GitHub at [automattic/wordpress-activitypub](https://github.com/automattic/wordpress-activitypub). += 1.0.10 = + +* Improved: better error messages if remote profile is not accessible + += 1.0.9 = + +* Fixed: broken following endpoint + += 1.0.8 = + +* Fixed: blocking of HEAD requests +* Fixed: PHP fatal error +* Fixed: several typos +* Fixed: error codes +* Improved: loading of shortcodes +* Updated: caching of followers +* Updated: Application-User is no longer "indexable" +* Updated: more consistent usage of the `application/activity+json` Content-Type +* Removed: featured tags endpoint + = 1.0.7 = * Fixed: broken function call diff --git a/tests/test-class-activitypub-shortcodes.php b/tests/test-class-activitypub-shortcodes.php index 8637a61..b1413e8 100644 --- a/tests/test-class-activitypub-shortcodes.php +++ b/tests/test-class-activitypub-shortcodes.php @@ -1,6 +1,10 @@ assertEquals( '

hallo

', $content ); + Shortcodes::unregister(); } public function test_password_protected_content() { + Shortcodes::register(); global $post; $post_id = -98; // negative ID, to avoid clash with a valid post @@ -54,5 +60,6 @@ class Test_Activitypub_Shortcodes extends WP_UnitTestCase { wp_reset_postdata(); $this->assertEquals( '', $content ); + Shortcodes::unregister(); } }