diff --git a/README.md b/README.md index dd8f780..f25239f 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,14 @@ Install and activate the plugin on both sites. You can migrate data in two ways: - **File export/import** -- Download your data as a file from the source site, then upload it on the destination site. - **Direct connection** -- Connect the two sites via API so the destination pulls data directly from the source. -Go to **D.T Migration** in the admin menu to configure what to include, run a preflight check for potential issues, and start the migration. +Go to **Extensions (D.T)** → **Migration** in the WordPress admin to configure what to include, run a preflight check for potential issues, and start the migration. **Important:** Importing records will replace existing records of the same type on the destination site. +## Documentation + +Step-by-step guides (file vs API), preflight, troubleshooting, and REST reference: see **[documentation/README.md](documentation/README.md)**. + ## Requirements - Disciple.Tools theme v1.20+ diff --git a/documentation/README.md b/documentation/README.md new file mode 100644 index 0000000..214f472 --- /dev/null +++ b/documentation/README.md @@ -0,0 +1,44 @@ +# Disciple.Tools Migration — Documentation + +This folder contains user and reference documentation for moving Disciple.Tools configuration and records between sites using the **Disciple.Tools – Migrations** plugin. + + +## Guides + +| Document | Description | +|----------|-------------| +| [User guide: Overview](user-guide/overview.md) | What the plugin does, requirements, and where to find it in WordPress | +| [User guide: Settings and scope](user-guide/settings-and-scope.md) | Enabling migration and choosing what to include | +| [User guide: Migration via file](user-guide/migration-via-file.md) | Export download → transfer → import from JSON | +| [User guide: Migration via API](user-guide/migration-via-api.md) | Connect to a live source site and pull data over the REST API | +| [User guide: Preflight and warnings](user-guide/preflight-and-warnings.md) | Optional checks before import | +| [User guide: Troubleshooting](user-guide/troubleshooting.md) | Common problems and constraints | + +## Reference + +| Document | Description | +|----------|-------------| +| [REST API](reference/rest-api.md) | Migration REST namespace, routes, and behavior | +| [Data and security](reference/data-and-security.md) | Passwords, users, roles, and destructive import semantics | + +## Typical workflows + +### A. File-based (offline-friendly) + +1. Install and activate the plugin on **source** and **destination** Disciple.Tools sites (see [Overview](user-guide/overview.md)). +2. On the **source** site, open **Extensions (D.T)** → **Migration** → **Settings**: enable migration and select what to export (including record types). +3. On the **source** site, open **Export** and download the JSON package. +4. Move the file to a secure location and upload it on the **destination** site under **Import**. +5. Optionally run **preflight**, review warnings, then start the import. + +### B. API-based (direct site-to-site) + +1. Ensure both sites have the plugin enabled and migration turned on; **source** must allow the same categories you plan to pull. +2. On the **destination** site, open **Import** → **API Connection to Source Site**: enter the source base URL and obtain a session (see [Migration via API](user-guide/migration-via-api.md)). +3. Fetch capabilities and previews from the source, optionally run **preflight**, then start the import so the destination pulls settings and records in batches. + +Both channels respect the same scope rules and the same import semantics on the destination (see [Data and security](reference/data-and-security.md)). + +## Screenshots + +Illustrations live next to the guides that reference them, under each section’s `imgs/` directory. Filenames are placeholders until real screenshots are added. diff --git a/documentation/reference/data-and-security.md b/documentation/reference/data-and-security.md new file mode 100644 index 0000000..ad9c7f5 --- /dev/null +++ b/documentation/reference/data-and-security.md @@ -0,0 +1,35 @@ +# Data and security + +## Passwords are never exported + +User **passwords** are **not** included in migration exports. New users created on the destination receive **generated passwords** (and normal WordPress password-reset flows apply). + +## System users + +- Users are matched primarily by **email**, then **login**, depending on the implementation in the system user importer. +- **Roles** from the export are applied only when the destination WordPress installation defines those role slugs and the acting user has permission to assign them (e.g. administrator-related capabilities). +- Role assignment avoids leaving an account **without any role** during import: invalid or missing role data falls back to the site’s **default role**, with a safe fallback if that default is misconfigured. +- **Multisite:** roles are **per subsite**. A network super admin may not look like a normal Administrator under **Users** on a subsite; see preflight informational text and add users to the subsite if needed. + +## Destructive record import + +For each **selected record type**, the destination import process is designed to **delete existing records of that type** and recreate them from the source so **IDs and relationships** can align with the exported data. + +**Plan backups** and test on staging before running against production. + +## JWT and API access + +API imports use a **bearer token** stored on the destination after a successful connection test. Protect administrator accounts on the source and restrict who can run imports on the destination. Prefer **HTTPS** everywhere. + +## File exports + +JSON export files contain **PII and ministry data**. Encrypt at rest and limit distribution to trusted operators. + +## Capabilities + +Migration admin UI and REST permission checks rely on **`manage_dt`**. Some user operations may require **`promote_users`** or other WordPress caps when creating or elevating accounts. + +## See also + +- [Overview](../user-guide/overview.md) +- [Troubleshooting](../user-guide/troubleshooting.md) diff --git a/documentation/reference/imgs/.gitkeep b/documentation/reference/imgs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/documentation/reference/rest-api.md b/documentation/reference/rest-api.md new file mode 100644 index 0000000..a53c10e --- /dev/null +++ b/documentation/reference/rest-api.md @@ -0,0 +1,62 @@ +# REST API reference + +Migration exposes routes under the namespace: + +```text +/wp-json/dt-migration/v1/ +``` + +## Authentication + +In-browser and server-side calls from an authenticated Disciple.Tools administrator use the normal WordPress REST authentication (cookies / application passwords as configured). + +**Site-to-site imports** on the destination use **`Authorization: Bearer `** after the destination obtains a token from Server A’s `jwt-auth/v1` flow. The migration routes check for the **`manage_dt`** capability for the current user context when the request is handled as that user. + +## Routes + +### `GET /dt-migration/v1/capabilities` + +Returns a summary of whether migration is **enabled** on this site, **`allowed_items`** (settings flags and per–post-type record toggles), **`site_meta`** (URL, WordPress version, PHP, Disciple.Tools theme version, multisite flag, etc.), and **`plugin_capabilities`** (whether API and file modes are supported and which record types are enabled). + +Use this from the destination to verify Server A before importing. + +### `POST /dt-migration/v1/export` + +**Non-destructive.** Builds a **settings-oriented** export payload: `dt_settings` (tiles, fields, post type structure, workflows, etc., according to **allowed_items**) and **`system_users`** when that category is allowed. The response **`note`** states that this payload does **not** include record rows. + +Callers may send a JSON body; the response includes it under **`request`** for traceability. **Record data** is fetched with **`GET .../records/{post_type}`** in batches. + +### `GET /dt-migration/v1/records-preview` + +**Non-destructive.** Returns **counts** of posts per **enabled** record post type from migration settings. + +### `GET /dt-migration/v1/records/{post_type}` + +**Readable.** Returns a **batch** of full record payloads for `post_type`. + +Query parameters: + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `offset` | `0` | Starting index for pagination | +| `limit` | `50` | Page size, clamped between **1** and **100** | + +The response includes `records`, `total`, `offset`, `limit`, and `has_more`. + +If `post_type` is **not allowed** in migration settings, the API returns **403** with an explanatory message. + +Record objects may include **`dt_migration_comments`** and other fields attached by the import/export pipeline. + +## Error responses + +Typical cases: + +- **403** — Post type not allowed for migration, or insufficient capabilities +- **500** — Missing `DT_Posts` or other server-side failure + +Always check the JSON **`message`** body when present. + +## See also + +- [Migration via API](../user-guide/migration-via-api.md) +- [Data and security](data-and-security.md) diff --git a/documentation/user-guide/imgs/.gitkeep b/documentation/user-guide/imgs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/documentation/user-guide/imgs/fig-01-extensions-dt-migration.png b/documentation/user-guide/imgs/fig-01-extensions-dt-migration.png new file mode 100644 index 0000000..4de6997 Binary files /dev/null and b/documentation/user-guide/imgs/fig-01-extensions-dt-migration.png differ diff --git a/documentation/user-guide/imgs/fig-02-settings-enable-and-scope.png b/documentation/user-guide/imgs/fig-02-settings-enable-and-scope.png new file mode 100644 index 0000000..29d1030 Binary files /dev/null and b/documentation/user-guide/imgs/fig-02-settings-enable-and-scope.png differ diff --git a/documentation/user-guide/imgs/fig-03-settings-record-types.png b/documentation/user-guide/imgs/fig-03-settings-record-types.png new file mode 100644 index 0000000..6465302 Binary files /dev/null and b/documentation/user-guide/imgs/fig-03-settings-record-types.png differ diff --git a/documentation/user-guide/imgs/fig-04-settings-api-connection.png b/documentation/user-guide/imgs/fig-04-settings-api-connection.png new file mode 100644 index 0000000..09b978b Binary files /dev/null and b/documentation/user-guide/imgs/fig-04-settings-api-connection.png differ diff --git a/documentation/user-guide/imgs/fig-05-export-tab.png b/documentation/user-guide/imgs/fig-05-export-tab.png new file mode 100644 index 0000000..2360047 Binary files /dev/null and b/documentation/user-guide/imgs/fig-05-export-tab.png differ diff --git a/documentation/user-guide/imgs/fig-06-import-file.png b/documentation/user-guide/imgs/fig-06-import-file.png new file mode 100644 index 0000000..42e14ed Binary files /dev/null and b/documentation/user-guide/imgs/fig-06-import-file.png differ diff --git a/documentation/user-guide/imgs/fig-07-import-api.png b/documentation/user-guide/imgs/fig-07-import-api.png new file mode 100644 index 0000000..1d48ffb Binary files /dev/null and b/documentation/user-guide/imgs/fig-07-import-api.png differ diff --git a/documentation/user-guide/imgs/fig-08-preflight.png b/documentation/user-guide/imgs/fig-08-preflight.png new file mode 100644 index 0000000..88dede3 Binary files /dev/null and b/documentation/user-guide/imgs/fig-08-preflight.png differ diff --git a/documentation/user-guide/imgs/fig-09-import-progress.png b/documentation/user-guide/imgs/fig-09-import-progress.png new file mode 100644 index 0000000..619244c Binary files /dev/null and b/documentation/user-guide/imgs/fig-09-import-progress.png differ diff --git a/documentation/user-guide/migration-via-api.md b/documentation/user-guide/migration-via-api.md new file mode 100644 index 0000000..816d378 --- /dev/null +++ b/documentation/user-guide/migration-via-api.md @@ -0,0 +1,43 @@ +# Migration via API + +In **API** mode, the **destination** site (Server B) connects to the **source** site (Server A) over HTTPS, authenticates, and **pulls** migration payloads through the `dt-migration/v1` REST namespace. + +## Prerequisites + +- Migration **enabled** on **both** sites +- **Server A** must expose the REST API and allow your Disciple.Tools user to authenticate (typically **JWT** via the `jwt-auth/v1` endpoints used by the plugin) +- You need a user on Server A with permission to call migration endpoints (same class of access as `manage_dt` for in-app REST checks) + +## Connect from the destination + +1. On the **destination**, open **Extensions (D.T)** → **Migration** → **Import**. +2. Under **API Connection to Source Site (Server A)**, enter: + - **Server A Base URL** (e.g. `https://source.example.org`) + - **Username** and **password** for a Disciple.Tools user on Server A + These credentials are used only to obtain a token; they are **not** stored. +3. Click **Test Connection & Fetch Capabilities**. + +On success, the plugin stores **Server A Base URL** and a **JWT** for subsequent requests. You will see a **capabilities summary**: migration enabled flag, allowed settings categories, and allowed record types. + + + +![Import tab: API connection and Server A capabilities](imgs/fig-07-import-api.png) + +## Preview and import + +After a successful connection you can fetch **settings** and **records previews** from Server A (non-destructive). When you start an import: + +- The destination may request **settings-only** export payloads and **paginated record batches** per post type (`offset` / `limit`). +- Record import uses the same **dependency-aware ordering** as file mode so related records stay consistent. + +Optional **preflight** uses samples or batches from the source to surface warnings before you commit to a full import. + +## Security notes + +- Use **HTTPS** for both sites. +- JWTs are bearer tokens; anyone with the token and URL can act as that session until expiry — protect admin accounts on Server A and restrict who can run imports on Server B. +- See [Data and security](../reference/data-and-security.md) for what is never exported (passwords). + +## See also + +- [REST API reference](../reference/rest-api.md) — exact routes and parameters diff --git a/documentation/user-guide/migration-via-file.md b/documentation/user-guide/migration-via-file.md new file mode 100644 index 0000000..d638990 --- /dev/null +++ b/documentation/user-guide/migration-via-file.md @@ -0,0 +1,40 @@ +# Migration via file + +Use a **downloaded JSON export** when the source and destination cannot talk to each other over the API, or when you want an auditable file to move through secure storage. + +## Prerequisites + +- Migration **enabled** on **both** sites +- On the **source**, the same **allowed items** you need must be checked on **Settings** (settings bundles and record types) +- At least one **record type** enabled if you need record data (otherwise the download may contain only configuration) + +## On the source site + +1. Go to **Extensions (D.T)** → **Migration** → **Export**. +2. Confirm the **API Export Preview** tables match what you expect (counts per post type, enabled settings categories). This mirrors what is allowed for API consumers; the file download uses the same scope. +3. Under **Download export (JSON)**, submit the form to download a JSON file containing **everything enabled on Settings** — configuration and **all records** for each enabled post type (unless your site exposes optional per-type range/limit controls via a developer filter). + + + +![Export tab: preview and Download export (JSON)](imgs/fig-05-export-tab.png) + +Advanced deployments can enable per-post-type **range** or **limit** controls for exports via the `dt_migration_show_export_record_filters` filter; default installs typically export **all** records for enabled types. + +## Transfer the file + +Use your organization’s secure channel (encrypted storage, controlled access). The file contains **user metadata and records**; treat it as sensitive. + +## On the destination site + +1. Go to **Extensions (D.T)** → **Migration** → **Import**. +2. In the **file** section, upload the JSON export. +3. Use **preflight** if you want warnings about collisions or field mismatches (see [Preflight and warnings](preflight-and-warnings.md)). +4. Choose what to apply (settings categories and record types) consistent with the export, then start the import. The UI runs imports in **stages** (settings, then records in **dependency-aware order** — for example types such as people groups and groups before contacts and trainings, then other enabled types). + + + +![Import tab: JSON file upload and actions](imgs/fig-06-import-file.png) + +## After import + +Verify records, users, and configuration in Disciple.Tools. If something failed mid-run, check the messages in the import UI and use [Troubleshooting](troubleshooting.md). diff --git a/documentation/user-guide/overview.md b/documentation/user-guide/overview.md new file mode 100644 index 0000000..a9d5bfb --- /dev/null +++ b/documentation/user-guide/overview.md @@ -0,0 +1,41 @@ +# Overview + +The **Disciple.Tools – Migrations** plugin helps you copy Disciple.Tools **settings** and **records** from one WordPress site to another. You can work **through a downloadable JSON file** or **over the REST API** so the destination site pulls directly from the source. + +## What you can migrate + +When enabled, exports can include (according to your **Settings** checkboxes): + +- **General settings**, **custom lists**, **tiles**, **fields**, **roles**, and **workflows** +- **WordPress users** (system users): profile and role information used by Disciple.Tools — **passwords are not included** in exports +- **Records** for each **Disciple.Tools record type** your site registers (for example contacts, groups, trainings, people groups, and custom types): including comments and structure needed to preserve **connections between records** + +Imports on the destination are designed to **replace** existing data for the selected record types so that **post IDs** from the source can be preserved and relationships stay consistent. Treat the destination as a target you are intentionally overwriting for those types. + +## Requirements + +- **WordPress** 4.7+ (see plugin header for tested-up-to) +- **Disciple.Tools theme** version **1.20+** (the plugin checks the active theme version) +- A user with the **`manage_dt`** capability (Disciple.Tools administrator access) on **both** sites when performing exports and imports + +## Where to find Migration in WordPress + +Open the WordPress admin, then go to **Extensions (D.T)** → **Migration**. The screen has three tabs: **Settings**, **Export**, and **Import**. + + + +![Extensions (D.T) menu with Migration highlighted](imgs/fig-01-extensions-dt-migration.png) + +You can also open the same screen with explicit tabs, for example: + +- `admin.php?page=disciple_tools_migration&tab=settings` +- `admin.php?page=disciple_tools_migration&tab=export` +- `admin.php?page=disciple_tools_migration&tab=import` + +Older bookmarks that pointed at separate export or import submenu slugs are redirected to the main Migration screen with the matching tab. + +## Next steps + +- [Settings and scope](settings-and-scope.md) — enable migration and choose record types +- [Migration via file](migration-via-file.md) or [Migration via API](migration-via-api.md) — pick a channel +- [Preflight and warnings](preflight-and-warnings.md) — optional checks before import diff --git a/documentation/user-guide/preflight-and-warnings.md b/documentation/user-guide/preflight-and-warnings.md new file mode 100644 index 0000000..c485adb --- /dev/null +++ b/documentation/user-guide/preflight-and-warnings.md @@ -0,0 +1,40 @@ +# Preflight and warnings + +**Preflight** runs **non-destructive** checks before a full import. It helps surface mismatches between the **source export** and the **destination** site so you can fix issues or accept risk before overwriting data. + +## When to use it + +Use preflight when: + +- You are importing **records** for types that already exist on the destination +- You are bringing in **fields** or **system users** where policies differ between sites +- You want a quick summary of **unknown fields** or **ID collisions** before a long import + +You can still start an import without preflight; the UI offers both flows. + + + +![Preflight warnings and informational lines](imgs/fig-08-preflight.png) + +## What preflight may report + +Examples of messages you might see (wording comes from the plugin and may vary slightly by release): + +- **Unknown or unexpected fields** on records compared to destination field definitions — especially relevant if you are **not** importing field definitions but are importing records that use custom keys from the source. +- **Post ID collisions**: exported IDs that already exist on the destination **for a different post type** — importing could overwrite or conflict; review before proceeding. +- **System users**: duplicate emails, missing export data when users were selected, or permission constraints (e.g. assigning administrator roles). +- **Multisite**: informational notes that roles are per-site and super-admin visibility may differ from single-site expectations. +- **Sample-based checks**: when the source is only partially sampled (e.g. first API batches), an info line may state that **not every record** was inspected. + +Preflight is implemented to stay responsive on **large sites**: collision and lookup work is done in a way that scales to many IDs without loading each post individually in tight loops. + +## Interpreting results + +- **Warnings** are not always hard blockers; they are signals to review. +- **Info** lines explain context (multisite, sampling). +- If warnings are unacceptable, adjust **destination** data (delete conflicting posts, align field definitions), change **export scope** on the source, or import **settings** before **records**. + +## See also + +- [Troubleshooting](troubleshooting.md) +- [Data and security](../reference/data-and-security.md) diff --git a/documentation/user-guide/settings-and-scope.md b/documentation/user-guide/settings-and-scope.md new file mode 100644 index 0000000..39b59f4 --- /dev/null +++ b/documentation/user-guide/settings-and-scope.md @@ -0,0 +1,50 @@ +# Settings and scope + +The **Settings** tab controls whether migration is allowed on this site and **which categories of data** may be included in exports (and therefore available to API consumers or file downloads). + +## Enable migration + +Turn on **Allow this site to perform Disciple.Tools migrations**. If migration is disabled, export and import actions are not available. + + + +![Migration settings: enable and configuration checkboxes](imgs/fig-02-settings-enable-and-scope.png) + +## Settings and admin data + +These options apply to **configuration**, not individual contact/group rows (except where noted): + +| Option | Meaning | +|--------|---------| +| General settings | Core Disciple.Tools options eligible for migration | +| Custom lists | Custom list definitions | +| Tiles | Tile layouts per post type | +| Fields | Field definitions per post type | +| Roles | Role-related configuration included in the export | +| Workflows | Workflow definitions | +| WordPress users (system) | Safe user profile data; **no passwords**. See [Data and security](../reference/data-and-security.md) | + +## Record types + +Under **Record types**, enable each **Disciple.Tools post type** you want in exports and imports. The list reflects **all migratable types** registered on your site (labels shown in the UI; the internal slug appears in the description). + +For each selected type, importing on a destination **removes existing records of that type** and recreates them using data from the source, **preserving IDs** where the import process allows, so links between records remain valid. + + + +![Record types: checkboxes per Disciple.Tools post type](imgs/fig-03-settings-record-types.png) + +Save changes with **Save Settings**. + +## API connection storage (destination) + +The plugin stores the **source site base URL** and a **JWT** obtained after a successful connection test (see [Migration via API](migration-via-api.md)). **Username and password** used to fetch the token are **not** stored. JWT and URL are kept in the migration settings option for subsequent API import batches. + + + +![API connection fields on Settings or Import as applicable](imgs/fig-04-settings-api-connection.png) + +## See also + +- [Export tab](migration-via-file.md) — how the download reflects these choices +- [REST API capabilities](../reference/rest-api.md) — how the source reports `allowed_items` diff --git a/documentation/user-guide/troubleshooting.md b/documentation/user-guide/troubleshooting.md new file mode 100644 index 0000000..36ce40d --- /dev/null +++ b/documentation/user-guide/troubleshooting.md @@ -0,0 +1,72 @@ +# Troubleshooting + +## Migration is disabled + +**Symptom:** Export or Import says migration is disabled. + +**Fix:** On **Settings**, enable **Allow this site to perform Disciple.Tools migrations** and save. + +## Permission errors + +**Symptom:** Cannot access Migration screens or REST returns forbidden. + +**Fix:** Use a Disciple.Tools account with **`manage_dt`**. Importing some user roles may require **`promote_users`** on the destination. + +## API connection fails + +**Symptom:** Test connection shows an error; no capabilities table. + +**Checks:** + +- **URL** is the site root (no trailing path to wp-admin required; use the public site URL pattern you use for REST). +- **HTTPS** and valid certificates. +- **JWT** plugin / `jwt-auth/v1` available on Server A and credentials correct. +- Firewall allows **Server B → Server A** requests. + +Re-run **Test Connection** after fixing Server A. Clear old tokens by saving a fresh connection if the UI still fails. + +## JWT expired or invalid + +**Symptom:** Import batches fail after a delay. + +**Fix:** Obtain a new token via **Test Connection** on the destination. + +## Preflight shows ID collisions + +**Symptom:** Warnings list post IDs that exist on the destination with a **different** type than the import expects. + +**Fix:** Manually resolve conflicts (delete or rename the conflicting content), choose a clean destination database for those types, or adjust export scope. Do not ignore if you need strict ID preservation. + +## Unknown field warnings + +**Symptom:** Preflight lists fields on records that the destination does not recognize. + +**Fix:** Import **fields** (and related tiles/settings) before records, or add matching field definitions on the destination first. + +## User import / role messages + +**Symptom:** Errors assigning roles, or unexpected role after import. + +**Fix:** Ensure role slugs in the export **exist** on the destination. The import path validates roles and assigns a **safe default role** when an export row has no valid roles, so users are not left without a role mid-import. On multisite, add users to the subsite explicitly if they do not appear as expected. + +## Large exports or timeouts + +**Symptom:** Download or API batch stalls. + +**Fix:** Increase PHP / web server timeouts where appropriate; for API imports, batches use pagination — retry from the UI. For very large file uploads, check `upload_max_filesize` / `post_max_size`. + +## Theme version notice + +**Symptom:** Admin notice that Disciple.Tools theme is below required version. + +**Fix:** Upgrade the **Disciple.Tools theme** to the version required by the plugin (see main plugin file / readme). + +## Import progress appears stuck + +**Symptom:** Progress bar or counts stop updating. + +**Fix:** Check browser console and server error logs; session or nonce expiry can interrupt long jobs — refresh and consult whether partial import requires cleanup (records may be half imported depending on stage). + + + +![Import in progress (batches or progress indicator)](imgs/fig-09-import-progress.png)