diff --git a/.github/workflows/cs-lint.yml b/.github/workflows/cs-lint.yml
index fe4dac4..68536e8 100644
--- a/.github/workflows/cs-lint.yml
+++ b/.github/workflows/cs-lint.yml
@@ -62,9 +62,9 @@ jobs:
xml-schema-file: ./vendor/phpunit/phpunit/phpunit.xsd
# Check the code-style consistency of the PHP files.
-# - name: Check PHP code style
-# continue-on-error: true
-# run: vendor/bin/phpcs --report-full --report-checkstyle=./phpcs-report.xml
+ - name: Check PHP code style
+ continue-on-error: true
+ run: vendor/bin/phpcs --report-full --report-checkstyle=./phpcs-report.xml
-# - name: Show PHPCS results in PR
-# run: cs2pr ./phpcs-report.xml
+ - name: Show PHPCS results in PR
+ run: cs2pr ./phpcs-report.xml
diff --git a/.github/workflows/integrations.yml b/.github/workflows/integrations.yml
deleted file mode 100644
index 8f5577e..0000000
--- a/.github/workflows/integrations.yml
+++ /dev/null
@@ -1,85 +0,0 @@
-name: Run PHPUnit
-
-on:
- # Run on all pushes and on all pull requests.
- # Prevent the "push" build from running when there are only irrelevant changes.
- push:
- paths-ignore:
- - "**.md"
- pull_request:
- # Allow manually triggering the workflow.
- workflow_dispatch:
-
-jobs:
- test:
- name: WP ${{ matrix.wordpress }} on PHP ${{ matrix.php }}
- # Ubuntu-20.x includes MySQL 8.0, which causes `caching_sha2_password` issues with PHP < 7.4
- # https://www.php.net/manual/en/mysqli.requirements.php
- # TODO: change to ubuntu-latest when we no longer support PHP < 7.4
- runs-on: ubuntu-18.04
-
- env:
- WP_VERSION: ${{ matrix.wordpress }}
-
- strategy:
- matrix:
- wordpress: ["5.5", "5.6", "5.7"]
- php: ["5.6", "7.0", "7.1", "7.2", "7.3", "7.4"]
- include:
- - php: "8.0"
- # Ignore platform requirements, so that PHPUnit 7.5 can be installed on PHP 8.0 (and above).
- composer-options: "--ignore-platform-reqs"
- extensions: pcov
- ini-values: pcov.directory=., "pcov.exclude=\"~(vendor|tests)~\""
- coverage: pcov
- exclude:
- - php: "8.0"
- wordpress: "5.5"
- fail-fast: false
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Setup PHP ${{ matrix.php }}
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php }}
- extensions: ${{ matrix.extensions }}
- ini-values: ${{ matrix.ini-values }}
- coverage: ${{ matrix.coverage }}
-
- - name: Setup problem matchers for PHP
- run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
-
- # Setup PCOV since we're using PHPUnit < 8 which has it integrated. Requires PHP 7.1.
- # Ignore platform reqs to make it install on PHP 8.
- # https://github.com/krakjoe/pcov-clobber
- - name: Setup PCOV
- if: ${{ matrix.php == 8.0 }}
- run: |
- composer require pcov/clobber --ignore-platform-reqs
- vendor/bin/pcov clobber
-
- - name: Setup Problem Matchers for PHPUnit
- run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
-
- - name: Install Composer dependencies
- uses: ramsey/composer-install@v1
- with:
- composer-options: "${{ matrix.composer-options }}"
-
- - name: Start MySQL Service
- run: sudo systemctl start mysql.service
-
- - name: Prepare environment for integration tests
- run: composer prepare-ci
-
- - name: Run integration tests (single site)
- if: ${{ matrix.php != 8.0 }}
- run: composer test
- - name: Run integration tests (single site with code coverage)
- if: ${{ matrix.php == 8.0 }}
- run: composer coverage-ci
- - name: Run integration tests (multisite)
- run: composer test-ms
diff --git a/cheeztest-examples.php b/cheeztest-examples.php
index 8e866e0..359e390 100644
--- a/cheeztest-examples.php
+++ b/cheeztest-examples.php
@@ -1,29 +1,36 @@
'chrome-ab',
- 'groups' => array(
- 'active' => array(
+ 'name' => 'chrome-ab',
+ 'groups' => array(
+ 'active' => array(
'threshold' => 30,
),
'control' => array(
'threshold' => 70,
- )
+ ),
),
- 'is_qualified' => 'return stripos( $_SERVER[ "HTTP_USER_AGENT" ], "Chrome" ) !== false;'
+ 'is_qualified' => 'return stripos( $_SERVER[ "HTTP_USER_AGENT" ], "Chrome" ) !== false;',
)
);
-// This will display a fixed position bar at the bottom of the screen to users in the test condition (i.e. 30% of Chrome users)
+// This will display a fixed position bar at the bottom of the screen to users in the test condition (i.e. 30% of Chrome users).
if ( CheezTest::is_in_group( 'chrome-ab', 'active' ) ) {
- add_action( 'wp_footer', function() {
- ?>
+ add_action(
+ 'wp_footer',
+ function() {
+ ?>
Howdy, Chrome user!
@@ -44,6 +51,7 @@
line-height: 28px;
}
- check if user is qualified to participate >
- * get segment from either server or cookie > execute 'action' callback if present
- * > write segment cookie if neccessary
- *
- * User's qualification, segment, and group tests are done in batcache
- * so as to ensure correct cache variants are served.
- *
- * User's segment is assigned via client-side javascript. Mutliple test
- * segments are assigned at once - so if a user is qualified to participate
- * in more than one test, all segments are assigned at the same time. When
- * segments need to be set, a small javascript is injected into the
- * via a call to CheezTest::write_segment_cookie(). This javascript sets a
- * cookie to retain the assigned segment.
- *
- * Test case data (name, is_qualified, & group) are stored in the $active_tests
- * static hash and made accessible via the 'is_qualified_for', 'get_group_for', and
- * 'is_in_group' static methods. This enables theme branching via:
- *
- * if ( CheezTest::is_qualified_for( 'my-example-test' ) {
- * //test-specific stuff goes here
- * }
*
- * - or -
- *
- * if ( CheezTest::is_in_group( 'my-example-test', 'my-example-group' ) ) {
- * //group-specific stuff goes here
- * }
- *
- * @access public
- * @author Matt Mirande, I Can Haz Cheezburger
- * @author Mohammad Jangda, Automattic
- *
* @license GPL v2
+ * @package CheezTest
*/
-class CheezTest {
-
- public $name = '';
- public $group = null;
- public $is_qualified = true;
- private $expires = 0;
- /**
- * @access public
- * @staticvar array [ $active_tests ] key / val map with name, is_qualified,
- * and group for all child objects. Enables easier accesss
- * across the application via "is_qualified_for", etc helpers.
- */
- public static $active_tests = array();
-
- private static $is_excluded = false;
-
- /**
- * __construct - main constructor routine
- *
- * Configures and initiates an A/B test object.
- *
- * @access public
- * @param array [ $opts ] key / value map containing configuration
- * options. Options include: name, expires, groups, action,
- * and is_qualified settings. The group property can optionally
- * contain a simple array of strings representing group names or each
- * group can be represented as an object with a 'threshold' property.
- * The 'threshold' will then be used to establish the group size -
- * e.g. 'threshold' => 10 indicates 10% of segments (segments 0 - 9)
- * will be assigned to this group.
- *
- */
- function __construct( $opts = array() ) {
- //exclude non-user requests
- if ( ! static::is_user_request() ){
- return;
- }
-
- $defaults = array(
- 'name' => 'ab-test',
- 'expires' => 31536000, //how long the user's segment cookie will persist
- 'groups' => array( 'seg-group-a', 'seg-group-b' ),
- 'is_qualified' => '', //accepts string that will be evaluated as func by batcache.
- 'action' => false //accepts anon-func e.g. function( $group ){} or false to bypass
- );
-
- //merge opts w/ defaults to establish child's configuration
- $cfg = array_merge( $defaults, $opts );
-
- $this->name = $cfg[ "name" ];
-
- //establish basic eligibility if 'is_qualified' is empty, all visitors are qualified to receive a segment
- if ( ! empty( $cfg[ 'is_qualified' ] ) && ! $this->qualify_user( $cfg[ "is_qualified" ] ) ) {
- return;
- }
-
- //establish user's group
- $this->group = $this->assign_group( $cfg[ "groups" ] );
-
- //add object's state to active tests collection to enable theme branching
- static::$active_tests[ $this->name ] = array(
- 'is_qualified' => $this->is_qualified,
- 'group' => $this->group
- );
-
- //fire 'action' callback if present
- if ( $this->group && is_callable( $cfg[ "action" ] ) ) {
- $cfg[ "action" ]( $this->group );
- }
-
- //if segment needs to be recorded in cookie, enqueue JS to do so
- if ( ! $this->has_segment_cookie() ) {
- $this->expires = $cfg[ 'expires' ] ? ( gmdate( 'r', time() + $cfg[ 'expires' ] ) ) : 0;
- add_action( 'wp_print_footer_scripts' , array( $this, 'write_segment_cookie' ), 1 );
- }
- }
-
- /**
- * qualify_user - batcahe-friendly test to determine if user is qualified for test
- *
- * Determines if user is eligible to participate in AB test by
- * running an arbitrary function body provided via $test argument.
- * Result is stored within object via $this->is_qualified.
- *
- * @access private
- * @param string [ $test ] function body used to determine user's
- * eligibility.
- * @return bool true if the user is eligible to participate
- */
- private function qualify_user( $test ) {
- $this->is_qualified = static::run_vary_cache_func( $test );
- return $this->is_qualified;
- }
-
- /**
- * has_segment_cookie - batcahe-friendly test to determine if user has a segment cookie
- *
- * @access private
- * @return bool whether or not segment cookie exists
- */
- private function has_segment_cookie(){
- $test = sprintf( 'return (bool) isset( $_COOKIE["%s"] );', $this->name );
- return static::run_vary_cache_func( $test );
- }
-
- /**
- * assign_group - assign a segment group (e.g. A, B, etc)
- *
- * Determines what group the assigned segment belongs in and
- * creates a batcache-friendly test to ensure proper variant
- * is shown.
- *
- * If the user has a segment cookie, the segment in the cookie
- * is returned. If not, the server returns a random group based
- * on the thresholds provided in the test config.
- *
- * @access private
- * @param array [ $groups ] key / value map which contains the
- * group names to use. Unless 'threshold' property is supplied
- * the count of the array's items determines how many possible
- * groups there are as well as each group's size.
- * @return string group assigned (as derived from $groups argument array)
- */
- private function assign_group( $groups ){
-
- $segment_checks = array();
- $cookie_checks = array();
- $block_size = 100 / count( $groups );
- $block_end = $block_size;
- $block_start = 0;
-
- //loop through groups and build up test logic to determine group assignment
- foreach ( $groups as $group => $group_args ){
-
- //use 'threshold' to determine group sizing if available
- if ( isset( $group_args[ 'threshold' ] ) && is_array( $group_args ) ){
- $block_end = $block_start + ( int ) $group_args[ 'threshold' ];
- } else {
- $group = $groups[ $group ];
- }
-
- if ( $block_end > 100 ){
- $block_end = 100;
- }
-
- //setup batcache vary on cache conditions
- $segment_checks[] = sprintf(
- '( $seg_num >= %1$d && $seg_num < %2$d ) return "%3$s";',
- $block_start,
- $block_end,
- $group
- );
-
- $cookie_checks[] = sprintf(
- '( $_COOKIE["%1$s"] === "%2$s" ) return "%2$s";',
- $this->name,
- $group
- );
-
- //update block
- $block_start = $block_end;
- $block_end = $block_start + $block_size;
- }
-
- // Take array of checks and turn into string of if/then return statements
- $segment_checks_str = 'if' . implode( 'elseif', $segment_checks );
- $cookie_checks_str = 'if' . implode( 'elseif', $cookie_checks );
-
- $test = sprintf( 'if( isset( $_COOKIE["%1$s"] ) ){ %2$s } else { $seg_num = rand( 0,99 ); %3$s }', $this->name, $cookie_checks_str, $segment_checks_str );
- return static::run_vary_cache_func( $test );
- }
-
- /**
- * run_vary_cache_func - environment-neutral interface to batcache's "vary_cache_on_function"
- *
- * Establishes whether or not to use a new cache variant by
- * running an arbitrary function body provided via $test argument.
- * $test is run both locally and in the batcache.
- *
- * @access private
- * @param string [ $test ] function body used to determine user's
- * eligibility. Must be a string in order to work with
- * WP's batcache 'vary_cache_on_function' feature. Must
- * include one or more references to "$_" variables.
- * @return mixed (bool | string | int)
- */
- private static function run_vary_cache_func( $test ){
-
- if ( preg_match('/include|require|echo|print|dump|export|open|sock|unlink|`|eval/i', $test) )
- trigger_error('Illegal word in cache variant function determiner.', E_USER_ERROR );
-
- if ( !preg_match('/\$_/', $test) )
- trigger_error('Cache variant function should refer to at least one $_ variable.', E_USER_ERROR );
-
- if ( function_exists( 'vary_cache_on_function' ) ) {
- vary_cache_on_function( $test );
- }
-
- $test_func = create_function( '', $test );
- return $test_func();
- }
-
- /**
- * is_user_request - Determines if the request type is one typically made
- * by a user
- *
- * Test whether or not the request being processed matches what would typically
- * be made by a user. Cron jobs, requests for the admin section or feeeds, and
- * any request made by google, ms/bing, or yahoo's slurp bot are flagged.
- *
- * @access public
- * @return bool true if request appears to be user-generated
- */
- private static function is_user_request(){
- //bail if we already know this request is not valid
- if ( static::$is_excluded ){
- return false;
- }
-
- $is_bot_test = 'return stripos( $_SERVER[ "HTTP_USER_AGENT" ], "googlebot" ) !== false || ' .
- 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "bingbot" ) !== false || ' .
- 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "msnbot" ) !== false || ' .
- 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "slurp" ) !== false || ' .
- 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "feedburner" ) !== false || ' .
- 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "facebook" ) !== false || ' .
- 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "technoratisnoop" ) !== false;';
-
- $is_bot = static::run_vary_cache_func( $is_bot_test );
-
- if ( ( defined( 'DOING_CRON' ) && DOING_CRON )
- || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
- || ( defined( 'WP_ADMIN' ) && WP_ADMIN )
- || is_admin()
- || $is_bot ) {
- static::$is_excluded = true;
- return false;
- }
- return true;
- }
-
- /**
- * write_segment_cookie - serves javascript response to client to write the user's
- * segment into a cookie so it will persist across visits
- *
- * @return
- */
- function write_segment_cookie(){
- ?>
-
- check if user is qualified to participate >
+ * get segment from either server or cookie > execute 'action' callback if present
+ * > write segment cookie if neccessary
+ *
+ * User's qualification, segment, and group tests are done in batcache
+ * so as to ensure correct cache variants are served.
+ *
+ * User's segment is assigned via client-side javascript. Mutliple test
+ * segments are assigned at once - so if a user is qualified to participate
+ * in more than one test, all segments are assigned at the same time. When
+ * segments need to be set, a small javascript is injected into the
+ * via a call to CheezTest::write_segment_cookie(). This javascript sets a
+ * cookie to retain the assigned segment.
+ *
+ * Test case data (name, is_qualified, & group) are stored in the $active_tests
+ * static hash and made accessible via the 'is_qualified_for', 'get_group_for', and
+ * 'is_in_group' static methods. This enables theme branching via:
+ *
+ * if ( CheezTest::is_qualified_for( 'my-example-test' ) {
+ * //test-specific stuff goes here
+ * }
+ *
+ * - or -
+ *
+ * if ( CheezTest::is_in_group( 'my-example-test', 'my-example-group' ) ) {
+ * //group-specific stuff goes here
+ * }
+ */
+class CheezTest {
+
+ /**
+ * Configuration name.
+ *
+ * @var string
+ */
+ public $name = '';
+
+ /**
+ * User's assigned group.
+ *
+ * @var null|string
+ */
+ public $group = null;
+
+ /**
+ * Condition to be evaluated as func by batcache.
+ *
+ * @var bool|string
+ */
+ public $is_qualified = true;
+
+ /**
+ * How long the user's segment cookie will persist.
+ *
+ * @var int
+ */
+ private $expires = 0;
+
+ /**
+ * Key / val map with name, is_qualified,
+ * and group for all child objects. Enables easier accesss
+ * across the application via "is_qualified_for", etc helpers.
+ *
+ * @access public
+ * @var array
+ */
+ public static $active_tests = array();
+
+ /**
+ * If the current request should be excluded from the test.
+ *
+ * @var bool
+ */
+ private static $is_excluded = false;
+
+ /**
+ * Main constructor routine
+ *
+ * Configures and initiates an A/B test object.
+ *
+ * @access public
+ * @param array $opts key / value map containing configuration
+ * options. Options include: name, expires, groups, action,
+ * and is_qualified settings. The group property can optionally
+ * contain a simple array of strings representing group names or each
+ * group can be represented as an object with a 'threshold' property.
+ * The 'threshold' will then be used to establish the group size -
+ * e.g. 'threshold' => 10 indicates 10% of segments (segments 0 - 9)
+ * will be assigned to this group.
+ */
+ public function __construct( $opts = array() ) {
+ // exclude non-user requests.
+ if ( ! static::is_user_request() ) {
+ return;
+ }
+
+ $defaults = array(
+ 'name' => 'ab-test',
+ 'expires' => 31536000, // how long the user's segment cookie will persist.
+ 'groups' => array( 'seg-group-a', 'seg-group-b' ),
+ 'is_qualified' => '', // accepts string that will be evaluated as func by batcache.
+ 'action' => false, // accepts anon-func e.g. function( $group ){} or false to bypass.
+ );
+
+ // merge opts w/ defaults to establish child's configuration.
+ $cfg = array_merge( $defaults, $opts );
+
+ $this->name = $cfg['name'];
+
+ // establish basic eligibility if 'is_qualified' is empty, all visitors are qualified to receive a segment.
+ if ( ! empty( $cfg['is_qualified'] ) && ! $this->qualify_user( $cfg['is_qualified'] ) ) {
+ return;
+ }
+
+ // establish user's group.
+ $this->group = $this->assign_group( $cfg['groups'] );
+
+ // add object's state to active tests collection to enable theme branching.
+ static::$active_tests[ $this->name ] = array(
+ 'is_qualified' => $this->is_qualified,
+ 'group' => $this->group,
+ );
+
+ // fire 'action' callback if present.
+ if ( $this->group && is_callable( $cfg['action'] ) ) {
+ $cfg['action']( $this->group );
+ }
+
+ // if segment needs to be recorded in cookie, enqueue JS to do so.
+ if ( ! $this->has_segment_cookie() ) {
+ $this->expires = $cfg['expires'] ? ( gmdate( 'r', time() + $cfg['expires'] ) ) : 0;
+ add_action( 'wp_print_footer_scripts', array( $this, 'write_segment_cookie' ), 1 );
+ }
+ }
+
+ /**
+ * Batcahe-friendly test to determine if user is qualified for test
+ *
+ * Determines if user is eligible to participate in AB test by
+ * running an arbitrary function body provided via $test argument.
+ * Result is stored within object via $this->is_qualified.
+ *
+ * @access private
+ * @param string $test Function body used to determine user's
+ * eligibility.
+ * @return bool true if the user is eligible to participate
+ */
+ private function qualify_user( $test ) {
+ $this->is_qualified = static::run_vary_cache_func( $test );
+ return $this->is_qualified;
+ }
+
+ /**
+ * Batcahe-friendly test to determine if user has a segment cookie
+ *
+ * @access private
+ * @return bool whether or not segment cookie exists
+ */
+ private function has_segment_cookie() {
+ $test = sprintf( 'return (bool) isset( $_COOKIE["%s"] );', $this->name );
+ return static::run_vary_cache_func( $test );
+ }
+
+ /**
+ * Assign a segment group (e.g. A, B, etc)
+ *
+ * Determines what group the assigned segment belongs in and
+ * creates a batcache-friendly test to ensure proper variant
+ * is shown.
+ *
+ * If the user has a segment cookie, the segment in the cookie
+ * is returned. If not, the server returns a random group based
+ * on the thresholds provided in the test config.
+ *
+ * @access private
+ * @param array $groups key / value map which contains the
+ * group names to use. Unless 'threshold' property is supplied
+ * the count of the array's items determines how many possible
+ * groups there are as well as each group's size.
+ * @return string group assigned (as derived from $groups argument array)
+ */
+ private function assign_group( $groups ) {
+ $segment_checks = array();
+ $cookie_checks = array();
+ $block_size = 100 / count( $groups );
+ $block_end = $block_size;
+ $block_start = 0;
+
+ // loop through groups and build up test logic to determine group assignment.
+ foreach ( $groups as $group => $group_args ) {
+
+ // use 'threshold' to determine group sizing if available.
+ if ( isset( $group_args['threshold'] ) && is_array( $group_args ) ) {
+ $block_end = $block_start + (int) $group_args['threshold'];
+ } else {
+ $group = $groups[ $group ];
+ }
+
+ if ( $block_end > 100 ) {
+ $block_end = 100;
+ }
+
+ // setup batcache vary on cache conditions.
+ $segment_checks[] = sprintf(
+ '( $seg_num >= %1$d && $seg_num < %2$d ) return "%3$s";',
+ $block_start,
+ $block_end,
+ $group
+ );
+
+ $cookie_checks[] = sprintf(
+ '( $_COOKIE["%1$s"] === "%2$s" ) return "%2$s";',
+ $this->name,
+ $group
+ );
+
+ // update block.
+ $block_start = $block_end;
+ $block_end = $block_start + $block_size;
+ }
+
+ // Take array of checks and turn into string of if/then return statements.
+ $segment_checks_str = 'if' . implode( 'elseif', $segment_checks );
+ $cookie_checks_str = 'if' . implode( 'elseif', $cookie_checks );
+
+ $test = sprintf( 'if( isset( $_COOKIE["%1$s"] ) ){ %2$s } else { $seg_num = rand( 0,99 ); %3$s }', $this->name, $cookie_checks_str, $segment_checks_str );
+ return static::run_vary_cache_func( $test );
+ }
+
+ /**
+ * Environment-neutral interface to batcache's "vary_cache_on_function"
+ *
+ * Establishes whether or not to use a new cache variant by
+ * running an arbitrary function body provided via $test argument.
+ * $test is run both locally and in the batcache.
+ *
+ * @access private
+ * @param string $test Function body used to determine user's
+ * eligibility. Must be a string in order to work with
+ * WP's batcache 'vary_cache_on_function' feature. Must
+ * include one or more references to "$_" variables.
+ * @return bool|string|int
+ */
+ private static function run_vary_cache_func( $test ) {
+ if ( preg_match( '/include|require|echo|print|dump|export|open|sock|unlink|`|eval/i', $test ) ) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
+ trigger_error( 'Illegal word in cache variant function determiner.', E_USER_ERROR );
+ }
+
+ if ( ! preg_match( '/\$_/', $test ) ) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
+ trigger_error( 'Cache variant function should refer to at least one $_ variable.', E_USER_ERROR );
+ }
+
+ if ( function_exists( 'vary_cache_on_function' ) ) {
+ vary_cache_on_function( $test );
+ }
+
+ // @todo create_function() is deprecated as of PHP 7.2, please use full fledged functions or anonymous functions instead. (WordPress.PHP.RestrictedPHPFunctions.create_function_create_function)
+ $test_func = create_function( '', $test );
+ return $test_func();
+ }
+
+ /**
+ * Determines if the request type is one typically made
+ * by a user
+ *
+ * Test whether or not the request being processed matches what would typically
+ * be made by a user. Cron jobs, requests for the admin section or feeeds, and
+ * any request made by google, ms/bing, or yahoo's slurp bot are flagged.
+ *
+ * @access private
+ * @return bool true if request appears to be user-generated
+ */
+ private static function is_user_request() {
+ // bail if we already know this request is not valid.
+ if ( static::$is_excluded ) {
+ return false;
+ }
+
+ $is_bot_test = 'return stripos( $_SERVER[ "HTTP_USER_AGENT" ], "googlebot" ) !== false || ' .
+ 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "bingbot" ) !== false || ' .
+ 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "msnbot" ) !== false || ' .
+ 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "slurp" ) !== false || ' .
+ 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "feedburner" ) !== false || ' .
+ 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "facebook" ) !== false || ' .
+ 'stripos( $_SERVER[ "HTTP_USER_AGENT" ], "technoratisnoop" ) !== false;';
+
+ $is_bot = static::run_vary_cache_func( $is_bot_test );
+
+ if ( ( defined( 'DOING_CRON' ) && DOING_CRON )
+ || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
+ || ( defined( 'WP_ADMIN' ) && WP_ADMIN )
+ || is_admin()
+ || $is_bot ) {
+ static::$is_excluded = true;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Serves javascript response to client to write the user's
+ * segment into a cookie so it will persist across visits
+ */
+ public function write_segment_cookie() {
+ ?>
+
+ _toc = $cheeztest;
- }
-}