Skip to content
wiki.fftac.org

Integrating Participants Database Into Anti Christ.Org - Part 04

Back to Integrating Participants Database Into Anti Christ.Org

**Source path:** Wiki.FFTAC.org/raw/system-archives/anti-christ.org/file-intake/2026-05-10-improvement-and-content/Improvement/Integrating Participants Database into anti-christ.org.md

PDb documents `pdb-access_capability`, and WordPress documents custom roles/capabilities via `add_role()`. citeturn16view0turn24view0turn12search3turn25view5

#### Add a custom endpoint for the current member’s linked participant record

' ' ' php
<?php
add_action( 'rest_api_init', function() {
	register_rest_route( 'fftac/v1', '/me/participant', array(
		'methods'  => 'GET',
		'permission_callback' => function() {
			return is_user_logged_in();
		},
		'callback' => function() {
			if ( ! class_exists( 'Participants_Db' ) ) {
				return new WP_Error( 'pdb_missing', 'Participants Database is not active.', array( 'status' => 500 ) );
			}

			$record_id = fftac_find_pdb_record_id_by_user( get_current_user_id() );
			if ( ! $record_id ) {
				return rest_ensure_response( array( 'record' => null ) );
			}

			return rest_ensure_response( array(
				'record_id' => $record_id,
				'record'    => Participants_Db::get_participant( $record_id ),
			) );
		},
	) );
} );
' ' ' 

This uses WordPress’s documented `register_rest_route()` pattern and the PDb public `get_participant()` method. citeturn25view10turn25view11turn16view0

### Shortcodes to use

The core plugin shortcodes most useful for this project are:

' ' ' text
[pdb_signup]
[pdb_signup_thanks]
[pdb_record]
[pdb_list]
[pdb_single]
[pdb_search]
[pdb_request_link]
' ' ' 

A practical pattern for a public intake page is:

' ' ' text
[pdb_signup fields="first_name,last_name,email,primary_interest,intake_lane,consent_privacy,consent_terms,captcha"]
' ' ' 

And for more secure link recovery where email may not be enough:

' ' ' text
[pdb_request_link fields="email,first_name,captcha"]
' ' ' 

These shortcodes and attributes are documented in the official PDb materials, including custom-field/group selection and edit-record-page handling. citeturn5view2turn5view1turn23view3turn33search4turn0search11

### Participants Database REST API usage

If you need staff-side integration with automation, use the official PDb REST API only for **staff/system operations**, not for front-end member authentication. It must be explicitly enabled, can optionally allow limited anonymous GET access, and uses **WordPress Application Passwords** for authorized requests. Official docs state that non-public requests require a user with a PDb plugin role of **Admin or Editor**. citeturn29view4turn5view11

Example read request:

' ' ' bash
curl --user "staff-username:APPLICATION-PASSWORD" \
  https://anti-christ.org/wp-json/participants-database/v1/record/705
' ' ' 

Example update request:

' ' ' bash
curl --user "staff-username:APPLICATION-PASSWORD" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"member_status":"approved","intake_lane":"research-cohort"}' \
  https://anti-christ.org/wp-json/participants-database/v1/record/update/705
' ' ' 

For POST-based writes, validate on the caller side because PDb’s REST write routes do **not** validate incoming data. citeturn29view4turn30view5

## Operations, privacy, security, migration, testing, and deployment

### Privacy and regulatory design

The official PDb GDPR guidance is very clear about the obligations that matter most here: provide a **clear statement of use**, capture **evidence of consent**, use **opt-in only** rather than pre-checked consent, provide a way for users to **see** and **delete** their stored personal data, and treat server security and breach notification as part of the compliance posture. For anti-christ.org, that means consent should be explicit and versioned, not implied by general site use. citeturn5view7

A compliant field set should therefore include:

- `consent_privacy`
- `consent_terms`
- `consent_version`
- `consent_timestamp`
- `consent_ip`
- optional `marketing_opt_in` or `briefing_opt_in`

Use these only where needed and avoid collecting more data than the site actually uses. Because the current public site already separates member accounts from “briefing list” subscribers, do not force a full account-creation flow just to collect newsletter-style interest. citeturn15view0turn14view0turn5view7

### Personal-data export and erasure

