movie icon image

ExpressionEngine How-to Articles

Topics range from beginner to advanced, but are all born out of real world, professional, day-to-day use of ExpressionEngine. Need more information? Get training videos and ebooks on ExpressionEngine from Mijingo.

Password Protected Content Made Simple

Every so often I come across a project where part of the spec involves a private area of content accessible via a password. ExpressionEngine gives us a number of ways to protect content out of the box.

One of the basic approaches is to restrict content to member groups thus requiring a member account for each person. If your content is not member-specific another approach is to create a generic user account and supply each individual with the username and password with which to log in.

Each approach would work in numerous scenarios. However, today I want to look at how we can utilize weblogs on a very basic level to manage password protected content very easily. Our goal is to result in a process that uses default EE functionality and that the “average client” can manage with little difficulty or confusion.

We will be using a single weblog to manage the password-protected content. The type of content is irrelevant at this point so let’s focus on how we can achieve this. At the end I’ll show you a working example of this technique.

How do we store the password?

Considering that we don’t need a deep level of security we only have a few requirements to meet. The most obvious is that no two entries can have the same password. Since we are working “out of the box” with ExpressionEngine we are limited to how we do this. The approach we will take is to use the URL Title field to store the password. EE never stores two URL Titles with the same string so that makes it a perfect way to store our unique password.

Next, we need a way for the user to submit the password to query the database. We will use the standard weblog entries tag pair to do this inside a template running some simple PHP.

So what does this all look like?

The first thing we will need is a weblog, a custom field group and a template. We will work off of the name Private Content so let’s create the following:

Weblog:

  • Name: Private Content
  • Short Name: private_content

Custom Field Group:

  • Name: Private Content fields
  • 1 field called “private_content” set to textarea

Template Group:

  • Name: “private”
  • Templates: index is all we need with PHP on input and no caching

Now that we have created our puzzle pieces go to your weblog groups and assign the custom field to the weblog. Before we dive into templating let’s just add a few entries, so we have something to work with as we add the code to our template.

Go to Publish > Private Content and create an entry with the title “Private Content One” and the URL Title (which is our password) of “password1”. In our content textarea we can just put something simple like “Did this work?”. Feel free to create a few additional entries if you’d like to test them as well. Now that we have some password protected content in the database, we can look at our template.

Our Template Code

Our template code is actually quite concise. We have enabled PHP in our template and set it to input because we will want to use some PHP to determine what to show our users.

Be sure that caching is turned off. Due to the nature of this approach you could potentially cache the private content and we don’t want that.

Let’s first look at the entire template and then go step-by-step.

<h2>Private Content</h2>

<?php
global $IN;

if ( ! 
$the_password $IN->GBL('the_password''POST') ) :

?>

<form action="" method="post">
 <
p>
  
Enter your password:<br/>
  <
input type="password" name="the_password" value="" id="the_password" />
  <
input type="submit" name="submit" value="Access Content &rarr;" id="submit" />
 </
p>
</
form>

<?php else : ?>
   
{exp
:weblog:entries weblog="private_content" 
 
url_title="<?php echo $the_password;?>" 
 
dynamic="off" limit="1"}

 {if no_results}
<p>Your password is incorrectWould you like to
    
<a href="{path='private'}">try again</a>?</p>{/if}

 {private_content}
   
{
/exp:weblog:entries}
   
   
<?php 
endif; ?> 

Let’s look at this in two pieces: PHP and ExpressionEngine tags. Here’s the PHP without anything else distracting us:

<?php
global $IN;

if ( ! 
$the_password $IN->GBL('the_password''POST') ) :

?>

 
// our form

<?php else : ?>

 
// EE weblog entries tag pair

<?php endif; ?> 

The first thing we have to do with PHP is globalize the EE Input class. This gives us access to some of the code that ExpressionEngine provides us, thus reducing the amount of work we have to do. In this case we will be using a function (GBL()) to retrieve a POST variable.

(Now you may be asking yourself, “why would I use a function if I can just get the variable with $_POST[‘variable’]?” Well I’m glad you asked! The GBL() function in ExpressionEngine does a bit of house cleaning for us and first checks if the variable is set and has a value. If it is not set then the function returns FALSE which is very useful to us.)

