pretty_print = defined( 'JSON_PRETTY_PRINT' ) ? JSON_PRETTY_PRINT : null; /** * UM hook * * @type filter * @title um_api_log_requests * @description Allow API request logging to be turned off * @input_vars * [{"var":"$allow_log","type":"bool","desc":"Enable api logs"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $this->log_requests = apply_filters( 'um_api_log_requests', $this->log_requests ); } /** * Registers a new rewrite endpoint for accessing the API * * @param $rewrite_rules */ public function add_endpoint( $rewrite_rules ) { add_rewrite_endpoint( 'um-api', EP_ALL ); } /** * Registers query vars for API access * * @param $vars * * @return array */ public function query_vars( $vars ) { $vars[] = 'key'; $vars[] = 'token'; $vars[] = 'format'; $vars[] = 'query'; $vars[] = 'type'; $vars[] = 'data'; $vars[] = 'fields'; $vars[] = 'value'; $vars[] = 'number'; $vars[] = 'id'; $vars[] = 'email'; $vars[] = 'orderby'; $vars[] = 'order'; $vars[] = 'include'; $vars[] = 'exclude'; $this->vars = $vars; return $vars; } /** * Validate the API request */ private function validate_request() { global $wp_query; $this->override = false; // Make sure we have both user and api key if ( ! empty( $wp_query->query_vars['um-api'] ) ) { if ( empty( $wp_query->query_vars['token'] ) || empty( $wp_query->query_vars['key'] ) ) $this->missing_auth(); // Retrieve the user by public API key and ensure they exist if ( ! ( $user = $this->get_user( $wp_query->query_vars['key'] ) ) ) : $this->invalid_key(); else : $token = urldecode( $wp_query->query_vars['token'] ); $secret = get_user_meta( $user, 'um_user_secret_key', true ); $public = urldecode( $wp_query->query_vars['key'] ); if ( hash_equals( md5( $secret . $public ), $token ) ) $this->is_valid_request = true; else $this->invalid_auth(); endif; } } /** * Retrieve the user ID based on the public key provided * * @param string $key * * @return bool|mixed|null|string */ public function get_user( $key = '' ) { global $wpdb, $wp_query; if( empty( $key ) ) $key = urldecode( $wp_query->query_vars['key'] ); if ( empty( $key ) ) { return false; } $user = get_transient( md5( 'um_api_user_' . $key ) ); if ( false === $user ) { $user = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'um_user_public_key' AND meta_value = %s LIMIT 1", $key ) ); set_transient( md5( 'um_api_user_' . $key ) , $user, DAY_IN_SECONDS ); } if ( $user != NULL ) { $this->user_id = $user; return $user; } return false; } /** * Displays a missing authentication error if all the parameters aren't * provided */ private function missing_auth() { $error = array(); $error['error'] = __( 'You must specify both a token and API key!', 'ultimate-member' ); $this->data = $error; $this->output( 401 ); } /** * Displays an authentication failed error if the user failed to provide valid credentials */ private function invalid_auth() { $error = array(); $error['error'] = __( 'Your request could not be authenticated', 'ultimate-member' ); $this->data = $error; $this->output( 401 ); } /** * Displays an invalid API key error if the API key provided couldn't be validated */ private function invalid_key() { $error = array(); $error['error'] = __( 'Invalid API key', 'ultimate-member' ); $this->data = $error; $this->output( 401 ); } /** * Listens for the API and then processes the API requests */ public function process_query() { global $wp_query; // Check for um-api var. Get out if not present if ( ! isset( $wp_query->query_vars['um-api'] ) ) return; // Check for a valid user and set errors if necessary $this->validate_request(); // Only proceed if no errors have been noted if( ! $this->is_valid_request ) return; if( ! defined( 'UM_DOING_API' ) ) { define( 'UM_DOING_API', true ); } // Determine the kind of query $args = array(); $query_mode = $this->get_query_mode(); foreach( $this->vars as $k ) { $args[ $k ] = isset( $wp_query->query_vars[ $k ] ) ? $wp_query->query_vars[ $k ] : null; } $data = array(); switch( $query_mode ) { case 'get.stats': $data = $this->get_stats( $args ); break; case 'get.users': $data = $this->get_users( $args ); break; case 'get.user': $data = $this->get_auser( $args ); break; case 'update.user': $data = $this->update_user( $args ); break; case 'delete.user': $data = $this->delete_user( $args ); break; default: /** * UM hook * * @type filter * @title um_rest_query_mode * @description Change query attributes * @input_vars * [{"var":"$data","type":"array","desc":"Query Data"}, * {"var":"$query_mode","type":"string","desc":"Query Mode"}, * {"var":"$args","type":"array","desc":"Query Arguments"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $data = apply_filters( 'um_rest_query_mode', $data, $query_mode, $args ); } /** * UM hook * * @type filter * @title um_api_output_data * @description Change output data for Rest API call * @input_vars * [{"var":"$data","type":"array","desc":"Output Data"}, * {"var":"$query_mode","type":"string","desc":"Query Mode"}, * {"var":"$api_class","type":"REST_API","desc":"REST_API instance"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $this->data = apply_filters( 'um_api_output_data', $data, $query_mode, $this ); // Log this API request, if enabled. We log it here because we have access to errors. $this->log_request( $this->data ); // Send out data to the output function $this->output(); } /** * Get some stats * * @param $args * * @return array|mixed|void */ public function get_stats( $args ) { global $wpdb; extract( $args ); $response = array(); $query = "SELECT COUNT(*) FROM {$wpdb->prefix}users"; $count = absint( $wpdb->get_var($query) ); $response['stats']['total_users'] = $count; $pending = UM()->user()->get_pending_users_count(); $response['stats']['pending_users'] = absint( $pending ); /** * UM hook * * @type filter * @title um_rest_api_get_stats * @description Change output data for Rest API get stats call * @input_vars * [{"var":"$response","type":"array","desc":"Output Data"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $response = apply_filters( 'um_rest_api_get_stats', $response ); return $response; } /** * Update user API query * * @param $args * * @return array */ public function update_user( $args ) { extract( $args ); $response = array(); $error = array(); if ( !$id ) { $error['error'] = __('You must provide a user ID','ultimate-member'); return $error; } if ( !$data ) { $error['error'] = __('You need to provide data to update','ultimate-member'); return $error; } um_fetch_user( $id ); switch ( $data ) { case 'status': UM()->user()->set_status( $value ); $response['success'] = __('User status has been changed.','ultimate-member'); break; case 'role': $wp_user_object = new \WP_User( $id ); $old_roles = $wp_user_object->roles; $wp_user_object->set_role( $value ); /** * UM hook * * @type action * @title um_after_member_role_upgrade * @description Action after user role was changed * @input_vars * [{"var":"$new_roles","type":"array","desc":"New User Roles"}, * {"var":"$old_roles","type":"array","desc":"Old roles"}] * @change_log * ["Since: 2.0"] * @usage add_action( 'um_after_member_role_upgrade', 'function_name', 10, 2 ); * @example * */ do_action( 'um_after_member_role_upgrade', array( $value ), $old_roles ); $response['success'] = __( 'User role has been changed.', 'ultimate-member' ); break; default: update_user_meta( $id, $data, esc_attr( $value ) ); $response['success'] = __('User meta has been changed.','ultimate-member'); break; } return $response; } /** * Process Get users API Request * * @param $args * * @return array */ public function get_users( $args ) { extract( $args ); $response = array(); $error = array(); if ( !$number ) $number = 10; if ( !$orderby ) $orderby = 'user_registered'; if ( !$order ) $order = 'desc'; $loop_a = array('number' => $number, 'orderby' => $orderby, 'order' => $order ); if ( $include ) { $include = explode(',', $include ); $loop_a['include'] = $include; } if ( $exclude ) { $exclude = explode(',', $exclude ); $loop_a['exclude'] = $exclude; } $loop = get_users( $loop_a ); foreach( $loop as $user ) { unset( $user->data->user_status ); unset( $user->data->user_activation_key ); unset( $user->data->user_pass ); um_fetch_user( $user->ID ); foreach( $user as $key => $val ) { if ( $key != 'data' ) continue; if ( $key == 'data' ) { $key = 'profile'; $val->roles = $user->roles; $val->first_name = um_user('first_name'); $val->last_name = um_user('last_name'); $val->account_status = um_user('account_status'); $val->profile_pic_original = um_get_user_avatar_url('', 'original'); $val->profile_pic_normal = um_get_user_avatar_url('', 200); $val->profile_pic_small = um_get_user_avatar_url('', 40); $val->cover_photo = $this->getsrc( um_user('cover_photo', 1000) ); /** * UM hook * * @type filter * @title um_rest_userdata * @description Change output data for Rest API userdata call * @input_vars * [{"var":"$value","type":"array","desc":"Output Data"}, * {"var":"$user_id","type":"string","desc":"User ID"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $val = apply_filters( 'um_rest_userdata', $val, $user->ID ); } $response[ $user->ID ] = $val; } } return $response; } /** * Process delete user via API * * @param $args * * @return array */ public function delete_user( $args ) { extract( $args ); $response = array(); $error = array(); if ( !isset( $id ) ) { $error['error'] = __('You must provide a user ID','ultimate-member'); return $error; } $user = get_userdata( $id ); if ( !$user ) { $error['error'] = __('Invalid user specified','ultimate-member'); return $error; } um_fetch_user( $id ); UM()->user()->delete(); $response['success'] = __('User has been successfully deleted.','ultimate-member'); return $response; } /** * Process Get user API Request * * @param $args * * @return array|mixed|void */ public function get_auser( $args ) { extract( $args ); $response = array(); $error = array(); if ( !isset( $id ) ) { $error['error'] = __('You must provide a user ID','ultimate-member'); return $error; } $user = get_userdata( $id ); if ( ! $user ) { $error['error'] = __('Invalid user specified','ultimate-member'); return $error; } unset( $user->data->user_status ); unset( $user->data->user_activation_key ); unset( $user->data->user_pass ); um_fetch_user( $user->ID ); if ( isset( $fields ) && $fields ) { $fields = explode(',', $fields ); $response['ID'] = $user->ID; $response['username'] = $user->user_login; foreach ( $fields as $field ) { switch( $field ) { default: $response[ $field ] = ( um_profile( $field ) ) ? um_profile( $field ) : ''; /** * UM hook * * @type filter * @title um_rest_get_auser * @description Change output data for Rest API user authentification call * @input_vars * [{"var":"$response","type":"array","desc":"Output Data"}, * {"var":"$field","type":"string","desc":"Field Key"}, * {"var":"$user_id","type":"int","desc":"User ID"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $response = apply_filters( 'um_rest_get_auser', $response, $field, $user->ID ); break; case 'cover_photo': $response['cover_photo'] = $this->getsrc( um_user('cover_photo', 1000) ); break; case 'profile_pic': $response['profile_pic_original'] = um_get_user_avatar_url('', 'original'); $response['profile_pic_normal'] = um_get_user_avatar_url('', 200); $response['profile_pic_small'] = um_get_user_avatar_url('', 40); break; case 'status': $response['status'] = um_user('account_status'); break; case 'role': //get priority role here $response['role'] = um_user( 'role' ); break; case 'email': case 'user_email': $response['email'] = um_user('user_email'); break; } } } else { foreach( $user as $key => $val ) { if ( $key != 'data' ) continue; if ( $key == 'data' ) { $key = 'profile'; $val->roles = $user->roles; $val->first_name = um_user('first_name'); $val->last_name = um_user('last_name'); $val->account_status = um_user('account_status'); $val->profile_pic_original = um_get_user_avatar_url('', 'original'); $val->profile_pic_normal = um_get_user_avatar_url('', 200); $val->profile_pic_small = um_get_user_avatar_url('', 40); $val->cover_photo = $this->getsrc( um_user('cover_photo', 1000) ); /** * UM hook * * @type filter * @title um_rest_userdata * @description Change output data for Rest API userdata call * @input_vars * [{"var":"$value","type":"array","desc":"Output Data"}, * {"var":"$user_id","type":"string","desc":"User ID"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ $val = apply_filters( 'um_rest_userdata', $val, $user->ID ); } $response = $val; } } return $response; } /** * Get source * * @param $image * * @return string */ public function getsrc( $image ) { if (preg_match('/ * @example * */ $accepted = apply_filters( 'um_api_valid_query_modes', array( 'get.users', 'get.user', 'update.user', 'delete.user', 'get.following', 'get.followers', 'get.stats', ) ); $query = isset( $wp_query->query_vars['um-api'] ) ? $wp_query->query_vars['um-api'] : null; $error = array(); // Make sure our query is valid if ( ! in_array( $query, $accepted ) ) { $error['error'] = __( 'Invalid query!', 'ultimate-member' ); $this->data = $error; $this->output(); } return $query; } /** * Get page number */ public function get_paged() { global $wp_query; return isset( $wp_query->query_vars['page'] ) ? $wp_query->query_vars['page'] : 1; } /** * Retrieve the output format */ public function get_output_format() { global $wp_query; $format = isset( $wp_query->query_vars['format'] ) ? $wp_query->query_vars['format'] : 'json'; /** * UM hook * * @type filter * @title um_api_output_format * @description UM Rest API output format * @input_vars * [{"var":"$format","type":"string","desc":"Format"}] * @change_log * ["Since: 2.0"] * @usage * * @example * */ return apply_filters( 'um_api_output_format', $format ); } /** * Log each API request, if enabled * * @param array $data */ private function log_request( $data = array() ) { if ( ! $this->log_requests ) return; } /** * Retrieve the output data */ public function get_output() { return $this->data; } /** * Output Query in either JSON/XML. The query data is outputted as JSON * by default */ public function output( $status_code = 200 ) { global $wp_query; $format = $this->get_output_format(); status_header( $status_code ); /** * UM hook * * @type action * @title um_api_output_before * @description Action before API output * @input_vars * [{"var":"$data","type":"array","desc":"API data"}, * {"var":"$rest_api","type":"object","desc":"REST API class"}, * {"var":"$format","type":"string","desc":"Format"}] * @change_log * ["Since: 2.0"] * @usage add_action( 'um_api_output_before', 'function_name', 10, 3 ); * @example * */ do_action( 'um_api_output_before', $this->data, $this, $format ); switch ( $format ) : case 'xml' : require_once um_path . 'includes/lib/array2xml.php'; $xml = Array2XML::createXML( 'um', $this->data ); echo $xml->saveXML(); break; case 'json' : case '' : header( 'Content-Type: application/json' ); if ( ! empty( $this->pretty_print ) ) echo json_encode( $this->data, $this->pretty_print ); else echo json_encode( $this->data ); break; default : // Allow other formats to be added via extensions /** * UM hook * * @type action * @title um_api_output_{$format} * @description Action before API output * @input_vars * [{"var":"$data","type":"array","desc":"API data"}, * {"var":"$rest_api","type":"object","desc":"REST API class"}] * @change_log * ["Since: 2.0"] * @usage add_action( 'um_api_output_{$format}', 'function_name', 10, 2 ); * @example * */ do_action( 'um_api_output_' . $format, $this->data, $this ); break; endswitch; /** * UM hook * * @type action * @title um_api_output_after * @description Action after API output * @input_vars * [{"var":"$data","type":"array","desc":"API data"}, * {"var":"$rest_api","type":"object","desc":"REST API class"}, * {"var":"$format","type":"string","desc":"Format"}] * @change_log * ["Since: 2.0"] * @usage add_action( 'um_api_output_after', 'function_name', 10, 3 ); * @example * */ do_action( 'um_api_output_after', $this->data, $this, $format ); die(); } /** * Modify User Profile Page fields * * @param $content * @param $user * @return string */ function user_key_field( $content, $user ) { if ( empty( $user ) ) return $content; if( ! isset( $user->ID ) ) return $content; if ( current_user_can( 'edit_users' ) && current_user_can( 'edit_user', $user->ID ) ) { $user = get_userdata( $user->ID ); ob_start(); ?>
um_user_public_key ) ) { ?>

 um_user_public_key; ?>
 um_user_secret_key; ?>
 get_token( $user->ID ); ?>

um_user_public_key ) ) { update_user_meta( $user_id, 'um_user_public_key', $this->generate_public_key( $user->user_email ) ); update_user_meta( $user_id, 'um_user_secret_key', $this->generate_private_key( $user->ID ) ); } elseif( $regenerate == true ) { $this->revoke_api_key( $user->ID ); update_user_meta( $user_id, 'um_user_public_key', $this->generate_public_key( $user->user_email ) ); update_user_meta( $user_id, 'um_user_secret_key', $this->generate_private_key( $user->ID ) ); } else { return false; } return true; } /** * Revoke a users API keys * * @param int $user_id * * @return bool */ public function revoke_api_key( $user_id = 0 ) { if( empty( $user_id ) ) { return false; } $user = get_userdata( $user_id ); if( ! $user ) { return false; } if ( ! empty( $user->um_user_public_key ) ) { delete_transient( md5( 'um_api_user_' . $user->um_user_public_key ) ); delete_user_meta( $user_id, 'um_user_public_key' ); delete_user_meta( $user_id, 'um_user_secret_key' ); } else { return false; } return true; } /** * Generate and Save API key * * @param $user_id */ public function update_key( $user_id ) { if ( current_user_can( 'edit_user', $user_id ) && isset( $_POST['um_set_api_key'] ) ) { $user = get_userdata( $user_id ); if ( empty( $user->um_user_public_key ) ) { update_user_meta( $user_id, 'um_user_public_key', $this->generate_public_key( $user->user_email ) ); update_user_meta( $user_id, 'um_user_secret_key', $this->generate_private_key( $user->ID ) ); } else { $this->revoke_api_key( $user_id ); } } } /** * Generate the public key for a user * * @param string $user_email * * @return string */ private function generate_public_key( $user_email = '' ) { $auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : ''; $public = hash( 'md5', $user_email . $auth_key . date( 'U' ) ); return $public; } /** * Generate the secret key for a user * * @param int $user_id * * @return string */ private function generate_private_key( $user_id = 0 ) { $auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : ''; $secret = hash( 'md5', $user_id . $auth_key . date( 'U' ) ); return $secret; } /** * Retrieve the user's token * * @param int $user_id * * @return string */ private function get_token( $user_id = 0 ) { $user = get_userdata( $user_id ); return hash( 'md5', $user->um_user_secret_key . $user->um_user_public_key ); } } }