SettingsPage.php
456 lines
| 1 | <?php |
| 2 | |
| 3 | namespace ProfilePress\Core\Admin\SettingsPages\Membership\CustomersPage; |
| 4 | |
| 5 | use ProfilePress\Core\Admin\SettingsPages\AbstractSettingsPage; |
| 6 | use ProfilePress\Core\Classes\RegistrationAuth; |
| 7 | use ProfilePress\Core\Admin\SettingsPages\Membership\ContextualStateChangeHelper; |
| 8 | use ProfilePress\Core\Membership\CheckoutFields; |
| 9 | use ProfilePress\Core\Membership\Models\Customer\CustomerEntity; |
| 10 | use ProfilePress\Core\Membership\Models\Customer\CustomerFactory; |
| 11 | use ProfilePress\Custom_Settings_Page_Api; |
| 12 | |
| 13 | class SettingsPage extends AbstractSettingsPage |
| 14 | { |
| 15 | public $error_bucket; |
| 16 | |
| 17 | /** @var CustomerWPListTable */ |
| 18 | private $customerListTable; |
| 19 | |
| 20 | function __construct() |
| 21 | { |
| 22 | add_action('ppress_register_menu_page', [$this, 'register_cpf_settings_page']); |
| 23 | add_action('ppress_admin_settings_page_customers', [$this, 'settings_page_function']); |
| 24 | |
| 25 | add_action('wp_ajax_ppress_mb_search_wp_users', [$this, 'search_wp_users']); |
| 26 | |
| 27 | if (ppressGET_var('page') == PPRESS_MEMBERSHIP_CUSTOMERS_SETTINGS_SLUG) { |
| 28 | |
| 29 | add_filter('set-screen-option', [__CLASS__, 'set_screen'], 10, 3); |
| 30 | add_filter('set_screen_option_rules_per_page', [__CLASS__, 'set_screen'], 10, 3); |
| 31 | |
| 32 | add_action('admin_init', function () { |
| 33 | $this->save_customer(); |
| 34 | $this->add_customer(); |
| 35 | }); |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | public function default_header_menu() |
| 40 | { |
| 41 | return 'customers'; |
| 42 | } |
| 43 | |
| 44 | public function register_cpf_settings_page() |
| 45 | { |
| 46 | global $ppress_customer_page; |
| 47 | |
| 48 | $hook = $ppress_customer_page = add_submenu_page( |
| 49 | PPRESS_DASHBOARD_SETTINGS_SLUG, |
| 50 | $this->admin_page_title() . ' - ProfilePress', |
| 51 | esc_html__('Customers', 'wp-user-avatar'), |
| 52 | 'manage_options', |
| 53 | PPRESS_MEMBERSHIP_CUSTOMERS_SETTINGS_SLUG, |
| 54 | [$this, 'admin_page_callback'] |
| 55 | ); |
| 56 | |
| 57 | add_action("load-$hook", [$this, 'add_options']); |
| 58 | |
| 59 | do_action('ppress_membership_customers_settings_page_register', $hook); |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * @return void |
| 64 | * @throws \Exception |
| 65 | */ |
| 66 | public function save_customer() |
| 67 | { |
| 68 | if ( ! isset($_POST['ppress_save_customer'])) return; |
| 69 | |
| 70 | ppress_verify_nonce(); |
| 71 | |
| 72 | if ( ! current_user_can('manage_options')) return; |
| 73 | |
| 74 | $user_id = absint($_POST['customer_wp_user']); |
| 75 | |
| 76 | $customer_id = absint($_GET['id']); |
| 77 | $customer = CustomerFactory::fromId($customer_id); |
| 78 | $customer->user_id = $user_id; |
| 79 | $customer->private_note = sanitize_textarea_field(stripslashes($_POST['private_note'])); |
| 80 | $customer->save(); |
| 81 | |
| 82 | $billing_fields = array_keys(CheckoutFields::billing_fields()); |
| 83 | |
| 84 | foreach ($_POST as $key => $value) { |
| 85 | if (in_array($key, $billing_fields)) { |
| 86 | update_user_meta($user_id, $key, sanitize_textarea_field($value)); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | do_action('ppress_customer_updated', $customer_id); |
| 91 | |
| 92 | wp_safe_redirect(add_query_arg([ |
| 93 | 'ppress_customer_action' => 'view', |
| 94 | 'id' => $customer_id, |
| 95 | 'saved' => 'true' |
| 96 | ], PPRESS_MEMBERSHIP_CUSTOMERS_SETTINGS_PAGE)); |
| 97 | exit; |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * @return void|string |
| 102 | * @throws \Exception |
| 103 | */ |
| 104 | public function add_customer() |
| 105 | { |
| 106 | if ( ! isset($_POST['save_ppress_customers'])) return; |
| 107 | |
| 108 | if ( ! current_user_can('create_users')) { |
| 109 | wp_die(__('You do not have permission to perform this action.', 'wp-user-avatar'), __('Error', 'wp-user-avatar'), array('response' => 403)); |
| 110 | } |
| 111 | |
| 112 | check_admin_referer('wp-csa-nonce', 'wp_csa_nonce'); |
| 113 | |
| 114 | $type = ! empty($_POST['user_account_type']) ? $_POST['user_account_type'] : 'new'; |
| 115 | |
| 116 | $customer_data = ppressPOST_var('ppress_customers', [], true); |
| 117 | |
| 118 | $customer_email = ppress_var($customer_data, 'email', ''); |
| 119 | $customer_user_id = ppress_var($customer_data, 'search_user', ''); |
| 120 | |
| 121 | if ($type == 'new' && empty($customer_email)) { |
| 122 | wp_die(__('Please enter a valid customer email.', 'wp-user-avatar'), __('Error', 'wp-user-avatar'), array('response' => 400)); |
| 123 | } |
| 124 | |
| 125 | if ('new' == $type) { |
| 126 | |
| 127 | $user_login = ! empty($customer_data['username']) ? $customer_data['username'] : $customer_email; |
| 128 | |
| 129 | $existing_user = get_user_by('login', $user_login); |
| 130 | |
| 131 | if ($existing_user && $existing_user->exists()) { |
| 132 | wp_die(sprintf(__('A user account already exists with the login %s.', 'wp-user-avatar'), esc_html($user_login)), __('Error', 'wp-user-avatar'), array('response' => 500)); |
| 133 | } |
| 134 | |
| 135 | $user_args = array( |
| 136 | 'user_login' => sanitize_text_field($user_login), |
| 137 | 'user_email' => sanitize_text_field($customer_email), |
| 138 | 'user_pass' => ! empty($_POST['pass1']) ? $_POST['pass1'] : wp_generate_password(24), |
| 139 | 'first_name' => ! empty($customer_data['first_name']) ? sanitize_text_field($customer_data['first_name']) : '', |
| 140 | 'last_name' => ! empty($customer_data['last_name']) ? sanitize_text_field($customer_data['last_name']) : '' |
| 141 | ); |
| 142 | |
| 143 | $user_args['display_name'] = trim($user_args['first_name'] . ' ' . $user_args['last_name']); |
| 144 | |
| 145 | if (empty($user_args['display_name'])) { |
| 146 | $user_args['display_name'] = $user_args['user_login']; |
| 147 | } |
| 148 | |
| 149 | $user_id = wp_insert_user($user_args); |
| 150 | |
| 151 | if (empty($user_id)) { |
| 152 | wp_die(__('Error creating customer account.', 'wp-user-avatar'), __('Error', 'wp-user-avatar'), array('response' => 500)); |
| 153 | } |
| 154 | |
| 155 | // Send welcome email to the user |
| 156 | RegistrationAuth::send_welcome_email($user_id, $user_args['user_pass']); |
| 157 | |
| 158 | $user = get_userdata($user_id); |
| 159 | |
| 160 | } else { |
| 161 | |
| 162 | $user = get_user_by('id', $customer_user_id); |
| 163 | |
| 164 | if ( ! is_a($user, 'WP_User')) { |
| 165 | wp_die(sprintf(__('Unable to locate existing account with the email %s.', 'wp-user-avatar'), esc_html($customer_email)), __('Error', 'wp-user-avatar'), array('response' => 500)); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | $customer = CustomerFactory::fromUserId($user->ID); |
| 170 | |
| 171 | if ($customer->exists()) { |
| 172 | wp_die(sprintf(__('A customer with the ID %d already exists with this account.', 'wp-user-avatar'), $customer->get_id()), __('Error', 'wp-user-avatar'), array('response' => 500)); |
| 173 | } |
| 174 | |
| 175 | $new_customer = new CustomerEntity(); |
| 176 | $new_customer->user_id = $user->ID; |
| 177 | $customer_id = $new_customer->save(); |
| 178 | |
| 179 | if (empty($customer_id)) { |
| 180 | wp_die(__('Error creating customer record.', 'wp-user-avatar'), __('Error', 'wp-user-avatar'), array('response' => 500)); |
| 181 | } |
| 182 | |
| 183 | do_action('ppress_customer_updated', $customer_id); |
| 184 | |
| 185 | wp_safe_redirect(esc_url_raw(CustomerWPListTable::view_customer_url($customer_id))); |
| 186 | exit; |
| 187 | } |
| 188 | |
| 189 | public function search_wp_users() |
| 190 | { |
| 191 | if ( ! current_user_can('manage_options')) return; |
| 192 | |
| 193 | check_ajax_referer('ppress-admin-nonce', 'nonce'); |
| 194 | |
| 195 | $search = sanitize_text_field($_GET['search']); |
| 196 | |
| 197 | $results['results'] = []; |
| 198 | |
| 199 | $users = get_users([ |
| 200 | 'search' => '*' . $search . '*', |
| 201 | 'search_columns' => ['user_email', 'user_login', 'user_nicename', 'display_name'], |
| 202 | 'fields' => ['ID', 'user_email', 'user_login'], |
| 203 | 'number' => 1000 |
| 204 | ]); |
| 205 | |
| 206 | if (is_array($users) && ! empty($users)) { |
| 207 | |
| 208 | foreach ($users as $user) { |
| 209 | |
| 210 | $results['results'][$user->ID] = array( |
| 211 | 'id' => $user->ID, |
| 212 | 'text' => sprintf('%s (%s)', $user->user_login, $user->user_email), |
| 213 | ); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | $results['results'] = array_values($results['results']); |
| 218 | |
| 219 | wp_send_json($results, 200); |
| 220 | } |
| 221 | |
| 222 | public function admin_page_title() |
| 223 | { |
| 224 | $title = esc_html__('Customers', 'wp-user-avatar'); |
| 225 | |
| 226 | if (ppressGET_var('ppress_customer_action') == 'new') { |
| 227 | $title = esc_html__('Add New Customer', 'wp-user-avatar'); |
| 228 | } |
| 229 | |
| 230 | if (ppressGET_var('ppress_customer_action') == 'view') { |
| 231 | $title = esc_html__('Customer Details', 'wp-user-avatar'); |
| 232 | } |
| 233 | |
| 234 | return $title; |
| 235 | } |
| 236 | |
| 237 | public static function set_screen($status, $option, $value) |
| 238 | { |
| 239 | return $value; |
| 240 | } |
| 241 | |
| 242 | public function add_options() |
| 243 | { |
| 244 | $args = [ |
| 245 | 'label' => esc_html__('Customers', 'wp-user-avatar'), |
| 246 | 'default' => 10, |
| 247 | 'option' => 'customers_per_page' |
| 248 | ]; |
| 249 | |
| 250 | add_screen_option('per_page', $args); |
| 251 | |
| 252 | $this->customerListTable = new CustomerWPListTable(); |
| 253 | } |
| 254 | |
| 255 | public function admin_notices() |
| 256 | { |
| 257 | if ( ! isset($_GET['saved']) && ! isset($this->error_bucket)) return; |
| 258 | |
| 259 | $status = 'updated'; |
| 260 | $message = ''; |
| 261 | |
| 262 | if ( ! empty($this->error_bucket)) { |
| 263 | $message = $this->error_bucket; |
| 264 | $status = 'error'; |
| 265 | } |
| 266 | |
| 267 | if (isset($_GET['saved'])) { |
| 268 | $message = esc_html__('Changes saved.', 'wp-user-avatar'); |
| 269 | } |
| 270 | |
| 271 | printf('<div id="message" class="%s notice is-dismissible"><p>%s</strong></p></div>', $status, $message); |
| 272 | } |
| 273 | |
| 274 | public function settings_page_function() |
| 275 | { |
| 276 | add_action('admin_footer', [$this, 'js_script']); |
| 277 | add_filter('wp_cspa_main_content_area', [$this, 'admin_settings_page_callback'], 10, 2); |
| 278 | add_action('wp_cspa_before_closing_header', [$this, 'add_new_button']); |
| 279 | |
| 280 | add_action('wp_cspa_form_tag', function ($option_name) { |
| 281 | if ($option_name == 'ppress_customers') { |
| 282 | printf(' action="%s"', ppress_get_current_url_query_string()); |
| 283 | } |
| 284 | }); |
| 285 | |
| 286 | $instance = Custom_Settings_Page_Api::instance(); |
| 287 | if ( ! isset($_GET['ppress_customer_action'])) { |
| 288 | $instance->form_method('get'); |
| 289 | $instance->remove_nonce_field(); |
| 290 | } |
| 291 | |
| 292 | if (ppressGET_var('ppress_customer_action') == 'new') { |
| 293 | |
| 294 | $instance->main_content([ |
| 295 | apply_filters('ppress_admin_new_customer_form_fields', [ |
| 296 | 'account_type' => [ |
| 297 | 'label' => __('User Account', 'wp-user-avatar'), |
| 298 | 'type' => 'custom_field_block', |
| 299 | 'data' => self::user_account_type_settings() |
| 300 | ], |
| 301 | 'search_user' => [ |
| 302 | 'label' => __('Search User', 'wp-user-avatar'), |
| 303 | 'type' => 'select', |
| 304 | 'options' => [], |
| 305 | 'attributes' => ['class' => 'ppress-select2-field customer_wp_user'] |
| 306 | ], |
| 307 | 'first_name' => [ |
| 308 | 'label' => __('First Name', 'wp-user-avatar'), |
| 309 | 'type' => 'text' |
| 310 | ], |
| 311 | 'last_name' => [ |
| 312 | 'label' => __('Last Name', 'wp-user-avatar'), |
| 313 | 'type' => 'text' |
| 314 | ], |
| 315 | 'email' => [ |
| 316 | 'label' => __('Email Address', 'wp-user-avatar'), |
| 317 | 'type' => 'text' |
| 318 | ], |
| 319 | 'username' => [ |
| 320 | 'label' => __('Username', 'wp-user-avatar'), |
| 321 | 'type' => 'text' |
| 322 | ], |
| 323 | 'password' => [ |
| 324 | 'label' => __('Password', 'wp-user-avatar'), |
| 325 | 'type' => 'custom_field_block', |
| 326 | 'data' => self::password_field() |
| 327 | ] |
| 328 | ]) |
| 329 | ]); |
| 330 | |
| 331 | $instance->remove_white_design(); |
| 332 | |
| 333 | $instance->sidebar(self::sidebar_args()); |
| 334 | } |
| 335 | |
| 336 | $instance->add_view_classes('ppview'); |
| 337 | $instance->option_name('ppress_customers'); |
| 338 | $instance->page_header($this->admin_page_title()); |
| 339 | $instance->build(ppressGET_var('ppress_customer_action') != 'new'); |
| 340 | } |
| 341 | |
| 342 | |
| 343 | protected static function user_account_type_settings() |
| 344 | { |
| 345 | $html = sprintf( |
| 346 | '<label><input checked class="user-account-type" type="radio" name="user_account_type" value="new">%s</label> ', |
| 347 | __('New Account', 'wp-user-avatar') |
| 348 | ); |
| 349 | |
| 350 | $html .= sprintf( |
| 351 | '<label><input class="user-account-type" type="radio" name="user_account_type" value="existing">%s</label> ', |
| 352 | __('Existing Account', 'wp-user-avatar') |
| 353 | ); |
| 354 | |
| 355 | return $html; |
| 356 | } |
| 357 | |
| 358 | protected static function password_field() |
| 359 | { |
| 360 | ob_start(); |
| 361 | ?> |
| 362 | <div id="password" class="user-pass1-wrap"> |
| 363 | <input class="hidden" value=" "/><!-- #24364 workaround --> |
| 364 | <button type="button" class="button wp-generate-pw hide-if-no-js" aria-expanded="false"><?php _e('Show password', 'wp-user-avatar'); ?></button> |
| 365 | <div class="wp-pwd hide-if-js"> |
| 366 | <span class="password-input-wrapper"> |
| 367 | <input style="width:25em!important;" type="password" name="pass1" id="pass1" class="regular-text" value="" autocomplete="new-password" data-pw="<?php echo esc_attr(wp_generate_password(24)); ?>"/> |
| 368 | </span> |
| 369 | <button type="button" class="button wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e('Hide password', 'wp-user-avatar'); ?>"> |
| 370 | <span class="dashicons dashicons-hidden" aria-hidden="true"></span> |
| 371 | <span class="text"><?php _e('Hide', 'wp-user-avatar'); ?></span> |
| 372 | </button> |
| 373 | <button type="button" class="button wp-cancel-pw hide-if-no-js" data-toggle="0"> |
| 374 | <span class="dashicons dashicons-no" aria-hidden="true"></span> |
| 375 | <span class="text"><?php _e('Cancel', 'wp-user-avatar'); ?></span> |
| 376 | </button> |
| 377 | <div style="display:none" id="pass-strength-result" aria-live="polite"></div> |
| 378 | </div> |
| 379 | </div> |
| 380 | <?php |
| 381 | return ob_get_clean(); |
| 382 | } |
| 383 | |
| 384 | public function add_new_button() |
| 385 | { |
| 386 | if ( ! isset($_GET['ppress_customer_action'])) { |
| 387 | $url = esc_url_raw(add_query_arg('ppress_customer_action', 'new', PPRESS_MEMBERSHIP_CUSTOMERS_SETTINGS_PAGE)); |
| 388 | echo "<a class=\"add-new-h2\" href=\"$url\">" . esc_html__('Add New', 'wp-user-avatar') . '</a>'; |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | public function admin_settings_page_callback($content) |
| 393 | { |
| 394 | if (ppressGET_var('ppress_customer_action') == 'view') { |
| 395 | $this->admin_notices(); |
| 396 | ContextualStateChangeHelper::init(); |
| 397 | require_once dirname(dirname(__FILE__)) . '/views/customers/view-customer.php'; |
| 398 | |
| 399 | return; |
| 400 | } |
| 401 | |
| 402 | if (ppressGET_var('ppress_customer_action') == 'new') return $content; |
| 403 | |
| 404 | $this->customerListTable->prepare_items(); |
| 405 | |
| 406 | echo '<input type="hidden" name="page" value="' . PPRESS_MEMBERSHIP_CUSTOMERS_SETTINGS_SLUG . '" />'; |
| 407 | echo '<input type="hidden" name="view" value="customers" />'; |
| 408 | if (isset($_GET['status'])) { |
| 409 | echo '<input type="hidden" name="status" value="' . esc_attr($_GET['status']) . '" />'; |
| 410 | } |
| 411 | $this->customerListTable->views(); |
| 412 | $this->customerListTable->filter_bar(); |
| 413 | $this->customerListTable->display(); |
| 414 | |
| 415 | do_action('ppress_customer_wp_list_table_bottom'); |
| 416 | } |
| 417 | |
| 418 | public function js_script() |
| 419 | { |
| 420 | ?> |
| 421 | <script type="text/javascript"> |
| 422 | jQuery(function ($) { |
| 423 | $("input.user-account-type").on("change", function () { |
| 424 | if ($("input[name=\'user_account_type\']:checked").val() === "new") { |
| 425 | $("#search_user_row").hide(); |
| 426 | $("#first_name_row").show(); |
| 427 | $("#last_name_row").show(); |
| 428 | $("#email_row").show(); |
| 429 | $("#username_row").show(); |
| 430 | $("#password_row").show(); |
| 431 | } else { |
| 432 | $("#search_user_row").show(); |
| 433 | $("#first_name_row").hide(); |
| 434 | $("#last_name_row").hide(); |
| 435 | $("#email_row").hide(); |
| 436 | $("#username_row").hide(); |
| 437 | $("#password_row").hide(); |
| 438 | } |
| 439 | }).trigger('change'); |
| 440 | }); |
| 441 | </script> |
| 442 | <?php |
| 443 | } |
| 444 | |
| 445 | public static function get_instance() |
| 446 | { |
| 447 | static $instance = null; |
| 448 | |
| 449 | if (is_null($instance)) { |
| 450 | $instance = new self(); |
| 451 | } |
| 452 | |
| 453 | return $instance; |
| 454 | } |
| 455 | } |
| 456 |