ID . ': ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } } } } // Remove fcom_action and fcom_url_hash from the current url $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $url = remove_query_arg(['fcom_action', 'fcom_url_hash'], $currentUrl); $this->redirectAndExit($url); } /** * Send a redirect and stop. * * Extracted only so it can be observed: a bare `exit()` terminates the PHP * process, which in a test run kills the whole suite with no result (see * FIX-PLAN item 22 for the same problem on PortalHandler). A test subclass * overrides this and the two methods below to record what was about to * happen and throw instead. Behaviour in production is unchanged — this is * the original call, moved. * * This one keeps the UNSAFE variant its single caller already used. That * caller builds its target with home_url(), so it is same-host by * construction rather than by validation. Kept as a separate method from * safeRedirectAndExit(), rather than a $safe flag, so the distinction stays * visible to anyone grepping for wp_redirect. */ protected function redirectAndExit($url, $status = 302) { wp_redirect($url, $status); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect exit(); } /** * Send a host-confined redirect and stop. See redirectAndExit(). */ protected function safeRedirectAndExit($url) { wp_safe_redirect($url); exit(); } /** * Render the headless page and stop. See redirectAndExit(). */ protected function renderPageAndExit($template, $pageVars) { status_header(200); App::make('view')->render($template, $pageVars); exit(200); } public function viewAuthPage() { add_filter('login_form_defaults', function ($defaults) { $defaults['label_username'] = __('Email Address', 'fluent-community'); return $defaults; }); add_filter('fluent_community/has_color_scheme', '__return_false'); $currentUserId = get_current_user_id(); // check if there has any invitation token $inivtationToken = Arr::get($_GET, 'invitation_token'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $inviation = null; if ($inivtationToken) { $inviation = apply_filters('fluent_community/auth/invitation', null, $inivtationToken); if ($inviation && !$inviation->isValid()) { $inviation = null; } } if ($currentUserId && !$inviation) { $redirectUrl = null; if (!empty($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $redirectUrl = sanitize_url(wp_unslash($_REQUEST['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } if (!$redirectUrl) { $redirectUrl = Helper::baseUrl(); } $this->safeRedirectAndExit($redirectUrl); } if ($currentUserId && $inviation) { /** @var BaseSpace|null $space */ $space = BaseSpace::withoutGlobalScopes()->find($inviation->post_id); if ($space) { if (Helper::isUserInSpace($currentUserId, $inviation->post_id)) { // let's redirect the user to the space $redirectUrl = $space->getPermalink(); $this->safeRedirectAndExit($redirectUrl); } if (!empty($_REQUEST['auto_accept'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $redirectUrl = (new InvitationHandler())->handleInvitationLogin(Helper::baseUrl(), get_user_by('ID', $currentUserId), $inviation->message_rendered); if (is_wp_error($redirectUrl) || !$redirectUrl) { $redirectUrl = Helper::baseUrl(); } $this->safeRedirectAndExit($redirectUrl); } } } do_action('fluent_community/auth/before_auth_page_process', $currentUserId, $inviation); $acceptedForms = ['login', 'register', 'reset_password']; $targetForm = Arr::get($_GET, 'form'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $explicitForm = in_array($targetForm, $acceptedForms, true); if (!$explicitForm) { $targetForm = 'login'; } if ($inviation && !$explicitForm) { if ($inviation->message) { $isUserAvailable = get_user_by('email', $inviation->message); $targetForm = $isUserAvailable ? 'login' : 'register'; } else { $targetForm = 'register'; } } if ($inviation && $currentUserId && $inviation->isValid()) { if ($inviation->message) { $invitedUser = get_user_by('email', $inviation->message); if ($invitedUser && $invitedUser->ID == $currentUserId) { $targetForm = 'accept_invitation'; } } else { $targetForm = 'accept_invitation'; } } $isFluentAuth = AuthHelper::isFluentAuthAvailable(); if (!$isFluentAuth && $targetForm == 'reset_password') { $this->safeRedirectAndExit(wp_lostpassword_url(Helper::baseUrl())); } $portalSettings = Helper::generalSettings(); $titleVar = Arr::get($portalSettings, 'site_title'); $frameData = [ 'logo' => Arr::get($portalSettings, 'logo', ''), /* translators: %s is replaced by the title of the site */ 'title' => sprintf(__('Join %s', 'fluent-community'), $titleVar), 'description' => __('Login or Signup to join the community', 'fluent-community'), 'button_label' => __('Login', 'fluent-community'), ]; if ($targetForm == 'register') { $frameData['button_label'] = __('Signup', 'fluent-community'); if (!$inviation) { $customSignupUrl = Arr::get($portalSettings, 'custom_signup_url'); if ($customSignupUrl) { $this->safeRedirectAndExit($customSignupUrl); } } } $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended do_action('fluent_community/enqueue_global_assets', true); add_action('wp_enqueue_scripts', function () use ($isFluentAuth, $targetForm, $inviation) { wp_enqueue_style('fluent_auth_styles', Vite::getStaticSrcUrl('user_registration.css'), [], FLUENT_COMMUNITY_PLUGIN_VERSION); if(!$isFluentAuth || $targetForm == 'register' || $inviation) { wp_enqueue_script('fluent_auth_scripts', Vite::getStaticSrcUrl('user_registration.js'), [], FLUENT_COMMUNITY_PLUGIN_VERSION, true); wp_localize_script('fluent_auth_scripts', 'fluentComRegistration', array( 'ajax_url' => admin_url('admin-ajax.php'), 'is_logged_in' => is_user_logged_in(), 'redirecting_text' => __('Redirecting...', 'fluent-community'), 'i18n' => [ 'generic_error' => esc_html__('Something went wrong. Please try again later', 'fluent-community'), 'network_error' => esc_html__('Could not reach the server. Please check your connection and try again.', 'fluent-community'), ] )); } }, 10); $pageVars = [ 'title' => $frameData['title'], 'og_title' => $frameData['title'], 'description' => $frameData['description'], 'url' => $currentUrl, 'featured_image' => '', 'css_files' => [], 'js_files' => [], 'js_vars' => [], 'scope' => 'user_registration', 'layout' => 'signup', 'portal' => [ 'logo' => Arr::get($portalSettings, 'logo', ''), /* translators: %s is replaced by the title of the site */ 'title' => \sprintf(__('Welcome to %s', 'fluent-community'), Arr::get($portalSettings, 'site_title')), 'description' => get_bloginfo('description') ] ]; if (Utility::isDev()) { $pageVars['js_files'] = [ Vite::getStaticSrcUrl('public/js/user_registration.js') ]; } $formType = ($targetForm == 'register') ? 'signup' : 'login'; $formSettings = AuthenticationService::getFormattedAuthSettings($formType); if ($formSettings) { $pageVars['portal'] = Arr::get($formSettings, 'banner'); $pageVars['portal']['form'] = Arr::get($formSettings, 'form'); } add_action('fluent_community/headless/content', function ($context) use ($targetForm, $currentUrl, $frameData, $inviation, $formSettings) { $preContent = apply_filters('fluent_community/auth/pre_content', '', $context, $targetForm, $frameData); if ($preContent) { return; } if ($targetForm == 'login') { $frameData['button_label'] = Arr::get($formSettings, 'form.button_label', __('Login', 'fluent-community')); $this->showLoginForm($frameData, $inviation); } else if ($targetForm == 'reset_password') { $frameData['title'] = __('Reset your password', 'fluent-community'); ?>

' . esc_html__('Registration is disabled for this community', 'fluent-community') . '

'; return; } $frameData['hiddenFields'] = [ 'register' => 'yes', 'action' => 'fcom_user_signup', '_fcom_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') ]; $frameData['loginUrl'] = add_query_arg('form', 'login', $currentUrl); $frameData = wp_parse_args(Arr::get($formSettings, 'form'), $frameData); $this->renderRegistrationForm($frameData, $inviation); } }, 10, 1); add_action('fluent_community/headless/head_early', function ($scope) use ($formSettings) { $bannerColors = array_filter(Arr::only($formSettings['banner'], ['title_color', 'text_color', 'background_color'])); $css = Utility::getColorCssVariables(); $sideVars = ''; foreach ($bannerColors as $colorKey => $colorValue) { $sideVars .= '--fcom_' . $colorKey . ': ' . $colorValue . ';'; } ?> renderPageAndExit('headless_page', $pageVars); } public function handleUserSignup() { if (is_user_logged_in()) { return $this->handleSignupCompleted(get_current_user_id()); } $signupNonce = isset($_POST['_fcom_signup_nonce']) ? sanitize_text_field(wp_unslash($_POST['_fcom_signup_nonce'])) : ''; if (!$signupNonce || !wp_verify_nonce($signupNonce, 'fluent_auth_signup_nonce')) { wp_send_json([ 'message' => esc_html__('Invalid request. Please refresh the page and try again.', 'fluent-community') ], 403); } $invitationToken = isset($_POST['invitation_token']) ? sanitize_text_field(wp_unslash($_POST['invitation_token'])) : ''; $hasValidInvitation = false; if ($invitationToken) { $pendingInvitation = Invitation::where('message_rendered', $invitationToken)->first(); $hasValidInvitation = $pendingInvitation && $pendingInvitation->isValid(); } // A valid invitation must still allow signup even when public registration is disabled. if (!$hasValidInvitation && !AuthHelper::isRegistrationEnabled()) { wp_send_json([ 'message' => esc_html__('Registration is disabled for this community', 'fluent-community') ], 422); } $app = App::make('app'); $request = $app->make('request'); $fields = AuthHelper::getFormFields(); $authSettings = AuthenticationService::getAuthSettings(); $termsField = Arr::get($authSettings, 'signup.form.fields.terms'); $fields['terms'] = $termsField ?: $fields['terms']; $requiredFields = array_filter($fields, function ($field) { return ($field['required'] && empty($field['disabled'])) ?? false; }); $keys = array_keys($fields); $data = Arr::only($request->all(), $keys); // remove space and special characters from username $data['username'] = sanitize_user(strtolower(preg_replace('/[^A-Za-z0-9_]/', '', $data['username']))); if (empty($data['username'])) { wp_send_json([ 'message' => esc_html__('Username is not valid', 'fluent-community'), 'errors' => [ 'username' => __('Please provide a valid username', 'fluent-community') ] ], 422); } if (!ProfileHelper::isUsernameAvailable($data['username'])) { wp_send_json([ 'message' => esc_html__('Username is already taken', 'fluent-community'), 'errors' => [ 'username' => __('Username is already taken. Please use a different username', 'fluent-community') ] ], 422); } $invitationToken = $request->get('invitation_token'); $invitation = null; if ($invitationToken) { $invitation = Invitation::where('message_rendered', $invitationToken)->first(); if (!$invitation) { wp_send_json([ 'message' => __('Invalid invitation token', 'fluent-community') ], 422); } if ($invitation->message && $invitation->message != $data['email']) { wp_send_json([ 'message' => esc_html__('Email does not match with the invitation', 'fluent-community') ], 422); } if ($invitation->message) { add_filter('fluent_community/auth/two_factor_enabled', '__return_false'); add_filter('fluent_auth/verify_signup_email', '__return_false'); } } if (!$invitation && AuthenticationService::getCustomSignupPageUrl()) { // we have custom signup page enabled wp_send_json([ 'message' => esc_html__('Direct Registration is disabled for this community', 'fluent-community') ], 422); } $data['email'] = sanitize_email($data['email']); $validations = [ 'full_name' => 'required|max:100|string', 'username' => 'required|unique:users,user_login|unique:fcom_xprofile,username|min:4|max:30', 'email' => 'required|email|unique:users,user_email', 'password' => 'required|same:conf_password|max:50|string', 'conf_password' => 'required|same:password' ]; if (!AuthHelper::isPasswordConfRequired()) { unset($validations['conf_password']); $validations['password'] = 'required|max:50|string'; } foreach ($requiredFields as $key => $field) { if (!isset($data[$key])) { $validations[$key] = 'required'; } } $validator = $app->make('validator')->make($data, $validations, [ 'username.required' => __('Username is required', 'fluent-community'), 'username.unique' => __('Username is already taken', 'fluent-community'), 'email.required' => __('Email is required', 'fluent-community'), 'email.email' => __('Email is not valid', 'fluent-community'), 'email.unique' => __('Email is already taken', 'fluent-community'), 'password.required' => __('Password is required', 'fluent-community'), 'password.same' => __('Password and confirmation password do not match', 'fluent-community'), 'conf_password.required' => __('Password confirmation is required', 'fluent-community'), 'conf_password.same' => __('Password and confirmation password do not match', 'fluent-community'), 'terms.required' => __('You must agree to the terms and conditions', 'fluent-community'), 'full_name.required' => __('Full name is required', 'fluent-community'), ]); if ($validator->fails()) { wp_send_json([ 'message' => __('Please fill in all required fields correctly.', 'fluent-community'), 'errors' => $validator->errors() ], 422); } foreach ($data as $key => $value) { // let's sanitize the data $callBack = $fields[$key]['sanitize_callback'] ?? null; if ($callBack) { $data[$key] = call_user_func($callBack, $value); } } // let's extract the full_name and set the first_name and last_name if (!empty($data['full_name'])) { $nameParts = explode(' ', $data['full_name']); $data['first_name'] = $nameParts[0]; $data['last_name'] = implode(' ', array_slice($nameParts, 1)); unset($data['full_name']); $data = array_filter($data); } $rateLimit = AuthHelper::isAuthRateLimit(); if (is_wp_error($rateLimit)) { wp_send_json([ 'message' => $rateLimit->get_error_message() ], 422); } // We need two-factor authentication here if (AuthHelper::isTwoFactorEnabled()) { // Check if Two Factor code is given $verificationToken = $request->get('__two_fa_signed_token'); if ($verificationToken) { $code = $request->get('_email_verification_code'); if (!$code) { wp_send_json([ 'message' => __('Verification code is required', 'fluent-community') ], 422); } $validated = AuthHelper::validateVerificationCode($code, $verificationToken, $data); if (is_wp_error($validated)) { wp_send_json([ 'message' => $validated->get_error_message() ], 422); } } else { // Let's send the verification code $htmlForm = AuthHelper::get2FaRegistrationCodeForm($data); wp_send_json([ 'verifcation_html' => $htmlForm ]); } } // let's create the user now $userId = AuthHelper::registerNewUser($data['username'], $data['email'], $data['password'], [ 'first_name' => Arr::get($data, 'first_name'), 'last_name' => Arr::get($data, 'last_name'), 'role' => get_option('default_role', 'subscriber') ]); if (is_wp_error($userId)) { wp_send_json([ 'message' => $userId->get_error_message() ], 422); } $this->handleSignupCompleted($userId); } private function handleSignupViaFlentAuth($data) { add_action('fluent_auth/after_creating_user', function ($userId) { $this->handleSignupCompleted($userId); }, 1, 1); add_filter('fluent_auth/signup_enabled', '__return_true'); (new CustomAuthHandler())->handleSignupAjax(); } private function handleSignupCompleted($userId) { // We have the user now let's set the community membership $user = User::find($userId); $user->syncXProfile(true, true); $redirectUrl = Helper::baseUrl(); if (!empty($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $redirectUrl = wp_validate_redirect(sanitize_url(wp_unslash($_REQUEST['redirect_to'])), Helper::baseUrl()); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } $redirectUrl = apply_filters('fluent_community/auth/after_signup_redirect_url', $redirectUrl, $user, $_REQUEST); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $btnText = __('Continue to the community', 'fluent-community'); $html = '

' . __('Congratulations!', 'fluent-community') . '

'; $html .= '

' . __('You have successfully registered to the community', 'fluent-community') . '

'; $html .= '' . $btnText . ''; $html .= '
'; if (!get_current_user_id()) { $wpUser = get_user_by('ID', $userId); AuthHelper::makeLogin($wpUser); } wp_send_json([ 'success_html' => $html, 'redirect_url' => $redirectUrl ]); } public function handleUserLogin() { if (is_user_logged_in()) { $user = get_user_by('ID', get_current_user_id()); return $this->handleUserLoginSuccess($user); } if (AuthHelper::isFluentAuthAvailable()) { wp_send_json([ 'message' => __('This form cannot be used to log in. Please reload the page and try again.', 'fluent-community') ], 422); } $loginNonce = isset($_POST['_fcom_login_nonce']) ? sanitize_text_field(wp_unslash($_POST['_fcom_login_nonce'])) : ''; if (!$loginNonce || !wp_verify_nonce($loginNonce, 'fcom_user_login_nonce')) { wp_send_json([ 'message' => esc_html__('Invalid request. Please refresh the page and try again.', 'fluent-community') ], 403); } $app = App::make('app'); $request = $app->make('request'); $data = $request->all(); $validator = $app->make('validator')->make($data, [ 'log' => 'required', 'pwd' => 'required' ], [ 'log.required' => __('Email is required', 'fluent-community'), 'pwd.required' => __('Password is required', 'fluent-community') ]); if ($validator->fails()) { wp_send_json([ 'message' => __('Please fill all the required fields correctly', 'fluent-community'), 'errors' => $validator->errors() ], 422); } $rateLimit = AuthHelper::isAuthRateLimit(); if (is_wp_error($rateLimit)) { wp_send_json([ 'message' => $rateLimit->get_error_message() ], 422); } $user = wp_authenticate($data['log'], $data['pwd']); if (is_wp_error($user)) { $enumerationCodes = ['invalid_username', 'invalid_email', 'incorrect_password']; if (in_array($user->get_error_code(), $enumerationCodes, true)) { $message = __('Email or password is incorrect.', 'fluent-community'); } else { $message = $user->get_error_message(); } wp_send_json([ 'message' => $message ], 422); } InvitationService::makeLogin($user); $redirectUrl = null; if (!empty($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $redirectUrl = wp_validate_redirect(sanitize_url(wp_unslash($_REQUEST['redirect_to'])), Helper::baseUrl()); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } if (!$redirectUrl) { $redirectUrl = Helper::baseUrl(); } if ($invitationToken = $request->get('invitation_token')) { $maybeRedirectUrl = apply_filters('fluent_community/auth/after_login_with_invitation', null, $user, $invitationToken); if ($maybeRedirectUrl && !is_wp_error($maybeRedirectUrl)) { $redirectUrl = $maybeRedirectUrl; } } $this->handleUserLoginSuccess($user, $redirectUrl); } private function handleUserLoginSuccess($user, $redirectUrl = null) { if (!$redirectUrl) { $redirectUrl = Helper::baseUrl(); } $redirectUrl = apply_filters('fluent_community/auth/after_login_redirect_url', $redirectUrl, $user); $btnText = __('Continue to the community', 'fluent-community'); $html = '

' . __('Welcome back!', 'fluent-community') . '

'; $html .= '

' . __('You have successfully logged in to the community', 'fluent-community') . '

'; $html .= '' . $btnText . ''; $html .= '
'; wp_send_json([ 'success_html' => $html, 'redirect_url' => $redirectUrl ]); } public function showLoginForm($frameData, $invitation = null) { $portalSettings = Helper::generalSettings(); $isFluentAuth = AuthHelper::isFluentAuthAvailable(); $loginSettings = AuthenticationService::getFormattedAuthSettings('login'); $formSettings = Arr::get($loginSettings, 'form'); $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended /* translators: %s is replaced by the title of the site */ $title = sprintf(__('Login to %s', 'fluent-community'), Arr::get($portalSettings, 'site_title')); $description = ''; if ($invitation) { $invitationBy = $invitation->xprofile ? $invitation->xprofile->display_name : __('Someone', 'fluent-community'); if ($invitation->post_id) { $space = BaseSpace::find($invitation->post_id); if ($space) { $title = $space->title . ' - ' . Arr::get($portalSettings, 'site_title'); } } /* translators: %s is replaced by the name of the inviter */ $inviteDescription = \sprintf(__('%s has invited you to join this community. Please login to accept your invitation.', 'fluent-community'), $invitationBy); add_action('fluent_community/before_auth_form_header', function ($formType) use ($inviteDescription) { ?>

'fcom_user_login_form', '_fcom_login_nonce' => wp_create_nonce('fcom_user_login_nonce'), ]; if ($invitation) { $frameData['button_label'] = __('Log In & Accept Invitation', 'fluent-community'); $frameData['hiddenFields']['invitation_token'] = $invitation->message_rendered; } $frameData['title'] = $title; $frameData['description'] = $description; $frameData['defaults'] = [ 'email' => $invitation ? $invitation->message : '' ]; if ($invitation || AuthHelper::isRegistrationEnabled()) { $frameData['signupUrl'] = $signupUrl; } $frameData['settings'] = $formSettings; if (isset($_GET['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $frameData['redirect_to'] = sanitize_url(wp_unslash($_GET['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } App::make('view')->render('auth.login_form', $frameData); } public function renderRegistrationForm($frameData, $invitation = null) { $formFields = AuthHelper::getFormFields($invitation); // Prefill the name from the invitation link's query param when present. $inviteName = isset($_GET['invite_name']) ? sanitize_text_field(wp_unslash($_GET['invite_name'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ($inviteName && isset($formFields['full_name']) && empty($formFields['full_name']['value'])) { $formFields['full_name']['value'] = $inviteName; } $authSettings = AuthenticationService::getAuthSettings(); $termsField = Arr::get($authSettings, 'signup.form.fields.terms'); if ($termsField) { unset($termsField['label']); // add new tab on the link for $termsField['inline_label'] $termsField['inline_label'] = FeedsHelper::addNewTabToLinks($termsField['inline_label']); $formFields['terms'] = $termsField; } $frameData['formFields'] = $formFields; if ($invitation) { $frameData['hiddenFields'] = [ 'invitation_token' => $invitation->message_rendered, 'action' => 'fcom_user_registration', '_fcom_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') ]; $invitationBy = $invitation->xprofile ? $invitation->xprofile->display_name : __('Someone', 'fluent-community'); /* translators: %s is replaced by the name of the inviter */ $inviteDescription = sprintf(__('%s has invited you to join this community. Please create an account to accept your invitation.', 'fluent-community'), $invitationBy); add_action('fluent_community/before_auth_form_header', function ($formType) use ($inviteDescription) { ?>
'yes', 'action' => 'fcom_user_registration', '_fcom_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce'), ]; if (!empty($_GET['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $frameData['hiddenFields']['redirect_to'] = sanitize_url(wp_unslash($_GET['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } } add_action('fluent_community/before_registration_form', function ($frameData) { if (AuthHelper::isFluentAuthAvailable()) { $currentUrl = esc_url(home_url(add_query_arg($_GET, $GLOBALS['wp']->request))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $titlePrefix = __('Signup with', 'fluent-community'); $html = do_shortcode('[fs_auth_buttons redirect="' . $currentUrl . '" title_prefix="' . $titlePrefix . ' " title=""]'); if ($html) { echo '
'; echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo '
'; } } }); App::make('view')->render('auth.user_invitation', $frameData); } }