This is the documentation for concrete5 version 5.6 and earlier. View Current Documentation

Now updated for concrete5.6!

Please note: the code we'll borrow from the Login and Register pages below is included only for example. We strongly recommend you use the latest code from your own core's login and register single pages, no matter what version of concrete5 you're using. The same concepts & approach should still apply.

You'll also likely want to spend some time stripping out any core styles from the HTML you recycle, and tweak it to suit your site's theme.

Overview

By default, the Login and Register pages are separate entities in the concrete5 core. If your site’s requirements specify that users should be able to either login or register from the same page, one easy option would be to create a new single page that submits its form information to the already existing login and register pages.

This how-to is a companion to Theming System Pages, where I explain how to apply your custom theme to single pages (like login and registration).

Remember, if you haven't already added this necessary validation code to your theme's view.php, now is a good time to do so! This will make sure empty & incorrectly filled-in form elements are caught by your individual login and register pages when we submit the form:

<?php Loader::element('system_errors', array('error' => $error)); ?>

The approach

Both Login and Register are single pages. While it’s possible to override either or both, this approach presents a few challenges involving specific functionality that’s tied to these pages. Making a new single page with forms that submit to the existing pages lets you customize the front end of your login process while leaving the complicated part of the login / registration process untouched. We’ll replicate the form fields we need on our new page and submit them to the existing login and registration pages.

Make the new single page

First, let’s create our new single page. Since it’s a custom page, we’ll place in in the single_pages override directory: (your_site_root)/single_pages/. Let’s call our new page sign_in.php.

Let’s think about how we’d like this combined login / register page to look. For the sake of simplicity, let’s use a side-by-side layout where our two forms live right next to each other, divided by a separator.

Bring in our borrowed form elements

Now we’ll take a look at the form elements on the Register page and re-create them in our new page. Open the core login.php page in /concrete/single_pages and let’s take a look what’s inside.

Here's the code I borrowed from the Login page. Note that the form still submits to /login, where we'll do our validation, etc. I added an ID to help style the div, but otherwise it's pretty much just the core login page code:

<?php  defined('C5_EXECUTE') or die("Access Denied."); ?>
<?php  Loader::library('authentication/open_id');?>


<?php  $form = Loader::helper('form'); ?>

<script type="text/javascript">
$(function() {
    $("input[name=uName]").focus();
});
</script>

<?php  if (isset($intro_msg)) { ?>
<div class="alert-message block-message success"><p><?php echo $intro_msg?></p></div>
<?php  } ?>

<div class="row">
<div class="span10 offset1">
<div class="page-header">
    <h1><?php echo t('Sign in to %s', SITE)?></h1>
</div>
</div>
</div>

<?php  if( $passwordChanged ){ ?>

    <div class="block-message info alert-message"><p><?php echo t('Password changed.  Please login to continue. ') ?></p></div>

<?php  } ?> 

<?php  if($changePasswordForm){ ?>

    <p><?php echo t('Enter your new password below.') ?></p>

    <div class="ccm-form">  

    <form method="post" action="<?php echo $this->url( '/login', 'change_password', $uHash )?>"> 

        <div class="control-group">
        <label for="uPassword" class="control-label"><?php echo t('New Password')?></label>
        <div class="controls">
            <input type="password" name="uPassword" id="uPassword" class="ccm-input-text">
        </div>
        </div>
        <div class="control-group">
        <label for="uPasswordConfirm"  class="control-label"><?php echo t('Confirm Password')?></label>
        <div class="controls">
            <input type="password" name="uPasswordConfirm" id="uPasswordConfirm" class="ccm-input-text">
        </div>
        </div>

        <div class="actions">
        <?php echo $form->submit('submit', t('Sign In') . ' >')?>
        </div>
    </form>

    </div>

<?php  }elseif($validated) { ?>

<h3><?php echo t('Email Address Verified')?></h3>

<div class="success alert-message block-message">
<p>
<?php echo t('The email address <b>%s</b> has been verified and you are now a fully validated member of this website.', $uEmail)?>
</p>
<div class="alert-actions"><a class="btn small" href="<?php echo $this->url('/')?>"><?php echo t('Continue to Site')?></a></div>
</div>


<?php  } else if (isset($_SESSION['uOpenIDError']) && isset($_SESSION['uOpenIDRequested'])) { ?>

<div class="ccm-form">

<?php  switch($_SESSION['uOpenIDError']) {
    case OpenIDAuth::E_REGISTRATION_EMAIL_INCOMPLETE: ?>

        <form method="post" action="<?php echo $this->url('/login', 'complete_openid_email')?>">
            <p><?php echo t('To complete the signup process, you must provide a valid email address.')?></p>
            <label for="uEmail"><?php echo t('Email Address')?></label><br/>
            <?php echo $form->text('uEmail')?>

            <div class="ccm-button">
            <?php echo $form->submit('submit', t('Sign In') . ' >')?>
            </div>
        </form>

    <?php  break;
    case OpenIDAuth::E_REGISTRATION_EMAIL_EXISTS:

    $ui = UserInfo::getByID($_SESSION['uOpenIDExistingUser']);

    ?>

        <form method="post" action="<?php echo $this->url('/login', 'do_login')?>">
            <p><?php echo t('The OpenID account returned an email address already registered on this site. To join this OpenID to the existing user account, login below:')?></p>
            <label for="uEmail"><?php echo t('Email Address')?></label><br/>
            <div><strong><?php echo $ui->getUserEmail()?></strong></div>
            <br/>

            <div>
            <label for="uName"><?php  if (USER_REGISTRATION_WITH_EMAIL_ADDRESS == true) { ?>
                <?php echo t('Email Address')?>
            <?php  } else { ?>
                <?php echo t('Username')?>
            <?php  } ?></label><br/>
            <input type="text" name="uName" id="uName" <?php echo  (isset($uName)?'value="'.$uName.'"':'');?> class="ccm-input-text">
            </div>          <div>

            <label for="uPassword"><?php echo t('Password')?></label><br/>
            <input type="password" name="uPassword" id="uPassword" class="ccm-input-text">
            </div>

            <div class="ccm-button">
            <?php echo $form->submit('submit', t('Sign In') . ' >')?>
            </div>
        </form>

    <?php  break;

    }
?>

</div>

<?php  } else if ($invalidRegistrationFields == true) { ?>

<div class="ccm-form">

    <p><?php echo t('You must provide the following information before you may login.')?></p>

<form method="post" action="<?php echo $this->url('/login', 'do_login')?>">
    <?php  
    $attribs = UserAttributeKey::getRegistrationList();
    $af = Loader::helper('form/attribute');

    $i = 0;
    foreach($unfilledAttributes as $ak) { 
        if ($i > 0) { 
            print '<br/><br/>';
        }
        print $af->display($ak, $ak->isAttributeKeyRequiredOnRegister());   
        $i++;
    }
    ?>

    <?php echo $form->hidden('uName', Loader::helper('text')->entities($_POST['uName']))?>
    <?php echo $form->hidden('uPassword', Loader::helper('text')->entities($_POST['uPassword']))?>
    <?php echo $form->hidden('uOpenID', $uOpenID)?>
    <?php echo $form->hidden('completePartialProfile', true)?>

    <div class="ccm-button">
        <?php echo $form->submit('submit', t('Sign In'))?>
        <?php echo $form->hidden('rcID', $rcID); ?>
    </div>

</form>
</div>  

<?php  } else { ?>

<form method="post" action="<?php echo $this->url('/login', 'do_login')?>" class="form-horizontal">

<div class="row">
<div class="span10 offset1">
<div class="row">
<div class="span5">

<fieldset>

    <legend><?php echo t('User Account')?></legend>

    <div class="control-group">

    <label for="uName" class="control-label"><?php  if (USER_REGISTRATION_WITH_EMAIL_ADDRESS == true) { ?>
        <?php echo t('Email Address')?>
    <?php  } else { ?>
        <?php echo t('Username')?>
    <?php  } ?></label>
    <div class="controls">
        <input type="text" name="uName" id="uName" <?php echo  (isset($uName)?'value="'.$uName.'"':'');?> class="ccm-input-text">
    </div>

    </div>
    <div class="control-group">

    <label for="uPassword" class="control-label"><?php echo t('Password')?></label>

    <div class="controls">
        <input type="password" name="uPassword" id="uPassword" class="ccm-input-text" />
    </div>

    </div>
</fieldset>

<?php  if (OpenIDAuth::isEnabled()) { ?>
    <fieldset>

    <legend><?php echo t('OpenID')?></legend>

    <div class="control-group">
        <label for="uOpenID" class="control-label"><?php echo t('Login with OpenID')?>:</label>
        <div class="controls">
            <input type="text" name="uOpenID" id="uOpenID" <?php echo  (isset($uOpenID)?'value="'.$uOpenID.'"':'');?> class="ccm-input-openid">
        </div>
    </div>
    </fieldset>
<?php  } ?>

</div>
<div class="span4 offset1">

    <fieldset>

    <legend><?php echo t('Options')?></legend>

    <?php  if (isset($locales) && is_array($locales) && count($locales) > 0) { ?>
        <div class="control-group">
            <label for="USER_LOCALE" class="control-label"><?php echo t('Language')?></label>
            <div class="controls"><?php echo $form->select('USER_LOCALE', $locales)?></div>
        </div>
    <?php  } ?>

    <div class="control-group">
        <label class="checkbox"><?php echo $form->checkbox('uMaintainLogin', 1)?> <span><?php echo t('Remain logged in to website.')?></span></label>
    </div>
    <?php  $rcID = isset($_REQUEST['rcID']) ? Loader::helper('text')->entities($_REQUEST['rcID']) : $rcID; ?>
    <input type="hidden" name="rcID" value="<?php echo $rcID?>" />

    </fieldset>
</div>
<div class="span10">
    <div class="actions">
    <?php echo $form->submit('submit', t('Sign In') . ' >', array('class' => 'primary'))?>
    </div>
</div>
</div>
</div>
</div>
</form>

<a name="forgot_password"></a>

<form method="post" action="<?php echo $this->url('/login', 'forgot_password')?>" class="form-horizontal">
<div class="row">
<div class="span10 offset1">

<h3><?php echo t('Forgot Your Password?')?></h3>

<p><?php echo t("Enter your email address below. We will send you instructions to reset your password.")?></p>

<input type="hidden" name="rcID" value="<?php echo $rcID?>" />

    <div class="control-group">
        <label for="uEmail" class="control-label"><?php echo t('Email Address')?></label>
        <div class="controls">
            <input type="text" name="uEmail" value="" class="ccm-input-text" >
        </div>
    </div>

    <div class="actions">
        <?php echo $form->submit('submit', t('Reset and Email Password') . ' >')?>
    </div>

</div>
</div>  
</form>


<?php  if (ENABLE_REGISTRATION == 1) { ?>
<div class="row">
<div class="span10 offset1">
<div class="control-group">
<h3><?php echo t('Not a Member')?></h3>
<p><?php echo t('Create a user account for use on this website.')?></p>
<div class="actions">
<a class="btn" href="<?php echo $this->url('/register')?>"><?php echo t('Register here!')?></a>
</div>
</div>
</div>
</div>
<?php  } ?>

<?php  } ?>

