| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| defined( 'ABSPATH' ) || exit;
|
|
|
|
|
|
|
|
|
| add_action( 'rest_api_init', function() {
|
|
|
|
|
|
|
|
|
| $user_fields = array(
|
|
|
|
|
|
|
| 'user_id' => 'integer',
|
| 'user_login' => 'string',
|
| 'user_email' => 'string',
|
| 'user_status' => 'string',
|
| 'user_roles' => 'string',
|
| 'display_name' => 'string',
|
| 'first_name' => 'string',
|
| 'last_name' => 'string',
|
| 'nickname' => 'string',
|
| 'phone' => 'string',
|
| 'user_url' => 'string',
|
| 'post_count' => 'integer',
|
| 'description' => 'string',
|
| 'user_registered' => 'string',
|
| 'last_login' => 'string',
|
| 'bb_last_activity' => 'string',
|
| 'user_edit_link' => 'string',
|
| 'user_profile_link' => 'string',
|
| 'bb_profile_link' => 'string',
|
|
|
|
|
|
|
|
|
| 'bb_profile_type' => 'string',
|
| 'bb_profile_type_label' => 'string',
|
| 'bb_friend_count' => 'integer',
|
| 'bb_group_count' => 'integer',
|
| 'bb_extended_fields_count' => 'integer',
|
| 'bb_extended_fields_list' => 'string',
|
|
|
|
|
|
|
|
|
| 'wpf_contact_id' => 'string',
|
| 'wpf_tags_count' => 'integer',
|
| 'wpf_tags_list' => 'string',
|
| 'wpf_tags_raw' => 'string',
|
|
|
|
|
|
|
|
|
| 'gf_total_entries' => 'integer',
|
| 'gf_forms_completed' => 'integer',
|
| 'gf_last_submission' => 'string',
|
| 'gf_submissions_summary' => 'string',
|
| 'gf_entry_ids' => 'string',
|
|
|
|
|
|
|
|
|
| 'llms_enrolled_courses' => 'integer',
|
| 'llms_completed_courses' => 'integer',
|
| 'llms_overall_progress' => 'integer',
|
| 'llms_overall_grade' => 'string',
|
| 'llms_course_details' => 'string',
|
| 'llms_enrolled_course_ids' => 'string',
|
| 'llms_completed_course_ids' => 'string',
|
|
|
|
|
|
|
|
|
| 'llms_membership_count' => 'integer',
|
| 'llms_membership_list' => 'string',
|
| 'llms_membership_ids' => 'string',
|
|
|
|
|
|
|
|
|
| 'llms_certificate_count' => 'integer',
|
| 'llms_achievement_count' => 'integer',
|
| 'llms_certificates_list' => 'string',
|
|
|
|
|
|
|
|
|
| 'all_user_meta' => 'string',
|
|
|
|
|
|
|
|
|
|
|
| 'kic_full_name' => 'string',
|
| 'kic_phone' => 'string',
|
| 'kic_phone_secondary' => 'string',
|
|
|
|
|
| 'kic_address_street' => 'string',
|
| 'kic_address_street_2' => 'string',
|
| 'kic_address_city' => 'string',
|
| 'kic_address_state' => 'string',
|
| 'kic_address_zip' => 'string',
|
|
|
|
|
| 'kic_staff_id' => 'string',
|
| 'kic_employee_id' => 'string',
|
| 'kic_member_id' => 'string',
|
| 'kic_group_id' => 'string',
|
| 'kic_org_id' => 'string',
|
| 'kic_scholar_id' => 'string',
|
| 'kic_vendor_id' => 'string',
|
| 'kic_intern_id' => 'string',
|
|
|
|
|
| 'kic_ghl_id' => 'string',
|
| 'kic_org_name' => 'string',
|
|
|
|
|
| 'kic_address_country' => 'string',
|
|
|
|
|
| 'kic_date_of_birth' => 'string',
|
| 'kic_hire_date' => 'string',
|
| 'kic_emergency_contact_name' => 'string',
|
| 'kic_emergency_contact_phone' => 'string',
|
|
|
|
|
|
|
|
|
| 'whalesync_status' => 'string',
|
| 'last_sync' => 'string',
|
| 'airtable_record_id' => 'string',
|
| 'sync_errors' => 'string',
|
| );
|
|
|
|
|
| foreach ( $user_fields as $field_name => $field_type ) {
|
| register_rest_field( 'users_bb_sync', $field_name, array(
|
| 'get_callback' => function( $object ) use ( $field_name, $field_type ) {
|
| $value = get_post_meta( $object['id'], $field_name, true );
|
|
|
|
|
| if ( $value === '' || $value === false ) {
|
| return null;
|
| }
|
|
|
|
|
| switch ( $field_type ) {
|
| case 'integer':
|
| return intval( $value );
|
| case 'boolean':
|
|
|
| if ( is_string( $value ) ) {
|
| return ( $value === '1' || $value === 'true' || $value === 'yes' );
|
| }
|
| return (bool) $value;
|
| case 'array':
|
|
|
| if ( is_string( $value ) ) {
|
|
|
| $decoded = json_decode( $value, true );
|
| if ( json_last_error() === JSON_ERROR_NONE ) {
|
| return $decoded;
|
| }
|
| }
|
| return is_array( $value ) ? $value : array();
|
| case 'object':
|
|
|
| if ( is_string( $value ) ) {
|
| $decoded = json_decode( $value );
|
| if ( json_last_error() === JSON_ERROR_NONE ) {
|
| return $decoded;
|
| }
|
| }
|
| return is_array( $value ) || is_object( $value ) ? $value : new stdClass();
|
| default:
|
|
|
| return strval( $value );
|
| }
|
| },
|
| 'update_callback' => function( $value, $object ) use ( $field_name ) {
|
| return update_post_meta( $object->ID, $field_name, $value );
|
| },
|
| 'schema' => array(
|
| 'description' => ucwords( str_replace( '_', ' ', $field_name ) ),
|
| 'type' => $field_type,
|
| 'context' => array( 'view', 'edit' ),
|
| ),
|
| ) );
|
| }
|
|
|
| } );
|
|
|
|
|
|
|
|
|
| add_filter( 'register_post_type_args', function( $args, $post_type ) {
|
|
|
| if ( $post_type === 'users_bb_sync' ) {
|
| $args['show_in_rest'] = true;
|
| $args['rest_base'] = 'users-bb-sync';
|
| $args['rest_controller_class'] = 'WP_REST_Posts_Controller';
|
|
|
|
|
| if ( ! in_array( 'custom-fields', $args['supports'] ) ) {
|
| $args['supports'][] = 'custom-fields';
|
| }
|
| }
|
|
|
| return $args;
|
| }, 10, 2 );
|
|
|
|
|
|
|
|
|
| add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
|
|
|
|
|
| $route = $request->get_route();
|
| if ( strpos( $route, '/wp/v2/users-bb-sync' ) === false &&
|
| strpos( $route, '/users-sync/v1' ) === false ) {
|
| return $result;
|
| }
|
|
|
|
|
| $user = wp_get_current_user();
|
|
|
| if ( ! $user || ! $user->exists() ) {
|
| return new WP_Error(
|
| 'rest_forbidden',
|
| __( 'Authentication required. Please use Application Password credentials.' ),
|
| array( 'status' => 401 )
|
| );
|
| }
|
|
|
|
|
| $auth_header = $request->get_header( 'authorization' );
|
|
|
|
|
| if ( empty( $auth_header ) ) {
|
| return new WP_Error(
|
| 'rest_forbidden',
|
| __( 'Application Password authentication required. Browser login not allowed.' ),
|
| array( 'status' => 403 )
|
| );
|
| }
|
|
|
|
|
| return $result;
|
|
|
| }, 10, 3 );
|
|
|
|
|
|
|
|
|
| add_action( 'rest_api_init', function() {
|
|
|
|
|
| register_rest_route( 'users-sync/v1', '/test', array(
|
| 'methods' => 'GET',
|
| 'callback' => function() {
|
|
|
| $posts = get_posts( array(
|
| 'post_type' => 'users_bb_sync',
|
| 'numberposts' => 1,
|
| ) );
|
|
|
| if ( empty( $posts ) ) {
|
| return new WP_REST_Response( array(
|
| 'status' => 'error',
|
| 'message' => 'No user sync posts found. Run sync first.',
|
| 'sync_url' => add_query_arg( 'sync_users', '1', admin_url() ),
|
| ), 404 );
|
| }
|
|
|
| $post = $posts[0];
|
|
|
|
|
| $user_id = get_post_meta( $post->ID, 'user_id', true );
|
| $user_email = get_post_meta( $post->ID, 'user_email', true );
|
| $bb_profile_type = get_post_meta( $post->ID, 'bb_profile_type', true );
|
| $gf_total_entries = get_post_meta( $post->ID, 'gf_total_entries', true );
|
|
|
| return new WP_REST_Response( array(
|
| 'status' => 'success',
|
| 'message' => 'Users Sync REST API is working!',
|
| 'post_info' => array(
|
| 'id' => $post->ID,
|
| 'title' => $post->post_title,
|
| 'user_id' => $user_id,
|
| 'user_email' => $user_email,
|
| 'bb_profile_type' => $bb_profile_type,
|
| 'gf_total_entries' => $gf_total_entries,
|
| ),
|
| 'total_fields_available' => 50,
|
| 'endpoints' => array(
|
| 'collection' => rest_url( 'wp/v2/users-bb-sync' ),
|
| 'single' => rest_url( 'wp/v2/users-bb-sync/' . $post->ID ),
|
| 'test' => rest_url( 'users-sync/v1/test' ),
|
| ),
|
| ), 200 );
|
| },
|
| 'permission_callback' => '__return_true',
|
| ) );
|
|
|
|
|
| register_rest_route( 'users-sync/v1', '/status', array(
|
| 'methods' => 'GET',
|
| 'callback' => function() {
|
|
|
|
|
| $user = wp_get_current_user();
|
| if ( ! $user || ! $user->exists() ) {
|
| return new WP_REST_Response( array(
|
| 'status' => 'error',
|
| 'message' => 'Authentication required.',
|
| ), 401 );
|
| }
|
|
|
|
|
| $total_users = count_users();
|
| $total_synced = wp_count_posts( 'users_bb_sync' )->publish;
|
|
|
|
|
| $latest_sync = get_posts( array(
|
| 'post_type' => 'users_bb_sync',
|
| 'numberposts' => 1,
|
| 'orderby' => 'modified',
|
| 'order' => 'DESC',
|
| ) );
|
|
|
| $last_sync_time = ! empty( $latest_sync ) ? $latest_sync[0]->post_modified : 'Never';
|
|
|
| return new WP_REST_Response( array(
|
| 'status' => 'success',
|
| 'sync_info' => array(
|
| 'total_users' => $total_users['total_users'],
|
| 'total_synced' => $total_synced,
|
| 'last_sync' => $last_sync_time,
|
| 'sync_percentage' => $total_users['total_users'] > 0
|
| ? round( ( $total_synced / $total_users['total_users'] ) * 100, 2 )
|
| : 0,
|
| ),
|
| 'user_roles' => $total_users['avail_roles'],
|
| ), 200 );
|
| },
|
| 'permission_callback' => function() {
|
| return current_user_can( 'edit_posts' );
|
| },
|
| ) );
|
|
|
| } );
|
|
|
|
|
|
|
|
|
| add_filter( 'rest_users_bb_sync_query', function( $args, $request ) {
|
|
|
|
|
| if ( isset( $request['user_id'] ) ) {
|
| $args['meta_key'] = 'user_id';
|
| $args['meta_value'] = intval( $request['user_id'] );
|
| }
|
|
|
|
|
| if ( isset( $request['user_role'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'user_roles',
|
| 'value' => sanitize_text_field( $request['user_role'] ),
|
| 'compare' => 'LIKE',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['profile_type'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'bb_profile_type',
|
| 'value' => sanitize_text_field( $request['profile_type'] ),
|
| 'compare' => '=',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['sync_status'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'whalesync_status',
|
| 'value' => sanitize_text_field( $request['sync_status'] ),
|
| 'compare' => '=',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['has_submissions'] ) && $request['has_submissions'] ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'gf_total_entries',
|
| 'value' => 0,
|
| 'compare' => '>',
|
| 'type' => 'NUMERIC',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['has_courses'] ) && $request['has_courses'] ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'llms_enrolled_courses',
|
| 'value' => 0,
|
| 'compare' => '>',
|
| 'type' => 'NUMERIC',
|
| );
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
| if ( isset( $request['kic_city'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'kic_address_city',
|
| 'value' => sanitize_text_field( $request['kic_city'] ),
|
| 'compare' => '=',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['kic_state'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'kic_address_state',
|
| 'value' => sanitize_text_field( $request['kic_state'] ),
|
| 'compare' => '=',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['kic_org_id'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'kic_org_id',
|
| 'value' => sanitize_text_field( $request['kic_org_id'] ),
|
| 'compare' => '=',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['kic_staff_id'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'kic_staff_id',
|
| 'value' => sanitize_text_field( $request['kic_staff_id'] ),
|
| 'compare' => '=',
|
| );
|
| }
|
|
|
|
|
| if ( isset( $request['kic_org_name'] ) ) {
|
| if ( ! isset( $args['meta_query'] ) ) {
|
| $args['meta_query'] = array();
|
| }
|
| $args['meta_query'][] = array(
|
| 'key' => 'kic_org_name',
|
| 'value' => sanitize_text_field( $request['kic_org_name'] ),
|
| 'compare' => 'LIKE',
|
| );
|
| }
|
|
|
| return $args;
|
|
|
| }, 10, 2 );
|
|
|
|
|
|
|
|
|
| add_filter( 'rest_users_bb_sync_collection_params', function( $params ) {
|
|
|
| $params['user_id'] = array(
|
| 'description' => 'Filter by WordPress User ID',
|
| 'type' => 'integer',
|
| 'sanitize_callback' => 'absint',
|
| );
|
|
|
| $params['user_role'] = array(
|
| 'description' => 'Filter by user role',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['profile_type'] = array(
|
| 'description' => 'Filter by BuddyBoss profile type',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['sync_status'] = array(
|
| 'description' => 'Filter by sync status',
|
| 'type' => 'string',
|
| 'enum' => array( 'active', 'paused', 'error' ),
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['has_submissions'] = array(
|
| 'description' => 'Filter to users with Gravity Forms submissions',
|
| 'type' => 'boolean',
|
| );
|
|
|
| $params['has_courses'] = array(
|
| 'description' => 'Filter to users enrolled in LifterLMS courses',
|
| 'type' => 'boolean',
|
| );
|
|
|
|
|
| $params['kic_city'] = array(
|
| 'description' => 'Filter by KIC City field',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['kic_state'] = array(
|
| 'description' => 'Filter by KIC State field (2-letter code)',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['kic_org_id'] = array(
|
| 'description' => 'Filter by KIC Organization ID',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['kic_staff_id'] = array(
|
| 'description' => 'Filter by KIC Staff ID',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| $params['kic_org_name'] = array(
|
| 'description' => 'Filter by KIC Organization Name',
|
| 'type' => 'string',
|
| 'sanitize_callback' => 'sanitize_text_field',
|
| );
|
|
|
| return $params;
|
|
|
| } );
|
|
|
|
|
|
|
|
|
| add_action( 'rest_api_init', function() {
|
|
|
| register_rest_route( 'users-sync/v1', '/sync', array(
|
| 'methods' => 'POST',
|
| 'callback' => function( $request ) {
|
|
|
|
|
| $user_id = $request->get_param( 'user_id' );
|
|
|
| if ( $user_id ) {
|
|
|
| $sync_instance = WPRUS_BB_Manual_Sync::get_instance();
|
| $result = $sync_instance->sync_single_user( intval( $user_id ) );
|
|
|
| if ( $result ) {
|
| return new WP_REST_Response( array(
|
| 'status' => 'success',
|
| 'message' => 'User ' . $user_id . ' synced successfully.',
|
| 'post_id' => $result,
|
| ), 200 );
|
| } else {
|
| return new WP_REST_Response( array(
|
| 'status' => 'error',
|
| 'message' => 'Failed to sync user ' . $user_id,
|
| ), 500 );
|
| }
|
| } else {
|
|
|
| $sync_instance = WPRUS_BB_Manual_Sync::get_instance();
|
| $synced = $sync_instance->sync_all_users();
|
|
|
| return new WP_REST_Response( array(
|
| 'status' => 'success',
|
| 'message' => 'All users synced successfully.',
|
| 'total_synced' => count( $synced ),
|
| 'user_ids' => $synced,
|
| ), 200 );
|
| }
|
| },
|
| 'permission_callback' => function() {
|
| return current_user_can( 'manage_options' );
|
| },
|
| 'args' => array(
|
| 'user_id' => array(
|
| 'description' => 'Optional: Specific User ID to sync',
|
| 'type' => 'integer',
|
| 'required' => false,
|
| 'sanitize_callback' => 'absint',
|
| ),
|
| ),
|
| ) );
|
|
|
| } );
|
|
|
|
|
|
|
|
|
| add_action( 'admin_notices', function() {
|
|
|
|
|
| $screen = get_current_screen();
|
| if ( ! $screen || strpos( $screen->id, 'users_bb_sync' ) === false ) {
|
| return;
|
| }
|
|
|
| ?>
|
| <div class="notice notice-info">
|
| <p><strong>Users Sync REST API Endpoints:</strong></p>
|
| <ul style="list-style: disc; margin-left: 20px;">
|
| <li>Collection: <code><?php echo rest_url( 'wp/v2/users-bb-sync' ); ?></code></li>
|
| <li>Test: <code><?php echo rest_url( 'users-sync/v1/test' ); ?></code></li>
|
| <li>Status: <code><?php echo rest_url( 'users-sync/v1/status' ); ?></code></li>
|
| <li>Sync: <code><?php echo rest_url( 'users-sync/v1/sync' ); ?></code> (POST)</li>
|
| </ul>
|
| <p><em>Authentication: Application Password required for all data endpoints.</em></p>
|
| </div>
|
| <?php
|
| } );
|
|
|
| /**
|
| * Log REST API access for debugging
|
| */
|
| add_filter( 'rest_request_after_callbacks', function( $response, $handler, $request ) {
|
|
|
| $route = $request->get_route();
|
|
|
|
|
| if ( strpos( $route, 'users-sync' ) !== false || strpos( $route, 'users_bb_sync' ) !== false ) {
|
|
|
|
|
| error_log( sprintf(
|
| 'USERS_REST_API: %s request to %s from user %s',
|
| $request->get_method(),
|
| $route,
|
| wp_get_current_user()->user_login ?: 'anonymous'
|
| ) );
|
| }
|
|
|
| return $response;
|
|
|
| }, 10, 3 );
|
| |
| |
Comments