Skip to content

Instantly share code, notes, and snippets.

@mjangda
Last active November 17, 2020 02:47
Show Gist options
  • Save mjangda/d5b8082ca902493318478f45daf207da to your computer and use it in GitHub Desktop.
Save mjangda/d5b8082ca902493318478f45daf207da to your computer and use it in GitHub Desktop.
Client-side, randomized, percentage-based segmentation using the WordPress Cache Segmentation API. Only supports 1 experiment and 1 control group.
<?php
require_once( WPMU_PLUGIN_DIR . '/cache/class-vary-cache.php' );
use Automattic\VIP\Cache\Vary_Cache;
Vary_Cache::register_group( 'beta' );
add_action( 'wp_head', function() {
// TODO: if possible, load this directly very early in the header.php (instead of wp_head)
// TODO: Could possibly even skip loading this if `Vary_Cache::is_user_in_group( 'beta' )`
include_once( __DIR__ . '/inline-script.php' );
}, -1000 );
add_action( 'wp_footer', function() {
$in_beta = Vary_Cache::is_user_in_group_segment( 'beta', 'yes' );
if ( ! $in_beta ) {
return;
}
?>
<style>
body {
background: yellow;
}
</style>
<?php
} );
<?php
use Automattic\VIP\Cache\Vary_Cache;
// Percentage of users to put in the experiment
$experiment_threshold = 10;
$cookie_name = Vary_Cache::COOKIE_SEGMENT;
$cookie_expires = time() + MONTH_IN_SECONDS;
$cookie_expires_formatted = gmdate( 'r', $cookie_expires );
$cookie_domain = COOKIE_DOMAIN;
$cookie_path = COOKIEPATH;
// Make sure we use the same server-side formatting for the cookie value.
// This is to allow us to use the Vary_Cache helper functions
// TODO: Vary_Cache should probably make stringify_groups a public method. Or just have this client-side stuff built-in :)
// TODO: Notably, this will not work if you have other cache segmentation happening server-side.
$cookie_value_control_group = 'vc-v1__beta_--_no';
$cookie_value_experiment_group = 'vc-v1__beta_--_yes';
?>
<script>
( function() {
// What percentage of users should land in the new group?
const threshold = <?php echo absint( $experiment_threshold ); ?>;
// TODO: skip if the browser or user doesn't support cookies
// If we have the cookie already, don't bother segmenting again
const hasCookie = -1 !== document.cookie.indexOf( '<?php echo esc_js( sprintf( '%s=', $cookie_name ) ); ?>' );
if ( hasCookie ) {
console.log( 'Have cookie; skipping segmentation' );
return;
}
// TODO: if bot user, don't segment
let inExperiment = false;
let cookieValue = '<?php echo esc_js( $cookie_value_control_group ); ?>';
const randomNumber = Math.floor( Math.random() * Math.floor( 100 ) );
if ( randomNumber < threshold ) {
console.log( 'Adding to experiment group' );
inExperiment = true;
cookieValue = '<?php echo esc_js( $cookie_value_experiment_group ); ?>';
} else {
console.log( 'Adding to control group' );
}
// Set the cache segementation cookie.
// Note: we set the cookie for both control and experiment groups.
// Otherwise we run the risk of control group users get re-assigned into the experiment.
// This does create an extra cache bucket for control users though which is unfortunate.
document.cookie = '<?php echo sprintf(
"%s=' + cookieValue + '; expires=%s; path=%s; domain=%s;",
// TODO: Consider better escaping for the values below, something that is cookie-friendly
esc_js( $cookie_name ),
esc_js( $cookie_expires_formatted ),
esc_js( $cookie_path ),
esc_js( $cookie_domain )
); ?>';
// Reload the page for users in experiment to make sure they get the correct
if ( inExperiment ) {
console.log( 'Reloading from experiment group' );
window.location.reload();
}
} )();
</script>
<?php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment