@geekity/plugin-wordpress 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -9
- package/dist/bundle/index.js +24337 -2098
- package/dist/bundle/plugin.json +2 -2
- package/dist/comments-import.d.ts +3 -0
- package/dist/comments-import.d.ts.map +1 -0
- package/dist/comments-import.js +155 -0
- package/dist/comments-import.js.map +1 -0
- package/dist/content-command.d.ts +3 -0
- package/dist/content-command.d.ts.map +1 -0
- package/dist/content-command.js +100 -0
- package/dist/content-command.js.map +1 -0
- package/dist/content-import.d.ts +53 -0
- package/dist/content-import.d.ts.map +1 -0
- package/dist/content-import.js +251 -0
- package/dist/content-import.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/media-import.d.ts +3 -0
- package/dist/media-import.d.ts.map +1 -0
- package/dist/media-import.js +89 -0
- package/dist/media-import.js.map +1 -0
- package/dist/media-redirect.d.ts +4 -0
- package/dist/media-redirect.d.ts.map +1 -0
- package/dist/media-redirect.js +28 -0
- package/dist/media-redirect.js.map +1 -0
- package/dist/media.d.ts +14 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +102 -0
- package/dist/media.js.map +1 -0
- package/dist/posts-import.d.ts +34 -0
- package/dist/posts-import.d.ts.map +1 -0
- package/dist/posts-import.js +301 -0
- package/dist/posts-import.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wordpress-html.d.ts +7 -0
- package/dist/wordpress-html.d.ts.map +1 -0
- package/dist/wordpress-html.js +360 -0
- package/dist/wordpress-html.js.map +1 -0
- package/dist/wxr.d.ts +80 -0
- package/dist/wxr.d.ts.map +1 -0
- package/dist/wxr.js +212 -0
- package/dist/wxr.js.map +1 -0
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
A [Geekity CMS](../cms/README.md) plugin for a site that moved from the
|
|
4
4
|
WordPress ActivityPub plugin. It answers the old plugin's inbox and collection
|
|
5
5
|
paths until every follower's server has refetched the actor, records when each
|
|
6
|
-
path was last asked for, and adds `geekity import wordpress
|
|
7
|
-
brings
|
|
6
|
+
path was last asked for, and adds two imports: `geekity import wordpress`,
|
|
7
|
+
which brings the content of a WordPress export across, and
|
|
8
|
+
`geekity import wordpress-actor`, which brings each person's key pair, actor id
|
|
9
|
+
and followers across.
|
|
8
10
|
|
|
9
11
|
A site born on the CMS never needs it. Stored actor ids, post object ids,
|
|
10
12
|
WebFinger aliases and the feed and archive layout are the site's own and are in
|
|
@@ -12,6 +14,9 @@ WebFinger aliases and the feed and archive layout are the site's own and are in
|
|
|
12
14
|
|
|
13
15
|
## Installing it
|
|
14
16
|
|
|
17
|
+
It works with every 0.x release of `@geekity/cms` from the one it was built
|
|
18
|
+
against, which its peer dependency names.
|
|
19
|
+
|
|
15
20
|
Add the package to the site and to `plugins` in its config:
|
|
16
21
|
|
|
17
22
|
```sh
|
|
@@ -34,16 +39,18 @@ under `/admin/plugins`:
|
|
|
34
39
|
docker compose exec geekity geekity plugin add @geekity/plugin-wordpress
|
|
35
40
|
```
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
old paths
|
|
39
|
-
and disabling it takes them away
|
|
42
|
+
Both imports work as soon as the plugin is installed. The
|
|
43
|
+
old paths, and the redirects from WordPress media URLs, are served only while
|
|
44
|
+
the plugin is enabled under `/admin/plugins`, and disabling it takes them away
|
|
45
|
+
on the next request, with nothing restarted.
|
|
40
46
|
|
|
41
47
|
The plugin keeps two files in `data/plugins/@geekity/plugin-wordpress/`:
|
|
42
48
|
|
|
43
|
-
| File | What it holds
|
|
44
|
-
| --------------- |
|
|
45
|
-
| `actors.json` | Each username and the number WordPress gave that person's actor, which the old paths are built from. Written by the import.
|
|
46
|
-
| `requests.json` | When each old path was last asked for, per user, and when the shared inbox was. Losing it resets what the screen says.
|
|
49
|
+
| File | What it holds |
|
|
50
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `actors.json` | Each username and the number WordPress gave that person's actor, which the old paths are built from. Written by the import. |
|
|
52
|
+
| `requests.json` | When each old path was last asked for, per user, and when the shared inbox was. Losing it resets what the screen says. |
|
|
53
|
+
| `import.json` | A hash of every file `geekity import wordpress` wrote, by path, and each `site.json`, `media.json` and redirect key it set. Losing it makes every imported file a clash on the next run. |
|
|
47
54
|
|
|
48
55
|
## The old paths
|
|
49
56
|
|
|
@@ -68,6 +75,164 @@ plugin's screen under Plugins, `/admin/plugins/@geekity/plugin-wordpress`,
|
|
|
68
75
|
lists each path with that instant, or _Never_. Once every follower's server has
|
|
69
76
|
refetched the actor, nothing asks any more, and the plugin can be disabled.
|
|
70
77
|
|
|
78
|
+
## Bringing the content across
|
|
79
|
+
|
|
80
|
+
`geekity import wordpress` reads the WXR file WordPress writes under Tools >
|
|
81
|
+
Export (or `wp export`) and writes what it holds into the content directory:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
geekity import wordpress example.WordPress.2026-10-08.xml \
|
|
85
|
+
--uploads ./wp-content/uploads \
|
|
86
|
+
--origins https://staging.example.com
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`--uploads` is a copy of the site's `wp-content/uploads` (an export carries
|
|
90
|
+
no files), and `--origins` names any other host the posts wrote media URLs
|
|
91
|
+
on, such as the staging host the site was built on, comma-separated. Both are
|
|
92
|
+
optional; see [Media](#media).
|
|
93
|
+
|
|
94
|
+
A file that is not a WordPress export is refused before anything is written,
|
|
95
|
+
with each problem named, and the command exits 1.
|
|
96
|
+
|
|
97
|
+
The command prints the totals, then one tab-separated row per item: its
|
|
98
|
+
outcome, post type, WordPress id, title, the file it went to, and why.
|
|
99
|
+
|
|
100
|
+
| Outcome | What it means |
|
|
101
|
+
| ----------- | -------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `written` | The file is new, was changed on WordPress since the last run, or was removed here and is written again. |
|
|
103
|
+
| `unchanged` | The file already holds what WordPress has. |
|
|
104
|
+
| `kept` | The file was edited on this site and WordPress has not changed it since. The edit stays. |
|
|
105
|
+
| `conflict` | The file was edited on this site and changed on WordPress too. The edit stays; the row gives both dates. |
|
|
106
|
+
| `clash` | A file the import never wrote is at the path. It is left alone. |
|
|
107
|
+
| `skipped` | The item has no Geekity counterpart, such as a revision, a menu or the ActivityPub plugin's records. |
|
|
108
|
+
| `warned` | The item was imported, with something the operator should check. |
|
|
109
|
+
|
|
110
|
+
**Run it as often as you like.** Two runs over one export leave the content
|
|
111
|
+
directory byte for byte as one run did, and a run over a newer export picks up
|
|
112
|
+
what was added or edited on WordPress since. The import never writes over a file
|
|
113
|
+
it did not write, and never deletes one, so a site can layer its own fixes on
|
|
114
|
+
top of an import. To take WordPress's side of a conflict, remove the file and
|
|
115
|
+
run the import again.
|
|
116
|
+
|
|
117
|
+
### Posts and pages
|
|
118
|
+
|
|
119
|
+
Each post becomes `posts/YYYY-MM-DD-slug.md`, dated by its local publish date,
|
|
120
|
+
and each page becomes `pages/slug.md`. The front matter keeps what readers,
|
|
121
|
+
feed readers and followers already know of it:
|
|
122
|
+
|
|
123
|
+
| Key | Where it comes from |
|
|
124
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
125
|
+
| `permalink` | The URL WordPress served, from the export's link. A draft has none yet, so it gets the one the published posts' structure gives it; a page gets its parents' slugs. |
|
|
126
|
+
| `redirect_from` | The URLs the post had before WordPress renamed or redated it: its permalink with each `_wp_old_slug` in place of its slug, and each `_wp_old_date` in place of its date. |
|
|
127
|
+
| `date` | `post_date_gmt`. A draft WordPress never dated has none. |
|
|
128
|
+
| `updated` | `post_modified_gmt`, when it differs from the date. |
|
|
129
|
+
| `tags` | The post's tags, by name. |
|
|
130
|
+
| `categories` | The post's categories, by name. |
|
|
131
|
+
| `draft` | `true` for a draft, a pending post, and a private or password-protected one, which the report names. A scheduled post keeps its date and publishes then. |
|
|
132
|
+
| `author` | The WordPress login, when the site has a user by that name. A post by any other login has no author, and the report names it. |
|
|
133
|
+
| `in-reply-to` | The URL an ActivityPub plugin reply block answers. |
|
|
134
|
+
| `activitypub` | On a published post, `id` is `https://example.com/?p=ID`, the object id the ActivityPub plugin served. A post the plugin federated (`activitypub_status` is `federated`) also has `published`. |
|
|
135
|
+
| `guid` | The WordPress guid, when it is not the post's `?p=` address, so feed readers see no old post as new. |
|
|
136
|
+
| `migrated` | `true` on everything but a scheduled post, so its arrival here, or a draft's publication later, sends nothing to anyone. A scheduled post publishes here as news, as it would have on WordPress. |
|
|
137
|
+
|
|
138
|
+
A post in the status format has no title, so it reads as a note. The page
|
|
139
|
+
WordPress served at the home URL becomes `homepage` in `_data/site.json`. The
|
|
140
|
+
import sets that key only while the site has not set it, or still holds what
|
|
141
|
+
the import last set.
|
|
142
|
+
|
|
143
|
+
The body becomes Markdown. Block comments go, a classic post's line breaks
|
|
144
|
+
become paragraphs as WordPress showed them, and a YouTube or Vimeo iframe or
|
|
145
|
+
embed becomes the video's URL on a line of its own, which the site plays.
|
|
146
|
+
What Markdown cannot say stays HTML: other iframes, a figure with a caption, a
|
|
147
|
+
table with spans, and an element carrying a `style` or microformats class.
|
|
148
|
+
`<!--more-->` stays where it was. Media URLs point at the files under
|
|
149
|
+
`/uploads/`, as [Media](#media) describes.
|
|
150
|
+
|
|
151
|
+
### Media
|
|
152
|
+
|
|
153
|
+
Each attachment's original is copied from `--uploads` into `content/uploads/`
|
|
154
|
+
at the path WordPress kept it under, such as `uploads/2024/03/photo.png`.
|
|
155
|
+
WordPress's size variants (`photo-1024x575.png`, `photo-scaled.png`) are not
|
|
156
|
+
copied: the site makes its own. A file a post or page shows that is no
|
|
157
|
+
attachment is copied too, for that post.
|
|
158
|
+
|
|
159
|
+
Every media URL in a body, in Markdown and in the HTML it keeps, on the
|
|
160
|
+
export's own origin, on an `--origins` host, or root-relative, becomes a
|
|
161
|
+
root-relative `/uploads/` URL of the original. One pointing at a size variant
|
|
162
|
+
points at its original. An upload URL on any other host is left alone.
|
|
163
|
+
|
|
164
|
+
Each file is held to the rules an upload through the editor is: the site's
|
|
165
|
+
allowed types and size limits, and location and camera details removed. A
|
|
166
|
+
file the site would refuse is not copied. The report names it, and names
|
|
167
|
+
each file missing from `--uploads`. Without `--uploads` nothing is copied and
|
|
168
|
+
the report names each attachment.
|
|
169
|
+
|
|
170
|
+
An attachment's alt text (`_wp_attachment_image_alt`) goes to
|
|
171
|
+
`_data/media.json` under its upload path, which is where the editor offers it
|
|
172
|
+
from. The import owns each key it set there, never the file.
|
|
173
|
+
|
|
174
|
+
While the plugin is enabled, a request for `/wp-content/uploads/<path>`
|
|
175
|
+
answers 301 at `/uploads/<path>`, so links from elsewhere still land on the
|
|
176
|
+
file. A size variant the import did not copy lands on its original, as
|
|
177
|
+
`import.json` records it, and the query string is kept. No `redirects.json`
|
|
178
|
+
entry is written per file. Keep the plugin enabled for as long as links to the
|
|
179
|
+
old media URLs matter.
|
|
180
|
+
|
|
181
|
+
### Comments and reactions
|
|
182
|
+
|
|
183
|
+
Every comment WordPress kept on a post or page the import writes goes into the
|
|
184
|
+
post's comment file, `_data/comments/<slug>.json`, the file the site's own
|
|
185
|
+
comments go to. That covers form comments, and the likes, reposts, replies,
|
|
186
|
+
mentions, bookmarks and pingbacks the ActivityPub and Webmention plugins stored
|
|
187
|
+
as comments. Each lands under the post as one the site received itself would:
|
|
188
|
+
|
|
189
|
+
| WordPress | Here |
|
|
190
|
+
| --------------------------------------------------------- | -------------------------------------------------------------- |
|
|
191
|
+
| `comment`, `like`, `repost` with `protocol` `activitypub` | A fediverse reply, like or boost, linked to the remote post. |
|
|
192
|
+
| `comment`, `like`, `repost` with `protocol` `webmention` | A webmention reply, like or repost, linked to its source page. |
|
|
193
|
+
| `mention`, `bookmark`, `webmention` | A mention, linked to the page that linked here. |
|
|
194
|
+
| `pingback`, `trackback` | A mention, linked to the page that pinged. |
|
|
195
|
+
| `comment` with no protocol | A comment left on the page. |
|
|
196
|
+
|
|
197
|
+
A reply keeps the comment it answers. An approved comment is approved here,
|
|
198
|
+
and one WordPress held for moderation waits here too. Spam and trash are left
|
|
199
|
+
out and named in the report. Each comment keeps the id WordPress's comments
|
|
200
|
+
feed gave it, `https://example.com/?p=ID#comment-N`, so a feed reader sees
|
|
201
|
+
nothing it has not seen. A commenter's email goes only to `data/comments/`.
|
|
202
|
+
Nothing is announced: no moderator is emailed and nothing is delivered.
|
|
203
|
+
|
|
204
|
+
The import merges by comment id. A rerun adds the comments WordPress received
|
|
205
|
+
since and picks up one edited there. It leaves alone a comment this site
|
|
206
|
+
received itself, and an imported one a moderator approved, filed as spam,
|
|
207
|
+
edited or deleted.
|
|
208
|
+
|
|
209
|
+
### Redirects
|
|
210
|
+
|
|
211
|
+
Links from elsewhere use URL forms WordPress answered and the site has no
|
|
212
|
+
document at. The import declares a redirect for each in
|
|
213
|
+
`_data/redirects/wordpress.json`, a file of its own, which the site reads beside
|
|
214
|
+
`_data/redirects.json` with no plugin enabled:
|
|
215
|
+
|
|
216
|
+
| URL | Answers 301 at |
|
|
217
|
+
| ------------------------------------------- | --------------------------- |
|
|
218
|
+
| `/?p=ID`, for every published post and page | Its permalink. |
|
|
219
|
+
| `/?page_id=ID`, for every published page | Its permalink. |
|
|
220
|
+
| An attachment's page, such as `/photo-jpg/` | Its file under `/uploads/`. |
|
|
221
|
+
| `/?attachment_id=ID` and `/?p=ID`, likewise | Its file under `/uploads/`. |
|
|
222
|
+
|
|
223
|
+
A draft, a pending, private, password-protected or scheduled post or page gets
|
|
224
|
+
no redirect, so its `?p=` answers as an id WordPress never had. An attachment
|
|
225
|
+
whose file was not copied gets none either, until a run copies it. A post's
|
|
226
|
+
old slugs and dates go into its own `redirect_from`, as
|
|
227
|
+
[Posts and pages](#posts-and-pages) says. A published post's `?p=` is also its
|
|
228
|
+
`activitypub.id`, which the site answers first, at the same permalink.
|
|
229
|
+
|
|
230
|
+
The import owns each key it set in `wordpress.json`, never the file, and never
|
|
231
|
+
touches `_data/redirects.json`. A key the site added there, or changed, is left
|
|
232
|
+
alone on every rerun. Where both files declare one URL, `redirects.json` wins.
|
|
233
|
+
A link to a comment, `#comment-N`, reaches the post: the fragment never
|
|
234
|
+
reaches the server, so the browser scrolls to it if the comment is there.
|
|
235
|
+
|
|
71
236
|
## Bringing a person across
|
|
72
237
|
|
|
73
238
|
`geekity import wordpress-actor` brings one person across. It writes the three
|