I’ve been on a journey to get WPwatercooler.com to be on the fediverse and it hasn’t been as easy as I was thinking it was going to be. Folks that run a website and want to use Mastodon to build community around it have a few options for being presented on the Fediverse. This post isn’t going to help you solve this yet but I hope we can work out what needs to be done in order to do so.
- Make an account on an existing Mastodon instance, share your links to your content there
- Build your own Mastodon instance and make an account there and share your content
- Use ActivityPub and allow people to follow your website on any Fediverse property
There is most likely more but for the most part its those 3 that you can select from.
I started out with WPwatercooler on Mastodon.online which can be found at https://mastodon.online/@wpwatercooler this works fine and people can follow it but I wanted to see if I could take it a step further and add WPwatercooler.com to the Fediverse directly and this is where ActivityPub comes in.
I installed these three plugins so that I could offer up ActivityPub via WebFinger and people on Mastodon will be able to find the website on there. I created 2 accounts on WPwatercooler.com one for each show wpwatercooler and devbranch and then I did a search for @wpwatercooler and @devbranch on my Mastodon instance and was able to find them.
The Problem
The thing I and other folks in our community ran into was that we could follow the accounts and if we tried a bunch sometimes it should register. Seems to be a caching issues I think. Let’s check and see.
WebFinger
In part WebFinger is a protocol that allows for discovery of information about people and things identified by a URI. Information about a person might be discovered via an acct: URI, for example, which is a URI that looks like an email address.
Both of these accounts can be found by going to https://wpwatercooler.com/author/devbranch/ and https://wpwatercooler.com/author/wpwatercooler/ as you can see both of these are authors on the WPwatercooler website like I spoke about before. When someone tries and searches for @wpwatercooler on Mastodon it accesses https://wpwatercooler.com/.well-known/webfinger?resource=acct:[email protected] and as you can see from the url it looks at the domain name in the .well-known/webfinder and looks for the resource with the account name of [email protected]
Webfinger offers up a json output that looks like the following:
{
“subject”: “acct:[email protected]”,
“aliases”: [
“acct:[email protected]”,
“https://wpwatercooler.com/author/wpwatercooler/”,
“mailto:[email protected]”
],
“links”: [
{
“rel”: “http://webfinger.net/rel/profile-page”,
“href”: “https://wpwatercooler.com/author/wpwatercooler/”,
“type”: “text/html”
},
{
“rel”: “http://webfinger.net/rel/avatar”,
“href”: “https://wpwatercooler.com/wp-content/uploads/2015/06/cropped-WPwatercooler-Avatar-2023-2-96x96.png”
},
{
“rel”: “http://webfinger.net/rel/profile-page”,
“href”: “https://www.wpwatercooler.com”,
“type”: “text/html”
},
{
“rel”: “self”,
“type”: “application/activity+json”,
“href”: “https://wpwatercooler.com/author/wpwatercooler/”
},
{
“rel”: “http://nodeinfo.diaspora.software/ns/schema/2.0”,
“href”: “https://wpwatercooler.com/wp-json/nodeinfo/2.0”
},
{
“rel”: “http://nodeinfo.diaspora.software/ns/schema/1.1”,
“href”: “https://wpwatercooler.com/wp-json/nodeinfo/1.1”
},
{
“rel”: “http://nodeinfo.diaspora.software/ns/schema/1.0”,
“href”: “https://wpwatercooler.com/wp-json/nodeinfo/1.0”
},
{
“rel”: “https://feneas.org/ns/serviceinfo”,
“type”: “application/ld+json”,
“href”: “https://wpwatercooler.com/wp-json/serviceinfo/1.0”,
“properties”: {
“https://feneas.org/ns/serviceinfo#software.name”: “WPwatercooler”
}
},
{
“rel”: “http://schemas.google.com/g/2010#updates-from”,
“href”: “https://wpwatercooler.com/author/wpwatercooler/feed/ostatus/”,
“type”: “application/atom+xml”
},
{
“rel”: “http://ostatus.org/schema/1.0/subscribe”,
“template”: “https://wpwatercooler.com/?profile={uri}”
},
{
“rel”: “feed”,
“type”: “application/stream+json”,
“title”: “Activity-Streams 1.0 Feed”,
“href”: “https://wpwatercooler.com/author/wpwatercooler/feed/as1/”
},
{
“rel”: “feed”,
“type”: “application/activity+json”,
“title”: “Activity-Streams 2.0 Feed”,
“href”: “https://wpwatercooler.com/author/wpwatercooler/feed/as2/”
}
]
}
the section we’re interested in is
{
“rel”: “self”,
“type”: “application/activity+json”,
“href”: “https://wpwatercooler.com/author/wpwatercooler/”
},
This section has the author url and you can see that its using the type of application/activity+json instead of something like text/html so when it queries that url it passes along in the header Accept: application/activity+json and it should return it in that format.
Running the following command
$ url -i -H “Accept: application/activity+json” “https://wpwatercooler.com/author/wpwatercooler”
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 —:—:— —:—:— —:—:— 0HTTP/2 200
date: Tue, 17 Jan 2023 17:42:34 GMT
content-type: text/html; charset=UTF-8
last-modified: Tue, 17 Jan 2023 16:11:53 GMT
cache-control: max-age=0
expires: Tue, 17 Jan 2023 16:40:07 GMT
vary: Accept-Encoding
age: 3746
x-cache: HIT
cf-cache-status: DYNAMIC
server-timing: cf-q-config;dur=9.0000003183377e-06
report-to: {“endpoints”:[{“url”:“https:\/\/a.nel.cloudflare.com\/report\/v3?s=hTOA5wCRdqy4Lkoey48CmI2UIbYym8HWAvtsssC4lRsXgli7%2BchgWImTY3ol%2FdS8gTcodIYZQ6cbSDMVZ1co5brwCJxEpkIdqJ%2FCEjwKcxOWhomHgfWISN9qzmkfkMd7tNo8fQORQ%3D%3D”}],“group”:“cf-nel”,“max_age”:604800}
nel: {“success_fraction”:0,“report_to”:“cf-nel”,“max_age”:604800}
server: cloudflare
cf-ray: 78b0e3631e862ea3-LAX
alt-svc: h3=“:443”; ma=86400, h3-29=“:443”; ma=86400
Cloudflare returns back text/html and outputs the author page and not the json we wanted. Talking with a few folks on Mastodon we found that people are having this issue with using Cloudflare and there isn’t anything we can do to resolve it sadly. I tried excluding the caching for the specific paths /author/(.*) and other such tricks and it keeps changing the content-type to text/html and not application/activity+json as requested.
Looking online I’ve found a bunch of people using Cloudflare + ActivityPub running into this issue and other technologies that also use Accept: application/activity+json and finding that it only returns text/html. Bummer.
The code that makes all that work can be found in the WordPress ActivityPub plugin class-activity-pub.php
/**
* Return a AS2 JSON version of an author, post or page.
*
* @param string $template The path to the template object.
*
* @return string The new path to the JSON template.
*/
public static function render_json_template( $template ) {
if ( ! \is_author() && ! \is_singular() && ! \is_home() ) {
return $template;
}
// check if user can publish posts
if ( \is_author() && ! user_can( \get_the_author_meta( 'ID' ), 'publish_posts' ) ) {
return $template;
}
if ( \is_author() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/author-json.php';
} elseif ( \is_singular() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-json.php';
} elseif ( \is_home() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/blog-json.php';
}
global $wp_query;
if ( isset( $wp_query->query_vars['activitypub'] ) ) {
return $json_template;
}
if ( ! isset( $_SERVER['HTTP_ACCEPT'] ) ) {
return $template;
}
$accept_header = $_SERVER['HTTP_ACCEPT'];
if (
\stristr( $accept_header, 'application/activity+json' ) ||
\stristr( $accept_header, 'application/ld+json' )
) {
return $json_template;
}
// Accept header as an array.
$accept = \explode( ',', \trim( $accept_header ) );
if (
\in_array( 'application/ld+json; profile=“https://www.w3.org/ns/activitystreams”', $accept, true ) ||
\in_array( 'application/activity+json', $accept, true ) ||
\in_array( 'application/ld+json', $accept, true ) ||
\in_array( 'application/json', $accept, true )
) {
return $json_template;
}
return $template;
}
Can this be done?
After discussing this with @tomfinley and @tim on mastodon in this tread https://simian.rodeo/@jasontucker/109701436056062907 we found that there is an endpoint that will return json https://wpwatercooler.com/author/wpwatercooler/activitypub
I’m wondering if instead we can force Webfinger to return that url with /activitypub at the end instead of expecting Cloudflare to return a non text/html content type. You can see this JSON output here https://wpwatercooler.com/author/wpwatercooler/activitypub/
“id”: “https://wpwatercooler.com/author/wpwatercooler/”,
“type”: “Person”,
“name”: “WPwatercooler Show”,
“summary”: “The world’s most influential WordPress podcast brought to you by Jason Tucker, Sé Reed & Jason Cosper”,
“preferredUsername”: “wpwatercooler”,
“url”: “https://wpwatercooler.com/author/wpwatercooler/”,
“icon”: {
“type”: “Image”,
“url”: “https://wpwatercooler.com/wp-content/uploads/2015/06/cropped-WPwatercooler-Avatar-2023-2-120x120.png”
},
“inbox”: “https://wpwatercooler.com/wp-json/activitypub/1.0/users/6260/inbox”,
“outbox”: “https://wpwatercooler.com/wp-json/activitypub/1.0/users/6260/outbox”,
“followers”: “https://wpwatercooler.com/wp-json/activitypub/1.0/users/6260/followers”,
“following”: “https://wpwatercooler.com/wp-json/activitypub/1.0/users/6260/following”,
“manuallyApprovesFollowers”: false,
“publicKey”: {
“id”: “https://wpwatercooler.com/author/wpwatercooler/#main-key”,
“owner”: “https://wpwatercooler.com/author/wpwatercooler/”,
What’s involved to make this work on Cloudflare? I’d love to hear in the comments and we can see about getting this combo of WordPress + CloudFlare + ActivityPub working, I’ve seen so many people complain about this not working with this very popular combo of technologies in the WordPress support forums.
Leave a Reply