/** * Get complete click type HTML * * @since 0.0.6 * * @param int $id Group ID * * @return string */ function ingot_click_test($id) { $html = ''; if (!is_array($id)) { $group = \ingot\testing\crud\group::read($id); } else { $group = $id; } if (!is_array($group) || 'click' !== $group['type']) { return $html; } $type = $group['sub_type']; if (in_array($type, \ingot\testing\types::allowed_click_types())) { switch ($type) { case in_array($type, \ingot\testing\types::internal_click_types()): $html = ingot_click_html_link($type, $group); break; case is_callable($type): $html = call_user_func($type, $group); break; default: $html = ''; } } return $html; }
public static function current_sequence($group, $what = 'click') { if (!is_array($group)) { $group = group::read($group); } return helpers::v('current_sequence', $group, array()); }
/** * Loop through a few renders to make sure nothing gets wonky -- IE new levers being created or something * * @since 0.4.0 * * @group bandit * @group group * @group front_ui * */ public function testMultiple() { $groups = ingot_tests_data::click_link_group(true, 1, 3); $group_id = $groups['ids'][0]; $variants = $groups['variants'][$groups['ids'][0]]; for ($i = 0; $i <= 5; $i++) { $this->check_render($groups); $group = \ingot\testing\crud\group::read($group_id); $levers = $group['levers']; $this->assertInternalType('array', $levers); $this->assertFalse(empty($levers)); $this->assertArrayHasKey($group_id, $levers); foreach ($variants as $variant_id) { $this->assertArrayHasKey($variant_id, $levers[$group_id], 'iteration: ' . $i); } } }
/** * Prepare price test details needed for use in cookies/tracking * * @since 0.2.0 * * @param array $price_test Price test config * @param string $a_or_b a|b * @param int $sequence_id Sequence ID * @param int $group_id Group ID * * @return array */ public static function price_detail($price_test, $a_or_b, $sequence_id, $group_id) { if (is_numeric($price_test)) { $price_test = price_test::read($price_test); } if (is_numeric($group_id)) { $group = group::read($group_id); } elseif (is_array($group_id)) { $group = $group_id; $group_id = helpers::v('ID', $group, 0); } else { return array(); } if (!is_array($price_test) || !is_array($group)) { return array(); } $details = array('plugin' => $group['plugin'], 'product_ID' => $price_test['product_ID'], 'test_ID' => $price_test['ID'], 'sequence_ID' => $sequence_id, 'group_ID' => $group_id, 'a_or_b' => $a_or_b); return $details; }
/** * Get HTML for our test. Use this function to output the test. * * Note that because this function has the same name as the test sub_type we registered, it can be called by the Ingot shortcode. * * @return string */ function my_custom_banner() { //check if is bot $is_bot = ingot_is_bot(); $variant = []; //if cookie isset get variant without registering as a new test instance if (!$is_bot && isset($_COOKIE['my_ingot_custom_test_variant']) && 0 < absint($_COOKIE['my_ingot_custom_test_variant'])) { $variant_id = absint($_COOKIE['my_ingot_custom_test_variant']); $variant = \ingot\testing\crud\variant::read($variant_id); } elseif (!$is_bot && isset($my_custom_test_variant_id) && 0 < absint($my_custom_test_variant_id)) { //if is same session as cookie was set, we use the global variable to get the ID $variant_id = absint($my_custom_test_variant_id); $variant = \ingot\testing\crud\variant::read($variant_id); } else { //this should never be reached unless this is a bot, the cookie should have been set at template_redirect //We still need to show something since we want crawlers to index the site properly and false postives on bot checks to look right. $id = my_ingot_custom_test_group(); if (is_numeric($id)) { $group = \ingot\testing\crud\group::read($id); if (is_array($group) && isset($group['variants']) && !empty($group['variants'])) { $variant = array_rand($group['variants']); //set up test and select a variant $test = new \ingot\testing\bandit\content($id); $variant_id = $test->choose(); //a test instance is now registered $variant = \ingot\testing\crud\variant::read($variant_id); } } } //get chosen image URL and return it in an image tag if (isset($variant['content'])) { $content = $variant['content']; } else { //something is very wrong, let's show a picture of a cat in a flower pot $content = 'http://hellogiggles.com/wp-content/uploads/2014/07/22/you-popular-cute-cat-the-very-creative_113506.jpg'; } return sprintf('<img src="%s" />', esc_url($content)); }
/** * Create groups with variants, optionally added to them. * * @param bool $add_variants Optional. If true, the default, variants are added to groups via groups object. If false, they are created, IDs are returned but they will nto be associated with a group properly. * @param int $total_groups Optional. Default is 5. * @param int $variants_per_group Optional. Default is 3. * @param array $args Optional * * @return array */ public static function make_groups($add_variants = true, $total_groups = 5, $variants_per_group = 3, $args = array()) { $defaults = ['group_args' => ['name' => rand(), 'type' => 'click', 'sub_type' => 'button', 'meta' => ['link' => 'https://bats.com']], 'variant_args' => ['type' => 'click', 'group_ID' => 1, 'content' => rand()]]; $keys = array_keys($defaults); foreach ($keys as $i => $key) { if (!empty($args[$key])) { $args[$key] = wp_parse_args($args[$key], $defaults[$key]); } else { $args[$key] = $defaults[$key]; } } $groups = ['ids' => [], 'variants' => []]; $group_args = $args['group_args']; $variant_args = $args['variant_args']; for ($g = 0; $g <= $total_groups; $g++) { $variants = []; $group_args['name'] = (string) $g . rand(); $group_id = \ingot\testing\crud\group::create($group_args, true); $groups['ids'][] = $group_id; $variant_args['group_ID'] = $group_id; for ($v = 0; $v <= $variants_per_group; $v++) { $variant_id = \ingot\testing\crud\variant::create($variant_args, true); $variants[] = $variant_id; } $groups['variants'][$group_id] = $variants; if ($add_variants) { if (is_user_logged_in()) { $obj = new \ingot\testing\object\group($group_id); $obj->update_group(['variants' => $variants]); } else { $_group = \ingot\testing\crud\group::read($group_id); $_group['variants'] = $variants; $saved = \ingot\testing\crud\group::update($_group, $group_id, true); } } } return $groups; }
/** * Test that EDD sale of non-variable product is properly priced/recorded * * @since 1.1.0 * * @group pricez * @group edd_price * * @covers \ingot\testing\tests\price\plugins\edd */ public function testPriceTrackingNonVariableProduct() { $price_is = 10; $product = ingot_test_data_price::edd_create_simple_download($price_is); $group_id = \ingot\testing\crud\group::create(['type' => 'price', 'sub_type' => 'edd', 'meta' => ['product_ID' => $product->ID], 'wp_ID' => $product->ID], true); $variant_one = \ingot\testing\crud\variant::create(['group_ID' => $group_id, 'type' => 'price', 'meta' => ['price' => [0.5]], 'content' => $product->ID], true); $variant_two = \ingot\testing\crud\variant::create(['group_ID' => $group_id, 'type' => 'price', 'meta' => ['price' => [0.5]], 'content' => $product->ID], true); $group = \ingot\testing\crud\group::read($group_id); $group['variants'] = [$variant_one, $variant_two]; \ingot\testing\crud\group::update($group, $group_id, true); $cookie_class = new \ingot\testing\cookies\price([]); $price_cookie = $cookie_class->get_cookie(); $this->assertArrayHasKey('edd', $price_cookie); $this->assertFalse(empty($price_cookie['edd'])); $this->assertInternalType('array', $price_cookie['edd']); $product_id = \ingot\testing\utility\price::get_product_ID($group); $this->assertEquals($product_id, $product->ID); $this->assertArrayHasKey($product_id, $price_cookie['edd']); new \ingot\testing\tests\price\plugins\edd($price_cookie['edd']); $test = \ingot\testing\utility\price::get_price_test_from_cookie('edd', $product->ID, $price_cookie); $this->assertInternalType('object', $test); $price_should_be = $test->get_price(); //NOTE: USING edd_get_download_price here is to ensure we don't have recursion $this->assertEquals(edd_get_download_price($product->ID), $price_should_be); $group_obj = new \ingot\testing\object\group($group_id); $lever = $group_obj->get_lever($test->ID); $this->assertInternalType('object', $lever); $before_wins = $lever->getNumerator(); $payment_id = ingot_test_data_price::edd_create_simple_payment($product); edd_complete_purchase($payment_id, 'publish', 'pending'); $group_obj = new \ingot\testing\object\group($group_id); $lever = $group_obj->get_lever($test->ID); $this->assertInternalType('object', $lever); $after_wins = $lever->getNumerator(); $this->assertEquals($before_wins + 1, $after_wins); }
/** * Create the variants and save in group * * @param int $group_id The group ID * * @return int|WP_Error Should return group ID. May return WP_Error if there was an error creating variants or saving them in group. */ protected function add_variants($group_id) { $variant_args = ['type' => 'click', 'group_ID' => $group_id]; /** * This array will be the HTML we output for each variant. * * As an example I'm using URLs of cute cate photos * * @TODO -- You should use something meaningful here. */ $variant_contents = ['https://placekitten.com/900/300', 'https://placekitten.com/900/200', 'https://placekitten.com/800/400']; $variant_ids = []; //create the variants foreach ($variant_contents as $content) { $variant_args['content'] = $content; $variant_id = \ingot\testing\crud\variant::create($variant_args); if (is_numeric($variant_id)) { $variant_ids[] = $variant_id; } else { return $variant_id; } } //save variant IDs in group $group = \ingot\testing\crud\group::read($group_id); $group['variants'] = $variant_ids; $saved = \ingot\testing\crud\group::update($group, $group_id); //this should be the group ID, could be an error. return $saved; }
/** * * * @since 1.1.0 * * @group group * @group destination * @group cookie * @group destination_cookie * * @covers \ingot\testing\tests\click\destination\init::get_test() * @covers \ingot\testing\tests\click\destination\init::set_tracking() * @covers \ingot\testing\tests\click\destination\cookie::get_cookie() */ public function testCookieTracking() { $data = ingot_test_desitnation::create('page'); $group_id = $data['group_ID']; $this->assertTrue(is_numeric($group_id)); $group = \ingot\testing\crud\group::read($group_id); $this->assertInternalType('array', $group); $bandit = new \ingot\testing\bandit\content($group_id); $variant_id = $bandit->choose(); $this->assertTrue(is_numeric($variant_id)); \ingot\testing\tests\click\destination\init::set_tracking(); \ingot\testing\tests\click\destination\init::get_test($group_id); $obj = new \ingot\testing\object\group($group_id); $levers = $obj->get_levers(); $this->assertInternalType('array', $levers); $cookie_name = \ingot\testing\tests\click\destination\cookie::cookie_key($group_id); $variant_id = \ingot\testing\tests\click\destination\init::get_test($group_id); $this->assertTrue(is_numeric($variant_id)); $_COOKIE[$cookie_name] = $variant_id; $this->assertEquals($variant_id, \ingot\testing\tests\click\destination\cookie::get_cookie($group_id)); $obj = new \ingot\testing\object\group($group_id); $_levers = $obj->get_levers(); for ($i = 0; $i <= 10; $i++) { \ingot\testing\tests\click\destination\init::set_tracking(); } $obj = new \ingot\testing\object\group($group_id); $levers = $obj->get_levers(); $this->assertEquals($levers, $_levers); $this->assertInternalType('array', $levers); $this->assertArrayHasKey($group_id, $levers); $this->assertArrayHasKey($variant_id, $levers[$group_id]); $lever = $levers[$variant_id]; $this->assertInternalType('object', $lever); $this->assertEquals(0, $lever->getNumerator()); $this->assertEquals(1, $lever->getDenominator()); }
/** * Get variant ID, by group ID. * * If no variant chosen, makes selection * * @since 1.1.0 * * @param int $group_id Group ID to get variant for * * @return int */ public static function get_test($group_id) { if (!isset(self::$tests[$group_id])) { if (!cookie::get_cookie($group_id)) { $group = group::read($group_id); if (group::valid($group) && !empty($group['variants'])) { $bandit = new content($group_id); $variant = $bandit->choose(); if (is_a($variant, 'MaBandit\\Lever')) { /** @var \MaBandit\Lever $variant */ $variant = $variant->getValue(); } if (is_numeric($variant)) { cookie::set_cookie($group_id, $variant); } } else { return false; } } else { $variant = cookie::get_cookie($group_id); } self::$tests[$group_id] = $variant; } return self::$tests[$group_id]; }
protected function create_experiment() { $group = group::read($this->ID); if (!empty($group['variants'])) { $variants = helpers::make_array_values_numeric($group['variants'], true); $creator = new CreateExperiment($variants, $this->ID, $this->bandit); $this->experiment = $creator->get_experiment(); } }
/** * Test that we can query by plugin and exclude those without variants * * @since 1.1.0 * * @group xs * @group price_query * @group price * * @covers \ingot\testing\crud\price_query::find_by_plugin() */ public function testQueryByPluginNoVariant() { $args = ['type' => 'price', 'sub_type' => 'edd', 'meta' => ['product_ID' => 5], 'wp_ID' => 5]; $variant_args = ['type' => 'price', 'meta' => ['price' => []], 'content' => 5]; for ($i = 0; $i <= 5; $i++) { $group_id = \ingot\testing\crud\group::create($args); $args['wp_ID'] = $args['wp_ID'] + 1; if (3 == $i) { $expected_id = $group_id; $variant_args['group_ID'] = $group_id; $variant_args['meta']['price'] = rand_float(); $variant_id = \ingot\testing\crud\variant::create($variant_args, true); $this->assertTrue(is_numeric($variant_id)); $group = \ingot\testing\crud\group::read($group_id); $group['variants'] = [$variant_id]; \ingot\testing\crud\group::update($group, $group_id, true); } } $groups = \ingot\testing\crud\price_query::find_by_plugin('edd', true); $this->assertInternalType('array', $groups); $this->assertFalse(empty($groups)); $ids = wp_list_pluck($groups, 'ID'); $this->assertTrue(in_array($expected_id, $ids)); $this->assertSame(1, count($groups)); }
/** * Test that when we can update other stuff through group object * * @since 0.4.0 * * @group group * @group group_object * * @covers \ingot\testing\object\group::get_group_config() * @covers \ingot\testing\object\group::update_group() */ public function testUpdateThroughObject() { $groups = ingot_tests_make_groups(true, 1, 3); $id = $groups['ids'][0]; $this->assertTrue(is_numeric($id)); $variants = $groups['variants'][$id]; $obj = new \ingot\testing\object\group($id); $this->assertEquals($variants, $obj->get_group_config()['variants']); $new_data = ['name' => 'BATMAN']; $obj->update_group($new_data); $group = \ingot\testing\crud\group::read($id); $this->assertEquals('BATMAN', $group['name']); $new_data = ['name' => 'Hi Roy', 'sub_type' => 'button_color']; $obj->update_group($new_data); $group = \ingot\testing\crud\group::read($id); $this->assertEquals('Hi Roy', $group['name']); $this->assertEquals('button_color', $group['sub_type']); }
/** * Test that when we can add levers directly * * @since 0.4.0 * * @group crud * @group group * @group group_crud * * @covers \ingot\testing\crud\group::update() */ public function testLevers() { $groups = ingot_tests_make_groups(true, 1, 3); $group_id = $groups['ids'][0]; $bandit = new \ingot\testing\bandit\content($group_id); $group = \ingot\testing\crud\group::read($group_id); $this->assertFalse(empty($group['levers'])); $this->assertArrayHasKey((int) $group_id, $group['levers']); $this->assertSame(4, count($group['levers'][$group_id])); }
/** * Set product property * * @since 1.1.0 * * @access private */ private function set_product() { if (!is_object($this->product)) { $group = group::read($this->variant['group_ID']); if (in_array($group['sub_type'], types::allowed_price_types())) { $this->product = price::get_product($group); } } }
/** * Track EDD sale conversions * * @since 1.1.0 * * @group group * @group destination * @group edd * * @covers \ingot\testing\tests\click\destination\hooks::edd_complete_purchase() * @covers \ingot\testing\tests\click\destination\hooks::add_hooks() */ public function testEDDConversionsSale() { if (ingot_is_edd_active()) { $this->assertTrue(\ingot\testing\tests\click\destination\types::allowed_destination_type('sale_edd')); $product = ingot_test_data_price::edd_create_simple_download(10); $data = ingot_test_desitnation::create('sale_edd'); $group_id = $data['group_ID']; $this->assertTrue(is_numeric($group_id)); $variants = $data['variants']; new \ingot\testing\bandit\content($group_id); $variant_id = \ingot\testing\tests\click\destination\init::get_test($group_id); $this->assertTrue(is_numeric($variant_id)); \ingot\testing\tests\click\destination\init::set_tracking(); $this->assertTrue(in_array(\ingot\testing\tests\click\destination\init::get_test($group_id), $variants)); $variant_id = \ingot\testing\tests\click\destination\init::get_test($group_id); $hooks = new \ingot\testing\tests\click\destination\hooks([$group_id]); $payment_id = ingot_test_data_price::edd_create_simple_payment($product); edd_complete_purchase($payment_id, 'publish', 'pending'); $group = \ingot\testing\crud\group::read($group_id); $totals = \ingot\testing\utility\group::get_total($group); $this->assertEquals(3, $totals['total']); $this->assertEquals(2, $totals['conversions']); } }
/** * Get stats for a group * * @since 0.4.0 * * @param \WP_REST_Request $request Full data about the request. * @return \WP_Error|\WP_REST_Response */ public function get_stats($request) { $url = $request->get_url_params(); $id = helpers::v('id', $url, 0); $group = group::read($id); if (!is_array($group)) { if (is_wp_error($group)) { return $group; } return ingot_rest_response(['message' => esc_html__('No group found', 'ingot')]); } $obj = new \ingot\testing\object\group($group); $stats = $obj->get_stats(); if ('admin' == $request->get_param('context')) { $names = $obj->names(); if (!empty($stats['variants']) && !empty($names['variants'])) { foreach ($names['variants'] as $v_id => $name) { if (isset($stats['variants'][$v_id])) { $stats['variants'][$v_id] = (array) $stats['variants'][$v_id]; $stats['variants'][$v_id]['name'] = $name; $stats['variants'][$v_id] = (object) $stats['variants'][$v_id]; } } } $stats['names'] = $names; } return ingot_rest_response($stats, 200); }
/** * Test deleting one item * * @since 0.4.0 * * @group rest * @group group_rest * @group group * * @covers ingot\testing\api\rest\groups::create_item() */ public function testCreateItem() { wp_set_current_user(1); $request = new \WP_REST_Request('POST', $this->namespaced_route); $request->set_query_params(array('type' => 'click', 'sub_type' => 'button_color', 'name' => 'x2')); $response = $this->server->dispatch($request); $response = rest_ensure_response($response); $this->assertEquals(201, $response->get_status()); $data = (array) $response->get_data(); $this->assertArrayHasKey('ID', $data); $group = \ingot\testing\crud\group::read($data['ID']); $fields = $this->get_fields_to_check_for(); $this->assertTrue(is_array($data)); $this->assertEquals(count($fields), count($data), var_export($data, true)); foreach ($fields as $field) { $this->assertArrayHasKey($field, $data); $this->assertSame($group[$field], $data[$field]); } }
/** * Check getting page ID * * @since 1.1.0 * * @group group * @group destination * * \ingot\testing\utility\destination::get_page_id() */ public function testGetPageID() { $data = ingot_test_desitnation::create('page', true); $group = \ingot\testing\crud\group::read($data['group_ID']); $this->assertSame($data['page'], \ingot\testing\utility\destination::get_page_id($group)); }
/** * @param $group * * @return \ingot\testing\object\price\test */ protected function setup_test_object($group) { if (is_numeric($group)) { $group = group::read($group); } if (!group::valid($group)) { return false; } $bandit = new \ingot\testing\bandit\price($group['ID']); $variant = $bandit->choose(); $product = \ingot\testing\utility\price::get_product($group); $test = new test(['plugin' => $group['sub_type'], 'ID' => $group['ID'], 'expires' => $this->expires(), 'variant' => $variant, 'product' => $product, 'price_callback' => \ingot\testing\utility\price::get_price_callback($group['sub_type'])]); return $test; }
/** * Get product ID from a group * * @param array|int $group * * @return int|null */ public static function get_product_ID($group) { if (is_numeric($group)) { $group = \ingot\testing\crud\group::read($group); } if (\ingot\testing\crud\group::valid($group)) { return (int) helpers::v('product_ID', $group['meta'], null); } }
/** * Set group property * * @since 0.0.5 * * @access private * * @param int|array $group */ private function set_group($group) { // @todo maybe use group object here since it will validate if (is_array($group)) { $this->group = $group; } else { $this->group = group::read($group); } }
/** * Set group property and ID property if group is valid * * @since 0.4.0 * * @access private * * @param array|int $group Group config or ID of a saved group * * @throws \Exception */ private function set_group($group) { if (is_numeric($group)) { $group = \ingot\testing\crud\group::read($group, true); } $this->validate_group($group); $this->group = $group; $this->ID = $this->group['ID']; }
/** * Test that we can create all sorts of destination tests * * @since 1.1.0 * * @group group * @group group_crud * @group destination * * @covers \ingot\testing\crud\group::create() * @covers \ingot\testing\crud\crud::save() * @covers \ingot\testing\tests\click\destination\types::destination_types() * @covers \ingot\testing\utility\destination::prepare_meta() */ public function testCreateDestinationTest() { foreach (\ingot\testing\tests\click\destination\types::destination_types() as $type) { if ('hook' == $type) { continue; } $args = ingot_test_desitnation::group_args($type); $id = \ingot\testing\crud\group::create($args); $this->assertTrue(is_numeric($id)); $group = \ingot\testing\crud\group::read($id); $this->assertInternalType('array', $group); $this->assertTrue(\ingot\testing\crud\group::valid($group)); } }