settings = $settings; } /** * Register shortcodes and assets. * * @return void */ public function register() { add_shortcode( 'anar_login', array( $this, 'login' ) ); add_shortcode( 'anar_account', array( $this, 'account' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) ); } /** * Register assets everywhere but enqueue them only where a shortcode is used. * * Pages without the form load no CSS, no JavaScript and no inline data at all. * When the shortcode sits in the post content, the stylesheet goes in the head * to avoid a flash of unstyled content; shortcodes rendered elsewhere (widgets, * page builders) still enqueue on demand from the render callback. * * @return void */ public function register_assets() { wp_register_style( 'anar-login', ANAR_LOGIN_URL . 'assets/css/frontend.css', array(), ANAR_LOGIN_VERSION ); wp_register_script( 'anar-login', ANAR_LOGIN_URL . 'assets/js/frontend.js', array(), ANAR_LOGIN_VERSION, array( 'in_footer' => true, 'strategy' => 'defer', ) ); $post = get_queried_object(); $in_use = is_singular() && $post instanceof \WP_Post && ( has_shortcode( $post->post_content, 'anar_login' ) || has_shortcode( $post->post_content, 'anar_account' ) ); /** * Filter whether this page needs the login assets in the head. * * Integrations that render the form from templates (e.g. WooCommerce) return true here. * * @param bool $in_use Whether the queried post contains a shortcode. */ if ( apply_filters( 'anar_login_enqueue_assets', $in_use ) ) { $this->assets(); } } /** * Login card. * * @param array|string $atts Shortcode attributes; redirect sets the post-login destination. * @return string */ public function login( $atts = array() ) { $atts = shortcode_atts( array( 'redirect' => '', 'password_link' => '', ), is_array( $atts ) ? $atts : array(), 'anar_login' ); $this->assets(); $direction = is_rtl() ? 'rtl' : 'ltr'; if ( is_user_logged_in() ) { $panel_id = absint( $this->settings->get( 'panel_page_id', 0 ) ); $panel_url = $panel_id ? get_permalink( $panel_id ) : home_url( '/' ); return sprintf( '
%2$s
%3$s

%4$s

%6$s
', esc_attr( $direction ), $this->logo(), // Escaped inside logo(). esc_html__( 'You are signed in', 'anar-toolkit' ), esc_html( wp_get_current_user()->display_name ), esc_url( $panel_url ), esc_html__( 'Go to my account', 'anar-toolkit' ) ); } $identity_id = wp_unique_id( 'anar-identity-' ); $code_id = wp_unique_id( 'anar-code-' ); $field = $this->identity_field(); $error = $this->query_error(); ob_start(); ?>
logo(); ?>

settings->get( 'google_enabled', 0 ) ) : ?>
>
assets(); $direction = is_rtl() ? 'rtl' : 'ltr'; if ( ! is_user_logged_in() ) { return $this->login(); } $user = wp_get_current_user(); $phone = get_user_meta( $user->ID, '_anar_phone', true ); $google = get_user_meta( $user->ID, '_anar_google_sub', true ); $avatar = UserService::avatar( $user, 192 ); ob_start(); ?>

' . esc_html( $user->display_name ) . '' ); ?>

✓
⌁
user_email ? 1 : 0 ) + ( $google ? 1 : 0 ) ); ?>
◷
user_registered ) ) ); ?>
settings->get( 'form_logo', 'site' ); $url = ''; if ( 'none' === $mode ) { return ''; } if ( 'custom' === $mode ) { $url = (string) $this->settings->get( 'form_logo_url', '' ); } elseif ( 'site' === $mode ) { $logo_id = (int) get_theme_mod( 'custom_logo' ); $url = $logo_id ? (string) wp_get_attachment_image_url( $logo_id, 'medium' ) : ''; $url = $url ? $url : (string) get_site_icon_url( 128 ); } /** * Filter the logo URL shown on the sign-in form; an empty string shows the lock icon. * * @param string $url Image URL. * @param string $mode Logo setting. */ $url = (string) apply_filters( 'anar_login_logo_url', $url, $mode ); if ( $url ) { return sprintf( '', esc_url( $url ), esc_attr( get_bloginfo( 'name' ) ) ); } return ''; } /** * Label, copy and keyboard hints for the identity field in the active sign-in mode. * * @return array */ private function identity_field() { $mode = (string) $this->settings->get( 'identity_mode', 'both' ); if ( 'phone' === $mode ) { return array( 'mode' => 'phone', 'label' => __( 'Mobile number', 'anar-toolkit' ), 'intro' => __( 'Enter your mobile number and we will text you a one-time password.', 'anar-toolkit' ), 'type' => 'tel', 'inputmode' => 'tel', 'autocomplete' => 'tel', 'placeholder' => '09121234567', ); } if ( 'email' === $mode ) { return array( 'mode' => 'email', 'label' => __( 'Email', 'anar-toolkit' ), 'intro' => __( 'Enter your email address and we will send you a one-time password.', 'anar-toolkit' ), 'type' => 'email', 'inputmode' => 'email', 'autocomplete' => 'email', 'placeholder' => 'name@example.com', ); } return array( 'mode' => 'both', 'label' => __( 'Mobile or email', 'anar-toolkit' ), 'intro' => __( 'Enter your mobile number or email address and we will send you a one-time password.', 'anar-toolkit' ), 'type' => 'text', 'inputmode' => 'text', 'autocomplete' => 'username', 'placeholder' => __( '09121234567 or name@example.com', 'anar-toolkit' ), ); } /** * Validation message for an empty identity field. * * @return string */ private function identity_required_message() { $mode = (string) $this->settings->get( 'identity_mode', 'both' ); if ( 'phone' === $mode ) { return __( 'Enter your mobile number.', 'anar-toolkit' ); } return 'email' === $mode ? __( 'Enter your email address.', 'anar-toolkit' ) : __( 'Enter your mobile number or email address.', 'anar-toolkit' ); } /** * Message for an error code sent back from the Google callback. * * Only known codes are mapped, so the query string cannot inject text. * * @return string */ private function query_error() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only display of a whitelisted message. $code = isset( $_GET[ GoogleAuth::ERROR_ARG ] ) ? sanitize_key( wp_unslash( $_GET[ GoogleAuth::ERROR_ARG ] ) ) : ''; if ( ! $code ) { return ''; } $messages = GoogleAuth::error_messages(); return $messages[ $code ] ?? $messages['google_failed']; } /** * Enqueue front assets once. * * @return void */ private function assets() { if ( ! wp_script_is( 'anar-login', 'registered' ) ) { $this->register_assets(); } wp_enqueue_style( 'anar-login' ); wp_enqueue_script( 'anar-login' ); if ( ! $this->localized ) { wp_localize_script( 'anar-login', 'AnarLogin', $this->script_config() ); $this->localized = true; } } /** * Configuration for the frontend script, shared with the lazily loaded popup. * * @return array */ public function script_config() { return array( 'restUrl' => esc_url_raw( rest_url( 'anar-login/v1/' ) ), // Only signed-in requests need a nonce; a cached nonce would otherwise break logins. 'nonce' => is_user_logged_in() ? wp_create_nonce( 'wp_rest' ) : '', 'otpLength' => absint( $this->settings->get( 'otp_length', 5 ) ), 'locale' => str_replace( '_', '-', determine_locale() ), 'errorArg' => GoogleAuth::ERROR_ARG, 'strings' => array( 'network' => __( 'Could not connect. Please try again.', 'anar-toolkit' ), 'processing' => __( 'Please wait…', 'anar-toolkit' ), 'redirecting' => __( 'Signing you in…', 'anar-toolkit' ), 'resend' => __( 'Resend code', 'anar-toolkit' ), 'identityRequired' => $this->identity_required_message(), 'codeRequired' => __( 'Enter the complete verification code.', 'anar-toolkit' ), ), ); } }