Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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+
Expand Down
44 changes: 44 additions & 0 deletions documentation/README.md
Original file line number Diff line number Diff line change
@@ -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.
35 changes: 35 additions & 0 deletions documentation/reference/data-and-security.md
Original file line number Diff line number Diff line change
@@ -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)
Empty file.
62 changes: 62 additions & 0 deletions documentation/reference/rest-api.md
Original file line number Diff line number Diff line change
@@ -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 <JWT>`** 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)
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions documentation/user-guide/migration-via-api.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- Screenshot: Import tab — API connection form and capabilities summary -->

![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
40 changes: 40 additions & 0 deletions documentation/user-guide/migration-via-file.md
Original file line number Diff line number Diff line change
@@ -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).

<!-- Screenshot: Export tab with preview and download button -->

![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).

<!-- Screenshot: Import tab — file upload area -->

![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).
41 changes: 41 additions & 0 deletions documentation/user-guide/overview.md
Original file line number Diff line number Diff line change
@@ -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**.

<!-- Screenshot: WP Admin sidebar → Extensions (D.T) → Migration -->

![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
40 changes: 40 additions & 0 deletions documentation/user-guide/preflight-and-warnings.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- Screenshot: Preflight results list -->

![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)
Loading
Loading