And here's what I'm using from the Register page:

<div class="row">
<div class="span10 offset1">
<div class="page-header">
    <h1><?php echo t('Site Registration')?></h1>
</div>
</div>
</div>

<div class="ccm-form">

<?php  
$attribs = UserAttributeKey::getRegistrationList();

if($success) { ?>
<div class="row">
<div class="span10 offset1">
<?php   switch($success) { 
        case "registered": 
            ?>
            <p><strong><?php echo $successMsg ?></strong><br/><br/>
            <a href="<?php echo $this->url('/')?>"><?php echo t('Return to Home')?></a></p>
            <?php  
        break;
        case "validate": 
            ?>
            <p><?php echo $successMsg[0] ?></p>
            <p><?php echo $successMsg[1] ?></p>
            <p><a href="<?php echo $this->url('/')?>"><?php echo t('Return to Home')?></a></p>
            <?php 
        break;
        case "pending":
            ?>
            <p><?php echo $successMsg ?></p>
            <p><a href="<?php echo $this->url('/')?>"><?php echo t('Return to Home')?></a></p>
            <?php 
        break;
    } ?>
            </div>
</div>
<?php  
} else { ?>

<form method="post" action="<?php echo $this->url('/register', 'do_register')?>" class="form-horizontal">
<div class="row">
<div class="<?php  if (count($attribs) > 0) {?>span5<?php  } else {?>span10<?php  } ?> offset1">
    <fieldset>
        <legend><?php echo t('Your Details')?></legend>
        <?php  if ($displayUserName) { ?>
                <div class="control-group">
                <?php echo  $form->label('uName',t('Username')); ?>
                <div class="controls">
                    <?php echo  $form->text('uName'); ?>
                </div>
            </div>
        <?php } ?>

        <div class="control-group">
            <?php  echo $form->label('uEmail',t('Email Address')); ?>
            <div class="controls">
                <?php  echo $form->text('uEmail'); ?>
            </div>
        </div>
        <div class="control-group">
            <?php  echo $form->label('uPassword',t('Password')); ?>
            <div class="controls">
                <?php  echo $form->password('uPassword'); ?>
            </div>
        </div>
        <div class="control-group">
            <?php  echo $form->label('uPasswordConfirm',t('Confirm Password')); ?>
            <div class="controls">
                <?php  echo $form->password('uPasswordConfirm'); ?>
            </div>
        </div>

    </fieldset>
</div>
<?php  if (count($attribs) > 0) { ?>
<div class="span5">
    <fieldset>
        <legend><?php echo t('Options')?></legend>
    <?php 

    $af = Loader::helper('form/attribute');

    foreach($attribs as $ak) { ?> 
            <?php echo  $af->display($ak, $ak->isAttributeKeyRequiredOnRegister()); ?>
    <?php  }?>
    </fieldset>
</div>
<?php  } ?>
<div class="span10 offset1 ">
    <?php  if (ENABLE_REGISTRATION_CAPTCHA) { ?>

        <div class="control-group">
            <?php  $captcha = Loader::helper('validation/captcha'); ?>          
            <?php echo $captcha->label()?>
            <div class="controls">
            <?php 
              $captcha->showInput(); 
              $captcha->display();
              ?>
            </div>
        </div>


    <?php  } ?>

</div>
<div class="span10 offset1">
    <div class="actions">
    <?php echo $form->hidden('rcID', $rcID); ?>
    <?php echo $form->submit('register', t('Register') . ' >', array('class' => 'primary'))?>
    </div>
</div>

</div>
</form>
<?php  } ?>

</div>

Now let's clean up a couple of things. Since we don't need the "Register here!" link from the original core login page, let's cut it (and the conditional that surrounds it) out: Remove all this code:

<?php  if (ENABLE_REGISTRATION == 1) { ?>
<div class="row">
<div class="span10 offset1">
<div class="control-group">
<h3><?php echo t('Not a Member')?></h3>
<p><?php echo t('Create a user account for use on this website.')?></p>
<div class="actions">
<a class="btn" href="<?php echo $this->url('/register')?>"><?php echo t('Register here!')?></a>
</div>
</div>
</div>
</div>
<?php  } ?>

Now notice that the code we copied from the Registration page seems to be missing the Username field. That's because there's another now-unnecessary conditional wrapped around it. Comment this out, or remove the PHP tags that contain the if statement and its closing bracket:

<?php  //if ($displayUserName) { ?>
                <div class="control-group">
                <?php echo  $form->label('uName',t('Username')); ?>
                <div class="controls">
                    <?php echo  $form->text('uName'); ?>
                </div>
            </div>
        <?php // } ?>

After we make a single page, we need to add it to our site from Dashboard > Pages and Themes > Single Pages. The new page will be available at index.php/sign_in.

Here's the end result:

our finished product

If a form field needs to be corrected, users will land on the single page they’re submitting their form to—where they can correct their data and proceed. If you’ve already skinned your login and registration pages to match your site’s theme, correcting a form and re-submitting it should be a fairly seamless process for the end user.

Here's our login page, incomplete form submitted:

login validate

And if a user doesn't fill out the registration form correctly, our register page handles the error messages:

register validate

Conclusion

Now we can direct users to our new unified sign-in page as needed. We've left the core Login and Register pages intact, and themed / skinned them to match our theme to present a unified experience for our users.

Loading Conversation