Use WordPress’s privacy request system rather than relying only on ad hoc CSV export. WordPress core provides plugin hooks for personal-data **exporters** and **erasers**, specifically `wp_privacy_personal_data_exporters` and `wp_privacy_personal_data_erasers`. The plugin handbook also documents how pluggable erasers participate in the admin’s privacy-removal workflow. citeturn25view0turn25view1turn25view2turn25view3

A good implementation pattern is:

- export the linked PDb record(s) by the user’s current email address and/or `wp_user_id`
- export consent timestamps/version values and program/intake metadata
- on delete requests, decide whether to:
  - **deactivate**
  - **anonymize**
  - or **hard-delete**
  based on retention policy and legal needs

If you use the official WordPress User Profile add-on, its settings already contemplate what should happen to the associated WP account when a PDb record is deleted: **Deactivate**, **Do Nothing**, or **Delete**, with explicit safeguards for admins and users who authored posts. For this site, I would default to **deactivate + retention review** rather than immediate account deletion, unless the request is an authenticated data-erasure request that must be fully honored. citeturn28view0

### Backup, migration, and rollback

For backup scope, include all of the following:

- `wp_users`
- `wp_usermeta`
- `wp_participants_database`
- `wp_participants_database_fields`
- `wp_participants_database_groups`
- `participants-database_options`
- `wp-content/uploads/participants-database/`
- current theme and custom plugins/mu-plugins

Official PDb migration docs explicitly identify the fields/groups tables and the `participants-database_options` option as core configuration elements, while the plugin’s upload documentation identifies its uploads directory, and the table-reset tutorial identifies the main records table. citeturn18view0turn22view0turn20view0

Recommended rollback posture:

1. Full DB export before installation/configuration.
2. Separate export after field definitions are finalized but before production data migration.
3. Retain a snapshot before enabling live sync.
4. For production rollout, create a restore point immediately before plugin activation / bridge activation.
5. If a record is deleted accidentally, assume **backup restore is the real recovery path**; official support discussion says the practical route is recovery from backup rather than a built-in undelete feature. citeturn28view0turn20view0

Useful commands:

' ' ' bash
wp db export pre-pdb-prod.sql
wp option get participants-database_options > participants-database-options.txt
wp db export post-field-config.sql
' ' ' 

### Migration script outline

Use a dry-run-capable WP-CLI command or one-off admin script. The algorithm should be:

1. Load users in batches.
2. For each WP user:
   - look for a PDb record by `wp_user_id`
   - if not found, optionally look for a single exact email match
   - if exactly one email match exists, link it and write `wp_user_id`
   - if multiple candidates exist, write to a manual-review CSV
   - if none exist, create a new PDb record
3. Sync mapped fields.
4. Log `user_id`, action, `pdb_record_id`, and errors.
5. Run a second audit pass that verifies one-to-one linkage.

Outline:

' ' ' php
<?php
// Pseudocode outline for a WP-CLI command or one-off admin script.
$users = get_users( array( 'number' => 200, 'paged' => $page ) );

foreach ( $users as $user ) {
    $pdb_id = find_by_wp_user_id( $user->ID );

    if ( ! $pdb_id ) {
        $matches = find_pdb_records_by_email( $user->user_email );

        if ( count( $matches ) === 1 ) {
            $pdb_id = $matches[0];
        } elseif ( count( $matches ) > 1 ) {
            log_manual_review( $user->ID, $user->user_email, $matches );
            continue;
        }
    }

    $data = map_wp_user_to_pdb( $user );

    if ( $pdb_id ) {
        Participants_Db::write_participant( $data, $pdb_id );
    } else {
        $pdb_id = Participants_Db::write_participant( $data );
    }

    verify_link( $user->ID, $pdb_id );
}
' ' ' 

If you need custom duplicate detection during import/submission, PDb documents `pdb-incoming_record_match` and `pdb-process_form_matched_record` as the two filters for implementing alternate record-matching logic. citeturn16view0

### Security hardening

The core security decisions for this integration are straightforward:

**Use WordPress accounts for member auth.** The official Participant Login add-on can store passwords in encrypted or plain-text fields depending on field choice, and it is not a WP login. That is not the right primary-auth pattern for a protected member portal. citeturn10view1turn10view2