Moving on to the next line we begin our conditional statement. We are trying to set the variable $the_password to the POST value of the respective input. If it has not been set yet then it will return FALSE. So in plain English the conditional says “if the password has not been set then show our form, otherwise run our ExpressionEngine weblog entries tag pair.”

ExpressionEngine code

Now let’s look at the EE code being used to retrieve our entry. We have a few things going on here so here’s the weblog entries tag pair isolated.

{exp:weblog:entries weblog="private_content" 
 
url_title="<?php echo $the_password;?>" 
 
dynamic="off" limit="1"}
 
 {if no_results}
  
<p>Your password is incorrectWould you like to <a href="{path='private'}">try again</a>?</p>
 
{/if}

  {private_content}
   
{
/exp:weblog:entries} 

A quick look will tell you that we are specifying the url_title directly in the entries tag and setting dynamic to off. This is key to returning the correct result. If dynamic is not set to off then anyone can use the URL to access the private content. We also use the no_results conditional to show the user an error message with a link to try again. If a result is returned then that means that the password the user entered was correct and it will display for them.

A note on security

You may have already realized this, but this approach is not for elements or content that you really need to lock down tightly. The url_title field is stored in the database as plain text so anyone with database access can retrieve this data. I’ve found this approach to be nice for “private” blog posts and similar use while not requiring someone to register on your site (thus using the member_group restriction approach mentioned earlier). Perhaps some add-on developer reading this will be inspired to write a custom fieldtype that is for password storing and actually encrypts the data. Only time will tell.

Taking this one step further

With the use of custom fields this approach can provide quite a nice offering to your site. Consider using FF Matrix and LinkLocker to provide private content for downloads via a single password for the entry. Or perhaps you could have a rich-content article that is private and managed with a WYSIWYG add-on like Wygwam or LG TinyMCE. Using a hint of creativity with this could allow for some pretty neat solutions.

You can try out this method by visiting my example implementation: Password Protected Content Demo.

Posted on Apr 13, 2010

Filed Under: How-To, Displaying Content, ExpressionEngine Development

Pat Brumfield07:24 on 04.13.2010

thanks for this thorough look at setting up password-protected content. i could have used this a few months ago, but instead just built my own little php-based solution. this will definitely come in useful in the future. cheers.

Garrett Winder10:33 on 04.13.2010

Just used this on a current project and, needless to say, it works perfectly. Thanks for the great post!

Erik Reagan10:37 on 04.13.2010

Thanks Pat and Garrett. I’m glad you’ve found use in this smile

cmac18:56 on 04.13.2010

Thank you for this.  Just today we were trying to figure out the best solution to provide simple password protected content on a per entry level rather than having to create a new member group or weblog.  GREAT tip!

hcabbos15:02 on 04.14.2010

Awesome article! The demo isn’t case sensitive, though. It’s supposed to be according to the response text.

Erik Reagan02:16 on 04.15.2010

@cmac
Thanks! Glad you found it useful.

@hcabbos
Thanks for pointing out the case (in)sensitivity. smile

Elliot07:08 on 05.12.2010

