This document describes proposals for the evolvment of the [WordPress ActivityPub plugin](https://github.com/Automattic/WordPress-ActivityPub/) in the field of the interaction with other WordPress plugins that may add additional ActivityPub features.
- **Transformers:** a piece of code that transfers a WordPress-post of a specific WordPress-post-type to an ActivityPub object of a specific WordPress-object-type. For example a transformer that can transform:
-`post` to a `Note`
-`post` to a `Article`
-`post` 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`
- 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
* collisions that happen afterwards (e.g. a new user registering with the same username as the blog-wide actor)
- maybe distinguishes between the default admin user interface and advanced sections which give the user more fine-grained control:
Our primary goal is to make it possible that events created within an event plugin can federate properly as an ActivityPub object with Type `Event` along with all the meta-data belonging to the event, as found in common ActivityPub implementations, e.g. of Mobilizon, in order to ensure maximum compatibly between those services.
Nevertheless, we see a lot of other cases that can benefit, if we achieve this using a modularized approach as proposed below. The following list indicates examples what might be those other benefits:
- Other types of content get federated in a more feature rich way:
-`PodcastEpisode` (as proposed by CastoPod)
-`Question` (as used by Mastodon)
-`Product`
- ...
- 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).
Every public WordPress post type may be transformed (have different transformers available) to a different ActivityPub object types. Transformations that are not
- 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.
- If two transformers with the same source and target are installed, then we have two possibilities:
1. A dropdown menu is displayed to select one of the transformers.
2. Adding another column and maybe add indicators where the transformer comes from (e.g. `builtin`, `custom` or showing the source)
- Should a transformer be always a many-to-one relationship or may it be a many-to-many one.
- Do we really want to manage which transformers apply to what directly or do users prefer a setting like "let a certain plugin take care of this post type"? Then further configuration would have to be managed by the other plugins.
Currently, only one hard-coded transformer exists in [`includes/transformer/class-post.php`](https://github.com/Automattic/wordpress-activitypub/blob/master/includes/transformer/class-post.php).
```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() {
...
```
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_target_activitypub_object_type(): string;
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.
With the design above the transformer does a lot and leaves a lot of responsibility to the developer implementing it.
Possible alternatives and solutions:
- The ActivityPub plugin could provide reusable Traits for common tasks.
- 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.
- Don't use an interface with implementations, (miss)use class extensions.
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.
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.
- If both are enabled the `blog`-actor will announce (boosting) the posts of the
ActivityPub knows several [actor types](https://www.w3.org/TR/activitystreams-core/#actors):
- Application
- Group
- Organization
- Person
- Service
The specifications allow for a lot of flexibility in their use. As WordPress websites serve a variety of tasks and goals, providing more detailed capabilities and options in this area **may prove challenging to accomplish in a user-friendly manner**.
- 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.
- 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, or create events if the `author`-actors are not enabled.
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 site, even if they choose to federate them."
Each ActivityPub actor must have a [unique ID](https://www.w3.org/TR/activitypub/#obj-id). In our case this is a HTTPS URI.
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.
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.
- 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>`.
Anyway it seems the question has to be raised wheter activitypub should store a history of all past and currently mapped actors.
[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.
They can also chain extractors recursivly, 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.