3

What are techniques you use to show different features / versions of your EE site to different users?

I use "feature flag" techniques in my client-side Javascript (my Javascript Feature Flags library is a temporarily out-of-date example), and want to enable something(s) similar in EE. Scenarios I'd like to support--e.g., on a live, production site, at the same URL:

  • allow developers to see different templates than regular users
  • allow developers to see different content than regular users
  • allow user group A to see one feature, and user group B to see a different feature (e.g., A/B testing, or gradual rollout of new features)

The obvious EE technique that comes to mind is having simple "router" templates, that conditionally embed other templates. Like:

{if member_id==1} {!-- ideally, abstracted to {if dev==1} --}
  {embed="developer/index"}
{if:else}
  {embed="production/index"}
{/if}

I could imagine abstracting that, such that I could set a global feature flag that is triggered by specific conditions (specific member_id, group_id, ip_address or a cookie value). Using Freebie, one could use URL segments as trigger, as well.

I've done this kind of thing on an ad hoc basis within a template, but I'm curious if others have done anything like this, systematically. If so, what technique(s) have you used? Have you found it useful and maintainable over time?

Updated: ideas for ad hoc techniques are appreciated. But I'm especially interested to know of any systematic approaches being taken, and their relative pros / cons for maintainability and ongoing usefulness.

For example, is there some code you make available to every template that allows you to switch things on and off across many templates? Is there an add-on or htaccess technique that gives you top-level control over routing, that allows you to conditionally set routes (based on user, cookie, ip address, etc.)?

4

Have you seen the Focus Lab Master Config? It has environment switching built-in and has become the preferred way to do all that you're asking:

https://github.com/focuslabllc/ee-master-config

If that's too heavy, you can instead create some simple high-level variables yourself in your main index.php file and/or your config.php file depending on, say, your hostname or IP address. Typically you'd have variables for:

  • template file basepath override to use a different set of templates (preferably with some kind of version control to automatically deploy from the dev location to the live location to save the hassle of manually copying from dev to live)
  • environment name for extra per-template conditionals (dev/live/staging etc)
  • entry status for use in channel entries tags (dev site = "open|draft" live site = "open")

Then in your templates any time you use a channel entries tag you'd add status="{env_statuses}" to show draft content on your dev site.

For A/B testing, try Google Experiments in Google Analytics, works better than anything you can build in EE.

1
  • 1
    I'm using master config, and I didn't think of it as serving this need, since it's designed for dev / staging / production being on different machines. But, you gave an idea, that I haven't tried: I already point multiple domains at the same production site as a way of triggering things based on different URLs, e.g. example.com vs dev.example.com go to the same EE. And, I can use this in the master config, too, to set different globals, etc. – Jay F Sep 1 '13 at 19:15
2

Here's a different embed approach to ponder, it may make maintenace much easier. Lets say you have 50 templates, each with the same basic html structure. Under your current approach youd most likely need to add that feature code to each template.

Now, think inside out and consider using partials like we do. about partials

Heres our layout. Template = layout/.default

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{exp:stash:head_title} - LocalYak</title>
        {sn_head}
        {gv_jquery}
        {exp:stash:head_links}
        {gv_google_analytics}
    </head>
    <body>
        {sn_body_top}
        <div id="main_bkgd">
            <div id="main" class="device_{ress} view_{view}">
                {exp:stash:content_above}
                <div id="content" class="{if ress > 1}rounded{/if} {exp:stash:get name='content_class'}">
                    {exp:stash:content}
                </div>
                {exp:stash:content_below}
            </div>
        </div>
        {sn_footer}
    </body>
</html>

And heres a (page) template that calls and uses that layout.

{embed="layout/.default"}
{exp:stash:set name='head_title'}Compare{/exp:stash:set}
{exp:stash:set name='head_links'}
    <link rel='stylesheet' type='text/css' media='screen' href="{stylesheet='advertise/.css_advertise'}" />
    <link rel='stylesheet' type='text/css' media='screen' href="{stylesheet='pages/.css_pages'}" />
    <meta name="description" content="LocalYak | Compare LocalYak advertising packages" />
{/exp:stash:set}
{exp:stash:set name='content_class'}tab-advertise outline{/exp:stash:set}
{exp:stash:set name='content'}
    <div class="page_select body_wrap">
        <h1>Compare packages</h1>
        [put your page content here.... or if you are forced to like we did on this occassion, create an extra embed]{embed="advertise/.select_type"}
    </div>
{/exp:stash:set}

And finally, you could then simply add this conditional to each template where you need dev to see a different layout

{embed="layout/.default{if group_id==123}_dev{/if}"}

Or, go one step further and put your view conditions (using if, not if:else) inside a snippet and use preload_replace.

{embed="layout/.default{sn_view_switch}"}

And of course you would then need to create that extra .default_dev layout. So, whats the benefit of doing it this way? Well, all your special dev view stuff could simply be added into template layout/.default_dev. One spot, easy to maintain.

And if you need to show different content for the page, simply wrap using simple conditional like this

{if segment_3 == ""}
    {exp:stash:set name='content_class'}category splash{/exp:stash:set}
    {exp:stash:set name='content'}some content or tags{/exp:stash:set}
{/if}
{if segment_3 != ""}
    {exp:stash:set name='content_class'}category splash{/exp:stash:set}
    {exp:stash:set name='content'}some different content or tags{/exp:stash:set}
{/if}

Our site is mostly built on that one single default layout, however we do use a total of seven layouts.

4
  • Thanks @dadonike! I'm changing over to using partials / MVVM, too--and I appreciate seeing this as an example. For my feature flag needs, I also have cases where there are alternate "View Models" that could use the same layout, or could use different layouts. So, I still potentially have a routing need that's up a level / that happens before the request reaches the page template (that embeds the partial). – Jay F Aug 31 '13 at 19:20
  • Updated answer. Snippet + Preload_replace could be used to do that – Lloyd Hill Aug 31 '13 at 19:28
  • Updated answer again – Lloyd Hill Aug 31 '13 at 20:04
  • I appreciate the update / additional info. Part of my question is: are folks out there maintaining conditionals like this across all of their templates, and if so, how--and how well is that working, over time. – Jay F Sep 1 '13 at 19:36
1

OK, I'm now developing a systematic way for doing Feature Flags in EE--I'll post more examples as I get a bit farther along.

My "system" does uses config-file global variables, Low Variables and/or Snippets. This should allow flags to alter which templates display, which entry_ids or channels are used, which external assets (CSS, JS) appear on the page, and more. (It's kind-of a combination of the answers from @dadonbike and @JamesSmith.)

It uses a simple PHP class for Feature Flags, that I've created. And, for example, if you need a blunt instrument and can you turn-off page caching, you can use a flag to do this kind of major swap from directly in the config.php:

// EE config items
...
$config['tmpl_file_basepath'] = $_SERVER['DOCUMENT_ROOT'] . '/templates/';

// FeatureFlag overrides
require_once  'php-feature-flags/feature-flags.php';
$FF = new FeatureFlags(array('cookie'=>'FF'));

if ($FF->isFlagged()) {
    $config['tmpl_file_basepath'] = $_SERVER['DOCUMENT_ROOT'] . '/templates-alt/';
}

So, that's checking for a cookie named FF, and if it's present, giving EE a totally different template folder.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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