$IN->GBL(

no longer seems to work in EE 2.x? Do you know how to access the same thing in EE 2.0.2? Thanks

Erik Reagan09:20 on 05.12.2010

Hey Elliot
For EE2.x you would use something like this I believe

$this->EE->input->post('the_password'); 
Michael Hughes23:42 on 11.02.2010

Hi Erik,

Thanks for the great article. Has it been determined if this does work in EE 2? I’ve tried to implement the code that is listed in the entry above but I’ve had no luck. Any insight would be greatly appreciated.

Thanks

3 Roads Media01:51 on 11.03.2010

Brilliant post—just what I needed. The fix for EE2 is swapping out:

if ( ! $the_password = $IN->GBL(‘the_password’, ‘POST’) ) :

with:
$the_password = $this->EE->input->post(‘the_password’);
if ( ! $the_password ) :

Michael Hughes02:34 on 11.03.2010

Thanks! That worked perfectly!

dr3w19:21 on 12.07.2010

i tried, but could not make it work, using EE, tried the changes above and it seemed to work, but after hitting submit, it comes back to the same page. no content or wrong password does anything…

any advise?

also, do i need to change weblog to channel in the code above?

Erik Reagan16:11 on 12.08.2010

@dr3w
Yes, for EE 2.x you need to change “weblog” to “channel”

dr3w16:22 on 12.08.2010

Erik,

thanks.  I have done that too, but I still am unable to get any results from it.  I have turned php on for the template, set to input,.. but no matter what, all i see is the box for entering the info…  and no matter if i try the right or wrong password, brings me back to the same page.  what can I be missing/done wrong? any idea?  thanks again, sorry for the trouble…

Erik Reagan16:23 on 12.08.2010

Tough to say. Why don’t you try to catch me on AIM or Skype sometime and I can take a look.

dr3w07:49 on 12.11.2010

Erik,

Thanks again for your very kind offer.  After speaking with you, we determined that the problem was with cutting and pasting the code, where the “‘s came wrong… thus, after fixing it, it worked like a charm.

Thanks again,

Erik Reagan07:50 on 12.11.2010

Glad to help! smile

Jessica13:16 on 02.07.2011

Hi Erik,

Thank you for sharing this!  Where in the above example(s) do I set/replace the desired password?  Also, how would you assign more than one password?

Thanks a ton!

Erik Reagan14:52 on 02.07.2011

Hi Jessica

The password is set in the URL Title field. Due to the nature of that field, you cannot store multiple passwords for a single entry with this method.

Erik

Jessica15:45 on 02.07.2011

Hi Erik,

Thank you for your quick response smile

Are there any issues in using this method with Structure? 

I’m using EE 2.x with Structure.  I’ve updated the code for 2.x compatibility as written in the above comments (and fixed the “s); however nothing happens when I enter the password/url title, or when I enter an incorrect password.

This is what I have in my template:

<?php
global $IN;
$the_password = $this->EE->input->post(‘POST’);
if ( ! $the_password ) :
?>
...
 
<form action=”” method=“post”>
<label>Enter your password:</label>
<input type=“password” name=“the_password” value=”” id=“the_password” /></p>
<input type=“submit” name=“submit” value=”” id=“submit” /></p>
</form>

<?php else : ?>

exp:channel:entries channel=”{staticchannel}” channelslug=”{staticchannelslug}” url_title=”<?php echo $the_password;?>” dynamic=“off” limit=“1” entry_id=”{entry_id}” disable=“categories|category_fields|member_data|pagination|trackbacks”}
 
...
 
  {if no_results}Your password is incorrect. Would you like to
  try again?{/if} 
 
  {/exp:channel:entries}

<?php endif; ?>

And here is the page:
http://www.dev.desertsunresort.com/the-resort/homeowners/

Thanks again for all of your help!

Erik Reagan15:47 on 02.07.2011

In EE 2.x the dynamic tag changed. Now instead of

dynamic="off" 

you use

dynamic="no" 

See if that change does the magic. smile

Erik Reagan15:49 on 02.07.2011

Jessica,

I also noticed you had an ‘entry_id’ parameter in your tag. You should remove that. I’m not sure if it would cause a problem but it’s not needed in this scenario since the url_title is being pulled from the _POST data.

Jessica16:11 on 02.07.2011

Hi Erik,

Thanks again for being so quick to help out!  I changed the dynamic parameter (silly me) to the new 2.x setting, and also removed the entry_id parameter…  still isn’t working :(

I’ll keep trying and I’ll let you know if/what I figure out! 

If you have any other ideas please let me know smile

Daniel18:24 on 03.13.2011

Hey Eric,
thank you dude. I was looking for more information on that issue and honestly its working really well for my private content. Thank you again.

Regards

Jon Bishop22:35 on 03.27.2011

Fantastic post! Is there a way to display multiple entries?

Thanks!

Erik Reagan10:45 on 03.28.2011

Daniel,

Glad you found this useful!

Jon,

Since we’re using the url_title to specify an entry there’s no direct way to use multiple entries.

I suppose you could use a playa field to map multiple entries to a single password-specific entry. That creativity is up to you though smile

Best,
Erik

Jon Bishop13:46 on 03.28.2011

Thanks Erik! By the way, the email I received about your comment being posted gave me the link below to come back to this post:http://eeinsider:8888/index.php/password-protected-content-made-simple/

Post a Comment
Commenting is not available in this section entry.

Hosting by EngineHosting

ExpressionEngine Training Videos and Screencasts