'Security check failed.' ), 403 ); } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => 'Insufficient permissions.' ), 403 ); } } // ─── SITES ───────────────────────────────── public static function wpuhm_add_site() { self::verify(); $url = isset( $_POST['site_url'] ) ? esc_url_raw( wp_unslash( $_POST['site_url'] ) ) : ''; $key = isset( $_POST['api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['api_key'] ) ) : ''; $name = isset( $_POST['site_name'] ) ? sanitize_text_field( wp_unslash( $_POST['site_name'] ) ) : ''; if ( empty( $url ) || empty( $key ) ) { wp_send_json_error( array( 'message' => 'Site URL and API Key are required.' ) ); } // Input limits checking if ( strlen( $url ) > 500 ) { wp_send_json_error( array( 'message' => 'Site URL must be 500 characters or less.' ) ); } if ( strlen( $key ) > 255 ) { wp_send_json_error( array( 'message' => 'API Key must be 255 characters or less.' ) ); } if ( strlen( $name ) > 255 ) { wp_send_json_error( array( 'message' => 'Site Name must be 255 characters or less.' ) ); } $result = WPUHM_Site_Manager::add( $url, $key, $name ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } // Auto-test connection WPUHM_Site_Manager::test_connection( $result ); $site = WPUHM_Site_Manager::get( $result ); wp_send_json_success( array( 'message' => 'Site added successfully!', 'site' => $site ) ); } public static function wpuhm_remove_site() { self::verify(); $id = isset( $_POST['site_id'] ) ? absint( $_POST['site_id'] ) : 0; if ( ! $id ) { wp_send_json_error( array( 'message' => 'Invalid site ID.' ) ); } WPUHM_Site_Manager::remove( $id ); wp_send_json_success( array( 'message' => 'Site removed.' ) ); } public static function wpuhm_update_site() { self::verify(); $id = isset( $_POST['site_id'] ) ? absint( $_POST['site_id'] ) : 0; $data = array(); if ( isset( $_POST['site_name'] ) ) { $site_name = sanitize_text_field( wp_unslash( $_POST['site_name'] ) ); if ( strlen( $site_name ) > 255 ) { wp_send_json_error( array( 'message' => 'Site Name must be 255 characters or less.' ) ); } $data['site_name'] = $site_name; } if ( isset( $_POST['site_url'] ) ) { $site_url = esc_url_raw( wp_unslash( $_POST['site_url'] ) ); if ( strlen( $site_url ) > 500 ) { wp_send_json_error( array( 'message' => 'Site URL must be 500 characters or less.' ) ); } $data['site_url'] = $site_url; } if ( isset( $_POST['api_key'] ) ) { $api_key = sanitize_text_field( wp_unslash( $_POST['api_key'] ) ); if ( strlen( $api_key ) > 255 ) { wp_send_json_error( array( 'message' => 'API Key must be 255 characters or less.' ) ); } $data['api_key'] = $api_key; } WPUHM_Site_Manager::update( $id, $data ); wp_send_json_success( array( 'message' => 'Site updated.' ) ); } public static function wpuhm_test_connection() { self::verify(); $id = isset( $_POST['site_id'] ) ? absint( $_POST['site_id'] ) : 0; if ( ! $id ) { wp_send_json_error( array( 'message' => 'Invalid site ID.' ) ); } $result = WPUHM_Site_Manager::test_connection( $id ); $site = WPUHM_Site_Manager::get( $id ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message(), 'site' => $site ) ); } if ( $result['success'] ) { wp_send_json_success( array( 'message' => 'Connection successful!', 'site' => $site, 'ping' => $result['data'] ) ); } else { wp_send_json_error( array( 'message' => $result['error'], 'site' => $site ) ); } } public static function wpuhm_test_all_connections() { self::verify(); $sites = WPUHM_Site_Manager::get_all(); $results = array(); foreach ( $sites as $site ) { $r = WPUHM_Site_Manager::test_connection( $site['id'] ); $results[] = array( 'site_id' => $site['id'], 'site_name' => $site['site_name'], 'success' => is_array( $r ) && $r['success'], ); } wp_send_json_success( array( 'results' => $results ) ); } public static function wpuhm_get_sites() { self::verify(); wp_send_json_success( array( 'sites' => WPUHM_Site_Manager::get_all() ) ); } // ─── USER OPERATIONS ────────────────────── public static function wpuhm_create_user() { self::verify(); $user_data = array( 'username' => isset( $_POST['username'] ) ? sanitize_user( wp_unslash( $_POST['username'] ) ) : '', 'email' => isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '', 'password' => isset( $_POST['password'] ) ? wp_unslash( $_POST['password'] ) : wp_generate_password( 16, true ), 'first_name' => isset( $_POST['first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['first_name'] ) ) : '', 'last_name' => isset( $_POST['last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['last_name'] ) ) : '', 'role' => isset( $_POST['role'] ) ? sanitize_text_field( wp_unslash( $_POST['role'] ) ) : 'subscriber', ); $site_ids = isset( $_POST['site_ids'] ) ? array_map( 'absint', (array) $_POST['site_ids'] ) : array(); if ( empty( $user_data['username'] ) || empty( $user_data['email'] ) ) { wp_send_json_error( array( 'message' => 'Username and email are required.' ) ); } if ( empty( $site_ids ) ) { wp_send_json_error( array( 'message' => 'Select at least one site.' ) ); } // Input limits and structure checking if ( strlen( $user_data['username'] ) > 60 ) { wp_send_json_error( array( 'message' => 'Username must be 60 characters or less.' ) ); } if ( strlen( $user_data['email'] ) > 100 ) { wp_send_json_error( array( 'message' => 'Email must be 100 characters or less.' ) ); } if ( ! is_email( $user_data['email'] ) ) { wp_send_json_error( array( 'message' => 'Invalid email address.' ) ); } if ( strlen( $user_data['password'] ) > 100 ) { wp_send_json_error( array( 'message' => 'Password must be 100 characters or less.' ) ); } if ( strlen( $user_data['first_name'] ) > 50 ) { wp_send_json_error( array( 'message' => 'First name must be 50 characters or less.' ) ); } if ( strlen( $user_data['last_name'] ) > 50 ) { wp_send_json_error( array( 'message' => 'Last name must be 50 characters or less.' ) ); } $allowed_roles = array( 'subscriber', 'contributor', 'author', 'editor', 'administrator' ); if ( ! in_array( $user_data['role'], $allowed_roles, true ) ) { wp_send_json_error( array( 'message' => 'Invalid user role requested.' ) ); } $results = WPUHM_User_Operations::create_user_on_sites( $user_data, $site_ids ); $success = count( array_filter( $results, function( $r ) { return $r['success']; } ) ); $failed = count( $results ) - $success; wp_send_json_success( array( 'message' => sprintf( 'User created on %d sites. %d failed.', $success, $failed ), 'results' => $results, ) ); } public static function wpuhm_delete_user() { self::verify(); $identifier = isset( $_POST['identifier'] ) ? sanitize_text_field( wp_unslash( $_POST['identifier'] ) ) : ''; $site_ids = isset( $_POST['site_ids'] ) ? array_map( 'absint', (array) $_POST['site_ids'] ) : array(); $site_users = isset( $_POST['site_users'] ) ? array_map( 'absint', (array) wp_unslash( $_POST['site_users'] ) ) : array(); if ( empty( $identifier ) ) { wp_send_json_error( array( 'message' => 'User email or username is required.' ) ); } if ( empty( $site_ids ) ) { wp_send_json_error( array( 'message' => 'Select at least one site.' ) ); } $results = WPUHM_User_Operations::delete_user_from_sites( $identifier, $site_ids, $site_users ); $success = count( array_filter( $results, function( $r ) { return $r['success']; } ) ); $failed = count( $results ) - $success; wp_send_json_success( array( 'message' => sprintf( 'User removed from %d sites. %d failed.', $success, $failed ), 'results' => $results, ) ); } public static function wpuhm_update_user() { self::verify(); $identifier = isset( $_POST['identifier'] ) ? sanitize_text_field( wp_unslash( $_POST['identifier'] ) ) : ''; $site_ids = isset( $_POST['site_ids'] ) ? array_map( 'absint', (array) $_POST['site_ids'] ) : array(); if ( strlen( $identifier ) > 100 ) { wp_send_json_error( array( 'message' => 'Identifier is too long.' ) ); } $changes = array(); if ( isset( $_POST['new_role'] ) && ! empty( $_POST['new_role'] ) ) { $role = sanitize_text_field( wp_unslash( $_POST['new_role'] ) ); $allowed_roles = array( 'subscriber', 'contributor', 'author', 'editor', 'administrator' ); if ( ! in_array( $role, $allowed_roles, true ) ) { wp_send_json_error( array( 'message' => 'Invalid user role requested.' ) ); } $changes['role'] = $role; } if ( isset( $_POST['new_email'] ) && ! empty( $_POST['new_email'] ) ) { $email = sanitize_email( wp_unslash( $_POST['new_email'] ) ); if ( strlen( $email ) > 100 ) { wp_send_json_error( array( 'message' => 'Email must be 100 characters or less.' ) ); } if ( ! is_email( $email ) ) { wp_send_json_error( array( 'message' => 'Invalid email address.' ) ); } $changes['email'] = $email; } if ( isset( $_POST['new_password'] ) && ! empty( $_POST['new_password'] ) ) { $password = wp_unslash( $_POST['new_password'] ); if ( strlen( $password ) > 100 ) { wp_send_json_error( array( 'message' => 'Password must be 100 characters or less.' ) ); } $changes['password'] = $password; } if ( isset( $_POST['new_first_name'] ) && ! empty( $_POST['new_first_name'] ) ) { $first_name = sanitize_text_field( wp_unslash( $_POST['new_first_name'] ) ); if ( strlen( $first_name ) > 50 ) { wp_send_json_error( array( 'message' => 'First name must be 50 characters or less.' ) ); } $changes['first_name'] = $first_name; } if ( isset( $_POST['new_last_name'] ) && ! empty( $_POST['new_last_name'] ) ) { $last_name = sanitize_text_field( wp_unslash( $_POST['new_last_name'] ) ); if ( strlen( $last_name ) > 50 ) { wp_send_json_error( array( 'message' => 'Last name must be 50 characters or less.' ) ); } $changes['last_name'] = $last_name; } if ( empty( $identifier ) || empty( $changes ) || empty( $site_ids ) ) { wp_send_json_error( array( 'message' => 'Identifier, changes, and sites are required.' ) ); } $results = WPUHM_User_Operations::update_user_on_sites( $identifier, $changes, $site_ids ); $success = count( array_filter( $results, function( $r ) { return $r['success']; } ) ); wp_send_json_success( array( 'message' => sprintf( 'User updated on %d sites.', $success ), 'results' => $results, ) ); } public static function wpuhm_search_user() { self::verify(); $query = isset( $_POST['query'] ) ? sanitize_text_field( wp_unslash( $_POST['query'] ) ) : ''; if ( empty( $query ) ) { wp_send_json_error( array( 'message' => 'Search query is required.' ) ); } $results = WPUHM_User_Operations::search_user_on_sites( $query ); $found = array_filter( $results, function( $r ) { return $r['found']; } ); wp_send_json_success( array( 'message' => sprintf( 'Found on %d out of %d sites.', count( $found ), count( $results ) ), 'results' => $results, 'found_count' => count( $found ), 'total_sites' => count( $results ), ) ); } public static function wpuhm_get_all_users() { self::verify(); $users = WPUHM_User_Operations::get_all_users(); wp_send_json_success( array( 'users' => $users, 'count' => count( $users ) ) ); } } // Initialize AJAX handlers WPUHM_Ajax_Handler::init();