File: //home/dfwparty/dfwchat.net/wp-content/plugins/buddyboss-tools/migration/peepso/ajax.php
<?php
/**
* PeepSo migration AJAX handlers.
*
* Provides the admin-ajax endpoints that drive the PeepSo migration modal:
* scanning source data, running migration batches, persisting state and batch
* size, and resetting a migration. Each handler verifies capability and nonce
* before doing any work.
*
* @package BuddyBoss\Tools\Migration\PeepSo
* @since 1.0.0
*/
defined( 'ABSPATH' ) || exit;
/**
* Scan PeepSo data and return per-category record counts.
*
* Responds with the source record counts, step inventory, batch size, and
* current migration state so the modal can show live figures when it opens.
*
* @since 1.0.0
*
* @return void
*/
function bb_tools_peepso_ajax_scan() {
if ( ! bb_tools_current_user_can() ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'buddyboss-tools' ) ), 403 );
}
check_ajax_referer( 'bb_tools_migration', '_ajax_nonce' );
if ( ! bb_tools_peepso_is_active() ) {
wp_send_json_error( array( 'message' => __( 'PeepSo is not installed or active. Migration is unavailable.', 'buddyboss-tools' ) ), 400 );
}
if ( ! class_exists( 'BB_Tools_Peepso_Data_Scanner' ) ) {
wp_send_json_error( array( 'message' => __( 'PeepSo scanner not available.', 'buddyboss-tools' ) ), 500 );
}
try {
$scanner = new BB_Tools_Peepso_Data_Scanner();
$counts = $scanner->get_all_counts();
} catch ( \Throwable $e ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Gated on WP_DEBUG.
error_log( sprintf( 'BB Tools: PeepSo scan failed: %s', $e->getMessage() ) );
}
wp_send_json_error( array( 'message' => __( 'Unable to scan PeepSo data. Check the WordPress debug log for details.', 'buddyboss-tools' ) ), 500 );
}
// autoload = false: only read when the modal opens.
update_option( 'bb_tools_peepso_scan_counts', $counts, false );
$state = get_option( 'bb_tools_peepso_migration_state', array() );
$state = is_array( $state ) ? $state : array();
wp_send_json_success(
array(
'counts' => $counts,
'steps' => bb_tools_peepso_step_inventory(),
'batch_size' => (int) get_option( 'bb_tools_peepso_batch_size', 25 ),
'started' => (bool) get_option( 'bb_tools_peepso_migration_started', false ),
'status' => isset( $state['status'] ) ? sanitize_key( $state['status'] ) : '',
'step_data' => ( isset( $state['step_data'] ) && is_array( $state['step_data'] ) ) ? array_values( $state['step_data'] ) : array(),
)
);
}
add_action( 'wp_ajax_bb_tools_peepso_scan', 'bb_tools_peepso_ajax_scan' );
/**
* Run one migration batch and report the next step.
*
* Dispatches the requested step to the migration engine and returns its progress
* along with the next step and parameters, letting the modal drive the migration
* one batch at a time until it finishes.
*
* @since 1.0.0
*
* @return void
*/
function bb_tools_peepso_ajax_migrate() {
if ( ! bb_tools_current_user_can() ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'buddyboss-tools' ) ), 403 );
}
check_ajax_referer( 'bb_tools_migration', '_ajax_nonce' );
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 0 );
}
ignore_user_abort( true );
if ( ! bb_tools_peepso_is_active() ) {
wp_send_json_error( array( 'message' => __( 'PeepSo is not installed or active. Migration is unavailable.', 'buddyboss-tools' ) ), 400 );
}
bb_tools_peepso_require_engine();
$step = isset( $_POST['step'] ) ? sanitize_key( wp_unslash( $_POST['step'] ) ) : '';
$limit = isset( $_POST['limit'] ) ? absint( $_POST['limit'] ) : 0;
$phase = isset( $_POST['phase'] ) ? sanitize_key( wp_unslash( $_POST['phase'] ) ) : 'likes';
$pending = isset( $_POST['pending'] ) ? absint( $_POST['pending'] ) : 0;
$methods = bb_tools_peepso_step_methods();
if ( '' === $step || ! isset( $methods[ $step ] ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid migration step.', 'buddyboss-tools' ) ), 400 );
}
update_option( 'bb_tools_peepso_migration_started', 1, false );
// The ported controller + helpers read the batch offset / phase / pending
// from the request superglobals; feed them from the validated AJAX inputs.
$_GET['limit'] = $limit;
$_POST['limit'] = $limit;
$_GET['phase'] = $phase;
$_GET['pending'] = $pending;
try {
$migrate = new BB_Tools_Peepso_Migrate();
$response = $migrate->{ $methods[ $step ] }();
} catch ( \Throwable $e ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Gated on WP_DEBUG.
error_log( sprintf( 'BB Tools: PeepSo migrate step "%s" failed: %s', $step, $e->getMessage() ) );
}
wp_send_json_error(
array(
'message' => __( 'A migration step failed. Check the WordPress debug log for details.', 'buddyboss-tools' ),
'step' => $step,
),
500
);
}
$response = is_array( $response ) ? $response : array();
$done = ! empty( $response['finished'] );
$next_step = '';
$next_params = array();
if ( ! $done && ! empty( $response['url'] ) ) {
$parsed = bb_tools_peepso_parse_descriptor( $response['url'] );
$next_step = $parsed['step'];
$next_params = $parsed['params'];
}
if ( $done && function_exists( 'bb_record_tool_usage' ) ) {
bb_record_tool_usage( 'migration', 'peepso-community', __( 'PeepSo Community to BuddyBoss', 'buddyboss-tools' ) );
}
wp_send_json_success(
array(
'class' => isset( $response['class'] ) ? sanitize_key( $response['class'] ) : $step,
'counter' => isset( $response['counter'] ) ? (int) $response['counter'] : 0,
'total' => isset( $response['total'] ) ? (int) $response['total'] : 0,
'skipped' => ( isset( $response['skipped'] ) && is_array( $response['skipped'] ) ) ? $response['skipped'] : array(),
'done' => $done,
'next_step' => $next_step,
'next_params' => $next_params,
)
);
}
add_action( 'wp_ajax_bb_tools_peepso_migrate', 'bb_tools_peepso_ajax_migrate' );
/**
* Persist the migration batch size.
*
* Validates the requested batch size against the allowed values and saves it for
* subsequent migration runs.
*
* @since 1.0.0
*
* @return void
*/
function bb_tools_peepso_ajax_save_batch_size() {
if ( ! bb_tools_current_user_can() ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'buddyboss-tools' ) ), 403 );
}
check_ajax_referer( 'bb_tools_migration', '_ajax_nonce' );
$allowed = array( 10, 25, 50 );
$size = isset( $_POST['batch_size'] ) ? absint( $_POST['batch_size'] ) : 25;
if ( ! in_array( $size, $allowed, true ) ) {
$size = 25;
}
update_option( 'bb_tools_peepso_batch_size', $size, false );
wp_send_json_success( array( 'batch_size' => $size ) );
}
add_action( 'wp_ajax_bb_tools_peepso_save_batch_size', 'bb_tools_peepso_ajax_save_batch_size' );
/**
* Persist migration run state.
*
* Stores the current status, counters, per-step data, and log entries so
* migration progress survives page reloads and closed browser tabs.
*
* @since 1.0.0
*
* @return void
*/
function bb_tools_peepso_ajax_save_state() {
if ( ! bb_tools_current_user_can() ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'buddyboss-tools' ) ), 403 );
}
check_ajax_referer( 'bb_tools_migration', '_ajax_nonce' );
$allowed = array( 'in_progress', 'completed', 'error' );
$status = isset( $_POST['status'] ) ? sanitize_key( wp_unslash( $_POST['status'] ) ) : '';
if ( ! in_array( $status, $allowed, true ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid status.', 'buddyboss-tools' ) ), 400 );
}
$step_data = array();
$raw_steps = ( isset( $_POST['step_data'] ) && is_string( $_POST['step_data'] ) ) ? json_decode( wp_unslash( $_POST['step_data'] ), true ) : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Decoded + sanitised field-by-field below.
if ( is_array( $raw_steps ) ) {
foreach ( $raw_steps as $index => $data ) {
$step_data[ absint( $index ) ] = array(
'counter' => isset( $data['counter'] ) ? absint( $data['counter'] ) : 0,
'total' => isset( $data['total'] ) ? absint( $data['total'] ) : 0,
);
}
}
$log_entries = array();
$raw_log = ( isset( $_POST['log_entries'] ) && is_string( $_POST['log_entries'] ) ) ? json_decode( wp_unslash( $_POST['log_entries'] ), true ) : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Decoded + sanitised field-by-field below.
if ( is_array( $raw_log ) ) {
foreach ( $raw_log as $entry ) {
$log_entries[] = array(
'type' => isset( $entry['type'] ) ? sanitize_text_field( $entry['type'] ) : 'INFO',
'message' => isset( $entry['message'] ) ? sanitize_text_field( $entry['message'] ) : '',
'time' => isset( $entry['time'] ) ? sanitize_text_field( $entry['time'] ) : '',
);
}
}
$state = array(
'status' => $status,
'total_records' => isset( $_POST['total_records'] ) ? absint( $_POST['total_records'] ) : 0,
'steps_completed' => isset( $_POST['steps_completed'] ) ? sanitize_text_field( wp_unslash( $_POST['steps_completed'] ) ) : '0/0',
'elapsed_time' => isset( $_POST['elapsed_time'] ) ? sanitize_text_field( wp_unslash( $_POST['elapsed_time'] ) ) : '00:00',
'completed_at' => current_time( 'mysql' ),
'step_data' => $step_data,
'log_entries' => $log_entries,
);
update_option( 'bb_tools_peepso_migration_state', $state, false );
if ( 'completed' === $status ) {
delete_option( 'bb_tools_peepso_migration_started' );
}
wp_send_json_success( $state );
}
add_action( 'wp_ajax_bb_tools_peepso_save_state', 'bb_tools_peepso_ajax_save_state' );
/**
* Reset the migration.
*
* Purges migrated BuddyBoss content in client-driven chunks and clears the saved
* migration state and mappings once the purge completes.
*
* @since 1.0.0
*
* @return void
*/
function bb_tools_peepso_ajax_reset() {
if ( ! bb_tools_current_user_can() ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'buddyboss-tools' ) ), 403 );
}
check_ajax_referer( 'bb_tools_migration', '_ajax_nonce' );
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 0 );
}
bb_tools_peepso_require_engine();
$offset = isset( $_POST['offset'] ) ? absint( $_POST['offset'] ) : 0;
$result = array(
'processed' => 0,
'total' => 0,
'done' => false,
);
// The purge runs in client-driven chunks so Cancel can stop it (the next
// chunk is simply never requested). Migration state is cleared only on the
// final chunk, so a cancelled reset leaves state intact and can be resumed.
try {
$migrate = new BB_Tools_Peepso_Migrate();
$result = $migrate->purge_buddyboss_content( $offset, 6 );
if ( ! empty( $result['done'] ) ) {
if ( function_exists( 'bb_tools_peepso_cleanup_migration' ) ) {
bb_tools_peepso_cleanup_migration();
}
delete_option( 'bb_tools_peepso_migration_state' );
delete_option( 'bb_tools_peepso_migration_started' );
}
} catch ( \Throwable $e ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Gated on WP_DEBUG.
error_log( sprintf( 'BB Tools: PeepSo reset failed: %s', $e->getMessage() ) );
}
wp_send_json_error( array( 'message' => __( 'Reset failed. Check the WordPress debug log for details.', 'buddyboss-tools' ) ), 500 );
}
wp_send_json_success(
array(
'processed' => (int) $result['processed'],
'total' => (int) $result['total'],
'done' => ! empty( $result['done'] ),
)
);
}
add_action( 'wp_ajax_bb_tools_peepso_reset', 'bb_tools_peepso_ajax_reset' );