, values: array, message: string} */ private $result = array( 'errors' => array(), 'values' => array(), 'message' => '', ); /** * Constructor. * * @param CustomerService $service Customer service. * @param Settings $settings Settings. * @param RateLimiter $limiter Rate limiter. */ public function __construct( CustomerService $service, Settings $settings, RateLimiter $limiter ) { $this->service = $service; $this->settings = $settings; $this->limiter = $limiter; } /** * {@inheritdoc} */ public function register(): void { add_action( 'init', array( $this, 'maybe_process' ), 20 ); add_shortcode( 'hostkhata_register', array( $this, 'render' ) ); } /** * Processes a submitted form. * * @since 0.1.0 * * @return void */ public function maybe_process(): void { if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] || ! isset( $_POST['hostkhata_register_nonce'] ) ) { return; } $nonce = sanitize_text_field( wp_unslash( $_POST['hostkhata_register_nonce'] ) ); if ( ! wp_verify_nonce( $nonce, 'hostkhata_register' ) ) { $this->fail( __( 'Your session expired. Please try again.', 'hostkhata' ) ); return; } if ( ! $this->settings->get( 'registration_enabled' ) || is_user_logged_in() ) { $this->fail( __( 'Registration is not available.', 'hostkhata' ) ); return; } // A real visitor never fills the hidden field. if ( ! empty( $_POST['hk_website'] ) ) { $this->fail( __( 'We could not create your account.', 'hostkhata' ) ); return; } if ( ! $this->limiter->hit( 'register', self::ATTEMPTS_PER_HOUR, HOUR_IN_SECONDS ) ) { $this->fail( __( 'Too many attempts. Please try again later.', 'hostkhata' ) ); return; } $fields = array( 'first_name', 'last_name', 'email', 'company', 'phone' ); $input = array(); foreach ( $fields as $field ) { $input[ $field ] = isset( $_POST[ $field ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field ] ) ) : ''; } // Passwords are used as typed: they are not sanitised, only handed to wp_insert_user(). $password = isset( $_POST['password'] ) ? wp_unslash( $_POST['password'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $confirm = isset( $_POST['password_confirm'] ) ? wp_unslash( $_POST['password_confirm'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $this->result['values'] = $input; $errors = array(); if ( ! is_string( $password ) || strlen( $password ) < self::MIN_PASSWORD_LENGTH ) { /* translators: %d: minimum number of characters. */ $errors['password'] = sprintf( __( 'Use at least %d characters.', 'hostkhata' ), self::MIN_PASSWORD_LENGTH ); } elseif ( $password !== $confirm ) { $errors['password_confirm'] = __( 'The passwords do not match.', 'hostkhata' ); } $customer = $errors ? null : $this->service->register( $input, $password ); if ( $customer instanceof WP_Error ) { $errors = array_merge( $errors, (array) ( $customer->get_error_data()['errors'] ?? array() ) ); if ( ! $errors ) { $errors['form'] = __( 'We could not create your account.', 'hostkhata' ); } } if ( $errors ) { $this->result['errors'] = $errors; return; } if ( CustomerStatus::ACTIVE === $customer['status'] ) { $this->log_in( (int) $customer['user_id'] ); } $this->result['message'] = CustomerStatus::PENDING === $customer['status'] ? __( 'Thank you! Your account was created and is waiting for approval.', 'hostkhata' ) : __( 'Your account was created. You can log in now.', 'hostkhata' ); } /** * Renders the shortcode. * * @since 0.1.0 * * @return string */ public function render(): string { if ( ! $this->settings->get( 'registration_enabled' ) ) { return '

' . esc_html__( 'Registration is currently closed.', 'hostkhata' ) . '

'; } if ( is_user_logged_in() && '' === $this->result['message'] ) { return '

' . esc_html__( 'You are already logged in.', 'hostkhata' ) . '

'; } wp_enqueue_style( 'hostkhata-register', HOSTKHATA_URL . 'assets/public/register.css', array(), HOSTKHATA_VERSION ); return View::render( 'portal/register-form', array( 'errors' => $this->result['errors'], 'values' => $this->result['values'], 'message' => $this->result['message'], 'login_url' => wp_login_url( $this->portal_url() ), 'approval' => (bool) $this->settings->get( 'registration_needs_approval' ), ) ); } /** * Records a general failure. * * @param string $message Message for the visitor. * @return void */ private function fail( string $message ): void { $this->result['errors'] = array( 'form' => $message ); } /** * Logs a new customer in. * * @param int $user_id User id. * @return void */ private function log_in( int $user_id ): void { $user = get_userdata( $user_id ); if ( ! $user ) { return; } wp_set_current_user( $user_id ); wp_set_auth_cookie( $user_id ); /** This action is documented in wp-includes/user.php. */ do_action( 'wp_login', $user->user_login, $user ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core hook, fired so other plugins see the login. } /** * URL of the customer portal page, or the home URL when none is set. * * @return string */ private function portal_url(): string { $page_id = (int) $this->settings->get( 'portal_page_id' ); $url = $page_id > 0 ? get_permalink( $page_id ) : ''; return $url ? $url : home_url( '/' ); } }