e'], $filter['interval'] ); foreach ( $dates as $date ) { $temp_data[ $date ]['date'] = $date; $temp_data[ $date ][ TVE_LEADS_CONVERSION ] = 0; $temp_data[ $date ][ TVE_LEADS_UNIQUE_IMPRESSION ] = 0; } foreach ( $report_data as $interval ) { if ( $filter['interval'] == 'day' ) { $interval->date_interval = date( 'd M, Y', strtotime( $interval->date_interval ) ); } if ( intval( $interval->event_type ) !== TVE_LEADS_CONVERSION ) { $temp_data[ $interval->date_interval ][ TVE_LEADS_UNIQUE_IMPRESSION ] += intval( $interval->log_count ); } else { $temp_data[ $interval->date_interval ][ TVE_LEADS_CONVERSION ] += intval( $interval->log_count ); } } $table_data = array(); foreach ( $temp_data as $interval ) { if ( ! isset( $interval[ TVE_LEADS_UNIQUE_IMPRESSION ] ) || ! isset( $interval[ TVE_LEADS_CONVERSION ] ) || $interval[ TVE_LEADS_UNIQUE_IMPRESSION ] == 0 ) { $rate = 0; } else { $rate = (float) tve_leads_conversion_rate( $interval[ TVE_LEADS_UNIQUE_IMPRESSION ], $interval[ TVE_LEADS_CONVERSION ], '', 2 ); } $table_data[] = array( 'date' => $interval['date'], 'rate' => $rate ); } if ( ! empty( $table_data ) ) { $table_pages = array_chunk( $table_data, $filter['itemsPerPage'] ); return array_reverse( $table_pages[ $filter['page'] - 1 ] ); } else { return array(); } } /** * Return data for the comparison report pie data and table * * @param $filter * * @return array */ function tve_leads_get_comparison_report_data( $filter ) { $filter['main_group_id'] = - 1; $defaults = array( 'group_by' => array( 'main_group_id' ), 'data_group' => 'main_group_id', 'event_type' => TVE_LEADS_CONVERSION, ); $filter = array_merge( $defaults, $filter ); global $tvedb; $report_data = $tvedb->tve_leads_get_report_data_count_event_type( $filter ); $lead_groups = get_posts( array( 'posts_per_page' => - 1, 'post_type' => array( TVE_LEADS_POST_GROUP_TYPE, TVE_LEADS_POST_SHORTCODE_TYPE, TVE_LEADS_POST_TWO_STEP_LIGHTBOX ) ) ); //store group name and id $group_names = array(); foreach ( $lead_groups as $group ) { $group_names[ $group->ID ] = $group->post_title; } $chart_data = array(); $table_data = array(); $conversions = 0; foreach ( $report_data as $interval ) { $chart_data[] = array( $group_names[ intval( $interval->data_group ) ], intval( $interval->log_count ) ); $conversions += intval( $interval->log_count ); } foreach ( $report_data as $interval ) { $table_data[] = array( 'lead_group' => $group_names[ intval( $interval->data_group ) ], 'percentage' => round( 100 * intval( $interval->log_count ) / $conversions, 1 ) . '%' ); unset( $group_names[ intval( $interval->data_group ) ] ); } //fill the table data with the empty groups foreach ( $group_names as $names ) { $table_data[] = array( 'lead_group' => $names, 'percentage' => '0%' ); } return array( 'chart_title' => __( 'How the total number of opt ins is distributed between Lead Groups and individual forms', 'thrive-leads' ), 'chart_data' => $chart_data, 'chart_y_axis' => '', 'chart_x_axis' => '', 'table_data' => $table_data ); } /** * Return data for the Lead Referral Report table * * @param $filter Array containing parameters for filtering the data logs * * @return array */ function tve_leads_get_lead_referral_report_data( $filter ) { $defaults = array( 'count' => true, 'itemsPerPage' => 10, 'page' => 1, 'event_type' => TVE_LEADS_CONVERSION, 'referral_type' => 'domain' ); $filter = array_merge( $defaults, $filter ); global $tvedb; $lead_referral = $tvedb->tve_leads_get_top_referring_links( $filter, $filter['count'] ); if ( $filter['referral_type'] == 'domain' && $filter['count'] == false ) { $temp = array(); foreach ( $lead_referral as $referrer ) { $domain = parse_url( $referrer->referring_url, PHP_URL_HOST ); $domain = str_replace( 'www.', '', $domain ); if ( empty( $temp[ $domain ] ) ) { $temp[ $domain ] = new stdClass(); $temp[ $domain ]->conversions = 0; $temp[ $domain ]->referring_url = $domain; } $temp[ $domain ]->conversions += $referrer->conversions; } $lead_referral = array_values( $temp ); } /* sort the result */ if ( $filter['count'] == false && ! empty( $filter['order_dir'] ) ) { for ( $i = 0; $i < count( $lead_referral ) - 1; $i ++ ) { for ( $j = $i + 1; $j < count( $lead_referral ); $j ++ ) { if ( ( $filter['order_by'] == 'url' && strcmp( $lead_referral[ $i ]->referring_url, $lead_referral[ $j ]->referring_url ) > 0 ) || ( $filter['order_by'] == 'conversions' && ( $lead_referral[ $i ]->conversions - $lead_referral[ $j ]->conversions > 0 ) ) ) { $aux = $lead_referral[ $i ]; $lead_referral[ $i ] = $lead_referral[ $j ]; $lead_referral[ $j ] = $aux; } } } if ( $filter['order_dir'] == 'DESC' ) { $lead_referral = array_reverse( $lead_referral ); } } if ( $filter['count'] == true ) { return array( 'table_data' => array( 'count_table_data' => $lead_referral ) ); } else { return $lead_referral; } } /** * Return data for the Lead Referral Report table * * @param $filter Array containing parameters for filtering the data logs * * @return array */ function tve_leads_get_lead_source_report_data( $filter ) { $defaults = array( 'count' => true, 'itemsPerPage' => 500, 'page' => 1, 'source_type' => 0, 'order_by' => '', 'order_dir' => '' ); $filter = array_merge( $defaults, $filter ); global $tvedb; $lead_report = $tvedb->tve_leads_get_lead_source_data( $filter, $filter['count'] ); $result = array(); foreach ( $lead_report as $row ) { list( $url, $type, $name ) = tve_get_current_screen_for_reporting_table( $row->screen_type, $row->screen_id ); $result[] = array( 'url' => $url, 'type' => $type, 'name' => $name, 'conversions' => $row->conversions, 'impressions' => $row->impressions, 'leads' => $row->leads, 'conversion_rate' => tve_leads_conversion_rate( $row->impressions, $row->conversions ), ); } if ( $filter['count'] == true ) { return array( 'table_data' => array( 'count_table_data' => count( $result ) ) ); } else { return $result; } } /** * Return data for the Lead Referral Report table * * @param $filter Array containing parameters for filtering the data logs * * @return array */ function tve_leads_get_lead_tracking_report_data( $filter ) { $defaults = array( 'count' => true, 'itemsPerPage' => 10, 'page' => 1, 'tracking_type' => 'all', 'event_type' => TVE_LEADS_CONVERSION ); $filter = array_merge( $defaults, $filter ); global $tvedb; $lead_tracking = $tvedb->tve_leads_get_tracking_links( $filter, $filter['count'] ); if ( $filter['count'] == true ) { return array( 'table_data' => array( 'count_table_data' => $lead_tracking ) ); } else { return $lead_tracking; } } /** * @param $test_id ID of the test we want to get data from * @param $interval can be 'day', 'week', or 'month' - the date interval of the chart * * @return array */ function tve_leads_get_test_chart_data( $test_id, $interval ) { $filter = array( 'ID' => $test_id ); global $tvedb; $test = $tvedb->tve_leads_get_test( $filter ); list( $test_items, $test_item_ids ) = tve_leads_get_test_items_with_names( $test_id ); //set the group by for the log data depending on the test type switch ( $test->test_type ) { case TVE_LEADS_SHORTCODE_TEST_TYPE: case TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE: case TVE_LEADS_VARIATION_TEST_TYPE: $group_by = array( 'variation_key', 'date_interval', 'event_type' ); $data_group = 'variation_key'; break; case TVE_LEADS_GROUP_TEST_TYPE: $group_by = array( 'form_type_id', 'date_interval', 'event_type' ); $data_group = 'form_type_id'; break; } $filter = array( 'interval' => $interval, 'group_names' => $test_items, 'data_group' => $data_group, 'group_ids' => array_keys( $test_items ), 'start_date' => $test->date_started, 'end_date' => $test->date_completed && $test->status == 'archived' ? $test->date_completed : date( "Y-m-d H:i:s" ), 'group_by' => $group_by ); $chart_data = tve_leads_get_conversion_rate_test_data( $filter ); foreach ( $chart_data['chart_data'] as $main_id => $item ) { foreach ( $item['data'] as $index => $conversion_rate ) { // calculate the new conversion rate as a sum of the total numbers from the beginning of the test until at this point $impressions = $conversions = 0; for ( $i = 0; $i <= $index; $i ++ ) { $impressions += $item['impression_count'][ $i ]; $conversions += $item['conversion_count'][ $i ]; } $chart_data['chart_data'][ $main_id ]['data'][ $index ] = (double) tve_leads_conversion_rate( $impressions, $conversions, '' ); unset( $chart_data['chart_data'][ $main_id ]['impression_count'], $chart_data['chart_data'][ $main_id ]['conversion_count'] ); } } $temp = array(); asort( $test_item_ids ); foreach ( $test_item_ids as $main_id => $order ) { if ( ! isset( $chart_data['chart_data'][ $main_id ] ) ) { continue; } $temp [] = $chart_data['chart_data'][ $main_id ]; } $chart_data['chart_data'] = $temp; unset( $chart_data['table_data'] ); return $chart_data; } function tve_leads_get_test( $test_id, $filters = array() ) { $defaults = array( 'load_test_items' => false, 'load_form_data' => false, ); $filters = array_merge( $defaults, $filters ); global $tvedb; $test = $tvedb->tve_leads_get_test( array( 'ID' => $test_id ) ); $test->form_title = get_the_title( $test->main_group_id ); if ( ! $test ) { return; } //load items if ( ! empty( $filters['load_test_items'] ) ) { $test->items = tve_leads_get_test_items( array( 'test_id' => $test_id ) ); $test->stopped_items = array(); //load item names foreach ( $test->items as $index => $item ) { $item->index = $index; //we need the conversion rate in both cases $item->conversion_rate = tve_leads_conversion_rate( $item->unique_impressions, $item->conversions, '' ); if ( ! empty( $filters['load_form_data'] ) ) { if ( $test->test_type == TVE_LEADS_VARIATION_TEST_TYPE || $test->test_type == TVE_LEADS_SHORTCODE_TEST_TYPE || $test->test_type == TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE ) { $variation = tve_leads_get_form_variation( $item->form_type_id, $item->variation_key ); $item->name = $variation['post_title']; $item->trigger_name = tve_leads_trigger_nice_name( $variation ); $item->animation_name = tve_leads_animation_nice_name( $variation ); $item->preview_url = tve_leads_get_preview_url( $item->form_type_id, $item->variation_key ); $item->edit_url = tve_leads_get_editor_url( $item->form_type_id, $item->variation_key ); } else { $variation_control = tve_leads_get_form_variation( $item->form_type_id, $item->variation_key ); $form_type = tve_leads_get_form_type( $item->form_type_id ); $item->name = $variation_control['post_title']; $item->trigger_name = tve_leads_trigger_nice_name( $variation_control ); $item->animation_name = tve_leads_animation_nice_name( $variation_control ); $item->preview_url = tve_leads_get_preview_url( $item->form_type_id, $variation_control['key'] ); $item->form_type = $form_type->post_title; } } $item->conversion_rate = tve_leads_conversion_rate( $item->unique_impressions, $item->conversions, '' ); //we don't calculate for the control item if ( $index > 0 ) { //Percentage improvement = conversion rate of variation - conversion rate of control if ( is_numeric( $test->items[0]->conversion_rate ) ) { $item->percentage_improvement = round( ( ( $item->conversion_rate - $test->items[0]->conversion_rate ) * 100 ) / $test->items[0]->conversion_rate, 2 ); } else { $item->percentage_improvement = 'N/A'; } $item->beat_original = tve_leads_test_item_beat_original( $item->conversion_rate, $item->unique_impressions, $test->items[0]->conversion_rate, $test->items[0]->unique_impressions ); } if ( $item->active == 0 && $item->is_control == 0 ) { $item->stopped_date = date( 'd-m-Y', strtotime( $item->stopped_date ) ); $test->stopped_items[] = $item; unset( $test->items[ $index ] ); } } } /*Reset the test items IDS*/ $test->items = array_values( $test->items ); return $test; } /** * Get an array with all the items of a test having the ID as a key and the name as value * * @param $test_id * * @return array */ function tve_leads_get_test_items_with_names( $test_id ) { global $tvedb; $test = $tvedb->tve_leads_get_test( array( 'ID' => $test_id ) ); $test_items = $tvedb->get_test_items( array( 'test_id' => $test_id ) ); $test_item_names = array(); $test_item_ids = array(); switch ( $test->test_type ) { case TVE_LEADS_VARIATION_TEST_TYPE: case TVE_LEADS_SHORTCODE_TEST_TYPE: case TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE: $test_items_id = array(); foreach ( $test_items as $item ) { $test_items_id[] = $item->variation_key; $test_item_ids[ $item->variation_key ] = $item->is_control ? - 1 : $item->id; } $variations = tve_leads_get_form_variations( $test->main_group_id, array( 'tracking_data' => false, 'post_status' => null ) ); foreach ( $variations as $variation ) { if ( in_array( $variation['key'], $test_items_id ) ) { $test_item_names[ $variation['key'] ] = $variation['post_title']; } } return array( $test_item_names, $test_item_ids ); break; case TVE_LEADS_GROUP_TEST_TYPE: $test_items_id = array(); foreach ( $test_items as $item ) { $test_items_id[] = $item->form_type_id; $test_item_ids[ $item->form_type_id ] = $item->is_control ? - 1 : $item->id; } $form_types = tve_leads_get_form_types( array( 'lead_group_id' => $test->main_group_id, 'tracking_data' => false ) ); foreach ( $form_types as $form_type ) { if ( ! isset( $form_type->ID ) ) { continue; } if ( in_array( $form_type->ID, $test_items_id ) ) { $test_item_names[ $form_type->ID ] = $form_type->post_title; } } return array( $test_item_names, $test_item_ids ); break; } return array(); } /** * General function that reads DB and returns test items by filters * * @param $filters * * @return test Items */ function tve_leads_get_test_items( $filters ) { global $tvedb; $defaults = array( 'test_id' => null, 'main_group_id' => null, 'form_type_id' => null ); $filters = array_merge( $defaults, $filters ); $test_items = $tvedb->get_test_items( $filters ); return $test_items; } function tve_leads_get_completed_form_test( WP_Post $form_type, $test_type = null ) { global $tvedb; $filters = array( 'test_type' => $test_type, 'main_group_id' => $form_type->ID, 'status' => TVE_LEADS_STATUS_ARCHIVED ); $tests = $tvedb->tve_leads_get_tests( $filters ); return $tests; } /** * Stops underperforming variations * * @param $test_id */ function tve_leads_stop_underperforming_variations( $test_id ) { if ( empty( $test_id ) ) { return; } $test_model = tve_leads_get_test( $test_id, array( 'load_test_items' => true ) ); if ( empty( $test_model ) || empty( $test_model->auto_win_enabled ) || $test_model->status != TVE_LEADS_TEST_STATUS_RUNNING ) { return; } if ( ! empty( $test_model->auto_win_min_duration ) ) { /* check if this amount of time has passed -> if not, no need for further processing */ if ( time() < strtotime( $test_model->date_started . ' +' . $test_model->auto_win_min_duration . 'days' ) ) { return; } /* The time interval has passed, we can check the other conditions */ } /*Minimum conversion check*/ global $tvedb; $total_test_data = $tvedb->get_total_test_data( $test_id ); if ( intval( $total_test_data->total_conversions ) < intval( $test_model->auto_win_min_conversions ) ) { return; } foreach ( $test_model->items as $test_item ) { if ( $test_item->is_control ) { $control = $test_item; break; } } /*Stop if there are no conversions on control*/ if ( empty( $control ) ) { return; } if ( empty( $control->conversions ) ) { return; } $variations_beat_original = 100.0 - (float) $test_model->auto_win_chance_original; foreach ( $test_model->items as $test_item ) { if ( $test_item->is_control ) { continue; } if ( (float) $test_item->beat_original < $variations_beat_original ) { tve_leads_stop_test_item( $test_item->id, $test_id ); } } } /** * check if the automatic winner settings are enabled for a test and automatically * detect the winner item if the conditions are met * * @param int $test_id */ function tve_leads_test_check_winner( $test_id ) { if ( empty( $test_id ) ) { return; } $test_model = tve_leads_get_test( $test_id, array( 'load_test_items' => true ) ); if ( empty( $test_model ) || empty( $test_model->auto_win_enabled ) || $test_model->status != TVE_LEADS_TEST_STATUS_RUNNING ) { return; } if ( ! empty( $test_model->auto_win_min_duration ) ) { /* check if this amount of time has passed -> if not, no need for further processing */ if ( time() < strtotime( $test_model->date_started . ' +' . $test_model->auto_win_min_duration . 'days' ) ) { return; } /* The time interval has passed, we can check the other conditions */ } /*MINIMUM CONVERSION CHECK*/ global $tvedb; $total_test_data = $tvedb->get_total_test_data( $test_id ); if ( intval( $total_test_data->total_conversions ) < intval( $test_model->auto_win_min_conversions ) ) { return; } /* check the number of conversions of each item, and the chance to beat original */ $test_item_win_array = array(); foreach ( $test_model->items as $test_item ) { // if ( $minimum_conversions > $test_item->conversions ) { // continue; // } if ( $test_item->is_control ) { $variations_beat_original = 100.0 - (float) $test_model->auto_win_chance_original; $control_win = true; foreach ( $test_model->items as $var ) { if ( $var->is_control ) { continue; } if ( $variations_beat_original < floatval( $var->beat_original ) || empty( $var->beat_original ) ) { $control_win = false; } } if ( $control_win ) { $test_item->is_winner = 1; tve_leads_save_test_item( (array) $test_item ); break; } } else { if ( (float) $test_item->beat_original > (float) $test_model->auto_win_chance_original ) { $test_item_win_array[] = $test_item; // $test_item->is_winner = 1; // tve_leads_save_test_item( (array) $test_item ); // break; } } } if ( ! empty( $test_item_win_array ) ) { $winner_test_item = $test_item_win_array[0]; foreach ( $test_item_win_array as $var_win_arr ) { if ( $winner_test_item->auto_win_chance_original <= $var_win_arr->auto_win_chance_original ) { $winner_test_item = $var_win_arr; } } /*Set the winner to the highest beat original*/ $winner_test_item->is_winner = 1; tve_leads_save_test_item( (array) $winner_test_item ); } } /** * in case of a group level test, we need to archive all the variations that are not related to the winner form type * in case of a form type level test, we need to archive all other variations * * @param stdClass $winner_test_item * * @return stdClass $test_model */ function tve_leads_set_test_item_winner( $winner_test_item, $test_model ) { global $tvedb; $to_be_updated = array(); foreach ( $test_model->items as $test_item ) { if ( $test_item->id == $winner_test_item->id ) { continue; } $variations = tve_leads_get_form_variations( $test_item->form_type_id, array( 'tracking_data' => false ) ); /* set all variations as archived, except for the one that's either the winner, or the control of the form type winner */ foreach ( $variations as $i => $variation ) { if ( $variation['key'] != $winner_test_item->variation_key ) { $to_be_updated [] = $variation['key']; } } } $tvedb->mass_update_field( 'form_variations', 'post_status', TVE_LEADS_STATUS_ARCHIVED, $to_be_updated, 'key' ); /* finally, mark the test as completed */ $test_model->status = TVE_LEADS_STATUS_ARCHIVED; $test_model->date_completed = date( 'Y-m-d H:i:s' ); $tvedb->save_test( $test_model ); } /** * get all the child states for a variation key (it does not include the default state) * * @param int $variation_key * * @return array */ function tve_leads_get_form_child_states( $variation_key ) { global $tvedb; return $tvedb->get_form_variations( array( 'parent_id' => $variation_key, 'order' => 'state_order ASC' ) ); } /** * get all the related states for a form variation * $variation can be either a state or the main form variation * * @param array $variation * * @return array all the related states */ function tve_leads_get_form_related_states( $variation ) { if ( is_numeric( $variation ) ) { $variation = tve_leads_get_form_variation( null, $variation ); } if ( empty( $variation['parent_id'] ) ) { $parent = $variation; } else { $parent = tve_leads_get_form_variation( null, $variation['parent_id'] ); } $variations = array( $parent ); $variations = array_merge( $variations, tve_leads_get_form_child_states( $parent['key'] ) ); /** * Nice-names for each of the possible states */ $state_names = array( 'lightbox' => __( 'Lightbox', 'thrive-leads' ), 'already_subscribed' => __( 'Already Subscribed', 'thrive-leads' ), 'default' => __( 'State', 'thrive-leads' ) ); $indexes = array(); foreach ( $variations as $k => $variation ) { if ( ! isset( $indexes[ $variation['form_state'] ] ) ) { $indexes[ $variation['form_state'] ] = 1; } $state_name = empty( $variation['parent_id'] ) ? __( 'Default State', 'thrive-leads' ) : $state_names[ $variation['form_state'] ]; if ( $variation['form_state'] && $variation['form_state'] != 'already_subscribed' ) { $state_name .= " {$indexes[$variation['form_state']]}"; } $variations[ $k ]['state_name'] = $state_name; $indexes[ $variation['form_state'] ] ++; } return $variations; } /** * get the form type string for a variation * if the variation is a state, then we first check if it's state === 'lightbox' and if true, the form_type returned will be lightbox * by default it will return the form type of the variation parent (tve_form_type or shortcode etc) * * @param int|array $variation * @param bool $get_from_parent optional, allows forcing the function to return the form_type of the variation parent form (or shortcode etc) * @param bool $map_type if true, it will match the type with its template association (e.g. two_step => lightbox) * * @return string */ function tve_leads_get_form_type_from_variation( $variation, $get_from_parent = false, $map_type = true ) { if ( is_numeric( $variation ) ) { $variation = tve_leads_get_form_variation( null, $variation ); } if ( ! $get_from_parent && ! empty( $variation['form_state'] ) && $variation['form_state'] == 'lightbox' ) { return 'lightbox'; } $form_type = get_post_meta( $variation['post_parent'], 'tve_form_type', true ); if ( $map_type ) { $form_type = Thrive_Leads_Template_Manager::tpl_type_map( $form_type ); } return $form_type; } /** * finds and returns the 'already_subscribed' state for a variation, if present (there can only be 1 subscribed state / veriation) * * @param array $default_state the parent (default state) variation * * @return array|null */ function tve_leads_get_already_subscribed_state( $default_state ) { global $tvedb; return $tvedb->get_variation_already_subscribed_state( $default_state['key'] ); } /** * get the tracking data for a post from the post-meta option * if no value is present there, count the logs and update the meta option value with that number * * applies to: Lead Groups, Form Types, Shortcodes, 2-step Shortcodes * * @param WP_Post|int $post * @param int $event_type * @param bool $fetch_if_not_found whether or not to count the logs if there is no entry in the cache * * @return int */ function tve_leads_get_post_tracking_data( $post, $event_type = TVE_LEADS_UNIQUE_IMPRESSION, $fetch_if_not_found = true ) { $post_id = $post; if ( is_array( $post ) ) { $post_id = $post['ID']; } elseif ( is_a( $post, 'WP_Post' ) ) { $post_id = $post->ID; } $meta_key = 'tve_leads_' . ( $event_type === TVE_LEADS_UNIQUE_IMPRESSION ? 'impressions' : 'conversions' ); $value = get_post_meta( $post_id, $meta_key, true ); if ( $value === '' && $fetch_if_not_found === true ) { $value = tve_leads_get_tracking_data( $event_type, array( $post->post_type === TVE_LEADS_POST_FORM_TYPE ? 'form_type_id' : 'main_group_id' => $post->ID ) ); update_post_meta( $post_id, $meta_key, $value ); } return $value; } /** * get tracking data for a form variation (design). Form variations are stored in a separate table, so we cannot use the WP post_meta API * * applies to: Form Variations * * @param array $variation * @param int $event_type * * @return int */ function tve_leads_get_variation_tracking_data( &$variation, $event_type = TVE_LEADS_UNIQUE_IMPRESSION ) { $key = 'cache_' . ( $event_type === TVE_LEADS_UNIQUE_IMPRESSION ? 'impressions' : 'conversions' ); if ( $variation[ $key ] === null ) { $variation[ $key ] = (int) tve_leads_get_tracking_data( $event_type, array( 'variation_key' => $variation['key'] ) ); $variation['save_flag'] = true; } return $variation[ $key ]; } /** * update the cached impression or conversion count for a post * * applies to: Lead Groups, Form Types, Shortcodes, 2-step Lightboxes * * @param mixed $post * @param int $value * @param int $event_type * * @return int|bool */ function tve_leads_set_post_tracking_data( $post, $value, $event_type = TVE_LEADS_UNIQUE_IMPRESSION ) { $post_id = $post; if ( is_array( $post ) ) { $post_id = $post['ID']; } elseif ( is_a( $post, 'WP_Post' ) ) { $post_id = $post->ID; } $meta_key = 'tve_leads_' . ( $event_type === TVE_LEADS_UNIQUE_IMPRESSION ? 'impressions' : 'conversions' ); return update_post_meta( $post_id, $meta_key, $value ); } /** * reset all cached impression and conversion count for a post (Lead Group / Form Type / Shortcode / 2-step Lightbox * * @param WP_Post $post * * @return bool */ function tve_leads_reset_post_tracking_data( $post ) { global $tvedb; if ( $post->post_parent ) { /** * if this is a Form Type, we need to also update the parent cached impression count */ $impressions = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION ); $conversions = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION ); $parent_impressions = tve_leads_get_post_tracking_data( $post->post_parent, TVE_LEADS_UNIQUE_IMPRESSION, false ); $parent_conversions = tve_leads_get_post_tracking_data( $post->post_parent, TVE_LEADS_CONVERSION, false ); if ( $parent_impressions !== '' ) { $parent_impressions -= $impressions; tve_leads_set_post_tracking_data( $post->post_parent, $parent_impressions, TVE_LEADS_UNIQUE_IMPRESSION ); } if ( $parent_conversions !== '' ) { $parent_conversions -= $conversions; tve_leads_set_post_tracking_data( $post->post_parent, $parent_conversions, TVE_LEADS_CONVERSION ); } } tve_leads_set_post_tracking_data( $post, 0, TVE_LEADS_UNIQUE_IMPRESSION ); tve_leads_set_post_tracking_data( $post, 0, TVE_LEADS_CONVERSION ); /** * also, we need to reset the data for all variations that have $post as post_parent */ $variations = tve_leads_get_form_variations( $post->ID, array( 'tracking_data' => false, 'post_status' => array( TVE_LEADS_STATUS_PUBLISH, TVE_LEADS_STATUS_ARCHIVED ) ) ); foreach ( $variations as $v ) { $tvedb->update_variation_fields( $v, array( 'cache_impressions' => 0, 'cache_conversions' => 0 ) ); } return true; } /** * reset the cached tracking data for a variation and also update the cached tracking data for its parents (the Form Type and the Lead Group, if any) * * @param array $variation */ function tve_leads_reset_variation_tracking_data( $variation ) { global $tvedb; /** * reset the cached variation logs */ $tvedb->update_variation_fields( $variation['key'], array( 'cache_impressions' => 0, 'cache_conversions' => 0 ) ); /** * decrease the number of impressions and conversions from the parent cached variations (if any) */ $parent_impressions = tve_leads_get_post_tracking_data( $variation['post_parent'], TVE_LEADS_UNIQUE_IMPRESSION, false ); $parent_conversions = tve_leads_get_post_tracking_data( $variation['post_parent'], TVE_LEADS_CONVERSION, false ); /** * update only if there actually is some cached data */ if ( $parent_impressions !== '' ) { $parent_impressions -= $variation['impressions']; tve_leads_set_post_tracking_data( $variation['post_parent'], $parent_impressions, TVE_LEADS_UNIQUE_IMPRESSION ); } if ( $parent_conversions !== '' ) { $parent_conversions -= $variation['conversions']; tve_leads_set_post_tracking_data( $variation['post_parent'], $parent_conversions, TVE_LEADS_CONVERSION ); } /** * go a level higher, and change the cached data for the Lead Group, if any is found */ $parent = get_post( $variation['post_parent'] ); if ( $parent && $parent->post_parent ) { $parent_impressions = tve_leads_get_post_tracking_data( $parent->post_parent, TVE_LEADS_UNIQUE_IMPRESSION, false ); $parent_conversions = tve_leads_get_post_tracking_data( $parent->post_parent, TVE_LEADS_CONVERSION, false ); if ( $parent_impressions !== '' ) { $parent_impressions -= $variation['impressions']; tve_leads_set_post_tracking_data( $parent->post_parent, $parent_impressions, TVE_LEADS_UNIQUE_IMPRESSION ); } if ( $parent_conversions !== '' ) { $parent_conversions -= $variation['conversions']; tve_leads_set_post_tracking_data( $parent->post_parent, $parent_conversions, TVE_LEADS_CONVERSION ); } } } /** * Send email with the contact * * @param $contact_id * @param $email * @param int $save * * @return array */ function tve_send_contacts_email( $contact_id, $email, $save = 0 ) { global $tvedb; if ( empty( $email ) || ! is_email( $email ) ) { return array( 'response' => __( 'Invalid Email.', 'thrive-leads' ), 'type' => 'error' ); } if ( $save ) { tve_leads_update_option( 'contacts_send_email', $email ); } else { tve_leads_update_option( 'contacts_send_email', '' ); } $contact = $tvedb->tve_get_contact( 'id', $contact_id ); $contact->custom_fields = json_decode( $contact->custom_fields, true ); $subject = __( 'You have a New Signup', 'thrive-leads' ); ob_start(); include dirname( dirname( __FILE__ ) ) . '/admin/views/contacts/email_template.php'; $message = ob_get_contents(); ob_end_clean(); $subject = apply_filters( 'tve_leads_new_contact_body_subject', $subject, $contact ); $message = apply_filters( 'tve_leads_new_contact_email_body', $message, $contact ); $result = wp_mail( $email, $subject, $message ); if ( $result ) { $return = array( 'response' => __( 'Email sent successfully!', 'thrive-leads' ), 'type' => 'success' ); } else { $return = array( 'response' => __( 'An error occurred while sending the email!', 'thrive-leads' ), 'type' => 'error' ); } return $return; } /** * Prepare the file for download. * * @param $source * @param $type * @param $params * * @return array|mixed|object */ function tve_leads_process_contact_download( $source, $type, $params ) { require_once dirname( dirname( __FILE__ ) ) . '/admin/inc/classes/Thrive_Leads_Export.php'; $upload_dir = wp_upload_dir(); $contact_upload_path = $upload_dir['basedir'] . "/thrive-contacts"; $contact_upload_url = $upload_dir['baseurl'] . "/thrive-contacts"; /* if we can't create a thrive contact folder, we just use the uploads one */ if ( ! wp_mkdir_p( $contact_upload_path ) ) { $contact_upload_path = $upload_dir['basedir']; $contact_upload_url = $upload_dir['baseurl']; } $filename = "contacts-export-" . date( 'Y-m-d_H-i-s' ); switch ( $type ) { case 'excel': $filename .= ".xls"; $exporter = new ThriveLeadsExportDataExcel( 'file', $contact_upload_path . '/' . $filename ); break; case 'csv': $filename .= ".csv"; $exporter = new ThriveLeadsExportDataCSV( 'file', $contact_upload_path . '/' . $filename ); break; default: $filename = $exporter = ''; } $exporter->initialize(); if ( empty( $filename ) || empty( $exporter ) ) { return array( 'response' => __( 'Invalid export type.', 'thrive-leads' ) ); } global $tvedb; /* get contacts needed for export */ $contacts = $tvedb->tve_leads_get_contacts_stored( $source, $params ); /* store the download in the database */ $id = $tvedb->tve_leads_write_contact_download( $source, $contact_upload_url . '/' . $filename, $params ); /* build file header with custom fields */ $contacts_header = array( __( "Name", "thrive-leads" ), __( "Email", "thrive-leads" ), __( "Date and Time", "thrive-leads" ) ); $custom_header = array(); foreach ( $contacts as $contact ) { $custom_fields = json_decode( $contact->custom_fields ); foreach ( $custom_fields as $k => $v ) { if ( ! in_array( $k, $custom_header ) ) { $custom_header [] = $k; } } } $exporter->addRow( array_merge( $contacts_header, $custom_header ) ); foreach ( $contacts as $contact ) { $fields = array( $contact->name, $contact->email, date( 'd M, Y G:i', strtotime( $contact->date ) ) ); $custom_fields = json_decode( $contact->custom_fields, true ); foreach ( $custom_header as $field ) { if ( isset( $custom_fields[ $field ] ) ) { $fields[] = $custom_fields[ $field ]; } else { $fields[] = ""; } } $exporter->addRow( $fields ); } $exporter->finalize(); /* mark the download as completed */ $tvedb->tve_leads_update_contacts_download_status( $id, 'complete' ); $result = array( 'status' => 'complete', 'response' => __( 'Export Completed', 'thrive-leads' ), 'link' => $contact_upload_url . '/' . $filename, 'id' => $id ); return $result; } /** * Return chart data for annotations * * @param $filter * @param $chart_data * * @return array */ function tve_leads_get_chart_annotations( $filter, $chart_data ) { $grow = 0; $grows_count = 0; /* Calculate the medium growth so we can set a threshold for which to display annotations */ for ( $i = 1; $i < count( $chart_data ); $i ++ ) { if ( $chart_data[ $i - 1 ] < $chart_data[ $i ] ) { $grow += $chart_data[ $i ] - $chart_data[ $i - 1 ]; $grows_count ++; } } $data = array( 'type' => 'scatter', 'id' => 'flags', 'zIndex' => 2, 'name' => __( 'Marketing Events', 'thrive-leads' ), 'color' => '#800080', 'onSeries' => 'dataseries', 'shape' => 'triangle', 'data' => array() ); if ( $grows_count ) { $medium_growth = $grow / $grows_count; } else { return $data; } $dates = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] ); /* We find the date interval where we have a growth bigger than the medium and we search events that we want to display */ for ( $i = 1; $i < count( $chart_data ); $i ++ ) { if ( $chart_data[ $i ] - $chart_data[ $i - 1 ] > $medium_growth ) { $current_date = $dates[ $i - 1 ]; if ( $i == count( $chart_data ) - 1 ) { /* If we're at the last value, we set the end date to today. */ $end_date = date( 'Y-m-d' ); } if ( strpos( $current_date, 'Week' ) !== false ) { $current_date = preg_replace( "/Week (\d*), (.\d*)/", "$2W$1", $current_date ); } /* Convert the chart date in mysql date format so we can search posts in that period */ $filter['start_date'] = date( 'Y-m-d', strtotime( $current_date ) ) . ' 00:00:00'; $filter['end_date'] = date( 'Y-m-d', strtotime( $current_date ) ) . ' 23:59:59'; $args = array( 'post_type' => array( 'tve_lead_group', 'tve_lead_shortcode', 'tve_lead_2s_lightbox', 'post', 'page' ), 'posts_per_page' => - 1, 'orderby' => 'date', 'order' => 'ASC', 'date_query' => array( array( 'after' => $filter['start_date'], 'before' => $filter['end_date'], 'inclusive' => true, ), ), ); $query = new WP_query(); $posts = $query->query( $args ); $events = array( 'post' => array(), 'page' => array(), 'tests' => array(), 'tve_lead_group' => array(), 'tve_lead_shortcode' => array(), 'tve_lead_2s_lightbox' => array() ); foreach ( $posts as $post ) { $_type = get_post_type( $post->ID ); if ( ! empty( $post->post_title ) && $_type && isset( $events[ $_type ] ) ) { $events[ $_type ][] = $post->post_title; } } global $tvedb; $tests = $tvedb->tve_leads_get_tests( $filter ); foreach ( $tests as $test ) { $events['tests'][] = $test->title; } if ( ! empty( $events['post'] ) || ! empty( $events['page'] ) || ! empty( $events['tests'] ) || ! empty( $events['tve_lead_group'] ) || ! empty( $events['tve_lead_shortcode'] ) || ! empty( $events['tve_lead_2s_lightbox'] ) ) { $title = ''; $title .= empty( $events['post'] ) ? '' : '' . __( 'Posts Created: ' ) . '' . implode( ', ', $events['post'] ) . '
'; $title .= empty( $events['page'] ) ? '' : '' . __( 'Pages Created: ' ) . '' . implode( ', ', $events['page'] ) . '
'; $title .= empty( $events['tve_lead_group'] ) ? '' : '' . __( 'Groups Created: ' ) . '' . implode( ', ', $events['tve_lead_group'] ) . '
'; $title .= empty( $events['tve_lead_shortcode'] ) ? '' : '' . __( 'Shortcodes Created: ' ) . '' . implode( ', ', $events['tve_lead_shortcode'] ) . '
'; $title .= empty( $events['tve_lead_2s_lightbox'] ) ? '' : '' . __( 'ThriveBoxes Created: ' ) . '' . implode( ', ', $events['tve_lead_2s_lightbox'] ) . '
'; $title .= empty( $events['tests'] ) ? '' : '' . __( 'Tests started: ' ) . '' . implode( ', ', $events['tests'] ) . ''; /* We display the annotation between the points that indicate a growth at the middle */ $data['data'][] = array( 'x' => $i - 0.5, 'y' => ( $chart_data[ $i ] - $chart_data[ $i - 1 ] ) / 2 + $chart_data[ $i - 1 ], 'dataLabels' => array( 'useHTML' => true, 'enabled' => true, 'format' => $title, 'verticalAlign' => 'bottom', 'y' => - 10 ) ); } } } return $data; } /** * Get data for asset wizard to decide if the wizard should show, list of connected apis, email templates, and file/group proprieties * * @param array $asset_groups * * @return mixed */ function tve_leads_get_wizard_proprieties( $asset_groups = array() ) { $connected_apis = Thrive_List_Manager::getAvailableAPIsByType( true, array( 'email' ) ); if ( empty( $connected_apis ) ) { $proprieties['connections'] = 0; } else { $proprieties['connections'] = 1; } $template_subject = get_option( 'tve_leads_asset_mail_subject' ); $template_body = get_option( 'tve_leads_asset_mail_body' ); if ( empty( $template_subject ) || empty( $template_body ) ) { $proprieties['template'] = 0; } else { $proprieties['template'] = 1; } if ( empty( $asset_groups ) ) { $proprieties['files'] = 0; } else { foreach ( $asset_groups as $asset_group ) { if ( ! empty( $asset_group->files ) ) { $proprieties['files'] = 1; } else { $proprieties['files'] = 0; } } } return $proprieties; } /** * Fetch the user's full name * * @return string */ function tve_leads_assets_get_admin_name() { global $current_user; wp_get_current_user(); return $current_user->user_firstname . " " . $current_user->user_lastname; } /** * Get the asset email template * * @return mixed */ function tve_leads_assets_get_email_data() { $email_data['template_subject'] = get_option( 'tve_leads_asset_mail_subject', '' ); $email_data['template_body'] = get_option( 'tve_leads_asset_mail_body', '' ); return $email_data; } /** * Sets the email template for asset delivery * * @param $data * * @return bool */ function tve_leads_set_email_template( $data ) { update_option( 'tve_leads_asset_mail_subject', stripslashes( $data['post_subject'] ) ); update_option( 'tve_leads_asset_mail_body', stripslashes( $data['post_content'] ) ); return true; } /** * Gets the running tests for inconclusive test check * * @return array|void */ function tve_get_running_inconclusive_tests() { /* @var Tho_Db */ global $tvedb; $return = array(); $active_tests = $tvedb->tve_leads_get_tests( array( 'status' => TVE_LEADS_STATUS_RUNNING, 'auto_win_enabled' => 1 ) ); if ( empty( $active_tests ) ) { return; } foreach ( $active_tests as $active_test ) { $test_items = $tvedb->get_test_items( array( 'test_id' => $active_test->id ) ); $conversions = 0; foreach ( $test_items as $item ) { $conversions += intval( $item->conversions ); } $minimum_duration_doubled = intval( $active_test->auto_win_min_duration ) * 2; if ( $active_test->auto_win_min_conversions * 2 <= $conversions && date( 'Y-m-d', strtotime( $active_test->date_started . ' + ' . $minimum_duration_doubled . ' days' ) ) <= date( 'Y-m-d' ) ) { $return[] = $active_test; } } return $return; } /** * Stops a test item and sets the variation as winner if it's the last variation * * @param $item_id * @param $test_id * * @return bool */ function tve_leads_stop_test_item( $item_id, $test_id ) { /* @var Tho_Db */ global $tvedb; $return = $tvedb->stop_test_item( $item_id ); if ( $return ) { $test_items = $tvedb->get_test_items( array( 'test_id' => $test_id, 'active' => 1 ) ); if ( count( $test_items ) == 1 ) { $test_items[0]->is_winner = 1; tve_leads_save_test_item( (array) $test_items[0] ); } return true; } return false; } /** * Read all asset delivery groups from DB and return them * * @param $arguments array filter the posts * * @param $arguments * * @return array of WP_Post groups */ function tve_leads_get_asset_delivery_groups( $arguments = array() ) { if ( ! is_array( $arguments ) ) { $arguments = array(); } $defaults = array( 'post_type' => 'tve_lead_asset_group', 'post_status' => 'publish', 'orderby' => 'date', 'order' => 'ASC', 'posts_per_page' => - 1, ); $arguments = array_merge( $defaults, $arguments ); return $posts_array = get_posts( $arguments ); }