Recently I’ve been looking for effective ways of performing A/B or Split testing on WordPress powered websites. I have come up with several approaches, the first of which utilizes theme switching to effectively segment users according to assigned percentages and then show them an assigned theme. To maintain consistency, the prescribed theme is stored in a cookie so that the user is always shown the same experience upon returning. Lastly, some user-defined JavaScript is appended to the page with the theme name substituted in to support tracking via services such as Google Analytics or Omniture.
Installation is standard, just activate the plugin. A new option will appear on the Settings section called Split Testing that allows you to configure which themes to use, what percentage of traffic to place into each theme and what JavaScript to append. After setting up your options, go ahead and save the form and you’re all set. With that, simply make sure to add a call to wp_footer() in each of your themes so that the tracking code can be output. You can also manually force a theme by specifying its name with the ‘force_theme’ parameter in the URL like so “http://www.example.com?force_theme=namehere”
Some example tracking code for Google Analytics:
try {
_gaq.push(["_setVar", "[themename]"]);
}
catch(err) {}
try {
pageTracker._setVar("[themename]");
}
catch (err2) {}
The admin interface was inspired by the original spit testing plugin which I had looked at, but it seems that it has been broken for some time, which is what inspired me to build this one.
As far as I know this works up to WP3, although it won’t be effective with caching solutions that stop plugins from running. For that reason, I’m continuing to implement other solutions that work with caching.
Download here.
Posted in PHP | No Comments »
An issue I’ve had in general app GUIs is finding a way to implement the menus and options in such a way that one could potentially abstract some or all of the actual menu details outside of the compiled code and into an XML or scripting format. In this case, I’m building a Java based game using Slick2D, a nicely done engine written on top of LWJGL and OpenGL.
My approach was to create a menu listener for each menu by implementing the InputListener interface. This class would then contain an ArrayList of MenuOptions, a class that implements my custom MenuAction interface (methods such as clickAction, hoverAction, etc). Using this approach allows menus and options to be defined externally and later created at runtime.
The MenuListener then implements the required methods, such as processing mouse clicks like so:
@Override
public void mouseClicked(int button, int x, int y, int clickCount) {
for(MenuOption option: menuOptions) {
if(option.isFocused(x, y)) {
acceptInput = option.clickAction();
return;
}
}
}
What happens here is simple. This listener processes clicks by checking if the click has fallen within the dimensions of the option, then the option’s clickAction is dispatched. Note that the return value is being saved to acceptInput. This variable is returned in the isAcceptingInput method. This allows menu options to return false and disable the listener.
Here is the clickAction implementation in the MenuOptionStart class. Clicking this menu option switches the game into the play state and disables the menu this option belongs to (the main menu).
@Override
public boolean clickAction() {
StateBasedGame game = (StateBasedGame) GameRegistry.GetObject("StateBasedGame");
game.enterState(GameStates.GAMEPLAY.hashCode());
return false;
}
This system is still pretty early and rough, but it has been working out decently for me. It also allows for menu item dimensions, images, ordering, and even visibility to be configured outside the code.
Posted in Java | No Comments »
I recently found a great example of the importance of the var keyword and properly scoping your variables in javascript. In the best case, we should be coding in an object oriented way and utilizing closures to properly contain our code, but sometimes we run into some plain old javascript written the old fashioned (read: messy) way.
By omitting var, we are essentially declaring the variable in the global scope, which is most likely not something we want to be doing. A great example is when declaring an iterator variable for a loop. Without var, the iterator is exposed to any functions called within the loop. If that function also has a variable of the same name that is not locally scoped, you will find that upon completion of the called function, your iterator is suddenly way off.
function parent() {
// some (incorrect) loop calling a function
for(iterator=0; iterator<5; iterator++) {
child();
}
};
// This function can then mess with our iterator!
function child() {
iterator = 99;
}
This example shows how some code hidden away in a called function may inadvertently mess with your variables. It is only made worse when both caller and callee are disregarding scope by omitting var. The proper loop is then obvious:
for(var iterator=0; iterator<5; iterator++)
By doing so, we ensure that no one else can accidentally mess with the internals of our code. This is an easy mistake to make, but fortunately not too difficult to identify and correct.
Posted in jQuery & Javascript | No Comments »
I’ve been using PHP as one of my toolbox languages for a few years, and there are both benefits and drawbacks to it when compared to more formal OO languages like C# and Java. One of the distinct annoyances I have with PHP is the for loop, and it’s not the loop itself, it’s the arrays that the loop iterates over.
The arrays in PHP are great and highly versatile, but they also lack a length field. Many new PHP programmers simply seek out a PHP counting function (count or sizeof) and throw it into the loop.
The result is that this function is called on every iteration of the loop because the loop must re-evaluate the condition each time it runs (hopefully this is obvious). Fortunately, there is an often overlooked syntactical option to store the length in a variable for comparison that doesn’t require an extra line of code before the loop.
for($i = 0, $len = count($myArray); $i < $len; $i++) {
// use $myArray[$i] as usual
}
And that’s it. Extremely simple, but it’s just one of those things that many people don’t even realize until they see it done.
Posted in PHP | No Comments »
I just came across and interesting issue while writing some CakePHP unit tests. I have a field that stores serialized data and the data is automatically unserialized via an afterFind() callback in the model.
When writing the test, I created a fixture and originally used run-time importing from the main database and all my tests worked fine. When I switched to prefabricated records written in the fixture file’s $records variable, I was getting errors with the unserialization.
Upon closer examination, I noticed that the bake script for fixtures was automatically escaping the double quotes in the serialized string, causing things to fail. So the point is, if creating fixture records via bake, be sure to remove any added slashes in fields containing serialized data.
Posted in PHP | No Comments »
Say you have a textarea field on an input form where the user inputs a list of items (like email addresses) and you intend to regularly use this list (for instance to send emails to each email address). Several things must be accomplished here:
- Change the text into an array of items
- Sanitize the items (unlike standard input, this list will be displayed and used much differently, so it is more convenient to store it in a ready-to-use state)
- Validate the items (No point storing invalid email addresses)
- Store the finished list in the database
If any step fails, the form should maintain the original input, so we also won’t touch the data on the controller side. We’ll utilize model hooks and and a custom validation method to do everything we need.
Let’s start by formatting and sanitizing the data so we can validate it. I define beforeValidate() as follows:
function beforeValidate
() {
// I allow this field to be empty
if(empty($this->data['Survey']['recipient_list'])) {
return true;
}
// try splitting by new lines first
$list = preg_split("[\n|\r]", $this->data['Survey']['recipient_list'], -1, PREG_SPLIT_NO_EMPTY
);
$final_list = array();
// check for comma splits
$L = count($list);
for($i=0; $i<$L; $i++) {
$rows = explode(',', $list[$i]);
if(count($rows) > 1) {
foreach($rows as $row) {
if(!empty($row)) {
$final_list[] = $row;
}
}
}
else {
$final_list[] = $list[$i];
}
}
// sanitize the final list
App
::import('Sanitize');
foreach($final_list as &$addr) {
$addr = Sanitize
::paranoid($addr, array('@', '.', '-', '_'));
}
// Update our soon-to-be-validated data
$this->data['Survey']['recipient_list'] = $final_list;
// Save will stop if we don't return true
return true;
}
This is obviously customized for my use, but it handles some pretty standard needs. It splits the input into items based on new lines and commas (any mix of the two). Then sanitizes each item, ensuring to preserve standard email address characters.
We then add our own validation method and define it as follows:
function validateRecipientList
($check) {
if(empty($check['recipient_list'])) {
return true;
}
// Using cake's built in validation class
$Validation = Validation
::getInstance();
foreach($check['recipient_list'] as $addr) {
if(!$Validation->email($addr)) {
return false;
}
}
// Needed to continue
return true;
}
I’m simply ensuring each item is an email address (note the use of Cake’s built in validation class).
Lastly, we utilize beforeSave() to serialize the list and prepare it for storage:
function beforeSave
() {
// serialize recipient list
$this->data['Survey']['recipient_list'] = serialize($this->data['Survey']['recipient_list']);
// Again, needed to continue
return true;
}
All of this will now happen automagically whenever this model’s save() is called. We can even handle unserializing the list via afterFind(), but that’ll be left to the reader.
Posted in PHP | No Comments »
For the past few days, I’ve been working with the newest 1.3 release of CakePHP. It has been a while since I’ve used it, but it seems there are some great new features and some improved documentation.
I’ve been building a generic layer for a new app (and subsequent apps, hence the generic part), including user management, authentication, and user groups/roles. I’ve been trying to discern the most effective approach for implementing very customizable permissions. I am envisioning an interface similar to Drupal, where permissions are based on roles, but can be very specific. Additionally, I’d like to have support for individual user permissions when required as well.
I can see how I would accomplish this with ACL, and have also implemented a custom permissions component, but I keep wondering if there is anyway to achieve such detailed permissions without having to mix in the permissions as conditional statements and jumble up the logic.
I had more to the post, until I realized yet again that I could change directions. More to come when I refine this layer further…
Posted in PHP, Rambling | No Comments »
Here’s a simple one that occurs often. Take for instance, the links on the sidebar of this blog. The links are wrapped in list items, however you’ll notice that you can just as easily click the big list item block as you can the link itself. Additionally, hovering over the list item triggers the hover state of the child link element. Here’s the code used to achieve this.
// Cause the parent list item to function like its child link
// Note we must use window.location as triggering a click event programmatically will not work!
$('li.widget_categories li, li.widget_archives li').click(function() {
window.location = $(this).children('a').attr('href');
});
// When mousing over a list item, we add a class to the child link that imitates its hoverstate.
// Triggering mouse events and the like will only cause recursion errors.
$('li.widget_categories li, li.widget_archives li').mouseenter(function() {
$(this).children('a').addClass('active');
});
// Same as above, only this time we return to normal
$('li.widget_categories li, li.widget_archives li').mouseleave(function() {
$(this).children('a').removeClass('active');
});
Simple stuff here, but that’s about all I seem to ever have time to write down.
Posted in Html/Css, jQuery & Javascript | No Comments »
More and more sites are adding the various slew of social sharing buttons onto their pages and blog posts. There are several widgets like ShareThis and AddToAny that attempt to handle this, but what if you only want to add specific sharing buttons to your page? And what if you want to delay the loading of these buttons so as to not block the loading of your page?
I spent about an hour today solving this problem to implement a Digg, Facebook, and TweetMeMe combo of buttons. The first two weren’t much trouble, but the ReTweet button and its generated iFrame were causing me headache. My soluction simply added the iFrame myself, note also that in order to add javascript via jQuery, one must use a quirky workaround:
tweetmeme_style = 'compact';
function loadSocialButtons() {
var str = '<ul>';
// add digg
str += '<li>';
str += '<script src="http://widgets.digg.com/buttons.js" type="text/javascript">// <![CDATA[';
str += '<';
str += '/script>';
str += '<a class="DiggThisButton DiggCompact"></a>';
str += '</li>';
// add facebook
str += '<li>';
str += '<a id="fb-share" name="fb_share" type="button_count" href="http://www.facebook.com/sharer.php" mce_href="http://www.facebook.com/sharer.php">Share</a>';
str += '<script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" mce_src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" type="text/javascript">';
str += '<';
str += '/script>';
str += '</li>';
// add retweet
str += '<li>';
str += '<iframe width="90" scrolling="no" height="20" frameborder="0" src="http://api.tweetmeme.com/button.js?url=ADD_YOUR_URL&style=compact" mce_src="http://api.tweetmeme.com/button.js?url=&style=compact"></iframe>';
str += '</li>';
str += '</ul>';
$('div#social').html(str);
}
$(document).ready(function() {
setTimeout("loadSocialButtons()", 1000);
});
Make sure to add your page’s url in the TweetMeMe section, you can do this with some server side code.
Posted in jQuery & Javascript | No Comments »