Sync your WordPress posts to standard.site records on your PDS
1=== Wireservice ===
2Contributors: tylrfishr
3Tags: atproto, bluesky, syndication
4Requires at least: 6.4
5Tested up to: 6.9
6Requires PHP: 8.3
7Stable tag: 1.2.0
8License: AGPLv3 or later
9License URI: https://www.gnu.org/licenses/agpl-3.0.html
10
11Publish your posts and pages to the AT Protocol using the standard.site lexicons.
12
13## Requirements
14
15- PHP 8.3+
16- WordPress 6.4+
17
18## Setup
19
201. Go to **Settings > Wireservice**.
212. Connect your AT Protocol account via the OAuth flow.
223. Configure your **Publication** settings (name, description, icon, theme colors) and sync to AT Protocol.
234. Enable **Document** syncing and configure how post titles, descriptions, and cover images are sourced.
24
25## How It Works
26
27### Publication
28
29Your WordPress site is represented as a `site.standard.publication` record on AT Protocol. The plugin syncs site-level metadata including:
30
31- **Name** — from WordPress site title, Yoast SEO, or a custom value
32- **Description** — from WordPress tagline, Yoast SEO, or a custom value
33- **Icon** — from WordPress site icon or a custom upload
34- **Theme colors** — background, foreground, accent, and accent foreground. NOTE: these are used by other ATProto platforms to style your content, not on your WordPress site.
35- **Discoverability** — opt in or out of discovery feeds. NOTE: these are used by other ATProto platforms to show your publication in algorithmic feeds, not on your WordPress site.
36
37The plugin also serves a `.well-known/site.standard.publication` endpoint that returns the AT-URI of your publication record.
38
39### Documents
40
41When document syncing is enabled, published posts and pages are automatically synced as `site.standard.document` records. Each document includes:
42
43- Title and description (configurable source)
44- Cover image (featured image, Yoast SEO image, or custom)
45- Publication date and last-updated date
46- Relative path (permalink)
47- Tags and categories
48- Optionally, full plain-text content
49
50Documents are created on publish, updated on edit, and deleted when a post is trashed, deleted, or unpublished.
51
52A `<link rel="site.standard.document">` tag is added to the `<head>` of each synced post for verification.
53
54Note that Wireservice does not have a content lexicon yet. This is in development.
55
56### Per-Post Overrides
57
58A **Wireservice** meta box appears on the post editor, allowing per-post overrides for:
59
60- Title source
61- Description source
62- Cover image source
63- Whether to include full content
64
65## Yoast SEO Integration
66
67When Yoast SEO is active, additional source options become available for both publication and document settings:
68
69- **Publication**: Yoast organization name, website name, homepage meta description
70- **Documents**: Yoast SEO title, social title, X title, meta description, social description, X description, social image, X image
71
72## Self-Hosting the OAuth Service
73
74Wireservice authenticates with AT Protocol through an external OAuth service. By default it uses `https://aip.wireservice.net`, but you can run your own instance using [AIP](https://github.com/graze-social/aip), a high-performance OAuth 2.1 authorization server with native AT Protocol integration.
75
76### Running AIP
77
78AIP requires Rust 1.87+. To run locally:
79
801. Generate an OAuth signing key with `goat`: `goat key generate -t p256`. Save the public and private keys somewhere safe.
81
822. Clone AIP: `git clone https://github.com/graze-social/aip.git`
83
843. Setup environment variables:
85
86```
87EXTERNAL_BASE=https://your-domain.com
88DPOP_NONCE_SEED=$(openssl rand -hex 32)
89STORAGE_BACKEND=sqlite
90ATPROTO_OAUTH_SIGNING_KEYS=`did:key:${YOUR_PRIVATE_KEY}`
91OAUTH_SIGNING_KEYS=`did:key:${YOUR_PRIVATE_KEY}`
92ENABLE_CLIENT_API=true
93OAUTH_SUPPORTED_SCOPES="atproto:atproto atproto:repo:site.standard.publication atproto:repo:site.standard.document
94atproto:blob:*/*"
95```
96
974. Run AIP: `cargo run --bin aip`
98
99Or with Docker:
100
101```
102docker build -t aip .
103docker run -p 8080:8080 \
104 // all of the above env vars here
105 aip
106```
107
108For production, use the `postgres` storage backend instead of `sqlite`. Depending on your hosting environment, you may need to manually set the `DNS_NAMESERVERS` env var so that your AIP service can resolve handles properly. (Wireservice uses `8.8.8.8,1.1.1.1`).
109
110### Configuring Wireservice
111
112Once your AIP instance is running, update the OAuth Service URL in WordPress:
113
1141. Go to **Settings > Wireservice**.
1152. Set the **OAuth Service URL** to your AIP instance (e.g., `https://your-domain.com`).
116
117This is stored as the `wireservice_oauth_url` option and can also be set programmatically:
118
119```
120update_option('wireservice_oauth_url', 'https://your-domain.com');
121```
122
123## Filters
124
125```
126// Customize which post types are synced (default: post, page)
127add_filter('wireservice_syncable_post_types', function ($types) {
128 $types[] = 'custom_post_type';
129 return $types;
130});
131
132// Control whether a specific post should sync
133add_filter('wireservice_should_sync_post', function ($should_sync, $post) {
134 return $should_sync;
135}, 10, 2);
136```
137
138## License
139
140[AGPL 3.0](LICENSE.md)