documentation/architecture design proposal.md

248 lines
17 KiB
Markdown
Raw Normal View History

2023-10-03 15:41:47 +02:00
---
gitea: none
title: WordPress/ActivityPub
authors:
- André Menrath
2023-10-10 15:20:02 +02:00
- ruruLanguageTool Linter
2023-10-03 15:41:47 +02:00
include_toc: true
---
2023-10-10 15:20:02 +02:00
This document outlines suggestions for the further development of the WordPress ActivityPub plugin regarding its interoperability with other WordPress plugins that could enhance ActivityPub functionality.
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
# Terms used
2023-10-03 15:41:47 +02:00
The following terms are used:
## Content related
- **post type:** post types and custom post types within WordPress
- **Object Type:** ActivityPub [object type](https://www.w3.org/TR/activitystreams-vocabulary/#object-types)
- **Transformers:** a piece of code that converts items of particular WordPress post types to an ActivityPub object. For example a transformer that can transform:
- every post type to a `Note`
- `post` or `page` to `Note`, `Article`, `Image`, `Audio` or `Article` depending on the [post-format](https://wordpress.org/documentation/article/post-formats/)
- `tribe_events` (Event post the of [The Event Calendar](https://wordpress.org/plugins/the-events-calendar/)) to `Event`
2023-10-10 15:39:04 +02:00
- `podcast` (Podcast post of [Podlove Podcast Publisher](https://github.com/podlove/podlove-publisher)) to `PodcastEpisode` (as proposed and [implemented by Castopod](https://code.castopod.org/adaures/castopod/-/blob/main/app/Libraries/PodcastEpisode.php))
2023-10-03 15:45:21 +02:00
## Actor related
2023-10-05 10:46:22 +02:00
- **Actors:** ActivityPub [Actor Objects](https://www.w3.org/TR/activitypub/#actor-objects)
2023-10-03 16:45:00 +02:00
- **Actor Types:** ActivityPub [Actor Types](https://www.w3.org/TR/activitystreams-vocabulary/#actor-types)
2023-10-03 15:41:47 +02:00
- **WordPress actor types:** Things on WordPress that can be mapped to actors:
- WordPress users →`Person`
- Whole Blog →`Application` or `Group`
2023-10-10 15:20:02 +02:00
- post types → e.g., `Organization`
- custom definitions → custom actor types
2023-10-10 15:20:02 +02:00
- **Mapping:** Which WordPress actor types are mapped to any ActivityPub actors at all and to which ones.
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
## General
2023-10-05 11:56:20 +02:00
- **publish/dispatch:** Sending a `Create`, `Update` or `Announce` [Activity](https://www.w3.org/TR/activitypub/#create-activity-outbox).
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
# Principals of the changes proposed to the ActivityPub plugin
2023-10-03 15:41:47 +02:00
The WordPress ActivityPub plugin
- should be aware (or even control) the whole chain from creating some content within WordPress to being published via ActivityPub. For sure, it should be the only plugin that directly sends and receives ActivityPub.
- should not get any more complex by default, the out-of-the box functionality/features and simplicity should be similar to version 1.0.0.
- offers other plugins the possibility to register custom transformers.
- (maybe) offers other plugins the possibility to register new WordPress actor types, e.g. the `tribe_organizer` post type of [The Event Calendar](https://wordpress.org/plugins/the-events-calendar/).
- handles the controls collisions of actor names:
* collisions that are already present during activation of a WordPress actor type on the settings page
2023-10-10 15:20:02 +02:00
* collisions that happen afterwards (e.g., a new user registering with the same username as the blog-wide actor)
2023-10-05 11:56:20 +02:00
* (maybe) show notifications/warnings when using an actor name which has been used and followed by in the past, as there may be issues due to caching of the old public key.
2023-10-10 15:20:02 +02:00
- maybe distinguishes between the default user interface and advanced sections which give the user more fine-grained control:
2023-10-03 15:41:47 +02:00
* transformer management
* actor management
2023-10-03 15:45:21 +02:00
# Goals
2023-10-03 15:41:47 +02:00
2023-10-10 15:20:02 +02:00
## Goals of the WordPress Event Federation project
The aim of the event federations project is to enable seamless federation of events created within an event plugin as an ActivityPub object with Type `Event` and accompanying meta-data, as typically seen in common ActivityPub implementations like Mobilizon. This will guarantee optimal compatibility between various services.
2023-10-03 15:41:47 +02:00
## Tangential Objectives:
Nevertheless, we see a lot of other cases that can benefit, if the primary goals of the event federation project are achieved this using a modularized approach as proposed below. The following list indicates examples what might be those other benefits:
2023-10-03 15:41:47 +02:00
- Other types of content get federated in a more feature rich way:
2023-10-05 11:56:20 +02:00
- `PodcastEpisode` [as proposed by CastoPod](https://code.castopod.org/adaures/castopod/-/blob/main/app/Libraries/PodcastEpisode.php)
- `Question`
2023-10-03 15:41:47 +02:00
- `Product`
2023-10-10 15:20:02 +02:00
-
2023-10-03 15:41:47 +02:00
- ActivityPub offers features how to deal with multilingual content ([contentMap - see Example 115](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-contentmap)) which could be implemented differently by multilingual and translation plugins (example search for the current use of `->set_content_map` within the ActivityPub plugin).
2023-10-10 15:20:02 +02:00
**Note:** CastoPod, to give an example, has currently decided that podcast episodes will not be sent to followers as a `Create` activity directly containing the `PodcastEpisode` object, but will send a `Note` which is linking to the `PodcastEpisode`, because most Fediverse implementations currently ignore by default all object types they don't know. This is likely the same reason [flohmarkt](https://codeberg.org/grindhold/flohmarkt) is currently also using the `Note` and not `Product` even though that one would be available in the official specification.
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
# Transformer Management
2023-10-03 15:41:47 +02:00
2023-10-10 16:00:34 +02:00
## Current situation
2023-10-03 15:41:47 +02:00
2023-10-10 16:00:34 +02:00
### Frontend
2023-10-03 15:41:47 +02:00
The admin user interface in v1.0.0 lets one choose to which object type all post get transformed to. The options are:
2023-10-10 15:20:02 +02:00
* [x] Note (default) — Should work with most platforms.
* [ ] Article — The presentation of the "Article" might change on different platforms.
* [ ] WordPress Post-Format — Maps the WordPress Post-Format to the ActivityPub Object Type.
2023-10-03 15:41:47 +02:00
2023-10-10 16:00:34 +02:00
### Backend
Currently, all this functionality is handled via one hard-coded transformer in `includes/transformer/class post.php` ([Source](https://github.com/Automattic/wordpress-activitypub/blob/master/includes/transformer/class-post.php)) and the actual logic that assigns the type is somewhere else.
2023-10-03 15:41:47 +02:00
```php
/**
* WordPress Post Transformer
*
* The Post Transformer is responsible for transforming a WP_Post object into different othe
* Object-Types.
*
* Currently supported are:
*
* - Activitypub\Activity\Base_Object
*/
class Post {
...
/**
* Transforms the WP_Post object to an ActivityPub Object
*
* @see \Activitypub\Activity\Base_Object
*
* @return \Activitypub\Activity\Base_Object The ActivityPub Object
*/
public function to_object() {
...
```
2023-10-10 16:00:34 +02:00
## Proposal
2023-10-10 15:57:10 +02:00
All publicly accessible WordPress post types can become active for ActivityPub federation when selecting a transformer available for the relevant post type. The transformer determines the target ActivityPub object type, which can vary depending on variables like the post type or post format. If there is no specific transformer available for a given post type, it cannot be assigned through the user interface.
2023-10-10 16:00:34 +02:00
### Frontend
2023-10-10 15:57:10 +02:00
| | Note | Post-Format | The Events Calendar Transformer | Custom Event Transformer |
| ----------------- |:----:|:-----------:|:-------------------------------:|:------------------------:|
| **post** | X | O | - | - |
| **page** | O | O | - | - |
| **tribe_events** | O | - | X | O |
| **custom_event** | O | - | - | O |
| **...** | O | - | - | - |
**x:** Available transformers
**y:** Public and non-password protected WordPress post types
**Note:** Only one or zero selections can be made in each row.
- For any custom post type, if there is a custom transformer registered, indicate that one should be selected as default (or select it right ahead?).
- Should not differ too much from the current view: Maybe completely hide the current activity object type part of the settings and only show the buttons for `enable` and `disable` and move the transformer table to an advanced settings page.
- Maybe make the tables more advanced and clearly show the origin of the transformer (built-in, etc.) and maybe a Pop-Up with a description, or even a link to a configuration page of the transformer.
2023-10-10 16:00:34 +02:00
### Backend
2023-10-10 15:57:10 +02:00
2023-10-03 15:41:47 +02:00
A solution could be to define a transformer interface and let the transformers be implementations.
```php
interface Transformer {
public function get_supported_post_types(): array;
public function get_transformer_info(): array;
2023-10-03 15:41:47 +02:00
public function to_object(WP_Post $post);
....
}
```
Use WordPress's hook system or a public API function to let other plugins register their custom transformer implementations to the ActivityPub plugin.
2023-10-05 14:33:17 +02:00
**Problem:** With the design above the transformer does a lot and leaves a lot of responsibility to the developer implementing it.
2023-10-03 15:41:47 +02:00
**Possible alternatives and solutions:**
2023-10-03 15:41:47 +02:00
- The ActivityPub plugin could provide reusable Traits for common tasks.
- Highly unlikely: The ActivityPub plugin provides an even more height level framework for adding transformers. For example for events the ActivityPub plugin could provide a built-in transformer to the object type `Event` which only needs a mapping (might make things harder, instead of making them easier). See Appendix.
2023-10-03 15:41:47 +02:00
- Don't use an interface with implementations, (miss)use class extensions.
2023-10-10 15:57:10 +02:00
- Provide useful functions, documentation, and examples for automatic testing of transformers.
2023-10-03 15:41:47 +02:00
2023-10-05 11:56:20 +02:00
# Mapping: Actors and Dispatching
2023-10-03 15:41:47 +02:00
More comprehensive actor management would benefit our project aims and potentially meet the needs of others in the future. Nevertheless, **its importance is considerably lower than that of Transformer management**. In the future, the following factors may become more important when larger websites should be using the ActivityPub plugin.
2023-10-05 11:56:20 +02:00
## Current situation
2023-10-03 15:41:47 +02:00
Currently, the admin user interface in v1.0.0 gives very limited options.
```
- [ ] Enable `blog`-actor
- [ ] Enable `author`-actors
```
Note that depending on which options are enabled, the method of federating via ActivityPub varies significantly:
- If the `blog`-actor is enabled, but the `author`-actors are not, posts are attributed and created by the blog actor.
2023-10-10 15:20:02 +02:00
- If both options are enabled the `blog`-actor will announce (boost) the posts of the `author`-actors.
2023-10-03 15:41:47 +02:00
2023-10-10 15:20:02 +02:00
Currently, the whole logic controlling this is written within the `Activity_Dispatcher` [class](https://github.com/Automattic/wordpress-activitypub/blob/master/includes/class-activity-dispatcher.php#L21) which is currently triggered only within the `Scheduler` [class](https://github.com/Automattic/wordpress-activitypub/blob/master/includes/class-scheduler.php#L14-L15).
Furthermore, although a blog actor is available, the ActivityPub plugin is still written in such a way that WordPress users are the default ActivityPub actors. This also reflects in things like the class which is responsible for the actor lookup is still called `Users` and yet handles the `Blog` and the `Application` user too, see the [Source](https://github.com/Automattic/wordpress-activitypub/blob/master/includes/collection/class-users.php).
2023-10-05 11:56:20 +02:00
2023-10-03 15:45:21 +02:00
## Possibilities
2023-10-03 15:41:47 +02:00
ActivityPub knows several [actor types](https://www.w3.org/TR/activitystreams-core/#actors):
- `Application`
- `Group`
- `Organization`
- `Person`
- `Service`
2023-10-03 15:41:47 +02:00
2023-10-10 15:20:02 +02:00
The ActivityPub specification allows for immense flexibility in its application. As WordPress websites fulfill a variety of tasks and objectives, it is **challenging to implement control features and options for actor management that are more capable without sacrificing user-friendliness.**
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
## What features does our event federation project need?
2023-10-06 13:02:37 +02:00
- For maximum Mobilizon compatibility we would love to have simply an actor of type `Application`, preferable called `@relay@wordpress.site`, that announces all events. Nonetheless, in theory, a Mobilizon instance should have the capability to follow any other actor as well. More or less this can already be achieved with the current blog-actor.
2023-10-10 13:04:40 +02:00
- Additionally, for example, organizers in [The Event Calendar](https://wordpress.org/plugins/the-events-calendar/) could also offer their own actor of type `Organizer` or `Group` to publicize events (getting referred to via [attributedTo](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attributedto)) if the `author`-actors are enabled, or create events (being the [actor](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-actor) directly) if the `author`-actors are not enabled.
- Optional: As events are sometimes published a long time before they start, adding the possibility that events get announced again at a scheduled time before the start, e.g. by sending an `Announce` activity.
2023-10-05 11:56:20 +02:00
2023-10-03 15:45:21 +02:00
## Other features
2023-10-10 15:20:02 +02:00
Other WordPress actor types might have valid use cases, like actors for categories, or specific post types in general: "I only want to see the blog updates, but I do not want to spam my timeline with each product they post on their website, even if they choose to federate them."
2023-10-03 15:41:47 +02:00
2023-10-05 14:33:17 +02:00
**Problems:**
2023-10-03 15:41:47 +02:00
- Overall complexity may lead to programming and usage errors.
- Naming collisions become more likely. See below.
2023-10-03 15:41:47 +02:00
- Who is the `actor`, who is the `attributedTo`, who is just sending an `Announce` of a post?
2023-10-03 15:45:21 +02:00
## Proposed starting point for evaluating use cases
2023-10-03 15:41:47 +02:00
We keep in mind that every post type shall only ever send as a `Create` Activity once by one single actor.
2023-10-05 14:33:17 +02:00
**User Interface:**
2023-10-05 15:27:08 +02:00
2023-10-03 15:41:47 +02:00
| | users | tribe_organizers | custom | blog | category |
| -----------------|:-----:|:----------------:|:------:|:-----:|:--------:|
| **post** | C | O | O | A | A |
| **page** | C | O | O | A | O |
| **tribe_events** | O | C | - | A | 0 |
| **product** | O | - | C | 0 | 0 |
**x:** WordPress actor-types
2023-10-05 10:48:09 +02:00
**y:** WordPress post types
2023-10-10 15:20:02 +02:00
**C:** `Create` — can only be assigned once per row
**A:** `Announce` — can be assigned multiple times per row, but only if a `Create` has been assigned before
2023-10-03 15:41:47 +02:00
**user:** the WordPress user publishing or updating something
**all:** blog-wide actor, everything that is published (like a relay)
2023-10-10 15:20:02 +02:00
**custom:** e.g. only a certain post type that gets announced with this actor
2023-10-03 15:41:47 +02:00
**tribe_organizers:** only posts by one organizer
- Only allow setting something to `Announce`, when a `Create` is already set.
- Maybe forbid, that a user can automatically announce a post, because it's the "lowest level".
2023-10-03 15:45:21 +02:00
## Actor collisions
2023-10-03 15:41:47 +02:00
Each ActivityPub actor must have a [unique ID](https://www.w3.org/TR/activitypub/#obj-id). In our case this is a HTTPS URI.
2023-10-10 15:20:02 +02:00
But in reality [webfinger](https://webfinger.net/) is used: `@actor-name@instance.tld`. Actors like Persons and Groups and Applications have public keys attached to them, as well as their ID is probably cached by most software. So assigning some actor-name to something new also can cause unintended behavior.
2023-10-03 15:41:47 +02:00
2023-10-10 15:20:02 +02:00
If multiple plugins want to individually federate their content (like events, products, and blog posts or even the built-in WordPress categories), they must be able to have something like an actor API, the ActivityPub plugin can register. The ActivityPub plugin being the main coordinator is necessary because actors are globally unique.
2023-10-03 15:41:47 +02:00
- For existing (collision was created before the installation/activation of the plugin)
- For new collisions (collision was/will be created after the installation/activation of the plugin)
It seems like it is the best if collisions are avoided in the first place by encouraging the use of prefixes, like `category_<category>`.
2023-10-03 15:45:21 +02:00
### Existing collisions
2023-10-03 15:41:47 +02:00
- **Easy:** Either we just tell the user to resolve all conflicts before a WordPress actor type can be activated at all
- **Complex:** We let him choose alternatives for conflicts.
2023-10-03 15:45:21 +02:00
### New collisions
2023-10-03 15:41:47 +02:00
- **Easy** Forbid the saving of new users or posts that would conflict with an existing actor.
2023-10-10 15:20:02 +02:00
- **Complex** …
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
## Conclusion
2023-10-03 15:41:47 +02:00
- Anyway it seems the question has to be raised whether the ActivityPub plugin should store a history of all past and currently mapped actors.
- Additionally, shouldn't the user have a detailed overview in each case if the actor management should get more complex?
2023-10-05 14:35:02 +02:00
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
# Appendix
2023-10-03 15:41:47 +02:00
2023-10-03 15:45:21 +02:00
## The approach of youtube-dl
[youtube-dl](https://github.com/ytdl-org/youtube-dl) is solving a similar problem with "extractors" that return data to the processing-chain of youtube-dl. They provide a base class that includes useful functions for common issues e.g. automatic testing, geo-bypassing, login/cookie/header management. The most [basic extractor](https://github.com/ytdl-org/youtube-dl#adding-support-for-a-new-site) is about 40 lines of code.
2023-10-10 15:20:02 +02:00
They can also chain extractors recursively, like a extractor for mastodon videos, that gets the video from the post and returns the source of the video, that could be YouTube, Vimeo or anything else youtube-dl supports.