WPO365 | CUSTOM USER FIELDS
Signed-off-by: Jeff <jeff@gotenzing.com>
Showing
17 changed files
with
2034 additions
and
0 deletions
| 1 | === WPO365 | CUSTOM USER FIELDS === | ||
| 2 | Contributors: wpo365 | ||
| 3 | Tags: office 365, O365, Microsoft 365, avatar, user profile, Microsoft Graph | ||
| 4 | Requires at least: 5.0 | ||
| 5 | Tested up to: 6.4 | ||
| 6 | Stable tag: 25.1 | ||
| 7 | Requires PHP: 5.6.40 | ||
| 8 | |||
| 9 | == Description == | ||
| 10 | |||
| 11 | Synchronize Azure AD user attributes e.g. department, job title etc. to WordPress user profiles (includes the PROFILE+ extension). | ||
| 12 | |||
| 13 | = Plugin Features = | ||
| 14 | |||
| 15 | - Synchronize Microsoft 365 / Azure AD profile fields e.g. job title, department or employee number to WordPress / BuddyPress. | ||
| 16 | |||
| 17 | = Prerequisites = | ||
| 18 | |||
| 19 | - The [WPO365 | LOGIN plugin](https://wordpress.org/plugins/wpo365-login/) must be installed and activated. See [online documentation](https://docs.wpo365.com/article/98-synchronize-microsoft-365-azure-ad-profile-fields) for configuration example. | ||
| 20 | |||
| 21 | = Support = | ||
| 22 | |||
| 23 | We will go to great length trying to support you if the plugin doesn't work as expected. Go to our [Support Page](https://www.wpo365.com/how-to-get-support/) to get in touch with us. We haven't been able to test our plugin in all endless possible Wordpress configurations and versions so we are keen to hear from you and happy to learn! | ||
| 24 | |||
| 25 | = Feedback = | ||
| 26 | |||
| 27 | We are keen to hear from you so share your feedback with us on [Twitter](https://twitter.com/WPO365) and help us get better! | ||
| 28 | |||
| 29 | == Installation == | ||
| 30 | |||
| 31 | 1. Purchase the plugin from the [website](https://www.wpo365.com/). | ||
| 32 | 2. Navigate to [Your Account](https://www.wpo365.com/your-account/) to download the premium extension. | ||
| 33 | 3. Go to WP Admin > Plugins > Add new and click Upload plugin. | ||
| 34 | 4. Upload the plugin. | ||
| 35 | 5. Wait until the installation finishes and then click Activate. | ||
| 36 | 6. See [online documentation](https://docs.wpo365.com/article/98-synchronize-microsoft-365-azure-ad-profile-fields) for configuration example. | ||
| 37 | |||
| 38 | == Frequently Asked Questions == | ||
| 39 | |||
| 40 | == Screenshots == | ||
| 41 | |||
| 42 | == Upgrade Notice == | ||
| 43 | |||
| 44 | == Changelog == | ||
| 45 | |||
| 46 | Please check the [online change log](https://www.wpo365.com/change-log/) for changes. | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | <?php | ||
| 2 | |||
| 3 | namespace Wpo\Services; | ||
| 4 | |||
| 5 | use \Wpo\Core\WordPress_Helpers; | ||
| 6 | use \Wpo\Services\Log_Service; | ||
| 7 | use \Wpo\Services\Options_Service; | ||
| 8 | use \Wpo\Services\User_Details_Service; | ||
| 9 | |||
| 10 | // Prevent public access to this script | ||
| 11 | defined('ABSPATH') or die(); | ||
| 12 | |||
| 13 | if (!class_exists('\Wpo\Services\BuddyPress_Service')) { | ||
| 14 | |||
| 15 | class BuddyPress_Service | ||
| 16 | { | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Adds an additional section to the bottom of the user profile page | ||
| 20 | * | ||
| 21 | * @since 5.3 | ||
| 22 | * | ||
| 23 | * @param WP_User $user whose profile is being shown | ||
| 24 | * @return void | ||
| 25 | */ | ||
| 26 | public static function bp_show_extra_user_fields($user) | ||
| 27 | { | ||
| 28 | |||
| 29 | if (false === Options_Service::get_global_boolean_var('graph_user_details')) { | ||
| 30 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Extra user fields disabled as per configuration'); | ||
| 31 | return; | ||
| 32 | } elseif (true === Options_Service::get_global_boolean_var('use_bp_extended')) { | ||
| 33 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Extra user fields will be display on BuddyPress Extended Profile instead'); | ||
| 34 | return; | ||
| 35 | } elseif (!class_exists('\Wpo\Services\User_Details_Service')) { | ||
| 36 | Log_Service::write_log('WARN', __METHOD__ . ' -> Cannot show extra BuddyPress fields because of missing dependency'); | ||
| 37 | return; | ||
| 38 | } else { | ||
| 39 | |||
| 40 | echo ('<div class="bp-widget base">'); | ||
| 41 | echo ('<h3 class="screen-heading profile-group-title">' . __('Directory Info', 'wpo365-login') . '</h3>'); | ||
| 42 | echo ('<table class="profile-fields bp-tables-user"><tbody>'); | ||
| 43 | |||
| 44 | \Wpo\Services\User_Custom_Fields_Service::process_extra_user_fields(function ($name, $title) use (&$user) { | ||
| 45 | $parsed_user_field_key = User_Details_Service::parse_user_field_key($name); | ||
| 46 | $name = $parsed_user_field_key[0]; | ||
| 47 | $wp_user_meta_key = $parsed_user_field_key[1]; | ||
| 48 | |||
| 49 | $value = get_user_meta(\bp_displayed_user_id(), $wp_user_meta_key, true); | ||
| 50 | echo ('<tr class="field_1 field_name required-field visibility-public field_type_textbox"><td class="label">' . esc_html($title) . '</td>'); | ||
| 51 | |||
| 52 | if (is_array($value)) { | ||
| 53 | echo ('<td class="data">'); | ||
| 54 | |||
| 55 | foreach ($value as $idx => $val) | ||
| 56 | echo ('<p>' . esc_html($val) . '</p>'); | ||
| 57 | |||
| 58 | echo ('</td>'); | ||
| 59 | } else | ||
| 60 | echo ('<td class="data"><p>' . esc_html($value) . '</p></td>'); | ||
| 61 | |||
| 62 | echo ("</tr>"); | ||
| 63 | }); | ||
| 64 | |||
| 65 | echo ('</tbody></table></div>'); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Helper method that returns the O365 avatar for Buddy Press. | ||
| 71 | * | ||
| 72 | * @since 9.0 | ||
| 73 | * | ||
| 74 | * @param $avatar Image tag for the user's avatar. | ||
| 75 | * @return string Image tag for the user's avatar possibly with img URL replaced with O365 profile image URL. | ||
| 76 | */ | ||
| 77 | public static function fetch_buddy_press_avatar($bp_avatar, $params) | ||
| 78 | { | ||
| 79 | |||
| 80 | if (false === Options_Service::get_global_boolean_var('use_bp_avatar')) { | ||
| 81 | return $bp_avatar; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (!is_array($params) || !isset($params['item_id'])) { | ||
| 85 | return $bp_avatar; | ||
| 86 | } | ||
| 87 | |||
| 88 | if (!class_exists('\Wpo\Services\Avatar_Service')) { | ||
| 89 | Log_Service::write_log('WARN', __METHOD__ . ' -> Cannot BuddyPress avatar because of missing dependency'); | ||
| 90 | return $bp_avatar; | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * @since 10.5 | ||
| 95 | * | ||
| 96 | * Don't return avatar if objec is not a user (e.g. but a group) | ||
| 97 | */ | ||
| 98 | if (is_array($params) && isset($params['object']) && false === WordPress_Helpers::stripos($params['object'], 'user')) { | ||
| 99 | return $bp_avatar; | ||
| 100 | } | ||
| 101 | |||
| 102 | $o365_avatar_url = \Wpo\Services\Avatar_Service::get_o365_avatar_url(intval($params['item_id'])); | ||
| 103 | |||
| 104 | return empty($o365_avatar_url) | ||
| 105 | ? $bp_avatar | ||
| 106 | : \preg_replace('/src=".+?"/', 'src="' . $o365_avatar_url . '"', $bp_avatar); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } |
| 1 | <?php | ||
| 2 | |||
| 3 | namespace Wpo\Services; | ||
| 4 | |||
| 5 | // Prevent public access to this script | ||
| 6 | defined('ABSPATH') or die(); | ||
| 7 | |||
| 8 | use \Wpo\Services\Log_Service; | ||
| 9 | use \Wpo\Services\Options_Service; | ||
| 10 | |||
| 11 | if (!class_exists('\Wpo\Services\User_Create_Update_Service')) { | ||
| 12 | |||
| 13 | class User_Create_Update_Service | ||
| 14 | { | ||
| 15 | |||
| 16 | /** | ||
| 17 | * Updates a WordPress user. | ||
| 18 | * | ||
| 19 | * @since 11.0 | ||
| 20 | * | ||
| 21 | * @param mixed $wp_user_id WordPress ID of the user that will be updated | ||
| 22 | * @param bool $is_deamon If true then actions that may sign out the user are ignored | ||
| 23 | * @param bool $exit_on_error If true the user my be signed out if an action fails | ||
| 24 | * | ||
| 25 | * @return int The WordPress ID of the user. | ||
| 26 | */ | ||
| 27 | public static function create_user(&$wpo_usr, $is_deamon = false, $exit_on_error = true) | ||
| 28 | { | ||
| 29 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 30 | |||
| 31 | $user_login = !empty($wpo_usr->preferred_username) | ||
| 32 | ? $wpo_usr->preferred_username | ||
| 33 | : $wpo_usr->upn; | ||
| 34 | |||
| 35 | if (Options_Service::get_global_boolean_var('use_short_login_name') || Options_Service::get_global_string_var('user_name_preference') == 'short') { | ||
| 36 | $user_login = \stristr($user_login, '@', true); | ||
| 37 | } | ||
| 38 | |||
| 39 | if (!empty($wpo_usr->custom_username)) { | ||
| 40 | $user_login = $wpo_usr->custom_username; | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | /** | ||
| 45 | * @since 12.5 | ||
| 46 | * | ||
| 47 | * Don't create a user when that user should not be added to a subsite in case of wpmu shared mode. | ||
| 48 | */ | ||
| 49 | if (!$is_deamon && is_multisite() && !Options_Service::mu_use_subsite_options() && !is_main_site() && Options_Service::get_global_boolean_var('skip_add_user_to_subsite')) { | ||
| 50 | $blog_id = get_current_blog_id(); | ||
| 51 | |||
| 52 | // Not using subsite options and administrator has disabled automatic adding of users to subsites | ||
| 53 | Log_Service::write_log('WARN', __METHOD__ . " -> Skipped creating a user with login $user_login for blog with ID $blog_id because administrator has disabled adding a user to a subsite"); | ||
| 54 | Authentication_Service::goodbye(Error_Service::USER_NOT_FOUND); | ||
| 55 | exit(); | ||
| 56 | } | ||
| 57 | |||
| 58 | if (!$is_deamon && !Options_Service::get_global_boolean_var('create_and_add_users')) { | ||
| 59 | Log_Service::write_log('ERROR', __METHOD__ . ' -> User not found and settings prevented creating a new user on-demand for user ' . $user_login); | ||
| 60 | Authentication_Service::goodbye(Error_Service::USER_NOT_FOUND); | ||
| 61 | exit(); | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * @since 23.0 Added possibility to hook up (custom) actions to pre-defined events for various WPO365 workloads. | ||
| 66 | */ | ||
| 67 | |||
| 68 | do_action( | ||
| 69 | 'wpo365/user/creating', | ||
| 70 | $wpo_usr->preferred_username, | ||
| 71 | $wpo_usr->email, | ||
| 72 | $wpo_usr->groups | ||
| 73 | ); | ||
| 74 | |||
| 75 | $usr_default_role = is_main_site() | ||
| 76 | ? Options_Service::get_global_string_var('new_usr_default_role') | ||
| 77 | : Options_Service::get_global_string_var('mu_new_usr_default_role'); | ||
| 78 | |||
| 79 | $password_length = Options_Service::get_global_numeric_var('password_length'); | ||
| 80 | |||
| 81 | if (empty($password_length) || $password_length < 16) { | ||
| 82 | $password_length = 16; | ||
| 83 | } | ||
| 84 | |||
| 85 | $userdata = array( | ||
| 86 | 'user_login' => $user_login, | ||
| 87 | 'user_pass' => wp_generate_password($password_length, true, false), | ||
| 88 | 'display_name' => $wpo_usr->full_name, | ||
| 89 | 'user_email' => $wpo_usr->email, | ||
| 90 | 'first_name' => $wpo_usr->first_name, | ||
| 91 | 'last_name' => $wpo_usr->last_name, | ||
| 92 | 'role' => $usr_default_role, | ||
| 93 | ); | ||
| 94 | |||
| 95 | /** | ||
| 96 | * @since 9.4 | ||
| 97 | * | ||
| 98 | * Optionally removing any user_register hooks as these more often than | ||
| 99 | * not interfer and cause unexpected behavior. | ||
| 100 | */ | ||
| 101 | |||
| 102 | $user_regiser_hooks = null; | ||
| 103 | |||
| 104 | if (Options_Service::get_global_boolean_var('skip_user_register_action') && isset($GLOBALS['wp_filter']) && isset($GLOBALS['wp_filter']['user_register'])) { | ||
| 105 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Temporarily removing all filters for the user_register action to avoid interference'); | ||
| 106 | $user_regiser_hooks = $GLOBALS['wp_filter']['user_register']; | ||
| 107 | unset($GLOBALS['wp_filter']['user_register']); | ||
| 108 | } | ||
| 109 | |||
| 110 | $existing_registering = remove_filter('wp_pre_insert_user_data', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registering', PHP_INT_MAX); | ||
| 111 | $existing_registered = remove_action('user_registered', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registered', PHP_INT_MAX); | ||
| 112 | $wp_usr_id = wp_insert_user($userdata); | ||
| 113 | |||
| 114 | if ($existing_registering) { | ||
| 115 | add_filter('wp_pre_insert_user_data', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registering', PHP_INT_MAX, 4); | ||
| 116 | } | ||
| 117 | |||
| 118 | if ($existing_registered) { | ||
| 119 | add_action('user_register', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registered', PHP_INT_MAX, 1); | ||
| 120 | } | ||
| 121 | |||
| 122 | if (!empty($GLOBALS['wp_filter']) && !empty($user_regiser_hooks)) { | ||
| 123 | $GLOBALS['wp_filter']['user_register'] = $user_regiser_hooks; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (is_wp_error($wp_usr_id)) { | ||
| 127 | Log_Service::write_log('ERROR', __METHOD__ . ' -> Could not create wp user. See next line for error information.'); | ||
| 128 | Log_Service::write_log('ERROR', $wp_usr_id); | ||
| 129 | |||
| 130 | if ($exit_on_error) { | ||
| 131 | Authentication_Service::goodbye(Error_Service::CHECK_LOG); | ||
| 132 | exit(); | ||
| 133 | } | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * @since 15.0 | ||
| 140 | */ | ||
| 141 | |||
| 142 | do_action('wpo365/user/created', $wp_usr_id); | ||
| 143 | |||
| 144 | $wpo_usr->created = true; | ||
| 145 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Created new user with ID ' . $wp_usr_id); | ||
| 146 | |||
| 147 | // WPMU -> Add user to current blog | ||
| 148 | if (\class_exists('\Wpo\Services\User_Create_Service') && \method_exists('\Wpo\Services\User_Create_Service', 'wpmu_add_user_to_blog')) { | ||
| 149 | \Wpo\Services\User_Create_Service::wpmu_add_user_to_blog($wp_usr_id, $wpo_usr->preferred_username); | ||
| 150 | } | ||
| 151 | |||
| 152 | if (\class_exists('\Wpo\Services\User_Role_Service') && \method_exists('\Wpo\Services\User_Role_Service', 'update_user_roles')) { | ||
| 153 | \Wpo\Services\User_Role_Service::update_user_roles($wp_usr_id, $wpo_usr); | ||
| 154 | } | ||
| 155 | |||
| 156 | add_filter('allow_password_reset', '\Wpo\Services\User_Create_Service::temporarily_allow_password_reset', PHP_INT_MAX, 1); | ||
| 157 | wp_new_user_notification($wp_usr_id, null, 'both'); | ||
| 158 | remove_filter('allow_password_reset', '\Wpo\Services\User_Create_Service::temporarily_allow_password_reset', PHP_INT_MAX); | ||
| 159 | |||
| 160 | return $wp_usr_id; | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Updates a WordPress user. | ||
| 165 | * | ||
| 166 | * @param mixed $wp_user_id WordPress ID of the user that will be updated | ||
| 167 | * @param mixed $wpo_usr Internal user representation (Graph and ID token data) | ||
| 168 | * @param bool $is_deamon If true then actions that may sign out the user are ignored | ||
| 169 | * | ||
| 170 | * @return void | ||
| 171 | */ | ||
| 172 | public static function update_user($wp_usr_id, $wpo_usr, $is_deamon = false) | ||
| 173 | { | ||
| 174 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 175 | |||
| 176 | // Save user's UPN | ||
| 177 | if (!empty($wpo_usr->upn)) { | ||
| 178 | update_user_meta($wp_usr_id, 'userPrincipalName', $wpo_usr->upn); | ||
| 179 | } | ||
| 180 | |||
| 181 | if (!$wpo_usr->created) { | ||
| 182 | |||
| 183 | if (!$is_deamon && \class_exists('\Wpo\Services\User_Create_Service') && \method_exists('\Wpo\Services\User_Create_Service', 'wpmu_add_user_to_blog')) { | ||
| 184 | \Wpo\Services\User_Create_Service::wpmu_add_user_to_blog($wp_usr_id, $wpo_usr->preferred_username); | ||
| 185 | } | ||
| 186 | |||
| 187 | if (\class_exists('\Wpo\Services\User_Role_Service') && \method_exists('\Wpo\Services\User_Role_Service', 'update_user_roles')) { | ||
| 188 | \Wpo\Services\User_Role_Service::update_user_roles($wp_usr_id, $wpo_usr); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | // Update Avatar | ||
| 193 | if (Options_Service::get_global_boolean_var('use_avatar') && class_exists('\Wpo\Services\Avatar_Service')) { | ||
| 194 | $default_avatar = get_avatar($wp_usr_id); | ||
| 195 | } | ||
| 196 | |||
| 197 | // Update custom fields | ||
| 198 | if (class_exists('\Wpo\Services\User_Custom_Fields_Service')) { | ||
| 199 | |||
| 200 | if (Options_Service::get_global_boolean_var('use_saml') && Options_Service::get_global_string_var('extra_user_fields_source') == 'samlResponse') { | ||
| 201 | \Wpo\Services\User_Custom_Fields_Service::update_custom_fields_from_saml_attributes($wp_usr_id, $wpo_usr); | ||
| 202 | } else { | ||
| 203 | \Wpo\Services\User_Custom_Fields_Service::update_custom_fields($wp_usr_id, $wpo_usr); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | // Update default WordPress user fields | ||
| 208 | self::update_wp_user($wp_usr_id, $wpo_usr); | ||
| 209 | } | ||
| 210 | |||
| 211 | /** | ||
| 212 | * @since 11.0 | ||
| 213 | */ | ||
| 214 | private static function update_wp_user($wp_usr_id, $wpo_usr) | ||
| 215 | { | ||
| 216 | // Update "core" WP_User fields | ||
| 217 | $wp_user_data = array('ID' => $wp_usr_id); | ||
| 218 | |||
| 219 | if (!empty($wpo_usr->email)) { | ||
| 220 | $wp_user_data['user_email'] = $wpo_usr->email; | ||
| 221 | } | ||
| 222 | |||
| 223 | if (!empty($wpo_usr->first_name)) { | ||
| 224 | $wp_user_data['first_name'] = $wpo_usr->first_name; | ||
| 225 | } | ||
| 226 | |||
| 227 | if (!empty($wpo_usr->last_name)) { | ||
| 228 | $wp_user_data['last_name'] = $wpo_usr->last_name; | ||
| 229 | } | ||
| 230 | |||
| 231 | if (!empty($wpo_usr->full_name)) { | ||
| 232 | $wp_user_data['display_name'] = $wpo_usr->full_name; | ||
| 233 | } | ||
| 234 | |||
| 235 | $existing_registering = remove_filter('wp_pre_insert_user_data', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registering', PHP_INT_MAX); | ||
| 236 | $existing_registered = remove_action('user_registered', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registered', PHP_INT_MAX); | ||
| 237 | wp_update_user($wp_user_data); | ||
| 238 | |||
| 239 | if ($existing_registering) { | ||
| 240 | add_filter('wp_pre_insert_user_data', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registering', PHP_INT_MAX, 4); | ||
| 241 | } | ||
| 242 | |||
| 243 | if ($existing_registered) { | ||
| 244 | add_action('user_register', '\Wpo\Services\Wp_To_Aad_Create_Update_Service::handle_user_registered', PHP_INT_MAX, 1); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | } | ||
| 248 | } |
| 1 | <?php | ||
| 2 | |||
| 3 | namespace Wpo\Services; | ||
| 4 | |||
| 5 | // Prevent public access to this script | ||
| 6 | defined('ABSPATH') or die(); | ||
| 7 | |||
| 8 | use \Wpo\Core\WordPress_Helpers; | ||
| 9 | use \Wpo\Services\Log_Service; | ||
| 10 | use \Wpo\Services\Options_Service; | ||
| 11 | use \Wpo\Services\Graph_Service; | ||
| 12 | use \Wpo\Services\Saml2_Service; | ||
| 13 | use \Wpo\Services\User_Service; | ||
| 14 | use \Wpo\Services\User_Details_Service; | ||
| 15 | |||
| 16 | if (!class_exists('\Wpo\Services\User_Custom_Fields_Service')) { | ||
| 17 | |||
| 18 | class User_Custom_Fields_Service | ||
| 19 | { | ||
| 20 | /** | ||
| 21 | * @since 11.0 | ||
| 22 | */ | ||
| 23 | public static function update_custom_fields($wp_usr_id, $wpo_usr) | ||
| 24 | { | ||
| 25 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 26 | |||
| 27 | if (empty($wpo_usr->graph_resource)) { | ||
| 28 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Cannot update custom user fields because the graph resource has not been retrieved'); | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | // Check to see if expanded properties need to be loaded (currently only manager is supported) | ||
| 33 | $extra_user_fields = Options_Service::get_global_list_var('extra_user_fields'); | ||
| 34 | $expanded_fields = array(); | ||
| 35 | |||
| 36 | // Iterate over the configured graph fields and identify any supported expandable properties | ||
| 37 | array_map(function ($kv_pair) use (&$expanded_fields) { | ||
| 38 | if (false !== WordPress_Helpers::stripos($kv_pair['key'], 'manager')) { | ||
| 39 | $expanded_fields[] = 'manager'; | ||
| 40 | } | ||
| 41 | }, $extra_user_fields); | ||
| 42 | |||
| 43 | // Query to expand property | ||
| 44 | if (in_array('manager', $expanded_fields)) { | ||
| 45 | $upn = User_Service::try_get_user_principal_name($wp_usr_id); | ||
| 46 | |||
| 47 | if (!empty($upn)) { | ||
| 48 | $user_manager = Graph_Service::fetch('/users/' . \rawurlencode($upn) . '/manager', 'GET', false, array('Accept: application/json;odata.metadata=minimal')); | ||
| 49 | |||
| 50 | // Expand user details | ||
| 51 | if (Graph_Service::is_fetch_result_ok($user_manager, 'Could not retrieve user manager details for user ' . $upn, 'WARN')) { | ||
| 52 | $wpo_usr->graph_resource['manager'] = $user_manager['payload']; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | self::process_extra_user_fields(function ($name, $title) use (&$wpo_usr, &$wp_usr_id) { | ||
| 58 | |||
| 59 | $parsed_user_field_key = User_Details_Service::parse_user_field_key($name); | ||
| 60 | $name = $parsed_user_field_key[0]; | ||
| 61 | $wp_user_meta_key = $parsed_user_field_key[1]; | ||
| 62 | |||
| 63 | $name_arr = explode('.', $name); | ||
| 64 | $current = $wpo_usr->graph_resource; | ||
| 65 | $value = null; | ||
| 66 | |||
| 67 | if (sizeof($name_arr) > 1) { | ||
| 68 | |||
| 69 | $found = false; | ||
| 70 | |||
| 71 | for ($i = 0; $i < sizeof($name_arr); $i++) { | ||
| 72 | /** | ||
| 73 | * Found must be true for the last iteration therefore it resets every cycle | ||
| 74 | */ | ||
| 75 | |||
| 76 | $found = false; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Administrator has specified to get the nth element of an array / object | ||
| 80 | */ | ||
| 81 | |||
| 82 | if (is_array($current) && \is_numeric($name_arr[$i]) && $i < sizeof($current) && array_key_exists($name_arr[$i], $current)) { | ||
| 83 | $current = $current[$name_arr[$i]]; | ||
| 84 | $found = true; | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Administrator has specified to get the named element of an array / object | ||
| 89 | */ | ||
| 90 | |||
| 91 | else if (is_array($current) && array_key_exists($name_arr[$i], $current)) { | ||
| 92 | $current = $current[$name_arr[$i]]; | ||
| 93 | $found = true; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | if ($found) { | ||
| 98 | $value = $current; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Administrator has specified a simple non-nested property | ||
| 104 | */ | ||
| 105 | |||
| 106 | else if (array_key_exists($name, $current) && !empty($current[$name])) { | ||
| 107 | $value = $name == 'manager' | ||
| 108 | ? self::parse_manager_details($current['manager']) | ||
| 109 | : $current[$name]; | ||
| 110 | } | ||
| 111 | |||
| 112 | if (empty($value)) { | ||
| 113 | $value = ''; | ||
| 114 | } | ||
| 115 | |||
| 116 | update_user_meta( | ||
| 117 | $wp_usr_id, | ||
| 118 | $wp_user_meta_key, | ||
| 119 | $value | ||
| 120 | ); | ||
| 121 | |||
| 122 | if (function_exists('xprofile_set_field_data') && true === Options_Service::get_global_boolean_var('use_bp_extended')) { | ||
| 123 | xprofile_set_field_data($title, $wp_usr_id, $value); | ||
| 124 | } | ||
| 125 | }); | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Processes the extra user fields and tries to read them from the SAML attributes | ||
| 130 | * and if found saves their value as WordPress user meta. | ||
| 131 | * | ||
| 132 | * @since 20.0 | ||
| 133 | * | ||
| 134 | * @param mixed $wp_usr_id | ||
| 135 | * @param mixed $wpo_usr | ||
| 136 | * @return void | ||
| 137 | */ | ||
| 138 | public static function update_custom_fields_from_saml_attributes($wp_usr_id, $wpo_usr) | ||
| 139 | { | ||
| 140 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 141 | |||
| 142 | if (empty($wpo_usr->saml_attributes)) { | ||
| 143 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Cannot update custom user fields because the SAML attributes are not found'); | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | |||
| 147 | self::process_extra_user_fields(function ($name, $title) use (&$wpo_usr, &$wp_usr_id) { | ||
| 148 | |||
| 149 | $parsed_user_field_key = User_Details_Service::parse_user_field_key($name); | ||
| 150 | $claim = $parsed_user_field_key[0]; | ||
| 151 | $wp_user_meta_key = $parsed_user_field_key[1]; | ||
| 152 | |||
| 153 | if (strcmp($claim, $wp_user_meta_key) === 0 && WordPress_Helpers::stripos($wp_user_meta_key, '/') > 0) { | ||
| 154 | $key_exploded = explode('/', $wp_user_meta_key); | ||
| 155 | $wp_user_meta_key = sprintf('saml_%s', array_pop($key_exploded)); | ||
| 156 | } | ||
| 157 | |||
| 158 | $value = Saml2_Service::get_attribute($claim, $wpo_usr->saml_attributes); | ||
| 159 | |||
| 160 | update_user_meta( | ||
| 161 | $wp_usr_id, | ||
| 162 | $wp_user_meta_key, | ||
| 163 | $value | ||
| 164 | ); | ||
| 165 | |||
| 166 | if (function_exists('xprofile_set_field_data') && true === Options_Service::get_global_boolean_var('use_bp_extended')) { | ||
| 167 | xprofile_set_field_data($title, $wp_usr_id, $value); | ||
| 168 | } | ||
| 169 | }); | ||
| 170 | } | ||
| 171 | |||
| 172 | /** | ||
| 173 | * | ||
| 174 | * @param function callback with signature ( $name, $title ) => void | ||
| 175 | * | ||
| 176 | * @return void | ||
| 177 | */ | ||
| 178 | public static function process_extra_user_fields($callback) | ||
| 179 | { | ||
| 180 | $extra_user_fields = Options_Service::get_global_list_var('extra_user_fields'); | ||
| 181 | |||
| 182 | if (sizeof($extra_user_fields) == 0) | ||
| 183 | return; | ||
| 184 | |||
| 185 | foreach ($extra_user_fields as $kv_pair) | ||
| 186 | $callback($kv_pair['key'], $kv_pair['value']); | ||
| 187 | } | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Adds an additional section to the bottom of the user profile page | ||
| 191 | * | ||
| 192 | * @since 2.0 | ||
| 193 | * | ||
| 194 | * @param WP_User $user whose profile is being shown | ||
| 195 | * @return void | ||
| 196 | */ | ||
| 197 | public static function show_extra_user_fields($user) | ||
| 198 | { | ||
| 199 | if (false === Options_Service::get_global_boolean_var('graph_user_details')) { | ||
| 200 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Extra user fields disabled as per configuration'); | ||
| 201 | return; | ||
| 202 | } elseif (true === Options_Service::get_global_boolean_var('use_bp_extended')) { | ||
| 203 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Extra user fields will be display on BuddyPress Extended Profile instead'); | ||
| 204 | return; | ||
| 205 | } else { | ||
| 206 | |||
| 207 | echo ("<h3>" . __('Office 365 Profile Information', 'wpo365-login') . "</h3>"); | ||
| 208 | echo ("<table class=\"form-table\">"); | ||
| 209 | |||
| 210 | self::process_extra_user_fields(function ($name, $title) use (&$user) { | ||
| 211 | |||
| 212 | $parsed_user_field_key = User_Details_Service::parse_user_field_key($name); | ||
| 213 | $name = $parsed_user_field_key[0]; | ||
| 214 | $wp_user_meta_key = $parsed_user_field_key[1]; | ||
| 215 | |||
| 216 | // The following may be true for SAML based custom attributes | ||
| 217 | if (strcmp($name, $wp_user_meta_key) === 0 && WordPress_Helpers::stripos($wp_user_meta_key, '/') > 0) { | ||
| 218 | $key_exploded = explode('/', $wp_user_meta_key); | ||
| 219 | $wp_user_meta_key = sprintf('saml_%s', array_pop($key_exploded)); | ||
| 220 | } | ||
| 221 | |||
| 222 | $value = get_user_meta($user->ID, $wp_user_meta_key, true); | ||
| 223 | |||
| 224 | echo ('<tr><th><label for="' . esc_attr($wp_user_meta_key) . '">' . esc_html($title) . '</label></th>'); | ||
| 225 | |||
| 226 | if (is_array($value)) { | ||
| 227 | |||
| 228 | echo ("<td>"); | ||
| 229 | |||
| 230 | foreach ($value as $idx => $val) { | ||
| 231 | |||
| 232 | if (empty($val)) { | ||
| 233 | continue; | ||
| 234 | } | ||
| 235 | |||
| 236 | echo '<input type="text" name="' . esc_attr($wp_user_meta_key) . '__##__' . esc_attr($idx) . '" id="' . esc_attr($wp_user_meta_key) . esc_attr($idx) . '" value="' . esc_attr($val) . '" class="regular-text" /><br />'; | ||
| 237 | } | ||
| 238 | |||
| 239 | echo ("</td>"); | ||
| 240 | } else { | ||
| 241 | |||
| 242 | echo ('<td><input type="text" name="' . esc_attr($wp_user_meta_key) . '" id="' . esc_attr($wp_user_meta_key) . '" value="' . esc_attr($value) . '" class="regular-text" /><br/></td>'); | ||
| 243 | } | ||
| 244 | |||
| 245 | echo ("</tr>"); | ||
| 246 | }); | ||
| 247 | |||
| 248 | echo ('</table>'); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | /** | ||
| 253 | * Allow users to save their updated extra user fields | ||
| 254 | * | ||
| 255 | * @since 4.0 | ||
| 256 | * | ||
| 257 | * @return mixed(boolean|void) | ||
| 258 | */ | ||
| 259 | public static function save_user_details($user_id) | ||
| 260 | { | ||
| 261 | if (!current_user_can('edit_user', $user_id)) { | ||
| 262 | return false; | ||
| 263 | } | ||
| 264 | |||
| 265 | self::process_extra_user_fields(function ($name, $title) use (&$user_id) { | ||
| 266 | |||
| 267 | $parsed_user_field_key = User_Details_Service::parse_user_field_key($name); | ||
| 268 | $name = $parsed_user_field_key[0]; | ||
| 269 | $wp_user_meta_key = $parsed_user_field_key[1]; | ||
| 270 | |||
| 271 | // The following may be true for SAML based custom attributes | ||
| 272 | if (strcmp($name, $wp_user_meta_key) === 0 && WordPress_Helpers::stripos($wp_user_meta_key, '/') > 0) { | ||
| 273 | $key_exploded = explode('/', $wp_user_meta_key); | ||
| 274 | $wp_user_meta_key = sprintf('saml_%s', array_pop($key_exploded)); | ||
| 275 | } | ||
| 276 | |||
| 277 | $lookup = str_replace('.', '_', $wp_user_meta_key); // '.' is changed to '_' when sent in a request | ||
| 278 | |||
| 279 | if (isset($_POST[$lookup])) { | ||
| 280 | |||
| 281 | update_user_meta( | ||
| 282 | $user_id, | ||
| 283 | $wp_user_meta_key, | ||
| 284 | sanitize_text_field($_POST[$lookup]) | ||
| 285 | ); | ||
| 286 | return; | ||
| 287 | } | ||
| 288 | |||
| 289 | $array_of_user_meta = array(); | ||
| 290 | |||
| 291 | foreach ($_POST as $key => $value) { | ||
| 292 | |||
| 293 | if (false !== WordPress_Helpers::strpos($key, $lookup . "__##__")) { | ||
| 294 | $array_of_user_meta[$key] = $value; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | if (false === empty($array_of_user_meta)) { | ||
| 299 | |||
| 300 | $array_of_user_meta_values = array_values($array_of_user_meta); | ||
| 301 | |||
| 302 | update_user_meta( | ||
| 303 | $user_id, | ||
| 304 | $wp_user_meta_key, | ||
| 305 | $array_of_user_meta_values | ||
| 306 | ); | ||
| 307 | return; | ||
| 308 | } | ||
| 309 | }); | ||
| 310 | } | ||
| 311 | |||
| 312 | /** | ||
| 313 | * Gets details of a user as an array with displayName, mail, officeLocation, department, | ||
| 314 | * businessPhones, mobilePhone. | ||
| 315 | * | ||
| 316 | * @since 15.0 | ||
| 317 | * | ||
| 318 | * @param int $wp_usr_id | ||
| 319 | * @return array | ||
| 320 | */ | ||
| 321 | public static function get_manager_details_from_wp_user($wp_usr_id) | ||
| 322 | { | ||
| 323 | |||
| 324 | if (empty($wp_usr = get_user_by('ID', $wp_usr_id))) { | ||
| 325 | return array(); | ||
| 326 | } | ||
| 327 | |||
| 328 | $displayName = $wp_usr->display_name; | ||
| 329 | $mail = $wp_usr->user_email; | ||
| 330 | $officeLocation = get_user_meta($wp_usr_id, 'officeLocation', true); | ||
| 331 | $department = get_user_meta($wp_usr_id, 'department', true); | ||
| 332 | $businessPhones = get_user_meta($wp_usr_id, 'businessPhones', true); | ||
| 333 | $mobilePhone = get_user_meta($wp_usr_id, 'mobilePhone', true); | ||
| 334 | |||
| 335 | return array( | ||
| 336 | 'displayName' => $displayName, | ||
| 337 | 'mail' => $mail, | ||
| 338 | 'officeLocation' => !empty($officeLocation) ? $officeLocation : '', | ||
| 339 | 'department' => !empty($department) ? $department : '', | ||
| 340 | 'businessPhones' => !empty($businessPhones) ? $businessPhones : '', | ||
| 341 | 'mobilePhone' => !empty($mobilePhone) ? $mobilePhone : '', | ||
| 342 | ); | ||
| 343 | } | ||
| 344 | |||
| 345 | /** | ||
| 346 | * Parses the manager details fetched from Microsoft Graph. | ||
| 347 | * | ||
| 348 | * @since 7.17 | ||
| 349 | * | ||
| 350 | * @return array Assoc. array with the most important manager details. | ||
| 351 | */ | ||
| 352 | private static function parse_manager_details($manager) | ||
| 353 | { | ||
| 354 | if (empty($manager)) { | ||
| 355 | return array(); | ||
| 356 | } | ||
| 357 | $displayName = !empty($manager['displayName']) | ||
| 358 | ? $manager['displayName'] | ||
| 359 | : ''; | ||
| 360 | $mail = !empty($manager['mail']) | ||
| 361 | ? $manager['mail'] | ||
| 362 | : ''; | ||
| 363 | $officeLocation = !empty($manager['officeLocation']) | ||
| 364 | ? $manager['officeLocation'] | ||
| 365 | : ''; | ||
| 366 | $department = !empty($manager['department']) | ||
| 367 | ? $manager['department'] | ||
| 368 | : ''; | ||
| 369 | $businessPhones = !empty($manager['businessPhones']) | ||
| 370 | ? $manager['businessPhones'][0] | ||
| 371 | : ''; | ||
| 372 | $mobilePhone = !empty($manager['mobilePhone']) | ||
| 373 | ? $manager['mobilePhone'][0] | ||
| 374 | : ''; | ||
| 375 | return array( | ||
| 376 | 'displayName' => $displayName, | ||
| 377 | 'mail' => $mail, | ||
| 378 | 'officeLocation' => $officeLocation, | ||
| 379 | 'department' => $department, | ||
| 380 | 'businessPhones' => $businessPhones, | ||
| 381 | 'mobilePhone' => $mobilePhone, | ||
| 382 | ); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | } |
| 1 | <?php | ||
| 2 | |||
| 3 | namespace Wpo\Services; | ||
| 4 | |||
| 5 | // Prevent public access to this script | ||
| 6 | defined('ABSPATH') or die(); | ||
| 7 | |||
| 8 | use \Wpo\Core\User; | ||
| 9 | use \Wpo\Core\WordPress_Helpers; | ||
| 10 | use \Wpo\Services\Log_Service; | ||
| 11 | use \Wpo\Services\Options_Service; | ||
| 12 | use \Wpo\Services\Graph_Service; | ||
| 13 | use \Wpo\Services\User_Service; | ||
| 14 | |||
| 15 | if (!class_exists('\Wpo\Services\User_Details_Service')) { | ||
| 16 | |||
| 17 | class User_Details_Service | ||
| 18 | { | ||
| 19 | |||
| 20 | /** | ||
| 21 | * @since 11.0 | ||
| 22 | */ | ||
| 23 | public static function try_improve_core_fields(&$wpo_usr) | ||
| 24 | { | ||
| 25 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 26 | |||
| 27 | if (isset($wpo_usr->graph_resource['userPrincipalName'])) { | ||
| 28 | $wpo_usr->upn = $wpo_usr->graph_resource['userPrincipalName']; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (isset($wpo_usr->graph_resource['mail'])) { | ||
| 32 | $wpo_usr->email = $wpo_usr->graph_resource['mail']; | ||
| 33 | } | ||
| 34 | |||
| 35 | if (isset($wpo_usr->graph_resource['givenName'])) { | ||
| 36 | $wpo_usr->first_name = $wpo_usr->graph_resource['givenName']; | ||
| 37 | } | ||
| 38 | |||
| 39 | if (isset($wpo_usr->graph_resource['surname'])) { | ||
| 40 | $wpo_usr->last_name = $wpo_usr->graph_resource['surname']; | ||
| 41 | } | ||
| 42 | |||
| 43 | if (isset($wpo_usr->graph_resource['displayName'])) { | ||
| 44 | $wpo_usr->full_name = $wpo_usr->graph_resource['displayName']; | ||
| 45 | } | ||
| 46 | |||
| 47 | $graph_display_name_format = Options_Service::get_global_string_var('graph_display_name_format'); | ||
| 48 | |||
| 49 | if ($graph_display_name_format == 'skip') { | ||
| 50 | $wpo_usr->full_name = ''; | ||
| 51 | } else { | ||
| 52 | if (!empty($wpo_usr->first_name) && !empty($wpo_usr->last_name)) { | ||
| 53 | |||
| 54 | if ($graph_display_name_format == 'givenNameSurname') { | ||
| 55 | $wpo_usr->full_name = sprintf('%s %s', $wpo_usr->first_name, $wpo_usr->last_name); | ||
| 56 | } elseif ($graph_display_name_format == 'surnameGivenName') { | ||
| 57 | $wpo_usr->full_name = sprintf('%s, %s', $wpo_usr->last_name, $wpo_usr->first_name); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | /** | ||
| 64 | * Retrieves the user's AAD group memberships and adds them to the internally used User. | ||
| 65 | * | ||
| 66 | * @since 11.0 | ||
| 67 | * | ||
| 68 | * @param string $resource_identifier Object ID or user principal name | ||
| 69 | * @param bool $use_me Deprecated, the method will decide for itself | ||
| 70 | * @param bool $use_delegated If the true the plugin will use a token with delegated permissions | ||
| 71 | * @param bool $return_error Whether the method should return the error if one occurs | ||
| 72 | * | ||
| 73 | * @return object The graph resource if request or else null | ||
| 74 | */ | ||
| 75 | public static function get_graph_user($resource_identifier = null, $use_me = false, $use_delegated = false, $return_error = false) | ||
| 76 | { | ||
| 77 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 78 | |||
| 79 | $query = empty($resource_identifier) | ||
| 80 | ? '/me' | ||
| 81 | : '/users/' . \rawurlencode($resource_identifier); | ||
| 82 | |||
| 83 | $select_properties = Options_Service::get_global_list_var('graph_select_properties'); | ||
| 84 | |||
| 85 | if (!empty($select_properties)) { | ||
| 86 | $default_properties = array('businessPhones', 'displayName', 'givenName', 'jobTitle', 'mail', 'mobilePhone', 'officeLocation', 'preferredLanguage', 'surname', 'userPrincipalName', 'id', 'city', 'companyName', 'country', 'department', 'employeeId', 'streetAddress', 'state', 'postalCode'); | ||
| 87 | $select_properties = array_merge($select_properties, $default_properties); | ||
| 88 | $select_properties = array_map(function ($item) { | ||
| 89 | return \trim($item); | ||
| 90 | }, $select_properties); | ||
| 91 | $query = sprintf( | ||
| 92 | '%s?$select=%s', | ||
| 93 | $query, | ||
| 94 | \implode(',', $select_properties) | ||
| 95 | ); | ||
| 96 | } | ||
| 97 | |||
| 98 | $headers = array( | ||
| 99 | 'Accept: application/json;odata.metadata=minimal', | ||
| 100 | 'Content-Type: application/json', | ||
| 101 | ); | ||
| 102 | |||
| 103 | $graph_resource = Graph_Service::fetch($query, 'GET', false, $headers, $use_delegated); | ||
| 104 | |||
| 105 | if (Graph_Service::is_fetch_result_ok($graph_resource, 'Could not retrieve user details')) { | ||
| 106 | return $graph_resource['payload']; | ||
| 107 | } | ||
| 108 | |||
| 109 | return $return_error ? $graph_resource : null; | ||
| 110 | } | ||
| 111 | |||
| 112 | /** | ||
| 113 | * This helper will create a new member graph_resource on the wpo_usr parameter, | ||
| 114 | * populates it with fields from the ID token instead and eventually returns the | ||
| 115 | * wpo_usr. | ||
| 116 | * | ||
| 117 | * @since 18.0 | ||
| 118 | * | ||
| 119 | * @param object &$wpo_usr By reference | ||
| 120 | * @param object $id_token | ||
| 121 | * @return void | ||
| 122 | */ | ||
| 123 | public static function update_wpo_usr_from_id_token(&$wpo_usr, $id_token) | ||
| 124 | { | ||
| 125 | $extra_user_fields = Options_Service::get_global_list_var('extra_user_fields'); | ||
| 126 | $wpo_usr->graph_resource = array(); | ||
| 127 | |||
| 128 | // Just copy these "core" fields for User_Details_Service::try_improve_core_fields | ||
| 129 | if (!empty($wpo_usr->email)) { | ||
| 130 | $wpo_usr->graph_resource['mail'] = $wpo_usr->email; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (!empty($wpo_usr->first_name)) { | ||
| 134 | $wpo_usr->graph_resource['givenName'] = $wpo_usr->first_name; | ||
| 135 | } | ||
| 136 | |||
| 137 | if (!empty($wpo_usr->last_name)) { | ||
| 138 | $wpo_usr->graph_resource['surname'] = $wpo_usr->last_name; | ||
| 139 | } | ||
| 140 | |||
| 141 | // Now try to add custom user fields to the mocked graph_resource | ||
| 142 | if (!empty($extra_user_fields)) { | ||
| 143 | $id_token_props = get_object_vars($id_token); | ||
| 144 | |||
| 145 | foreach ($extra_user_fields as $index => $keyValuePair) { | ||
| 146 | |||
| 147 | if (empty($keyValuePair) || !is_array($keyValuePair) || empty($keyValuePair['key'])) { | ||
| 148 | continue; | ||
| 149 | } | ||
| 150 | |||
| 151 | $parsed_user_field_key = self::parse_user_field_key($keyValuePair['key']); | ||
| 152 | $name = $parsed_user_field_key[0]; | ||
| 153 | |||
| 154 | $value = array_key_exists($name, $id_token_props) | ||
| 155 | ? $id_token_props[$name] | ||
| 156 | : false; | ||
| 157 | |||
| 158 | if (empty($value)) { | ||
| 159 | continue; | ||
| 160 | } | ||
| 161 | |||
| 162 | $wpo_usr->graph_resource[$name] = $value; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * This helper will create a new member graph_resource on the wpo_usr parameter, | ||
| 169 | * populates it with fields from the SAML response instead and eventually returns the | ||
| 170 | * wpo_usr. | ||
| 171 | * | ||
| 172 | * @since 20.0 | ||
| 173 | * | ||
| 174 | * @param mixed $wpo_usr | ||
| 175 | * @param mixed $saml_attributes | ||
| 176 | * @return void | ||
| 177 | */ | ||
| 178 | public static function update_wpo_usr_from_saml_attributes(&$wpo_usr, $saml_attributes) | ||
| 179 | { | ||
| 180 | if (is_array($saml_attributes)) { | ||
| 181 | $wpo_usr->saml_attributes = $saml_attributes; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 186 | * Parses the extra_user_fields key that since v19.5 may be a compound field that contains | ||
| 187 | * the name for the usermeta field in WordPress for the user attribute retrieved from Microsoft | ||
| 188 | * Graph. | ||
| 189 | * | ||
| 190 | * @since 20.0 | ||
| 191 | * | ||
| 192 | * @param mixed $name The name of the Microsoft Graph property possibly combined with a proposed name for the key for the usermeta e.g. mobilePhone;#msGraphMobilePhone | ||
| 193 | * @return array The name of the Microsoft Graph property and the proposed name for the key for the usermeta. | ||
| 194 | */ | ||
| 195 | public static function parse_user_field_key($name) | ||
| 196 | { | ||
| 197 | if (false !== WordPress_Helpers::stripos($name, ';#')) { | ||
| 198 | $name_arr = explode(';#', $name); | ||
| 199 | $name = $name_arr[0]; | ||
| 200 | |||
| 201 | if (sizeof($name_arr) > 1) { | ||
| 202 | $wp_user_meta_key = $name_arr[1]; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | $wp_user_meta_key = empty($wp_user_meta_key) ? $name : $wp_user_meta_key; | ||
| 207 | |||
| 208 | return array( | ||
| 209 | $name, | ||
| 210 | $wp_user_meta_key | ||
| 211 | ); | ||
| 212 | } | ||
| 213 | |||
| 214 | /** | ||
| 215 | * Administrators can prevent WordPress from sending emails when their email changed. | ||
| 216 | * This is especially useful since WordPress doesn't compare new and old email addresses | ||
| 217 | * case insensitive. | ||
| 218 | * | ||
| 219 | * @since 11.9 | ||
| 220 | * | ||
| 221 | * @return boolean Whether or not to send the email changed notification. | ||
| 222 | */ | ||
| 223 | public static function prevent_send_email_change_email() | ||
| 224 | { | ||
| 225 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 226 | |||
| 227 | if (Options_Service::get_global_boolean_var('prevent_send_email_change_email')) { | ||
| 228 | return false; | ||
| 229 | } | ||
| 230 | |||
| 231 | return true; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | } |
| 1 | <?php | ||
| 2 | |||
| 3 | namespace Wpo\Services; | ||
| 4 | |||
| 5 | use WP_Role; | ||
| 6 | use \Wpo\Core\Permissions_Helpers; | ||
| 7 | use \Wpo\Services\Log_Service; | ||
| 8 | use \Wpo\Services\Options_Service; | ||
| 9 | |||
| 10 | // Prevent public access to this script | ||
| 11 | defined('ABSPATH') or die(); | ||
| 12 | |||
| 13 | if (!class_exists('\Wpo\Services\User_Role_Service')) { | ||
| 14 | |||
| 15 | class User_Role_Service | ||
| 16 | { | ||
| 17 | |||
| 18 | public static function update_user_roles($wp_usr_id, $wpo_usr) | ||
| 19 | { | ||
| 20 | Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__); | ||
| 21 | |||
| 22 | if (Options_Service::get_global_boolean_var('enable_audiences') && class_exists('\Wpo\Services\Audiences_Service')) { | ||
| 23 | // Optionally update audience assignments | ||
| 24 | \Wpo\Services\Audiences_Service::aad_group_x_audience($wp_usr_id, $wpo_usr); | ||
| 25 | } | ||
| 26 | |||
| 27 | if (class_exists('\Wpo\Services\Mapped_Itthinx_Groups_Service') && method_exists('\Wpo\Services\Mapped_Itthinx_Groups_Service', 'aad_group_x_itthinx_group')) { | ||
| 28 | // Optionally update itthinx group assignments | ||
| 29 | \Wpo\Services\Mapped_Itthinx_Groups_Service::aad_group_x_itthinx_group($wp_usr_id, $wpo_usr); | ||
| 30 | } | ||
| 31 | |||
| 32 | if (class_exists('\Wpo\Services\Mapped_Itthinx_Groups_Service') && method_exists('\Wpo\Services\Mapped_Itthinx_Groups_Service', 'custom_field_x_itthinx_group')) { | ||
| 33 | // Optionally update itthinx group assignments | ||
| 34 | \Wpo\Services\Mapped_Itthinx_Groups_Service::custom_field_x_itthinx_group($wp_usr_id, $wpo_usr); | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | ||
| 38 | * @since 24.0 LearnDash Integration | ||
| 39 | */ | ||
| 40 | |||
| 41 | if (class_exists('\Wpo\Services\LearnDash_Integration_Service') && method_exists('\Wpo\Services\LearnDash_Integration_Service', 'update_ld_assignments')) { | ||
| 42 | \Wpo\Services\LearnDash_Integration_Service::update_ld_assignments($wp_usr_id, $wpo_usr->groups); | ||
| 43 | } | ||
| 44 | |||
| 45 | $update_strategy = strtolower(Options_Service::get_global_string_var('replace_or_update_user_roles')); | ||
| 46 | |||
| 47 | if ($update_strategy == 'skip') { | ||
| 48 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Target role for user could not be determined because the administrator configured the plugin to not update user roles'); | ||
| 49 | return; | ||
| 50 | } | ||
| 51 | |||
| 52 | // Get all possible roles for user | ||
| 53 | $user_roles = self::get_user_roles($wp_usr_id, $wpo_usr); | ||
| 54 | |||
| 55 | $wp_usr = \get_user_by('ID', $wp_usr_id); | ||
| 56 | |||
| 57 | if (!Options_Service::get_global_boolean_var('update_admins') && (\in_array('administrator', $wp_usr->roles) || is_super_admin($wp_usr_id))) { | ||
| 58 | Log_Service::write_log('DEBUG', __METHOD__ . ' -> Not updating the role for a user that is already an administrator.'); | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | |||
| 62 | $usr_default_role = is_main_site() | ||
| 63 | ? Options_Service::get_global_string_var('new_usr_default_role') | ||
| 64 | : Options_Service::get_global_string_var('mu_new_usr_default_role'); | ||
| 65 | |||
| 66 | // Remove default role -> It will be added later if requested as fallback | ||
| 67 | if (in_array($usr_default_role, $wp_usr->roles)) { | ||
| 68 | $wp_usr->remove_role($usr_default_role); | ||
| 69 | // refresh the user meta for | ||
| 70 | $wp_usr = \get_user_by('ID', $wp_usr_id); | ||
| 71 | } | ||
| 72 | |||
| 73 | // Empty any existing roles when configured to do so | ||
| 74 | if ($update_strategy == 'replace') { | ||
| 75 | foreach ($wp_usr->roles as $current_user_role) { | ||
| 76 | |||
| 77 | /** | ||
| 78 | * @since 24.0 Filters whether the role should be removed. | ||
| 79 | */ | ||
| 80 | $skip_remove_role = apply_filters('wpo365/roles/remove', false, $current_user_role); | ||
| 81 | |||
| 82 | if (!$skip_remove_role) { | ||
| 83 | $wp_usr->remove_role($current_user_role); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | // refresh the user meta for | ||
| 88 | $wp_usr = \get_user_by('ID', $wp_usr_id); | ||
| 89 | } | ||
| 90 | |||
| 91 | // Add from new roles if not already added | ||
| 92 | foreach ($user_roles as $user_role) { | ||
| 93 | if (false === in_array($user_role, $wp_usr->roles)) { | ||
| 94 | $wp_usr->add_role($user_role); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | // refresh the user meta for | ||
| 99 | $wp_usr = \get_user_by('ID', $wp_usr_id); | ||
| 100 | |||
| 101 | // Add default role if needed / configured | ||
| 102 | if (empty($wp_usr->roles) || (!empty($wp_usr->roles) && false === Options_Service::get_global_boolean_var('default_role_as_fallback'))) { | ||
| 103 | |||
| 104 | if (!empty($usr_default_role)) { | ||
| 105 | $wp_role = self::get_wp_role_case($usr_default_role); | ||
| 106 | |||
| 107 | if (empty($wp_role)) { | ||
| 108 | Log_Service::write_log('ERROR', __METHOD__ . ' -> Trying to add the default role but it appears undefined'); | ||
| 109 | } else { | ||
| 110 | $wp_usr->add_role($usr_default_role); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /** | ||
| 117 | * Find a WP role in an case insensitive matter. | ||
| 118 | * | ||
| 119 | * @since 24.0 | ||
| 120 | * | ||
| 121 | * @param mixed $role_name | ||
| 122 | * @return WP_Role|null | ||
| 123 | */ | ||
| 124 | public static function get_wp_role_case($role_name) | ||
| 125 | { | ||
| 126 | $wp_roles_objects = wp_roles()->role_objects; | ||
| 127 | |||
| 128 | foreach ($wp_roles_objects as $wp_role) { | ||
| 129 | |||
| 130 | if (strcasecmp($wp_role->name, $role_name) === 0) { | ||
| 131 | return $wp_role; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | return null; | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Gets the user's default role or if a mapping exists overrides that default role | ||
| 140 | * and returns the role according to the mapping. | ||
| 141 | * | ||
| 142 | * @since 3.2 | ||
| 143 | * | ||
| 144 | * | ||
| 145 | * @return mixed(array|WP_Error) user's role as string or an WP_Error if not defined | ||
| 146 | */ | ||
| 147 | private static function get_user_roles($wp_usr_id, $wpo_usr) | ||
| 148 | { | ||
| 149 | $user_roles = array(); | ||
| 150 | |||
| 151 | // Graph user resource property x WP role | ||
| 152 | if (class_exists('\Wpo\Services\Mapped_Custom_Fields_Service') && method_exists('\Wpo\Services\Mapped_Custom_Fields_Service', 'custom_field_x_role')) { | ||
| 153 | \Wpo\Services\Mapped_Custom_Fields_Service::custom_field_x_role($user_roles, $wpo_usr); | ||
| 154 | } | ||
| 155 | |||
| 156 | // AAD group x WP role | ||
| 157 | if (class_exists('\Wpo\Services\Mapped_Aad_Groups_Service') && method_exists('\Wpo\Services\Mapped_Aad_Groups_Service', 'aad_group_x_role')) { | ||
| 158 | \Wpo\Services\Mapped_Aad_Groups_Service::aad_group_x_role($user_roles, $wpo_usr); | ||
| 159 | } | ||
| 160 | |||
| 161 | // AAD group x Super Admin | ||
| 162 | if (class_exists('\Wpo\Services\Mapped_Aad_Groups_Service') && method_exists('\Wpo\Services\Mapped_Aad_Groups_Service', 'aad_group_x_super_admin')) { | ||
| 163 | \Wpo\Services\Mapped_Aad_Groups_Service::aad_group_x_super_admin($wp_usr_id, $wpo_usr, true); | ||
| 164 | } | ||
| 165 | |||
| 166 | // Logon Domain x WP role | ||
| 167 | if (class_exists('\Wpo\Services\Mapped_Domains_Service') && method_exists('\Wpo\Services\Mapped_Domains_Service', 'domain_x_role')) { | ||
| 168 | \Wpo\Services\Mapped_Domains_Service::domain_x_role($user_roles, $wpo_usr); | ||
| 169 | } | ||
| 170 | |||
| 171 | return $user_roles; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } |
| 1 | { | ||
| 2 | "name": "wpo365/wpo365-custom-fields", | ||
| 3 | "type": "plugin", | ||
| 4 | "description": "Synchronize Azure AD user attributes e.g. department, job title etc. to WordPress user profiles (includes the PROFILE+ extension).", | ||
| 5 | "keywords": ["wordpress", "Office 365", "O365", "Azure AD"], | ||
| 6 | "homepage": "https://www.wpo365.com/", | ||
| 7 | "license": "", | ||
| 8 | "authors": [ | ||
| 9 | { | ||
| 10 | "name": "Marco van Wieren", | ||
| 11 | "email": "support@wpo365.com", | ||
| 12 | "homepage": "https://www.wpo365.com/", | ||
| 13 | "role": "Developer" | ||
| 14 | } | ||
| 15 | ], | ||
| 16 | "require": { | ||
| 17 | "php": ">=5.6.40" | ||
| 18 | }, | ||
| 19 | "autoload": { | ||
| 20 | "psr-4": { | ||
| 21 | "Wpo\\": "", | ||
| 22 | "Wpo\\Services\\": "Services" | ||
| 23 | } | ||
| 24 | } | ||
| 25 | } |
| 1 | Downloads by van Wieren - WPO365 | EXTENSION | ||
| 2 | |||
| 3 | Copyright 2012 - 2014 | ||
| 4 | |||
| 5 | End User License Agreement | ||
| 6 | |||
| 7 | Commercial use | ||
| 8 | |||
| 9 | After you have purchased the plus version of our plugin | ||
| 10 | and have downloaded the plugin as ZIP file, you are licensed | ||
| 11 | to install the plugin only into the number of website(s) | ||
| 12 | corresponding to the license you purchased plus into a | ||
| 13 | corresponding staging environments. | ||
| 14 | |||
| 15 | You may not duplicate the plugin in whole or in part, | ||
| 16 | except that you may make one copy of it for backup or | ||
| 17 | archival purposes. | ||
| 18 | |||
| 19 | You may terminate this license at any time by destroying the | ||
| 20 | original and all copies of the plugin in whatever form. | ||
| 21 | |||
| 22 | You may permanently transfer all of your rights under this | ||
| 23 | EULA provided you transfer all copies of the plugin (including | ||
| 24 | copies of all prior versions if the plugin is an upgrade) and | ||
| 25 | retain none, and the recipient agrees to the terms of this EULA. | ||
| 26 | |||
| 27 | You may not redistribute, modify or resold the plugin in any | ||
| 28 | way without the written permission of Downloads by van Wieren. You may not rent, | ||
| 29 | lease, or lend the plugin. You may not use the plugin in any | ||
| 30 | software or application that compete with products and services | ||
| 31 | of Downloads by van Wieren. | ||
| 32 | |||
| 33 | School / Non-profit | ||
| 34 | |||
| 35 | If you purchase the School / Non-profit license, Downloads by van Wieren may | ||
| 36 | request you to submit proof of your organization’s status in | ||
| 37 | writing. | ||
| 38 | |||
| 39 | Warranty | ||
| 40 | |||
| 41 | Plugins sold and distributed by Downloads by van Wieren are done so in the hope | ||
| 42 | that they will be useful, but WITHOUT ANY WARRANTY. Inasmuch as | ||
| 43 | WordPress functions correctly on a clean install of itself, | ||
| 44 | Downloads by van Wieren plugins are guaranteed to function on a clean install | ||
| 45 | of the minimum, stable and required version of WordPress for | ||
| 46 | the plugins. Because the number and variety of third-party | ||
| 47 | plugins and themes is vast and wide, we do not guarantee that | ||
| 48 | the plugin will function with all third-party plugins, | ||
| 49 | themes or browsers of any kind. | ||
| 50 | |||
| 51 | We do not assume responsibility and will not be held responsible | ||
| 52 | for any conflicts or compatibility issues that may occur due to | ||
| 53 | third-party software. We assume no responsibility for any data | ||
| 54 | loss as a result of installing or using Downloads by van Wieren plugins. | ||
| 55 | Should conflicts occur with third-party software, we may provide support | ||
| 56 | at our discretion. | ||
| 57 | |||
| 58 | Refund Policy | ||
| 59 | |||
| 60 | We firmly believe in and stand behind our products 100%, but | ||
| 61 | we understand that they cannot work perfectly for everyone all | ||
| 62 | of the time. If you would like to request a refund, please contact | ||
| 63 | us at info@wpo365.com. | ||
| 64 | |||
| 65 | When requesting a refund, we respectfully ask that you meet the | ||
| 66 | following refund policy conditions: | ||
| 67 | |||
| 68 | Eligibility conditions for a refund request: | ||
| 69 | |||
| 70 | - You are within the first 30 days of the original purchase of the plugin. | ||
| 71 | - We cannot grant refunds after the first 30 days of the original purchase. | ||
| 72 | - You have purchased the plugin and after installing and testing the plugin, | ||
| 73 | have found that it will not work for your business or required setup. | ||
| 74 | |||
| 75 | Or | ||
| 76 | |||
| 77 | - You have an issue that we are unable to resolve which makes the system unusable. | ||
| 78 | We may ask you questions regarding the nature of your refund request so we can | ||
| 79 | improve the plugin in the future. | ||
| 80 | - If your issue(s) comes from not being able to install the plugin properly | ||
| 81 | or get the plugin to perform its basic functions, we will happily consider | ||
| 82 | your refund request. | ||
| 83 | - You have contacted our support team and allowed us to attempt to resolve | ||
| 84 | your issue(s), or have explained why the plugin will not work for you. | ||
| 85 | Please note, technical issues caused by 3rd party plugins, themes or other | ||
| 86 | software will not provide grounds for a refund. | ||
| 87 | - You agree to deactivate and uninstall the plugin from your site if a refund | ||
| 88 | is granted. | ||
| 89 | - Refunds will be offered at our sole discretion. By purchasing plugin(s) from | ||
| 90 | our site, you agree to this refund policy and relinquish any rights to subject | ||
| 91 | it to any questions, judgment or legal actions. We are not liable to cover any | ||
| 92 | differences in exchange rates between the time you purchased and the time you are | ||
| 93 | refunded. | ||
| 94 | |||
| 95 | Restrictions | ||
| 96 | |||
| 97 | Prohibition on Reverse Engineering, Decompilation, and Disassembly. You may not | ||
| 98 | reverse engineer, decompile, or disassemble the plugin in any way without the | ||
| 99 | written permission of Downloads by van Wieren. | ||
| 100 | |||
| 101 | Copyright | ||
| 102 | |||
| 103 | The plugin is owned by Downloads by van Wieren, and is protected by copyright laws | ||
| 104 | and international copyright treaties, as well as other intellectual property laws | ||
| 105 | and treaties. The plugin is licensed, not sold, to You for use solely subject to | ||
| 106 | the terms and conditions of this Agreement. | ||
| 107 | |||
| 108 | Termination | ||
| 109 | |||
| 110 | Without prejudice to any other rights, Downloads by van Wieren may terminate this | ||
| 111 | EULA if you fail to comply with the terms and conditions of this EULA. In such event, | ||
| 112 | you must destroy all copies of the plugin. | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | <?php | ||
| 2 | |||
| 3 | /* | ||
| 4 | * This file is part of Composer. | ||
| 5 | * | ||
| 6 | * (c) Nils Adermann <naderman@naderman.de> | ||
| 7 | * Jordi Boggiano <j.boggiano@seld.be> | ||
| 8 | * | ||
| 9 | * For the full copyright and license information, please view the LICENSE | ||
| 10 | * file that was distributed with this source code. | ||
| 11 | */ | ||
| 12 | |||
| 13 | namespace Composer\Autoload; | ||
| 14 | |||
| 15 | /** | ||
| 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. | ||
| 17 | * | ||
| 18 | * $loader = new \Composer\Autoload\ClassLoader(); | ||
| 19 | * | ||
| 20 | * // register classes with namespaces | ||
| 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); | ||
| 22 | * $loader->add('Symfony', __DIR__.'/framework'); | ||
| 23 | * | ||
| 24 | * // activate the autoloader | ||
| 25 | * $loader->register(); | ||
| 26 | * | ||
| 27 | * // to enable searching the include path (eg. for PEAR packages) | ||
| 28 | * $loader->setUseIncludePath(true); | ||
| 29 | * | ||
| 30 | * In this example, if you try to use a class in the Symfony\Component | ||
| 31 | * namespace or one of its children (Symfony\Component\Console for instance), | ||
| 32 | * the autoloader will first look for the class under the component/ | ||
| 33 | * directory, and it will then fallback to the framework/ directory if not | ||
| 34 | * found before giving up. | ||
| 35 | * | ||
| 36 | * This class is loosely based on the Symfony UniversalClassLoader. | ||
| 37 | * | ||
| 38 | * @author Fabien Potencier <fabien@symfony.com> | ||
| 39 | * @author Jordi Boggiano <j.boggiano@seld.be> | ||
| 40 | * @see http://www.php-fig.org/psr/psr-0/ | ||
| 41 | * @see http://www.php-fig.org/psr/psr-4/ | ||
| 42 | */ | ||
| 43 | class ClassLoader | ||
| 44 | { | ||
| 45 | // PSR-4 | ||
| 46 | private $prefixLengthsPsr4 = array(); | ||
| 47 | private $prefixDirsPsr4 = array(); | ||
| 48 | private $fallbackDirsPsr4 = array(); | ||
| 49 | |||
| 50 | // PSR-0 | ||
| 51 | private $prefixesPsr0 = array(); | ||
| 52 | private $fallbackDirsPsr0 = array(); | ||
| 53 | |||
| 54 | private $useIncludePath = false; | ||
| 55 | private $classMap = array(); | ||
| 56 | private $classMapAuthoritative = false; | ||
| 57 | private $missingClasses = array(); | ||
| 58 | private $apcuPrefix; | ||
| 59 | |||
| 60 | public function getPrefixes() | ||
| 61 | { | ||
| 62 | if (!empty($this->prefixesPsr0)) { | ||
| 63 | return call_user_func_array('array_merge', $this->prefixesPsr0); | ||
| 64 | } | ||
| 65 | |||
| 66 | return array(); | ||
| 67 | } | ||
| 68 | |||
| 69 | public function getPrefixesPsr4() | ||
| 70 | { | ||
| 71 | return $this->prefixDirsPsr4; | ||
| 72 | } | ||
| 73 | |||
| 74 | public function getFallbackDirs() | ||
| 75 | { | ||
| 76 | return $this->fallbackDirsPsr0; | ||
| 77 | } | ||
| 78 | |||
| 79 | public function getFallbackDirsPsr4() | ||
| 80 | { | ||
| 81 | return $this->fallbackDirsPsr4; | ||
| 82 | } | ||
| 83 | |||
| 84 | public function getClassMap() | ||
| 85 | { | ||
| 86 | return $this->classMap; | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * @param array $classMap Class to filename map | ||
| 91 | */ | ||
| 92 | public function addClassMap(array $classMap) | ||
| 93 | { | ||
| 94 | if ($this->classMap) { | ||
| 95 | $this->classMap = array_merge($this->classMap, $classMap); | ||
| 96 | } else { | ||
| 97 | $this->classMap = $classMap; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Registers a set of PSR-0 directories for a given prefix, either | ||
| 103 | * appending or prepending to the ones previously set for this prefix. | ||
| 104 | * | ||
| 105 | * @param string $prefix The prefix | ||
| 106 | * @param array|string $paths The PSR-0 root directories | ||
| 107 | * @param bool $prepend Whether to prepend the directories | ||
| 108 | */ | ||
| 109 | public function add($prefix, $paths, $prepend = false) | ||
| 110 | { | ||
| 111 | if (!$prefix) { | ||
| 112 | if ($prepend) { | ||
| 113 | $this->fallbackDirsPsr0 = array_merge( | ||
| 114 | (array) $paths, | ||
| 115 | $this->fallbackDirsPsr0 | ||
| 116 | ); | ||
| 117 | } else { | ||
| 118 | $this->fallbackDirsPsr0 = array_merge( | ||
| 119 | $this->fallbackDirsPsr0, | ||
| 120 | (array) $paths | ||
| 121 | ); | ||
| 122 | } | ||
| 123 | |||
| 124 | return; | ||
| 125 | } | ||
| 126 | |||
| 127 | $first = $prefix[0]; | ||
| 128 | if (!isset($this->prefixesPsr0[$first][$prefix])) { | ||
| 129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; | ||
| 130 | |||
| 131 | return; | ||
| 132 | } | ||
| 133 | if ($prepend) { | ||
| 134 | $this->prefixesPsr0[$first][$prefix] = array_merge( | ||
| 135 | (array) $paths, | ||
| 136 | $this->prefixesPsr0[$first][$prefix] | ||
| 137 | ); | ||
| 138 | } else { | ||
| 139 | $this->prefixesPsr0[$first][$prefix] = array_merge( | ||
| 140 | $this->prefixesPsr0[$first][$prefix], | ||
| 141 | (array) $paths | ||
| 142 | ); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Registers a set of PSR-4 directories for a given namespace, either | ||
| 148 | * appending or prepending to the ones previously set for this namespace. | ||
| 149 | * | ||
| 150 | * @param string $prefix The prefix/namespace, with trailing '\\' | ||
| 151 | * @param array|string $paths The PSR-4 base directories | ||
| 152 | * @param bool $prepend Whether to prepend the directories | ||
| 153 | * | ||
| 154 | * @throws \InvalidArgumentException | ||
| 155 | */ | ||
| 156 | public function addPsr4($prefix, $paths, $prepend = false) | ||
| 157 | { | ||
| 158 | if (!$prefix) { | ||
| 159 | // Register directories for the root namespace. | ||
| 160 | if ($prepend) { | ||
| 161 | $this->fallbackDirsPsr4 = array_merge( | ||
| 162 | (array) $paths, | ||
| 163 | $this->fallbackDirsPsr4 | ||
| 164 | ); | ||
| 165 | } else { | ||
| 166 | $this->fallbackDirsPsr4 = array_merge( | ||
| 167 | $this->fallbackDirsPsr4, | ||
| 168 | (array) $paths | ||
| 169 | ); | ||
| 170 | } | ||
| 171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { | ||
| 172 | // Register directories for a new namespace. | ||
| 173 | $length = strlen($prefix); | ||
| 174 | if ('\\' !== $prefix[$length - 1]) { | ||
| 175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | ||
| 176 | } | ||
| 177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | ||
| 178 | $this->prefixDirsPsr4[$prefix] = (array) $paths; | ||
| 179 | } elseif ($prepend) { | ||
| 180 | // Prepend directories for an already registered namespace. | ||
| 181 | $this->prefixDirsPsr4[$prefix] = array_merge( | ||
| 182 | (array) $paths, | ||
| 183 | $this->prefixDirsPsr4[$prefix] | ||
| 184 | ); | ||
| 185 | } else { | ||
| 186 | // Append directories for an already registered namespace. | ||
| 187 | $this->prefixDirsPsr4[$prefix] = array_merge( | ||
| 188 | $this->prefixDirsPsr4[$prefix], | ||
| 189 | (array) $paths | ||
| 190 | ); | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Registers a set of PSR-0 directories for a given prefix, | ||
| 196 | * replacing any others previously set for this prefix. | ||
| 197 | * | ||
| 198 | * @param string $prefix The prefix | ||
| 199 | * @param array|string $paths The PSR-0 base directories | ||
| 200 | */ | ||
| 201 | public function set($prefix, $paths) | ||
| 202 | { | ||
| 203 | if (!$prefix) { | ||
| 204 | $this->fallbackDirsPsr0 = (array) $paths; | ||
| 205 | } else { | ||
| 206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | /** | ||
| 211 | * Registers a set of PSR-4 directories for a given namespace, | ||
| 212 | * replacing any others previously set for this namespace. | ||
| 213 | * | ||
| 214 | * @param string $prefix The prefix/namespace, with trailing '\\' | ||
| 215 | * @param array|string $paths The PSR-4 base directories | ||
| 216 | * | ||
| 217 | * @throws \InvalidArgumentException | ||
| 218 | */ | ||
| 219 | public function setPsr4($prefix, $paths) | ||
| 220 | { | ||
| 221 | if (!$prefix) { | ||
| 222 | $this->fallbackDirsPsr4 = (array) $paths; | ||
| 223 | } else { | ||
| 224 | $length = strlen($prefix); | ||
| 225 | if ('\\' !== $prefix[$length - 1]) { | ||
| 226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | ||
| 227 | } | ||
| 228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | ||
| 229 | $this->prefixDirsPsr4[$prefix] = (array) $paths; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Turns on searching the include path for class files. | ||
| 235 | * | ||
| 236 | * @param bool $useIncludePath | ||
| 237 | */ | ||
| 238 | public function setUseIncludePath($useIncludePath) | ||
| 239 | { | ||
| 240 | $this->useIncludePath = $useIncludePath; | ||
| 241 | } | ||
| 242 | |||
| 243 | /** | ||
| 244 | * Can be used to check if the autoloader uses the include path to check | ||
| 245 | * for classes. | ||
| 246 | * | ||
| 247 | * @return bool | ||
| 248 | */ | ||
| 249 | public function getUseIncludePath() | ||
| 250 | { | ||
| 251 | return $this->useIncludePath; | ||
| 252 | } | ||
| 253 | |||
| 254 | /** | ||
| 255 | * Turns off searching the prefix and fallback directories for classes | ||
| 256 | * that have not been registered with the class map. | ||
| 257 | * | ||
| 258 | * @param bool $classMapAuthoritative | ||
| 259 | */ | ||
| 260 | public function setClassMapAuthoritative($classMapAuthoritative) | ||
| 261 | { | ||
| 262 | $this->classMapAuthoritative = $classMapAuthoritative; | ||
| 263 | } | ||
| 264 | |||
| 265 | /** | ||
| 266 | * Should class lookup fail if not found in the current class map? | ||
| 267 | * | ||
| 268 | * @return bool | ||
| 269 | */ | ||
| 270 | public function isClassMapAuthoritative() | ||
| 271 | { | ||
| 272 | return $this->classMapAuthoritative; | ||
| 273 | } | ||
| 274 | |||
| 275 | /** | ||
| 276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. | ||
| 277 | * | ||
| 278 | * @param string|null $apcuPrefix | ||
| 279 | */ | ||
| 280 | public function setApcuPrefix($apcuPrefix) | ||
| 281 | { | ||
| 282 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; | ||
| 283 | } | ||
| 284 | |||
| 285 | /** | ||
| 286 | * The APCu prefix in use, or null if APCu caching is not enabled. | ||
| 287 | * | ||
| 288 | * @return string|null | ||
| 289 | */ | ||
| 290 | public function getApcuPrefix() | ||
| 291 | { | ||
| 292 | return $this->apcuPrefix; | ||
| 293 | } | ||
| 294 | |||
| 295 | /** | ||
| 296 | * Registers this instance as an autoloader. | ||
| 297 | * | ||
| 298 | * @param bool $prepend Whether to prepend the autoloader or not | ||
| 299 | */ | ||
| 300 | public function register($prepend = false) | ||
| 301 | { | ||
| 302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); | ||
| 303 | } | ||
| 304 | |||
| 305 | /** | ||
| 306 | * Unregisters this instance as an autoloader. | ||
| 307 | */ | ||
| 308 | public function unregister() | ||
| 309 | { | ||
| 310 | spl_autoload_unregister(array($this, 'loadClass')); | ||
| 311 | } | ||
| 312 | |||
| 313 | /** | ||
| 314 | * Loads the given class or interface. | ||
| 315 | * | ||
| 316 | * @param string $class The name of the class | ||
| 317 | * @return bool|null True if loaded, null otherwise | ||
| 318 | */ | ||
| 319 | public function loadClass($class) | ||
| 320 | { | ||
| 321 | if ($file = $this->findFile($class)) { | ||
| 322 | includeFile($file); | ||
| 323 | |||
| 324 | return true; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Finds the path to the file where the class is defined. | ||
| 330 | * | ||
| 331 | * @param string $class The name of the class | ||
| 332 | * | ||
| 333 | * @return string|false The path if found, false otherwise | ||
| 334 | */ | ||
| 335 | public function findFile($class) | ||
| 336 | { | ||
| 337 | // class map lookup | ||
| 338 | if (isset($this->classMap[$class])) { | ||
| 339 | return $this->classMap[$class]; | ||
| 340 | } | ||
| 341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { | ||
| 342 | return false; | ||
| 343 | } | ||
| 344 | if (null !== $this->apcuPrefix) { | ||
| 345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); | ||
| 346 | if ($hit) { | ||
| 347 | return $file; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | $file = $this->findFileWithExtension($class, '.php'); | ||
| 352 | |||
| 353 | // Search for Hack files if we are running on HHVM | ||
| 354 | if (false === $file && defined('HHVM_VERSION')) { | ||
| 355 | $file = $this->findFileWithExtension($class, '.hh'); | ||
| 356 | } | ||
| 357 | |||
| 358 | if (null !== $this->apcuPrefix) { | ||
| 359 | apcu_add($this->apcuPrefix.$class, $file); | ||
| 360 | } | ||
| 361 | |||
| 362 | if (false === $file) { | ||
| 363 | // Remember that this class does not exist. | ||
| 364 | $this->missingClasses[$class] = true; | ||
| 365 | } | ||
| 366 | |||
| 367 | return $file; | ||
| 368 | } | ||
| 369 | |||
| 370 | private function findFileWithExtension($class, $ext) | ||
| 371 | { | ||
| 372 | // PSR-4 lookup | ||
| 373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; | ||
| 374 | |||
| 375 | $first = $class[0]; | ||
| 376 | if (isset($this->prefixLengthsPsr4[$first])) { | ||
| 377 | $subPath = $class; | ||
| 378 | while (false !== $lastPos = strrpos($subPath, '\\')) { | ||
| 379 | $subPath = substr($subPath, 0, $lastPos); | ||
| 380 | $search = $subPath . '\\'; | ||
| 381 | if (isset($this->prefixDirsPsr4[$search])) { | ||
| 382 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); | ||
| 383 | foreach ($this->prefixDirsPsr4[$search] as $dir) { | ||
| 384 | if (file_exists($file = $dir . $pathEnd)) { | ||
| 385 | return $file; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | // PSR-4 fallback dirs | ||
| 393 | foreach ($this->fallbackDirsPsr4 as $dir) { | ||
| 394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { | ||
| 395 | return $file; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | // PSR-0 lookup | ||
| 400 | if (false !== $pos = strrpos($class, '\\')) { | ||
| 401 | // namespaced class name | ||
| 402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) | ||
| 403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); | ||
| 404 | } else { | ||
| 405 | // PEAR-like class name | ||
| 406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; | ||
| 407 | } | ||
| 408 | |||
| 409 | if (isset($this->prefixesPsr0[$first])) { | ||
| 410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { | ||
| 411 | if (0 === strpos($class, $prefix)) { | ||
| 412 | foreach ($dirs as $dir) { | ||
| 413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | ||
| 414 | return $file; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | // PSR-0 fallback dirs | ||
| 422 | foreach ($this->fallbackDirsPsr0 as $dir) { | ||
| 423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | ||
| 424 | return $file; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | // PSR-0 include paths. | ||
| 429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { | ||
| 430 | return $file; | ||
| 431 | } | ||
| 432 | |||
| 433 | return false; | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | /** | ||
| 438 | * Scope isolated include. | ||
| 439 | * | ||
| 440 | * Prevents access to $this/self from included files. | ||
| 441 | */ | ||
| 442 | function includeFile($file) | ||
| 443 | { | ||
| 444 | include $file; | ||
| 445 | } |
| 1 | |||
| 2 | Copyright (c) Nils Adermann, Jordi Boggiano | ||
| 3 | |||
| 4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 5 | of this software and associated documentation files (the "Software"), to deal | ||
| 6 | in the Software without restriction, including without limitation the rights | ||
| 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 8 | copies of the Software, and to permit persons to whom the Software is furnished | ||
| 9 | to do so, subject to the following conditions: | ||
| 10 | |||
| 11 | The above copyright notice and this permission notice shall be included in all | ||
| 12 | copies or substantial portions of the Software. | ||
| 13 | |||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 20 | THE SOFTWARE. | ||
| 21 |
| 1 | <?php | ||
| 2 | |||
| 3 | // autoload_real.php @generated by Composer | ||
| 4 | |||
| 5 | class ComposerAutoloaderInitf106db3bb07a0cc7f373b495de3213f9 | ||
| 6 | { | ||
| 7 | private static $loader; | ||
| 8 | |||
| 9 | public static function loadClassLoader($class) | ||
| 10 | { | ||
| 11 | if ('Composer\Autoload\ClassLoader' === $class) { | ||
| 12 | require __DIR__ . '/ClassLoader.php'; | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | /** | ||
| 17 | * @return \Composer\Autoload\ClassLoader | ||
| 18 | */ | ||
| 19 | public static function getLoader() | ||
| 20 | { | ||
| 21 | if (null !== self::$loader) { | ||
| 22 | return self::$loader; | ||
| 23 | } | ||
| 24 | |||
| 25 | spl_autoload_register(array('ComposerAutoloaderInitf106db3bb07a0cc7f373b495de3213f9', 'loadClassLoader'), true, true); | ||
| 26 | self::$loader = $loader = new \Composer\Autoload\ClassLoader(); | ||
| 27 | spl_autoload_unregister(array('ComposerAutoloaderInitf106db3bb07a0cc7f373b495de3213f9', 'loadClassLoader')); | ||
| 28 | |||
| 29 | $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); | ||
| 30 | if ($useStaticLoader) { | ||
| 31 | require_once __DIR__ . '/autoload_static.php'; | ||
| 32 | |||
| 33 | call_user_func(\Composer\Autoload\ComposerStaticInitf106db3bb07a0cc7f373b495de3213f9::getInitializer($loader)); | ||
| 34 | } else { | ||
| 35 | $map = require __DIR__ . '/autoload_namespaces.php'; | ||
| 36 | foreach ($map as $namespace => $path) { | ||
| 37 | $loader->set($namespace, $path); | ||
| 38 | } | ||
| 39 | |||
| 40 | $map = require __DIR__ . '/autoload_psr4.php'; | ||
| 41 | foreach ($map as $namespace => $path) { | ||
| 42 | $loader->setPsr4($namespace, $path); | ||
| 43 | } | ||
| 44 | |||
| 45 | $classMap = require __DIR__ . '/autoload_classmap.php'; | ||
| 46 | if ($classMap) { | ||
| 47 | $loader->addClassMap($classMap); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | $loader->register(true); | ||
| 52 | |||
| 53 | return $loader; | ||
| 54 | } | ||
| 55 | } |
| 1 | <?php | ||
| 2 | |||
| 3 | // autoload_static.php @generated by Composer | ||
| 4 | |||
| 5 | namespace Composer\Autoload; | ||
| 6 | |||
| 7 | class ComposerStaticInitf106db3bb07a0cc7f373b495de3213f9 | ||
| 8 | { | ||
| 9 | public static $prefixLengthsPsr4 = array ( | ||
| 10 | 'W' => | ||
| 11 | array ( | ||
| 12 | 'Wpo\\Services\\' => 13, | ||
| 13 | 'Wpo\\' => 4, | ||
| 14 | ), | ||
| 15 | ); | ||
| 16 | |||
| 17 | public static $prefixDirsPsr4 = array ( | ||
| 18 | 'Wpo\\Services\\' => | ||
| 19 | array ( | ||
| 20 | 0 => __DIR__ . '/../..' . '/Services', | ||
| 21 | ), | ||
| 22 | 'Wpo\\' => | ||
| 23 | array ( | ||
| 24 | 0 => __DIR__ . '/../..' . '/', | ||
| 25 | ), | ||
| 26 | ); | ||
| 27 | |||
| 28 | public static function getInitializer(ClassLoader $loader) | ||
| 29 | { | ||
| 30 | return \Closure::bind(function () use ($loader) { | ||
| 31 | $loader->prefixLengthsPsr4 = ComposerStaticInitf106db3bb07a0cc7f373b495de3213f9::$prefixLengthsPsr4; | ||
| 32 | $loader->prefixDirsPsr4 = ComposerStaticInitf106db3bb07a0cc7f373b495de3213f9::$prefixDirsPsr4; | ||
| 33 | |||
| 34 | }, null, ClassLoader::class); | ||
| 35 | } | ||
| 36 | } |
| 1 | <?php | ||
| 2 | |||
| 3 | /** | ||
| 4 | * Plugin Name: WPO365 | CUSTOM USER FIELDS | ||
| 5 | * Plugin URI: https://www.wpo365.com/downloads/wpo365-custom-user-fields/ | ||
| 6 | * Description: Synchronize Azure AD user attributes e.g. department, job title etc. to WordPress user profiles (includes the PROFILE+ extension). | ||
| 7 | * Version: 25.1 | ||
| 8 | * Author: support@wpo365.com | ||
| 9 | * Author URI: https://www.wpo365.com | ||
| 10 | * License: See license.txt | ||
| 11 | */ | ||
| 12 | |||
| 13 | namespace Wpo; | ||
| 14 | |||
| 15 | require __DIR__ . '/vendor/autoload.php'; | ||
| 16 | |||
| 17 | // Prevent public access to this script | ||
| 18 | defined('ABSPATH') or die(); | ||
| 19 | |||
| 20 | if (!class_exists('\Wpo\Custom_Fields')) { | ||
| 21 | |||
| 22 | class Custom_Fields | ||
| 23 | { | ||
| 24 | |||
| 25 | public function __construct() | ||
| 26 | { | ||
| 27 | // Show admin notification when BASIC edition is not installed | ||
| 28 | add_action('admin_notices', array($this, 'ensure_wpo365_login'), 10, 0); | ||
| 29 | add_action('network_admin_notices', array($this, 'ensure_wpo365_login'), 10, 0); | ||
| 30 | add_action('plugins_loaded', array($this, 'ensure_wpo365_login'), 10, 0); | ||
| 31 | } | ||
| 32 | |||
| 33 | public function ensure_wpo365_login() | ||
| 34 | { | ||
| 35 | $version_exists = \class_exists('\Wpo\Core\Version') && isset(\Wpo\Core\Version::$current) && \Wpo\Core\Version::$current >= 20; | ||
| 36 | |||
| 37 | if (current_action() == 'plugins_loaded') { | ||
| 38 | |||
| 39 | if (!$version_exists) { | ||
| 40 | |||
| 41 | if (false === function_exists('deactivate_plugins')) { | ||
| 42 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; | ||
| 43 | } | ||
| 44 | |||
| 45 | deactivate_plugins(plugin_basename(__FILE__)); | ||
| 46 | } | ||
| 47 | |||
| 48 | return; | ||
| 49 | } | ||
| 50 | |||
| 51 | $plugin_exists = \file_exists(dirname(__DIR__) . '/wpo365-login'); | ||
| 52 | |||
| 53 | // Required version installed and activated | ||
| 54 | if ($version_exists) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | // Required plugin not installed | ||
| 59 | if (!$plugin_exists) { | ||
| 60 | $install_url = wp_nonce_url( | ||
| 61 | add_query_arg( | ||
| 62 | array( | ||
| 63 | 'action' => 'install-plugin', | ||
| 64 | 'plugin' => 'wpo365-login', | ||
| 65 | 'from' => 'plugins', | ||
| 66 | ), | ||
| 67 | self_admin_url('update.php') | ||
| 68 | ), | ||
| 69 | 'install-plugin_wpo365-login' | ||
| 70 | ); | ||
| 71 | echo '<div class="notice notice-error" style="margin-left: 2px;"><p>' | ||
| 72 | . sprintf(__('The %s plugin requires the latest version of %s to be installed and activated.', 'wpo365-login'), '<strong>WPO365 | CUSTOM USER FIELDS</strong>', '<strong>WPO365 | LOGIN (free)</strong>') | ||
| 73 | . '</p><p>' | ||
| 74 | . '<a class="button button-primary" href="' . esc_url($install_url) . '">' . __('Install plugin', 'wpo365-login') . '</a>.' | ||
| 75 | . '</p></div>'; | ||
| 76 | return; | ||
| 77 | } | ||
| 78 | |||
| 79 | // Required plubin installed but must either be activated or upgraded | ||
| 80 | $activate_url = add_query_arg( | ||
| 81 | array( | ||
| 82 | '_wpnonce' => wp_create_nonce('activate-plugin_wpo365-login/wpo365-login.php'), | ||
| 83 | 'action' => 'activate', | ||
| 84 | 'plugin' => 'wpo365-login/wpo365-login.php', | ||
| 85 | ), | ||
| 86 | network_admin_url('plugins.php') | ||
| 87 | ); | ||
| 88 | |||
| 89 | if (is_network_admin()) { | ||
| 90 | $activate_url = add_query_arg(array('networkwide' => 1), $activate_url); | ||
| 91 | } | ||
| 92 | |||
| 93 | $update_url = wp_nonce_url( | ||
| 94 | self_admin_url('update.php?action=upgrade-plugin&plugin=') . 'wpo365-login/wpo365-login.php', | ||
| 95 | 'upgrade-plugin_wpo365-login/wpo365-login.php' | ||
| 96 | ); | ||
| 97 | |||
| 98 | echo '<div class="notice notice-error" style="margin-left: 2px;"><p>' | ||
| 99 | . sprintf(__('The %s plugin requires the latest version of %s to be installed and activated.', 'wpo365-login'), '<strong>WPO365 | CUSTOM USER FIELDS</strong>', '<strong>WPO365 | LOGIN (free)</strong>') | ||
| 100 | . '</p><p>' | ||
| 101 | . '<a class="button button-primary" href="' . esc_url($activate_url) . '">' . __('Activate plugin', 'wpo365-login') . '</a> ' | ||
| 102 | . '<a class="button button-primary" href="' . esc_url($update_url) . '">' . __('Update plugin', 'wpo365-login') . '</a>' | ||
| 103 | . '</p></div>'; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | $wpo365_custom_fields = new Custom_Fields(); |
-
Please register or sign in to post a comment