Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am working on creating a small web-app with wordpress as the framework. It allows you to input a customer and in turn sends an email to the customer with a link back to the website in order to complete a short survey.

I have a "Customer" Custom Post Type which includes the survey questions as custom fields. I'm locking down the content and admin areas etc with s2member which so far has worked great.
However, I am after a way in which I can display a separate page which has the survey form on it and only display it for those which receive the link in an email. Possibly something with cookies and htaccess?

I've tried to find an answer for the last few hours but it's a bit over my head. Any help even if just a push in the right direction would be greatly appreciated!

share|improve this question
add comment

3 Answers

up vote 1 down vote accepted

I think what you want is a custom rewrite rule -- specifically, a custom endpoint.

This would have to live outside s2member.

To start, wrap everything in a class:

<?php
class WPSE71804
{
    // post type key, whatever this happens to be.
    const TYPE = 'customer';

    // endpoint mask, 2 ^ 18
    const EP = 262144;

    // key prefix, used for options
    const PREFIX = 'wpse71804_key_';

    // container for the instance of this class
    private static $ins = null;

    public static function instance()
    {
        is_null(self::$ins) && self::$ins = new self;
        return self::$ins;
    }

    public static function init()
    {
        add_action('plugins_loaded', array(self::instance(), '_setup'));
    }

    // add actions and such.
    public function _setup()
    {
       // we'll add actions here later.
    }
}

There are some constants there that we'll use later.

You'll need to modify your post type registration to include a custom endpoint mask in the rewrite argument.

<?php
class WPSE71804
{
    // snip snip

    // add actions and such.
    public function _setup()
    {
        add_action('init', array($this, 'register'));
    }

    // register the post type
    public function register()
    {
        // rewrite is the args to pay attention to we need 
        // to set a custom endpoint mask
        register_post_type(self::TYPE, array(
            'label'     => __('Customers', 'wpse'),
            'public'    => true,
            'rewrite'   => array(
                'slug'          => 'customer',
                'ep_mask'       => self::EP,
                'with_front'    => false,
            ),
        ));
    }
}

From there, we can hook into init and call add_rewrite_endpoint.

This sets up a rewrite so we can go to yoursite.com/customers/the-post/key/some_key_here.

<?php
class WPSE71804
{
    // snip snip

    // add actions and such.
    public function _setup()
    {
        add_action('init', array($this, 'register'));
        add_action('init', array($this, 'endpoint'), 11);
    }

    // snip snip

    public function endpoint()
    {
        add_rewrite_endpoint('key', self::EP);
    }
}

Now it's just a matter of hooking into template_redirect and validating the key.

<?php
class WPSE71804
{
    // snip snip

    public static function init()
    {
        add_action('plugins_loaded', array(self::instance(), '_setup'));
        register_activation_hook(__FILE__, array(__CLASS__, 'activate'));
    }

    // add actions and such.
    public function _setup()
    {
        add_action('init', array($this, 'register'));
        add_action('init', array($this, 'endpoint'), 11);
        add_action('template_redirect', array($this, 'validate_key'));
    }

    // snip snip

    public function validate_key()
    {
        // not a a singular customer page? Or have an admin user? bail.
        if(!is_singular(self::TYPE) || current_user_can('manage_options'))
            return;

        if(!($_key = get_query_var('key')) || !($key = self::get_key($_key)))
        {
            global $wp_query;
            $wp_query->set_404();
        }

        // if we're here, the key is okay, let the request go through
    }
}

It might also be helpful to create a nice API to use (the above bit of code uses one of those methods).

<?php
class WPSE71804
{
    // snip snip

    /********** API **********/

    // create a new key
    public static function create_key()
    {
        $k = wp_generate_password(24, false);
        self::update_key($k, 'notdone');
        return $k;
    }

    // update a key
    public static function update_key($key, $val='done')
    {
        return update_option(self::PREFIX . $key, $val);
    }

    // delete a key
    public static function delete_key($key)
    {
        return delete_option(self::PREFIX . $key);
    }

    public static function get_key($key)
    {
        return get_option(self::PREFIX . $key);
    }
}

Now you can use the above something like...

<?php
// create a key
$k = WPSE71804::create_key();

// send mail with key here!

// after they submit the survey, you might want to make a note of that.
WPSE71804::update_key($k, 'done');

// or maybe just delete it and revoke access to the page
WPSE71804::delete_key($k);

Not sure how well that will play along with s2member, but essentially this will block all access to the pages without a key on the front end. You may not need to restrict access with s2member at all. Here is all that as a plugin.

share|improve this answer
    
Thanks so much for taking the time to write such a detailed response Chris, I'll be taking the next day or so to wrap my head around it and understand exactly what is going on (my PHP knowledge is terribly basic, trying to learn by building something). This looks exactly the type of thing I'm after so I'll be doing some more reading up on the parts I don't understand and if I get stuck I'll report back. Thanks again! –  Wattsy Nov 10 '12 at 8:36
add comment

My (simple) solution would be put everything you need into

if ( ! is_user_logged_in() ){    
//stuff    
}

and everything in this if will be shown only for those who aren't logged in.

share|improve this answer
    
Thanks for the response! I already have basic if statements working, I guess what I am after is a way of making it so that it isn't possible for a non-user (or even a user I guess?) to come across a survey that doesn't belong to them via a URL manipulation. Is my only option somehow making the URL un-guessable? How would I go about adding a random string to each of the URLs? –  Wattsy Nov 8 '12 at 3:08
    
Well, if I understand correctly, in your case I would use template file for survey page and I'd add some meta data to users, who need to access survey. And then with simple if statement in template file you can check user meta and let people access survey or they would be redirected to home page or somewhere else. –  MadCom Nov 9 '12 at 7:14
    
Thanks for getting back to me! I apologise for the confusing way in which I put the question, probably the reason why I was having trouble finding an appropriate method in the first place! I'm going to have a go at implementing Chris' suggestion as I was to avoid making everyone who needs access a user. Thanks again! –  Wattsy Nov 10 '12 at 8:42
add comment

Posts can have password protected posts post_password column in the wp_posts table. Or you can use http://wordpress.org/extend/plugins/post-password-plugin/ to generate unique tokens.

share|improve this answer
    
Thought about somehow using the password protect feature but wasn't sure I'd be able to get it as transparent as I'd like (don't want the person doing the survey to have to input anything). The plugin looks great! I'll be giving that a go if I struggle implementing Chris' rewrite rule. Thanks for your response! –  Wattsy Nov 10 '12 at 8:39
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.