feat(integrity-check): add --fix flag to reconcile membership discrepancies#307
feat(integrity-check): add --fix flag to reconcile membership discrepancies#307
Conversation
Listen to wc_memberships_user_membership_transferred and dispatch a membership update event with previous_email. On nodes, find the existing managed membership by remote_id and reassign it.
…egrity-check command
3258feb to
db2a9fe
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends the Hub-side wp newspack-network integrity-check command with a --fix mode that attempts to reconcile detected Woo Membership discrepancies by dispatching newspack_network_woo_membership_updated events, supported by additional membership fields and a new node REST endpoint to expose managed-membership timestamps for recency comparison.
Changes:
- Adds
--fixflag to the integrity-check WP-CLI command, including discrepancy classification and event dispatch. - Expands integrity-check membership query results to include
post_modifiedandmembership_id. - Adds a node REST endpoint to return network-managed membership details (including modification timestamps).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
includes/cli/class-integrity-check.php |
Adds --fix reconciliation flow, discrepancy classification, and membership update event dispatch. |
includes/class-integrity-check-utils.php |
Extends membership query output with timestamp and membership ID fields used by reconciliation. |
includes/node/class-integrity-check-endpoints.php |
Adds /integrity-check/managed-memberships endpoint to expose managed membership details for reconciliation. |
tests/unit-tests/test-reconcile-memberships.php |
Adds unit tests covering discrepancy classification behavior used by --fix. |
Comments suppressed due to low confidence (1)
includes/class-integrity-check-utils.php:109
- The docblocks for
execute_membership_query()/get_membership_data()still say they return only(email, status, network_id), but the returned arrays now also includepost_modifiedandmembership_id. Update the PHPDoc so downstream callers/tests know the shape of the data.
/**
* Execute membership query and format results
*
* @param string $query The SQL query.
* @param array $prepare_args Arguments for wpdb->prepare.
* @param int|null $max_records Maximum number of records to return.
* @return array Array of (email, status, network_id) data
*/
private static function execute_membership_query( $query, $prepare_args, $max_records = null ) {
global $wpdb;
if ( $max_records ) {
$query .= $wpdb->prepare( ' LIMIT %d', $max_records );
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
$results = $wpdb->get_results( $wpdb->prepare( $query, ...$prepare_args ) );
$membership_data = [];
foreach ( $results as $result ) {
$membership_data[] = [
'email' => strtolower( $result->user_email ),
'status' => $result->status,
'network_id' => $result->network_id,
'post_modified' => $result->post_modified,
'membership_id' => (int) $result->membership_id,
];
}
return $membership_data;
}
/**
* Get all membership data
*
* @param int|null $max_records Maximum number of records to return (for testing).
* @return array Array of (email, status, network_id) data
*/
public static function get_membership_data( $max_records = null ) {
if ( ! class_exists( 'WC_Memberships_User_Membership' ) ) {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
All Submissions:
Changes proposed in this Pull Request:
Adds a
--fixflag to the existingwp newspack-network integrity-checkcommand. When passed, the command goes beyond reporting discrepancies and actively reconciles them by dispatching membership update events.Addresses NPPM-386.
How it works:
--fix, each discrepancy is classified and an action is determined:_remote_idis matched to the hub'smembership_id. Dispatches a transfer event withprevious_emailso the node reassigns the membership using the transfer handling from feat(memberships): improve integrity check and handle ownership transfers #306.post_modified_gmttimestamps (parsed viastrtotime()) to determine which side has fresher data. The newer side wins -- the hub is not blindly trusted as the source of truth.Sync lag safety (5a48dba, cda0e25):
--fixqueries each node's sync status via a new/integrity-check/sync-statusREST endpoint.wp newspack-network sync-allon the node first -- discrepancies may resolve after syncing without creating new events.--forceto skip the sync lag check.Review feedback (cda0e25):
post_modified_gmt(UTC) instead ofpost_modified(local timezone), both in the hub's utility queries and the node's managed-memberships endpoint.strtotime()instead of string comparison; parse failures are handled explicitly.time(), making dispatch idempotent.Woocommerce_Memberships\Admin::constants.Supporting changes:
Integrity_Check_Utilsnow includespost_modified_gmtandmembership_idin membership data queries (hashing is unchanged)./integrity-check/managed-membershipsREST endpoint on nodes returns managed membership details includingpost_modified_gmtand_remote_id, enabling both timestamp comparison and transfer detection./integrity-check/sync-statusREST endpoint on nodes returns thelast_processed_idfor sync lag detection.How to test the changes in this Pull Request:
_newspack_network_id.wp newspack-network integrity-check --verboseon the hub to confirm existing discrepancies are reported as before.wp newspack-network integrity-check --fix --verboseon the hub.newspack_network_woo_membership_updatedevents.--fix, and verify the action ispush_transferwith the correctprevious_email. Confirm the node reassigns the membership to User B.post_modified, run--fix, and verify the action isskip(node is newer).--fix, and verify it aborts with a suggestion to sync first. Run with--forceto confirm it proceeds anyway.Other information: