@contentrain/wp-import 0.6.0 → 0.8.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 CHANGED
@@ -102,6 +102,108 @@ these before claiming a complete migration. ACF field/group records and their
102
102
  cross-model parents remain in the content store; route discovery decides which
103
103
  records become public pages. Importing configuration does not execute a plugin.
104
104
 
105
+ ### Site name over REST
106
+
107
+ `fetchRestRawIR` reads the `/wp-json/` index for the site's name and tagline
108
+ (`RawIR.site.title` / `description`, the store's `site` singleton) and its
109
+ install and public addresses (`base_site_url` / `base_blog_url`). An index that
110
+ does not answer leaves them out.
111
+
112
+ ### Menus over REST
113
+
114
+ With an Application Password, `fetchRestRawIR` reads the site's menus into
115
+ `RawIR.menus`: classic menus (`/wp/v2/menus` + `/wp/v2/menu-items`, with the
116
+ theme locations each is assigned to) and a block theme's published
117
+ `wp_navigation` posts (links, submenus, page lists, home links). A block menu's
118
+ `locations` are the template-part areas (`header`, `footer`) whose navigation
119
+ block refers to it; an empty navigation block without a `ref` shows the most
120
+ recent published one, as WordPress does. Block menu items have no WordPress id
121
+ and get negative ids; the store claims no `wp_id` for them.
122
+
123
+ A navigation block in a template part that carries its own links (an inline
124
+ navigation, as in Twenty Twenty-Five's footer columns) is a menu of that part's
125
+ area: `Footer navigation 1`, `2`, … (its `ariaLabel` names it when set), links
126
+ in order and nested. Only template parts a template uses count — a theme ships
127
+ alternatives (`footer-columns`, `header-large-title`) that no page shows; without
128
+ the templates, the part named after its area (`header`, `footer`). A `#` link
129
+ stays `#`. Inline menus have no WordPress record: negative ids, no `wp_id`.
130
+
131
+ A menu item that is itself a draft, or whose post target is not proven public
132
+ — a draft, pending, private, scheduled or password-protected post, or one this
133
+ import never read (a type outside REST, a listing past a page cap) — is left
134
+ out, fail-closed: its label is often that post's title. Its children move up to the
135
+ nearest kept ancestor; `warnings` gives only the count.
136
+
137
+ Both need `edit_theme_options`. Without a credential, with a rejected one, or
138
+ with a user who lacks that right, no menus are read and the result's `gaps`
139
+ contains `menus_require_auth` — an empty menu list is never presented as the
140
+ site having none. The `menus` model gains a `locations` field only when the
141
+ source named them.
142
+
143
+ ### ACF fields, custom post types and taxonomies over REST
144
+
145
+ ACF / Secure Custom Fields values arrive on a post's `acf` key — only for field
146
+ groups set to "Show in REST API" (off by default). Each field is typed by one
147
+ versioned table (`ACF_MAPPING_VERSION`, exported with `ACF_SCALAR_TYPES` and
148
+ `ACF_REFERENCE_TYPES`): the ACF type is read from SCF's `<name>_source.type`
149
+ where the site states it, and inferred from the value's shape only when nothing
150
+ states it (the field description then says so).
151
+
152
+ | ACF | Contentrain |
153
+ | --- | --- |
154
+ | text, time picker | `string` |
155
+ | textarea | `text` |
156
+ | wysiwyg | `richtext` |
157
+ | email / url, oembed / number, range / true false | `email` / `url` / `number` / `boolean` |
158
+ | date picker / date time picker | `date` / `datetime` (ISO, with the site's offset) |
159
+ | color picker / icon picker | `color` / `icon` |
160
+ | select, radio, button group | `select` (its choices) |
161
+ | checkbox, multiple select | `array` of `select` |
162
+ | image / file | `image` / `file` (the URL) |
163
+ | link | `object { url, title, target }` |
164
+ | google map | `object { address, lat, lng, zoom }` |
165
+ | group | `object` of its fields |
166
+ | repeater | `array` of `object` (nested repeaters nest) |
167
+ | flexible content | `array` of `object`: a required `layout` select plus the union of the layouts' fields |
168
+ | post object, relationship | `relation` / `relations` to the entries' models |
169
+ | taxonomy / user / gallery | `relations` to the term model / `authors` / media |
170
+ | page link | `url`: the target's address, only when the target is published and unprotected |
171
+ | tab, accordion, message | nothing (layout only) |
172
+ | password | nothing, ever |
173
+
174
+ Sub-fields of a repeater, group or flexible layout are typed by the same table
175
+ when the site states their type (SCF's `_source` inside each row); a reference
176
+ inside a row, and a sub-field with no stated type, are typed from the value. A
177
+ select or checkbox value outside the field's stated choices is left out and
178
+ counted in the report's `acf_outside_choices`. A date time picker's value is written
179
+ with the site's UTC offset for that moment, DST included (the `/wp-json/`
180
+ index's `timezone_string`, else `gmt_offset`); with neither it stays local and
181
+ `acf_datetime_unzoned` counts it. `src/fixtures/acf-parity.json`
182
+ holds the cases the Contentrain Bridge must map the same way.
183
+
184
+ **A password field is never read** — at any depth: a password sub-field of a
185
+ repeater row, a group or a flexible layout is removed with its `_source` before
186
+ the value reaches `RawIR`. Where the source states the type, the type decides;
187
+ where it does not (plain ACF, no `<name>_source`), a field whose name has a
188
+ secret word in it (`password`, `user_pass`, `apiKey`, `access_token`, …; whole
189
+ words, so `passage` stays) is skipped instead. It never reaches `RawIR`, the
190
+ store, or a report.
191
+
192
+ ACF values follow their post: a draft's fields land in the store with the
193
+ draft (meta `status: draft`), like its body. A reference to an entry the import
194
+ did not read is dropped and counted in `dropped_relations`. The report's
195
+ `acf_fields` lists each field's type. When any post carries an `acf` key, the
196
+ result's `gaps` contains `acf_partial`: groups without REST exposure, options
197
+ pages and fields on post types outside REST are not visible to REST — the
198
+ Bridge reads those.
199
+
200
+ With an Application Password, post types are read with `context=edit` so their
201
+ `viewable` flag is known: a type that is in REST but not publicly queryable (a
202
+ testimonial post type, say) keeps its content but gets no address (`link` is
203
+ null), so no route or redirect claims a page that does not exist. Custom
204
+ taxonomies in REST are read with their terms, and a post's terms in them become
205
+ its relations.
206
+
105
207
 
106
208
  ### Publication and translation identity
107
209
 
package/dist/index.d.mts CHANGED
@@ -67,6 +67,15 @@ interface RestImportResult {
67
67
  status: 'none' | 'accepted' | 'rejected';
68
68
  fell_back: string[];
69
69
  };
70
+ /**
71
+ * What this rung could not read, as codes a caller can act on (the text is in `warnings`).
72
+ * `menus_require_auth`: menus and block navigation are only readable with an application password
73
+ * of a user who may edit theme options — none was given, the site rejected it, or it lacks that right.
74
+ * `acf_partial`: the site runs ACF / Secure Custom Fields; REST shows only the field groups set to
75
+ * `show_in_rest` (off by default) and no options page — the Bridge export reads the rest. Where the site
76
+ * states no field types (plain ACF, no `<name>_source`), a secret field is recognised by its name only.
77
+ */
78
+ gaps: string[];
70
79
  }
71
80
  declare function fetchRestRawIR(options: RestImportOptions): Promise<RestImportResult>;
72
81
  //#endregion
@@ -77,6 +86,10 @@ interface ImportReport {
77
86
  title_fallback: number;
78
87
  meta_fields: Record<string, string>;
79
88
  acf_fields: Record<string, string>;
89
+ /** ACF select/checkbox values outside their field's stated choices, left out (`field: count`). */
90
+ acf_outside_choices: Record<string, number>;
91
+ /** ACF date-times written without a zone because the source named none (`timezone_string` / `gmt_offset`). */
92
+ acf_datetime_unzoned: number;
80
93
  skipped_types: string[];
81
94
  dropped_relations: number;
82
95
  models: Record<string, {
@@ -96,6 +109,11 @@ interface ImportReport {
96
109
  * put that text on a public site. Publish only after deciding what to show.
97
110
  */
98
111
  password_protected_drafts: number;
112
+ /**
113
+ * The source named no site title (no REST index name, no WXR channel title): the `site` entry has no
114
+ * `title`. The field stays required, so the store says what is missing rather than inventing a name.
115
+ */
116
+ site_title_missing: boolean;
99
117
  }
100
118
  interface ContentrainResult {
101
119
  files: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/wxr.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.ts","../src/php-unserialize.ts","../src/core.ts","../src/delta.ts"],"mappings":";;;;UA2BiB,QAAA;EACf,UAAA;IAAc,QAAA;IAAkB,OAAA;IAAiB,MAAA;IAAgB,IAAA;EAAA;EACjE,UAAA;EACA,gBAAA;EACA,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,cAAA;EACf,GAAA,EAAK,KAAA;EACL,KAAA,EAAO,QAAA;AAAA;AAAA,iBAiBa,QAAA,CAAS,KAAA,WAAgB,QAAA,EAAU,IAAA;EAAS,IAAA;AAAA,IAAkB,OAAA,CAAQ,cAAA;;;UCtC3E,iBAAA;EACf,MAAA;;EAEA,SAAA,UAAmB,KAAA;EDSI;;;;;;;;ECAvB,IAAA;IAAS,IAAA;IAAc,WAAA;EAAA;EACvB,OAAA;EDGc;AAGhB;;;;ECAE,WAAA;EDCK;;;;ECIL,QAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EACf,GAAA,EAAK,KAAA;EACL,QAAA;EDQkF;;;;;;;;ECClF,UAAA;IAAc,MAAA;IAA0C,SAAA;EAAA;AAAA;AAAA,iBA+CpC,cAAA,CAAe,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;;;UC1EzD,YAAA;EACf,cAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA,EAAa,MAAA;EACb,UAAA,EAAY,MAAA;EACZ,aAAA;EACA,iBAAA;EACA,MAAA,EAAQ,MAAA;IAAiB,IAAA;IAAc,MAAA;IAAgB,MAAA;IAAgB,OAAA;EAAA;EFJvE;EEMA,OAAA;EFNc;EEQd,kBAAA;EFLe;;;;;;EEYf,yBAAA;AAAA;AAAA,UAGe,iBAAA;EACf,KAAA,EAAO,MAAA;EACP,gBAAA,EAAkB,cAAA;EAClB,MAAA,EAAQ,YAAA;AAAA;AAAA,iBAoCM,gBAAA,CAAiB,GAAA,EAAK,KAAA,EAAO,IAAA;EAAS,SAAA;AAAA,IAAuB,iBAAA;;;;;;AF7D7E;;;iBGbgB,cAAA,CAAe,GAAA,EAAK,KAAA;EAAU,QAAA,EAAU,UAAA;EAAc,QAAA,EAAU,WAAA,CAAY,cAAA;AAAA;AAAA,iBAgB5E,mBAAA,CAAoB,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,cAAA,EAAgB,IAAA;EAAS,YAAA;AAAA,IAA0B,cAAA;;iBAiB5F,iBAAA,CAAkB,GAAA,EAAK,cAAA,GAAiB,eAAA;;;UC3CvC,iBAAA;EACf,EAAA;EACA,UAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,iBAGc,eAAA,CAAgB,CAAA,YAAa,CAAA;AAAA,iBAI7B,cAAA,CAAe,GAAA;;iBAyFf,cAAA,CAAe,CAAA,WAAY,iBAAA;;;cC9F9B,KAAA,GAAS,CAAA;;cAST,KAAA,GAAS,CAAA;;cAcT,KAAA,GAAS,CAAA;;;;;;;;;ALCtB;cK8Ba,UAAA,EAAU,MAAA;;cAIV,WAAA,EAAW,MAAA;;cAOX,UAAA,GAAc,CAAA;AAAA,cAGd,OAAA,GAAW,CAAA;;;;UC3DP,UAAA;EACf,KAAA,EAAO,MAAA;EACP,gBAAA,EAAkB,cAAA;AAAA;AAAA,UAGH,oBAAA;ENOD;EMLd,KAAA,EAAO,eAAA;ENEO;EMAd,KAAA,EAAO,UAAA;ENA0C;EMEjD,QAAA,GAAW,UAAA;ENDX;;;;;EMOA,UAAA;ENFe;;;;EMOf,SAAA;AAAA;AAAA,cAGW,kBAAA;AAAA,cACA,iBAAA;;;ANQb;;;;;;;;;;iBM8NgB,eAAA,CAAgB,KAAA,EAAO,oBAAA,GAAuB,eAAA;;iBAkC9C,uBAAA,CAAwB,IAAA,EAAM,eAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/wxr.ts","../src/rest.ts","../src/contentrain.ts","../src/comments.ts","../src/php-unserialize.ts","../src/core.ts","../src/delta.ts"],"mappings":";;;;UA2BiB,QAAA;EACf,UAAA;IAAc,QAAA;IAAkB,OAAA;IAAiB,MAAA;IAAgB,IAAA;EAAA;EACjE,UAAA;EACA,gBAAA;EACA,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,cAAA;EACf,GAAA,EAAK,KAAA;EACL,KAAA,EAAO,QAAA;AAAA;AAAA,iBAiBa,QAAA,CAAS,KAAA,WAAgB,QAAA,EAAU,IAAA;EAAS,IAAA;AAAA,IAAkB,OAAA,CAAQ,cAAA;;;UCpC3E,iBAAA;EACf,MAAA;;EAEA,SAAA,UAAmB,KAAA;EDOI;;;;;;;;ECEvB,IAAA;IAAS,IAAA;IAAc,WAAA;EAAA;EACvB,OAAA;EDCc;AAGhB;;;;ECEE,WAAA;EDDK;;;;ECML,QAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EACf,GAAA,EAAK,KAAA;EACL,QAAA;EDMkF;;;;;;;;ECGlF,UAAA;IAAc,MAAA;IAA0C,SAAA;EAAA;;;AAvC1D;;;;;;EAgDE,IAAA;AAAA;AAAA,iBA2EoB,cAAA,CAAe,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;;;UChHzD,YAAA;EACf,cAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA,EAAa,MAAA;EACb,UAAA,EAAY,MAAA;EFFE;EEId,mBAAA,EAAqB,MAAA;EFPP;EESd,oBAAA;EACA,aAAA;EACA,iBAAA;EACA,MAAA,EAAQ,MAAA;IAAiB,IAAA;IAAc,MAAA;IAAgB,MAAA;IAAgB,OAAA;EAAA;EFNxD;EEQf,OAAA;;EAEA,kBAAA;EFTA;;;;;;EEgBA,yBAAA;EFE4B;;;;EEG5B,kBAAA;AAAA;AAAA,UAGe,iBAAA;EACf,KAAA,EAAO,MAAA;EACP,gBAAA,EAAkB,cAAA;EAClB,MAAA,EAAQ,YAAA;AAAA;AAAA,iBA0CM,gBAAA,CAAiB,GAAA,EAAK,KAAA,EAAO,IAAA;EAAS,SAAA;AAAA,IAAuB,iBAAA;;;;;;AF7E7E;;;iBGbgB,cAAA,CAAe,GAAA,EAAK,KAAA;EAAU,QAAA,EAAU,UAAA;EAAc,QAAA,EAAU,WAAA,CAAY,cAAA;AAAA;AAAA,iBAgB5E,mBAAA,CAAoB,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,cAAA,EAAgB,IAAA;EAAS,YAAA;AAAA,IAA0B,cAAA;;iBAiB5F,iBAAA,CAAkB,GAAA,EAAK,cAAA,GAAiB,eAAA;;;UC3CvC,iBAAA;EACf,EAAA;EACA,UAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,iBAGc,eAAA,CAAgB,CAAA,YAAa,CAAA;AAAA,iBAI7B,cAAA,CAAe,GAAA;;iBAyFf,cAAA,CAAe,CAAA,WAAY,iBAAA;;;cC9F9B,KAAA,GAAS,CAAA;;cAST,KAAA,GAAS,CAAA;;cAcT,KAAA,GAAS,CAAA;;;;;;;;;ALCtB;cK8Ba,UAAA,EAAU,MAAA;;cAIV,WAAA,EAAW,MAAA;;cAOX,UAAA,GAAc,CAAA;AAAA,cAGd,OAAA,GAAW,CAAA;;;;UC3DP,UAAA;EACf,KAAA,EAAO,MAAA;EACP,gBAAA,EAAkB,cAAA;AAAA;AAAA,UAGH,oBAAA;ENOD;EMLd,KAAA,EAAO,eAAA;ENEO;EMAd,KAAA,EAAO,UAAA;ENA0C;EMEjD,QAAA,GAAW,UAAA;ENDX;;;;;EMOA,UAAA;ENFe;;;;EMOf,SAAA;AAAA;AAAA,cAGW,kBAAA;AAAA,cACA,iBAAA;;;ANQb;;;;;;;;;;iBM8NgB,eAAA,CAAgB,KAAA,EAAO,oBAAA,GAAuB,eAAA;;iBAkC9C,uBAAA,CAAwB,IAAA,EAAM,eAAA"}