d' ); $contact->set_field_by_slug( 'automation-completed', $completed_aids ); $contact->set_field_by_slug( 'automation-entered', $entered_aids ); $contact->save_fields(); $processed ++; update_option( 'bwfan_automation_completed_processed', $processed ); } } /** * @param $contact BWFCRM_Contact * @param $new_aids * @param $field_slug * * @return false|string */ public static function get_automation_contact_field_value( $contact, $new_aids, $field_slug ) { $automation_aids = $contact->get_field_by_slug( $field_slug ); $automation_aids = json_decode( $automation_aids, true ); $automation_aids = ( ! empty( $automation_aids ) && is_array( $automation_aids ) ) ? $automation_aids : array(); $automation_aids = array_merge( $automation_aids, $new_aids ); $automation_aids = array_unique( $automation_aids ); sort( $automation_aids ); $automation_aids = wp_json_encode( $automation_aids ); return $automation_aids; } /** * Works with pro version only * * @return void */ public static function bwfan_store_automation_active_ids() { $max_count = get_option( 'bwfan_max_active_automation', 0 ); $processed = get_option( 'bwfan_active_automation_processed', 0 ); global $wpdb; $query = "SELECT `cid`, GROUP_CONCAT(`aid`) AS `aid` FROM `{$wpdb->prefix}bwfan_automation_contact` WHERE `ID` <= {$max_count} GROUP BY `cid` ORDER BY `cid` ASC LIMIT {$processed},20"; $automations = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $automations ) ) { delete_option( 'bwfan_max_active_automation' ); delete_option( 'bwfan_active_automation_processed' ); bwf_unschedule_actions( 'bwfan_store_automation_active_ids' ); return; } $start_time = time(); foreach ( $automations as $data ) { if ( ( time() - $start_time ) > 10 ) { return; } $aids = explode( ',', $data['aid'] ); $aids = array_unique( $aids ); $cid = $data['cid']; /** CRM contact object */ $contact = new BWFCRM_Contact( $cid ); if ( ! $contact->is_contact_exists() ) { $processed ++; update_option( 'bwfan_active_automation_processed', $processed ); continue; } /** Get automation ids in entered automation */ $entered_aids = self::get_automation_contact_field_value( $contact, $aids, 'automation-entered' ); /** Get automation ids in active automation */ $active_aids = self::get_automation_contact_field_value( $contact, $aids, 'automation-active' ); $contact->set_field_by_slug( 'automation-active', $active_aids ); $contact->set_field_by_slug( 'automation-entered', $entered_aids ); $contact->save_fields(); $processed ++; update_option( 'bwfan_active_automation_processed', $processed ); } } public static function get_contact_notes_type() { return apply_filters( 'bwfcrm_contact_note_types', array( array( 'value' => 'billing', 'label' => __( 'Billing', 'wp-marketing-automations' ), ), array( 'value' => 'shipping', 'label' => __( 'Shipping', 'wp-marketing-automations' ), ), array( 'value' => 'refund', 'label' => __( 'Refund', 'wp-marketing-automations' ), ), array( 'value' => 'subscription', 'label' => __( 'Subscription', 'wp-marketing-automations' ), ), array( 'value' => 'feedback', 'label' => __( 'Feedback', 'wp-marketing-automations' ), ), array( 'value' => 'log', 'label' => __( 'Log', 'wp-marketing-automations' ), ), array( 'value' => 'others', 'label' => __( 'Others', 'wp-marketing-automations' ), ), ) ); } /** * Checks if v1 older automation is active or not for functioning * * @return bool */ public static function is_automation_v1_active() { if ( defined( 'BWFAN_AUTOMATION_V1_DISABLE' ) && true === BWFAN_AUTOMATION_V1_DISABLE ) { return false; } $active = get_option( 'bwfan_automation_v1', 1 ); return ( 1 === intval( $active ) ) ? true : false; } public static function bulk_contact_automation_end( $option_key, $args, $scheduler_action ) { $data = get_option( $option_key, [] ); if ( empty( $data ) ) { delete_option( $option_key ); bwf_unschedule_actions( $scheduler_action, $args ); return; } $updated_data = $data; $start_time = time(); foreach ( $data as $key => $id ) { if ( ( time() - $start_time ) > 10 ) { return; } $automation_contact = BWFAN_Model_Automation_Contact::get( $id ); /** End Automation */ self::end_v2_automation( 0, $automation_contact, 'manually' ); /** Update status as success for any step trail where status was waiting */ BWFAN_Model_Automation_Contact_Trail::update_all_step_trail_status_complete( $automation_contact['trail'] ); self::update_automation_contact_fields( $automation_contact['cid'], $automation_contact['aid'] ); unset( $updated_data[ $key ] ); update_option( $option_key, $updated_data, false ); } } public static function bwfan_automation_contact_bulk_action( $dynamic_str, $aid, $action, $status ) { if ( 'end' === $action ) { $option_key = "bwfan_bulk_automation_contact_end_{$dynamic_str}"; $args = array( 'key' => $dynamic_str, 'aid' => $aid, 'action' => $action, 'status' => $status ); $scheduler_action = 'bwfan_automation_contact_bulk_action'; self::bulk_contact_automation_end( $option_key, $args, $scheduler_action ); return; } $option_key = "bwfan_bulk_automation_contact_{$action}_{$dynamic_str}"; $a_cids = get_option( $option_key, [] ); if ( empty( $a_cids ) ) { delete_option( $option_key ); bwf_unschedule_actions( 'bwfan_automation_contact_bulk_action', [ 'key' => $dynamic_str, 'aid' => $aid, 'action' => $action, 'status' => $status ] ); return; } if ( 'completed' === $status && 'rerun' !== $action ) { $action = 'delete_complete'; } self::perform_bulk_action( $a_cids, $option_key, $action, $status ); } public static function perform_bulk_action( $a_cids, $option_key, $action = '', $status = '' ) { $updated_a_cids = $a_cids; $start_time = time(); $batch_size = 20; while ( ( time() - $start_time ) < 10 ) { /** Get first 20 automation contacts */ $a_cids = ( count( $a_cids ) > $batch_size ) ? array_slice( $a_cids, 0, $batch_size ) : $a_cids; if ( empty( $a_cids ) ) { delete_option( $option_key ); return; } $a_cids = array_filter( $a_cids, 'intval' ); $stringPlaceholders = array_fill( 0, count( $a_cids ), '%d' ); $stringPlaceholders = implode( ', ', $stringPlaceholders ); global $wpdb; if ( 'delete_complete' === $action || 'completed' === $status ) { $query = $wpdb->prepare( " SELECT `ID`,`cid`,`aid`,`trail`,`event`,`data` FROM {$wpdb->prefix}bwfan_automation_complete_contact WHERE `ID` IN ( $stringPlaceholders ) ", $a_cids );// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders } else { $query = $wpdb->prepare( " SELECT `ID`,`cid`,`aid`,`trail` FROM {$wpdb->prefix}bwfan_automation_contact WHERE `ID` IN ( $stringPlaceholders )", $a_cids );// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders } try { BWFAN_Common::log_test_data( $option_key . ' - ' . $query, __FUNCTION__ ); $result = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } catch ( Error $e ) { delete_option( $option_key ); return; } if ( empty( $result ) ) { $updated_a_cids = array_diff( $updated_a_cids, $a_cids ); sort( $updated_a_cids ); update_option( $option_key, $updated_a_cids, false ); $a_cids = $updated_a_cids; continue; } $ids = array_column( $result, 'ID' ); /** Remove automation contact id if not in data */ $remove_ids = array_diff( $a_cids, $ids ); if ( ! empty( $remove_ids ) ) { $updated_a_cids = array_diff( $updated_a_cids, $remove_ids ); sort( $updated_a_cids ); update_option( $option_key, $updated_a_cids, false ); } $trails = array_column( $result, 'trail' ); switch ( true ) { case ( 'delete' === $action || 'delete_complete' === $action ): self::delete_automations( $ids, $trails, $action, $result ); break; case ( 'paused' === $action ) : BWFAN_Model_Automation_Contact::update_status_by_multiple_ids( $ids, 3 ); break; case ( 'unpaused' === $action ): BWFAN_Model_Automation_Contact::update_status_by_multiple_ids( $ids ); break; case ( 'retry' === $action ): BWFAN_Model_Automation_Contact::update_status_by_multiple_ids( $ids, 6 ); break; case ( 'run_now' === $action ): BWFAN_Model_Automation_Contact::update_e_time_col_of_ids( $ids ); break; case ( 'rerun' === $action || 're_run' === $action ): self::insert_automations( $result ); break; case ( 'startbegin' === $action ): $status = 1; $e_time = current_time( 'timestamp', 1 ); self::update_automation_status( $ids, $status, $trails, $e_time, true ); break; } /** Remove automation contact id from data after updating the status of automation and trail */ $updated_a_cids = array_diff( $updated_a_cids, $ids ); if ( empty( $updated_a_cids ) ) { delete_option( $option_key ); return; } sort( $updated_a_cids ); update_option( $option_key, $updated_a_cids, false ); /** Assign updated automation contact */ $a_cids = $updated_a_cids; } } public static function update_automation_status( $ids, $status, $trails, $e_time = '', $last = false ) { BWFAN_Model_Automation_Contact::update_status_by_multiple_ids( $ids, $status, $e_time, $last ); if ( 1 === $status ) { BWFAN_Model_Automation_Contact_Trail::update_multiple_trail_status( $trails, 0 ); } } public static function delete_automations( $ids, $trails, $action = '', $automation_data = [] ) { global $wpdb; $table_name = "{$wpdb->prefix}bwfan_automation_contact"; if ( 'delete_complete' === $action ) { $table_name = "{$wpdb->prefix}bwfan_automation_complete_contact"; } if ( ! empty( $ids ) ) { $ids = array_filter( $ids, 'intval' ); $stringPlaceholders = array_fill( 0, count( $ids ), '%d' ); $stringPlaceholders = implode( ', ', $stringPlaceholders ); $query = $wpdb->prepare( "DELETE FROM {$table_name} WHERE `ID` IN ( $stringPlaceholders )", $ids );// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders $wpdb->query( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } if ( ! empty( $trails ) ) { $trails = array_filter( $trails ); $placeholder = array_fill( 0, count( $trails ), '%s' ); $placeholder = implode( ', ', $placeholder ); $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}bwfan_automation_contact_trail WHERE tid IN ( $placeholder )", $trails ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders } if ( ! class_exists( 'BWFCRM_Contact' ) ) { /** Works with pro version only */ return; } foreach ( $automation_data as $data ) { self::maybe_remove_aid_from_contact_fields( $data['cid'], $data['aid'] ); } } /** * Get automation active and completed count then remove from contact fields */ public static function maybe_remove_aid_from_contact_fields( $cid, $aid ) { if ( ! class_exists( 'BWFCRM_Contact' ) ) { /** Works with pro version only */ return; } /** Get active automation contact count */ $active = BWFAN_Model_Automation_Contact::get_automation_count_by_cid( $cid, $aid ); /** if active count is 0 then remove automation id from automation completed field */ if ( 0 === absint( $active ) ) { self::remove_aid_from_contact_field( $cid, $aid, 'automation-active' ); } /**Get completed automation contact count */ $completed = BWFAN_Model_Automation_Complete_Contact::get_automation_count_by_cid( $cid, $aid ); /** if active and completed count is 0 then remove automation id from automation entered field */ $is_entered = absint( $active ) + absint( $completed ); if ( 0 === $is_entered ) { self::remove_aid_from_contact_field( $cid, $aid, 'automation-entered' ); } /** if completed count is 0 then remove automation id from automation completed field */ if ( 0 === absint( $completed ) ) { self::remove_aid_from_contact_field( $cid, $aid, 'automation-completed' ); } } /** * Remove automation id from contact fields */ public static function remove_aid_from_contact_field( $cid, $removed_aid, $field_slg ) { $contact = new BWFCRM_Contact( $cid ); if ( ! $contact->is_contact_exists() ) { return; } $automations = $contact->get_field_by_slug( $field_slg ); $automation_ids = json_decode( $automations, true ); $automation_ids = ( ! empty( $automation_ids ) && is_array( $automation_ids ) ) ? $automation_ids : array(); if ( empty( $automation_ids ) ) { return; } $aid = (string) $removed_aid; /**remove automation from field */ $aid_index = array_search( $aid, $automation_ids ); if ( false !== $aid_index ) { unset( $automation_ids[ $aid_index ] ); } sort( $automation_ids ); $automation_ids = wp_json_encode( $automation_ids, true ); $contact->set_field_by_slug( $field_slg, $automation_ids ); $contact->save_fields(); } public static function bwfan_bulk_action( $option_key, $type, $cart_type = '' ) { $option_key = "bwfan_bulk_action_{$option_key}"; $ids = get_option( $option_key, [] ); if ( empty( $ids ) ) { delete_option( $option_key ); bwf_unschedule_actions( "bwfan_bulk_action", [ 'key' => $option_key, 'type' => $type ] ); return; } $updated_ids = $ids; $start_time = time(); $batch_size = 20; while ( ( time() - $start_time ) < 15 ) { /** Get first 20 ids */ $ids = ( count( $ids ) > $batch_size ) ? array_slice( $ids, 0, $batch_size ) : $ids; $ids = array_filter( $ids, 'intval' ); $selected_ids = implode( ', ', $ids ); $stringPlaceholders = array_fill( 0, count( $ids ), '%d' ); $stringPlaceholders = implode( ', ', $stringPlaceholders ); global $wpdb; switch ( true ) { case ( 'tag' === $type || 'list' === $type || 'audience' === $type ): $query = "DELETE FROM {$wpdb->prefix}bwfan_terms WHERE `ID` IN ( $stringPlaceholders )"; $wpdb->query( $wpdb->prepare( $query, $ids ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL break; case ( 'automation_v1' === $type || 'automation_v2' === $type ): BWFAN_Core()->automations->delete_automation( $ids ); BWFAN_Core()->automations->delete_automationmeta( $ids ); if ( 'automation_v2' === $type ) { self::delete_automation_v2_migrations( $ids ); } if ( 'automation_v1' === $type ) { self::delete_automation_v1_migrations( $ids ); } break; case ( 'broadcast' === $type ): $query = "DELETE FROM {$wpdb->prefix}bwfan_broadcast WHERE `id` IN ( $stringPlaceholders )"; $wpdb->query( $wpdb->prepare( $query, $ids ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL /** Remove parent from child broadcasts */ if ( bwfan_is_autonami_pro_active() && method_exists( 'BWFAN_Model_Broadcast', 'remove_parent_from_child' ) ) { BWFAN_Model_Broadcast::remove_parent_from_child( $ids ); } break; case ( 'template' === $type ): BWFAN_Model_Templates::bwf_delete_template( $ids ); break; case ( 'form' === $type ): $query = "DELETE FROM {$wpdb->prefix}bwfan_form_feeds WHERE `ID` IN ( $stringPlaceholders )"; $wpdb->query( $wpdb->prepare( $query, $ids ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL break; case ( 'cart' === $type ): if ( 'recovered' === $cart_type ) { BWFAN_Recoverable_Carts::delete_recovered_carts( $selected_ids ); } else { $query = "DELETE FROM {$wpdb->prefix}bwfan_abandonedcarts WHERE `ID` IN ($stringPlaceholders )"; $wpdb->query( $wpdb->prepare( $query, $ids ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } break; case ( 'recovered-cart' === $type ): $query = "DELETE FROM {$wpdb->prefix}postmeta WHERE (`meta_key` = '_bwfan_recovered_ab_id' OR `meta_key` = '_bwfan_ab_cart_recovered_a_id') AND `post_id` IN ( $stringPlaceholders )"; $wpdb->query( $wpdb->prepare( $query, $ids ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL break; } /** Remove id from data after deleting */ $updated_ids = array_diff( $updated_ids, $ids ); if ( empty( $updated_ids ) ) { delete_option( $option_key ); return; } sort( $updated_ids ); update_option( $option_key, $updated_ids, false ); /** Assign updated ids */ $ids = $updated_ids; } return $ids; } public static function delete_automation_v2_migrations( $aids ) { BWFAN_Model_Automation_Step::delete_steps_by_aid( $aids ); BWFAN_Model_Automation_Contact::delete_automation_contact_by_aid( $aids ); BWFAN_Model_Automation_Complete_Contact::delete_automation_contact_by_aid( $aids ); BWFAN_Model_Automation_Contact_Trail::delete_automation_trail_by_id( $aids ); } public static function delete_automation_v1_migrations( $aids ) { BWFAN_Core()->tasks->delete_tasks( array(), $aids ); BWFAN_Core()->logs->delete_logs( array(), $aids ); BWFAN_Core()->automations->set_automation_id( $aids ); } /** * @return void */ public static function delete_expired_dynamic_coupons() { global $wpdb; //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $coupons = $wpdb->get_results( $wpdb->prepare( " SELECT m1.post_id as id FROM {$wpdb->prefix}postmeta as m1 LEFT JOIN {$wpdb->prefix}postmeta as m2 ON m1.post_id = m2.post_id WHERE m1.meta_key = %s AND m1.meta_value = %d AND m2.meta_key = %s AND TIMESTAMPDIFF(MINUTE,m2.meta_value,UTC_TIMESTAMP) > %d LIMIT %d ", '_is_bwfan_coupon', 1, 'expiry_date', 0, 20 ) ); if ( empty( $coupons ) ) { bwf_unschedule_actions( 'bwfan_delete_expired_coupons' ); return; } foreach ( $coupons as $coupon ) { wp_delete_post( $coupon->id, true ); } } public static function append_extra_url_arguments( $url, $url_utm_args = [] ) { $utm_campaign = filter_input( INPUT_GET, 'utm_campaign' ); if ( ! is_null( $utm_campaign ) && ! empty( $utm_campaign ) ) { $url_utm_args['utm_campaign'] = $utm_campaign; } $utm_term = filter_input( INPUT_GET, 'utm_term' ); if ( ! is_null( $utm_term ) && ! empty( $utm_term ) ) { $url_utm_args['utm_term'] = $utm_term; } $utm_source = filter_input( INPUT_GET, 'utm_source' ); if ( ! is_null( $utm_source ) && ! empty( $utm_source ) ) { $url_utm_args['utm_source'] = $utm_source; } $utm_content = filter_input( INPUT_GET, 'utm_content' ); if ( ! is_null( $utm_content ) && ! empty( $utm_content ) ) { $url_utm_args['utm_content'] = $utm_content; } $utm_medium = filter_input( INPUT_GET, 'utm_medium' ); if ( ! is_null( $utm_medium ) && ! empty( $utm_medium ) ) { $url_utm_args['utm_medium'] = $utm_medium; } $url = add_query_arg( $url_utm_args, $url ); return $url; } public static function get_contact_columns() { $columns = get_user_meta( get_current_user_id(), '_bwfan_contact_columns_v2', true ); if ( is_array( $columns ) ) { return $columns; } $wc_columns = []; $default_columns = [ [ 'country' => 'Country/Region', 'label' => __( 'Country/Region', 'wp-marketing-automations' ), 'groupKey' => 'geography', 'groupLabel' => __( 'Geography', 'wp-marketing-automations' ), ], [ 'state' => 'State', 'label' => __( 'State', 'wp-marketing-automations' ), 'groupKey' => 'geography', 'groupLabel' => __( 'Geography', 'wp-marketing-automations' ), ], [ 'tags' => 'Tags', 'label' => __( 'Tags', 'wp-marketing-automations' ), 'groupKey' => 'segments', 'groupLabel' => __( 'Segments', 'wp-marketing-automations' ), ], [ 'lists' => __( 'Lists', 'wp-marketing-automations' ), 'label' => 'Lists', 'groupKey' => 'segments', 'groupLabel' => __( 'Segments', 'wp-marketing-automations' ), ] ]; if ( class_exists( 'WooCommerce' ) ) { $wc_columns = [ [ 'total_order_count' => 'Orders Count', 'label' => __( 'Orders Count', 'wp-marketing-automations' ), 'groupKey' => 'woocommerce', 'groupLabel' => __( 'WooCommerce', 'wp-marketing-automations' ), ], [ 'total_order_value' => 'Total Revenue', 'label' => __( 'Total Revenue', 'wp-marketing-automations' ), 'groupKey' => 'woocommerce', 'groupLabel' => __( 'WooCommerce', 'wp-marketing-automations' ), ], [ 'l_order_date' => 'Last Order Date', 'label' => __( 'Last Order Date', 'wp-marketing-automations' ), 'groupKey' => 'woocommerce', 'groupLabel' => __( 'WooCommerce', 'wp-marketing-automations' ), ], ]; } return array_merge( $default_columns, $wc_columns ); } /** * Check if contact row found in the unsubscribe table and remove them. * * @param $contact * * @return bool */ public static function maybe_delete_unsubscribe_rows( $contact ) { if ( ! $contact instanceof WooFunnels_Contact ) { return false; } $email = $contact->get_email(); $contact_no = $contact->get_contact_no(); $data = array( 'recipient' => array( $email, $contact_no ), ); $rows = BWFAN_Model_Message_Unsubscribe::get_message_unsubscribe_row( $data, false ); if ( empty( $rows ) ) { return false; } $p_keys = array_column( $rows, 'ID' ); foreach ( $p_keys as $key ) { BWFAN_Model_Message_Unsubscribe::delete( $key ); } return true; } public static function get_admin_analytics_cache_lifespan() { $time = apply_filters( 'bwfan_admin_analytics_cache_lifespan', ( 1 * HOUR_IN_SECONDS ) ); return ( intval( $time ) > 0 ) ? intval( $time ) : ( 1 * HOUR_IN_SECONDS ); } /** * @param $diff_time * * @return string */ public static function get_difference_string( $diff_time ) { if ( empty( $diff_time ) || ! is_object( $diff_time ) ) { return ''; } if ( $diff_time->y > 0 ) { return $diff_time->y . __( ' year ago', 'wp-marketing-automations' ); } if ( $diff_time->m > 0 ) { return $diff_time->m . __( ' months ago', 'wp-marketing-automations' ); } if ( $diff_time->d > 0 ) { return $diff_time->d . __( ' days ago', 'wp-marketing-automations' ); } if ( $diff_time->h > 0 ) { return $diff_time->h . __( ' hours ago', 'wp-marketing-automations' ); } if ( $diff_time->i > 0 ) { return $diff_time->i . __( ' minutes ago', 'wp-marketing-automations' ); } if ( $diff_time->m > 0 ) { return $diff_time->s . __( ' seconds ago', 'wp-marketing-automations' ); } return ''; } public static function ping_woofunnels_worker() { $url = rest_url( '/woofunnels/v1/worker' ) . '?' . time(); $args = array( 'method' => 'GET', 'body' => array(), 'timeout' => 0.01, 'sslverify' => false, ); wp_remote_post( $url, $args ); } public static function get_formatted_price_wc( $price, $raw = true, $currency = '' ) { if ( true === $raw ) { return $price; } $decimal_separator = wc_get_price_decimal_separator(); $thousand_separator = wc_get_price_thousand_separator(); $decimals = wc_get_price_decimals(); if ( apply_filters( 'woocommerce_price_trim_zeros', false ) && $decimals > 0 ) { $price = wc_trim_zeros( $price ); } $output = number_format( $price, $decimals, $decimal_separator, $thousand_separator ); if ( ! empty( $currency ) ) { $position = get_option( 'woocommerce_currency_pos' ); $prefix = ''; $suffix = ''; switch ( $position ) { case 'left_space': $prefix = $currency . ' '; break; case 'left': $prefix = $currency; break; case 'right_space': $suffix = ' ' . $currency; break; case 'right': $suffix = $currency; break; } $output = $prefix . $output . $suffix; } return $output; } public static function get_formatting_for_wc_price( $attr, $order ) { $formatting = isset( $attr['format'] ) && ! empty( $attr['format'] ) ? $attr['format'] : 'raw'; $raw = ( 'raw' === strval( $formatting ) ) ? true : false; $currency_format = ''; if ( 'formatted-currency' === strval( $formatting ) ) { $currency = ! empty( $order ) && ! is_null( $order->get_currency() ) ? $order->get_currency() : get_option( 'woocommerce_currency' ); $currency_symbol = get_woocommerce_currency_symbol( $currency ); $currency_format = html_entity_decode( $currency_symbol ); } return array( 'raw' => $raw, 'currency' => $currency_format ); } /** * Advanced logging to check wp-json endpoint for event enabled or not * * @return bool */ public static function event_cb_advanced_log_enabled() { if ( self::is_log_enabled( 'bwfan_end_point_logging' ) ) { return true; } if ( defined( 'BWFAN_ALLOW_EVENT_ENDPOINT_LOGS' ) && true === BWFAN_ALLOW_EVENT_ENDPOINT_LOGS ) { return true; } if ( true === apply_filters( 'bwfan_allow_event_endpoint_logs', false ) ) { return true; } return false; } /** * Advanced logging for developers to check wp-json endpoint working or not * * @param $log * * @return void */ public static function event_advanced_logs( $log ) { if ( empty( $log ) || false === self::event_cb_advanced_log_enabled() ) { return; } $log = array( 't' => microtime( true ), 'm' => $log, ); BWFAN_Common::log_test_data( $log, 'fka-event-endpoint-check', true ); } /** * Update Contact WP User ID to 0 after a WP user is deleted * * @param $user_id * * @return void */ public static function update_contact_wp_id( $user_id ) { $bwf_contact = new WooFunnels_Contact( $user_id ); if ( 0 === intval( $bwf_contact->get_id() ) ) { return; } $bwf_contact->set_wpid( 0 ); $bwf_contact->save(); } /** * Get midnight time of tomorrow in store timezone * * @return int */ public static function get_midnight_store_time() { $timezone = new DateTimeZone( wp_timezone_string() ); $date = new DateTime(); $date->modify( '+1 days' ); $date->setTimezone( $timezone ); $date->setTime( 0, 0, 0 ); return $date->getTimestamp(); } /** * Fetch updated data * * @param $meta * * @return mixed */ public static function fetch_updated_data( $meta ) { if ( ! bwfan_is_autonami_pro_active() || ( ! isset( $meta['tags'] ) && ! isset( $meta['list'] ) ) ) { return $meta; } if ( isset( $meta['tags'] ) ) { $meta['tags'] = self::get_updated_tags_and_list( $meta['tags'] ); } if ( isset( $meta['list'] ) ) { $meta['list'] = self::get_updated_tags_and_list( $meta['list'] ); } return $meta; } /** * Modify automation steps data, fetch latest names in admin * * @param $step_type * @param $data * * @return mixed */ public static function modify_step_admin_data( $step_type, $data ) { if ( ! bwfan_is_autonami_pro_active() ) { return $data; } if ( defined( 'BWFAN_Disable_Automation_Fetch_Latest_Names' ) && 1 === intval( BWFAN_Disable_Automation_Fetch_Latest_Names ) ) { return $data; } if ( 'conditional' === $step_type ) { return BWFAN_Common::get_updated_tags_and_list_conditions( $data ); } if ( 'benchmark' === $step_type ) { if ( isset( $data->list ) ) { $data->list = BWFAN_Common::get_updated_tags_and_list( (array) $data->list ); } if ( isset( $data->tags ) ) { $data->tags = BWFAN_Common::get_updated_tags_and_list( (array) $data->tags ); } return $data; } if ( 'action' === $step_type ) { if ( isset( $data->tags ) ) { $data->tags = BWFAN_Common::get_updated_tags_and_list( (array) $data->tags ); } if ( isset( $data->list_id ) ) { $data->list_id = BWFAN_Common::get_updated_tags_and_list( (array) $data->list_id ); } } return $data; } /** * Get updated tags & lists names * * @param $terms * @param $id_key * @param $name_key * * @return array|array[]|mixed|object[] */ public static function get_updated_tags_and_list( $terms, $id_key = 'id', $name_key = 'name' ) { if ( ! bwfan_is_autonami_pro_active() ) { return $terms; } return array_map( function ( $term ) use ( $id_key, $name_key ) { $obj = false; /** If data is in object then convert into array */ if ( is_object( $term ) ) { $term = (array) $term; $obj = true; } $data = BWFAN_Model_Terms::get( $term[ $id_key ] ); $term[ $name_key ] = is_array( $data ) && ! empty( $data['name'] ) ? $data['name'] : $term[ $name_key ]; return ( true === $obj ) ? (object) $term : $term; }, $terms ); } /** * Get updated tags & lists names for conditional step * * @param $rules * * @return mixed */ public static function get_updated_tags_and_list_conditions( $rules ) { if ( empty( $rules ) ) { return $rules; } foreach ( $rules as $or_key => $or_rule ) { if ( ! is_array( $or_rule ) ) { continue; } /** OR block */ foreach ( $or_rule as $and_key => $rule ) { /** AND block */ if ( ! isset( $rule->filter ) || ! in_array( $rule->filter, [ 'contact_tags', 'contact_lists' ] ) ) { continue; } $rules[ $or_key ][ $and_key ]->data = self::get_updated_tags_and_list( $rule->data, 'key', 'label' ); } } return $rules; } /** * Get contact marketing status * * @param $contact_status * @param $email * @param $phone * * @return array */ public static function get_contact_status( $contact_status = 0, $email = '', $phone = '' ) { $response = [ 'status' => $contact_status, 'email_status' => 1, 'sms_status' => 1 ]; if ( empty( $email ) && empty( $phone ) ) { return $response; } $data = array( 'recipient' => array( $email, $phone ), ); $unsubscribed_rows = BWFAN_Model_Message_Unsubscribe::get_message_unsubscribe_row( $data, false ); if ( empty( $unsubscribed_rows ) || 0 === count( $unsubscribed_rows ) ) { return $response; } $unsubscribed_rows = array_column( $unsubscribed_rows, 'recipient' ); $response['email_status'] = in_array( $email, $unsubscribed_rows, true ) ? 0 : 1; $response['sms_status'] = in_array( $phone, $unsubscribed_rows, true ) ? 0 : 1; return $response; } /** * Validate create new order settings * * @param $data * * @return bool */ public static function validate_create_order_event_setting( $data ) { /** Any product case */ if ( ! isset( $data['event_meta'] ) || ! isset( $data['event_meta']['order-contains'] ) || 'any' === $data['event_meta']['order-contains'] ) { return true; } $order = wc_get_order( intval( $data['order_id'] ) ); if ( ! $order instanceof WC_Order ) { return false; } /** Specific product case */ $get_selected_product = isset( $data['event_meta']['products'] ) ? $data['event_meta']['products'] : []; $ordered_products = array(); foreach ( $order->get_items() as $item ) { $ordered_products[] = $item->get_product_id(); /** In case variation */ if ( $item->get_variation_id() ) { $ordered_products[] = $item->get_variation_id(); } } /** Selected product and ordered products */ $product_selected = array_column( $get_selected_product, 'id' ); $ordered_products = array_unique( $ordered_products ); sort( $ordered_products ); return count( array_intersect( $product_selected, $ordered_products ) ) > 0; } /** * Update Automation meta data * @return void */ public static function update_meta_automations_v2() { $key = 'bwfan_automation_v2_meta_normalize'; $offset_id = get_option( $key ); if ( intval( $offset_id ) < 1 ) { delete_option( $key ); bwf_unschedule_actions( 'bwfan_update_meta_automations_v2' ); return; } global $wpdb; $query = "SELECT am.meta_value, a.ID FROM `{$wpdb->prefix}bwfan_automationmeta` AS am JOIN `{$wpdb->prefix}bwfan_automations` AS a ON am.bwfan_automation_id = a.ID WHERE a.ID >= %d AND am.meta_key = %s AND a.v = %d LIMIT 20"; $rows = $wpdb->get_results( $wpdb->prepare( $query, $offset_id, 'steps', 2 ), ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $rows ) ) { delete_option( $key ); bwf_unschedule_actions( 'bwfan_update_meta_automations_v2' ); return; } $start_time = time(); foreach ( $rows as $single ) { if ( ( time() - $start_time ) > 10 ) { return; } if ( ! isset( $single['meta_value'] ) ) { continue; } $meta_value = maybe_unserialize( $single['meta_value'] ); if ( ! is_array( $meta_value ) ) { continue; } $meta_value = array_map( function ( $data ) { if ( isset( $data['data'] ) && 'yesNoNode' !== $data['type'] ) { $data['data'] = []; } return $data; }, $meta_value ); BWFAN_Model_Automationmeta::update_automation_meta_values( $single['ID'], [ 'steps' => maybe_serialize( $meta_value ) ] ); /** updating the option key for next call */ update_option( 'bwfan_automation_v2_meta_normalize', ( intval( $single['ID'] ) + 1 ) ); } } /** * deleting logs older than 1 month * scheduler runs every month * * @return void */ public static function delete_bwfan_logs() { $wp_dir = wp_upload_dir(); $autonami_log_dir = $wp_dir['basedir'] . '/funnelkit/autonami-logs/'; $files = @scandir( $autonami_log_dir ); // @codingStandardsIgnoreLine. if ( empty( $files ) ) { return; } $expire_time = strtotime( "-30 days" ); foreach ( $files as $file ) { if ( in_array( $file, array( '.', '..' ), true ) ) { continue; } if ( is_dir( $file ) ) { continue; } if ( filemtime( $autonami_log_dir . $file ) > $expire_time ) { continue; } @unlink( trailingslashit( $autonami_log_dir ) . $file ); // @codingStandardsIgnoreLine. } } /** * get desired store time * * @param $hours * @param $mins * @param $sec * * @return int */ public static function get_store_time( $hours = 0, $mins = 0, $sec = 0 ) { $timezone = new DateTimeZone( wp_timezone_string() ); $date = new DateTime(); $date->setTimezone( $timezone ); $date->setTime( $hours, $mins, $sec ); if ( current_time( 'timestamp', 1 ) > $date->getTimestamp() ) { $date->modify( '+1 days' ); } return $date->getTimestamp(); } /** * Get database query cached result * * @param $query * * @return false|mixed */ public static function get_db_cache_data( $query = '' ) { if ( empty( $query ) ) { return false; } $query = md5( $query ); if ( ! is_array( self::$cached_db_data ) || ! isset( self::$cached_db_data[ $query ] ) ) { return false; } return self::$cached_db_data[ $query ]; } /** * Set database query cached result * * @param $query * @param $result * * @return bool */ public static function set_db_cache_data( $query = '', $result = '' ) { if ( empty( $query ) ) { return false; } $query = md5( $query ); self::$cached_db_data[ $query ] = $result; return true; } /** * Unset database query cached result * * @param $query * * @return false|void */ public static function unset_db_cache_key( $query = '' ) { if ( empty( $query ) ) { return false; } $query = md5( $query ); if ( isset( self::$cached_db_data[ $query ] ) ) { unset( self::$cached_db_data[ $query ] ); } } /** * get last order of the contact * * @param $contact * * @return array|stdClass|WC_Order[] */ public static function fetch_last_order_by_contact( $contact ) { if ( ! $contact instanceof WooFunnels_Contact ) { return []; } return wc_get_orders( array( 'meta_key' => '_woofunnel_cid', 'meta_value' => $contact->get_id(), 'orderby' => 'ID', 'order' => 'DESC', 'limit' => 1, ) ); } /** * @param $contact * * @return array|object|stdClass|null */ public static function fetch_last_refund_of_contact( $contact ) { if ( ! $contact instanceof WooFunnels_Contact ) { return []; } global $wpdb; $orders_ids = wc_get_orders( array( 'meta_key' => '_woofunnel_cid', 'meta_value' => $contact->get_id(), 'limit' => - 1, 'return' => 'ids' ) ); if ( empty( $orders_ids ) ) { return []; } $orders_ids = implode( ',', $orders_ids ); if ( BWF_WC_Compatibility::is_hpos_enabled() ) { $query = $wpdb->prepare( "SELECT `id` AS refund_id, `parent_order_id` AS order_id FROM {$wpdb->prefix}wc_orders WHERE type = %s AND status = %s AND `parent_order_id` IN ($orders_ids) ORDER BY id DESC LIMIT 1", 'shop_order_refund', 'wc-completed' );// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders $refund = $wpdb->get_row( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } else { $query = $wpdb->prepare( "SELECT `ID` AS refund_id, `post_parent` AS order_id FROM {$wpdb->prefix}posts WHERE `post_type` = %s AND `post_status` = %s AND `post_parent` IN ($orders_ids) ORDER BY `ID` DESC LIMIT 1", 'shop_order', 'publish' );// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders $refund = $wpdb->get_row( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } return $refund; } /** * Insert multiple contacts in automation contact table * * @param $automation_data * * @return void */ public static function insert_automations( $automation_data ) { foreach ( $automation_data as $auto_data ) { $data = [ 'cid' => $auto_data['cid'], 'aid' => $auto_data['aid'], 'event' => $auto_data['event'], 'c_date' => current_time( 'mysql', 1 ), 'e_time' => current_time( 'timestamp', 1 ), 'last_time' => current_time( 'timestamp', 1 ), 'data' => $auto_data['data'] ]; BWFAN_Model_Automation_Contact::insert( $data ); } } /** * Bulk action for all the contacts of different automation ids * * @param $dynamic_str * @param $action * @param $status * * @return void */ public static function bwfan_automation_all_contact_bulk_action( $dynamic_str, $action, $status ) { if ( 'end' === $action ) { $option_key = "bwfan_bulk_automation_all_contact_end_{$dynamic_str}"; $args = array( 'key' => $dynamic_str, 'action' => $action, 'status' => $status ); $scheduler_action = 'bwfan_automation_all_contact_bulk_action'; self::bulk_contact_automation_end( $option_key, $args, $scheduler_action ); return; } $option_key = "bwfan_bulk_automation_all_contact_{$action}_{$dynamic_str}"; $a_cids = get_option( $option_key, [] ); if ( empty( $a_cids ) ) { delete_option( $option_key ); bwf_unschedule_actions( 'bwfan_automation_all_contact_bulk_action', [ 'key' => $dynamic_str, 'action' => $action, 'status' => $status ] ); return; } if ( 'completed' === $status && 'rerun' !== $action ) { $action = 'delete_complete'; } self::perform_bulk_action( $a_cids, $option_key, $action, $status ); } /** * Correct shortcode string for block editor * * @param $body * @param $type * * @return array|mixed|string|string[] */ public static function correct_shortcode_string( $body, $type ) { if ( ! bwfan_is_autonami_pro_active() || ( $type !== 'block' && $type !== 5 ) || strpos( $body, 'bwfan_email_block_visibility' ) === false ) { return $body; } BWFAN_Core()->rules->load_rules_classes(); $body = str_replace( "', "]", $body ); return str_replace( "", "[/bwfbe_email_block_visibility]", $body ); } /** * Get default contact's count * * @return int[] */ public static function get_contact_data_counts() { $bulk_actions_all_count = 0; $bulk_actions_active_count = 0; if ( bwfan_is_autonami_pro_active() ) { $bulk_actions_count = BWFAN_Model_Bulk_Action::get_bulk_actions_total_count( false ); $bulk_actions_all_count = isset( $bulk_actions_count['all'] ) ? $bulk_actions_count['all'] : 0; $bulk_actions_active_count = isset( $bulk_actions_count['1'] ) ? $bulk_actions_count['1'] : 0; } return [ 'contacts_contacts' => 0, 'contacts_manage_audiences' => 0, 'contacts_manage_fields' => 0, 'contacts_manage_lists' => 0, 'contacts_manage_tags' => 0, 'contacts_bulk_actions' => $bulk_actions_all_count, 'contacts_active_bulk_actions' => $bulk_actions_active_count, ]; } /** * Get formatted string for mysql query * * @param $value * * @return array|mixed|string|string[] */ public static function get_formatted_value_for_dbquery( $value ) { return ( false !== strpos( $value, "'" ) ) ? str_replace( "'", "\'", $value ) : $value; } /** * Get store average order value * * @return float|int */ public static function get_store_aov() { $store_aov_key = 'bwfan_store_aov'; /** Get store aov from transient */ $store_aov = get_transient( $store_aov_key ); if ( ! empty( $store_aov ) ) { return floatval( $store_aov ); } /** Transient expiration time */ $exp = 12 * HOUR_IN_SECONDS; global $wpdb; $sql = "SELECT count(`order_id`) as `orders`, SUM(`total_sales`) as `total` FROM {$wpdb->prefix}wc_order_stats WHERE `status` NOT IN('wc-failed', 'wc-pending', 'wc-cancelled', 'wc-refunded') "; $result = $wpdb->get_results( $sql, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL $aov = 0; if ( ! empty( $result[0]['orders'] ) && ! empty( $result[0]['total'] ) ) { $aov = ( floatval( $result[0]['total'] ) / absint( $result[0]['orders'] ) ); } set_transient( $store_aov_key, $aov, $exp ); return $aov; } /** * @param string $message * @param array $data * @param int $code * * @return WP_Error */ public static function crm_error( $message = '', $data = array(), $code = 500 ) { $wp_error = new WP_Error( $code, $message ); if ( ! empty( $data ) ) { $wp_error->add_data( $data ); } return $wp_error; } /** * Remove filter before sending mail */ public static function bwf_remove_filter_before_wp_mail() { remove_all_filters( 'wp_mail_from' ); remove_all_filters( 'wp_mail_from_name' ); remove_all_filters( 'wp_mail_content_type' ); remove_all_filters( 'wp_mail_charset' ); } /** * Update automation contact's step trail status * * @return void */ public static function bwfan_update_contact_trail() { global $wpdb; $start_time = time(); do { $query = "SELECT ct.ID FROM `{$wpdb->prefix}bwfan_automation_contact_trail` AS ct JOIN `{$wpdb->prefix}bwfan_automation_complete_contact` AS cc ON ct.tid = cc.trail WHERE ct.status = 2 LIMIT 0,20"; $ids = $wpdb->get_col( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $ids ) ) { bwf_unschedule_actions( 'bwfan_update_contact_trail' ); break; } $ids = implode( ',', $ids ); $query = "UPDATE `{$wpdb->prefix}bwfan_automation_contact_trail` SET `status` = 1, `data` = NULL WHERE ID IN ($ids);"; $wpdb->query( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } while ( ( time() - $start_time ) < 10 ); } /** * Get product price with tax * * @param $product * * @return float|mixed|string|null */ public static function get_prices_with_tax( $product ) { if ( ! wc_tax_enabled() ) { return $product instanceof WC_Product && ! empty( $product->get_price() ) ? $product->get_price() : 0; } if ( ! $product instanceof WC_Product ) { return 0; } $tax_display_cart = get_option( 'woocommerce_tax_display_cart', '' ); if ( 'incl' === $tax_display_cart ) { return wc_get_price_including_tax( $product ); } if ( 'excl' === $tax_display_cart ) { return wc_get_price_excluding_tax( $product ); } return 0; } /** * Set headers to prevent caching * * @return void */ public static function nocache_headers() { do_action( 'litespeed_control_set_nocache', 'fkautomations' ); if ( headers_sent() ) { return; } header( 'Cache-Control: no-cache, no-store, must-revalidate, max-age=0' ); header( 'Pragma: no-cache' ); header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' ); header( 'Last-Modified: false' ); } /** * Check if contact is in automation for a particular order related event * * @param $aid * @param $cid * @param $order_id * @param $item_id * @param $event * * @return true|void */ public static function is_contact_in_automation( $aid, $cid, $order_id, $item_id = 0, $event = 'wc_new_order' ) { $active_contact = BWFAN_Model_Automation_Contact::is_contact_with_same_order( $aid, $cid, $order_id, $item_id, $event ); if ( ! empty( $active_contact ) ) { return true; } return BWFAN_Model_Automation_Complete_Contact::is_contact_with_same_order( $aid, $cid, $order_id, $item_id, $event ); } /** * Append extra data for order status change * * @param $extra_data * @param $order_id * @param $from * @param $to * * @return mixed */ public static function order_status_change( $extra_data, $order_id, $from, $to ) { $data = [ 'order_id' => $order_id, 'from' => $from, 'to' => $to, 'unique_key' => get_option( 'bwfan_u_key', false ), 'function_name' => 'wc_order_status_changed', ]; try { $a_e_id = BWFAN_Model_Automation_Events::insert_data( $data ); } catch ( Error $e ) { BWFAN_Common::log_test_data( 'Automation Event Insert Row Error: ' . $e->getMessage(), 'db-creation-errors', true ); $table_instance = new BWFAN_DB_Table_Automation_Events(); $table_instance->create_table(); $a_e_id = BWFAN_Model_Automation_Events::insert_data( $data ); } if ( ! empty( $a_e_id ) && intval( $a_e_id ) > 0 ) { $extra_data['a_e_id'] = $a_e_id; } return $extra_data; } public static function order_status_change_async_capture( $order_data ) { /** Delete row from automation events */ if ( isset( $order_data['a_e_id'] ) ) { BWFAN_Model_Automation_Events::delete( $order_data['a_e_id'] ); } $order = wc_get_order( $order_data['order_id'] ); if ( ! $order instanceof WC_Order ) { return; } do_action( 'bwfan_wc_order_status_changed', $order, $order_data['from'], $order_data['to'] ); } /** * Set dynamic string prop * * @return void */ public static function set_dynamic_string() { self::$dynamic_str = self::get_dynamic_string( 10 ); } /** * Get email from order * * @param $order_id * @param $order * * @return string|null */ public static function get_email_from_order( $order_id = '', ?WC_Order $order = null ) { if ( empty( $order_id ) && ! $order instanceof WC_Order ) { return ''; } if ( ! $order instanceof WC_Order ) { $order = wc_get_order( $order_id ); } return $order instanceof WC_Order ? $order->get_billing_email() : ''; } /** * Get phone from order * * @param $order_id * @param $order * * @return mixed|string|null */ public static function get_phone_from_order( $order_id = '', ?WC_Order $order = null ) { if ( empty( $order_id ) && ! $order instanceof WC_Order ) { return ''; } if ( ! $order instanceof WC_Order ) { $order = wc_get_order( $order_id ); } if ( ! $order instanceof WC_Order ) { return ''; } $phone = BWFAN_Woocommerce_Compatibility::get_order_data( $order, '_billing_phone' ); if ( empty( $phone ) ) { $phone = BWFAN_Woocommerce_Compatibility::get_order_data( $order, '_shipping_phone' ); } if ( empty( $phone ) || ! class_exists( 'BWFAN_Phone_Numbers' ) ) { return $phone; } $country = BWFAN_Woocommerce_Compatibility::get_order_data( $order, '_billing_country' ); if ( empty( $country ) ) { $country = BWFAN_Woocommerce_Compatibility::get_order_data( $order, '_shipping_country' ); } if ( ! empty( $country ) ) { $phone = BWFAN_Phone_Numbers::add_country_code( $phone, $country ); } return $phone; } /** * Get WP user id from order * * @param string $order_id * @param $order * * @return int|string */ public static function get_wp_user_id_from_order( $order_id = '', ?WC_Order $order = null ) { if ( empty( $order_id ) && ! $order instanceof WC_Order ) { return ''; } if ( ! $order instanceof WC_Order ) { $order = wc_get_order( $order_id ); } return $order instanceof WC_Order ? $order->get_customer_id() : ''; } /** * Save meta in order * * @param $order_id * @param $meta_key * @param $meta_value * * @return void */ public static function save_order_meta( $order_id, $meta_key, $meta_value ) { global $wpdb; $hpos_enabled = BWF_WC_Compatibility::is_hpos_enabled(); if ( $hpos_enabled ) { $table = "{$wpdb->prefix}wc_orders_meta"; $query = " SELECT `id`,`meta_value` FROM {$table} WHERE `order_id` = %d AND `meta_key` = %s "; } else { $table = "{$wpdb->prefix}postmeta"; $query = " SELECT `meta_id`,`meta_value` FROM {$table} WHERE `post_id` = %d AND `meta_key` = %s "; } $row = $wpdb->get_row( $wpdb->prepare( $query, $order_id, $meta_key ), ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL /** If no data found */ if ( empty( $row ) ) { $data = [ 'meta_key' => $meta_key, 'meta_value' => $meta_value, ]; if ( $hpos_enabled ) { $data['order_id'] = $order_id; } else { $data['post_id'] = $order_id; } $wpdb->insert( $table, $data ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery return; } /** If old value is equal to new value */ if ( $meta_value === $row['meta_value'] ) { return; } /** update meta value */ $column = ( $hpos_enabled ) ? 'id' : 'meta_id'; $wpdb->update( $table, [ 'meta_value' => $meta_value ], [ $column => $row[ $column ] ] ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching } /** * Get FK Automation links * * @return array */ public static function get_fk_site_links() { $default_args = [ 'utm_source' => 'WordPress', 'utm_campaign' => 'FKA+Lite+Plugin' ]; return [ 'upgrade' => apply_filters( 'bwfan_upgrade_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/exclusive-offer/' ) ), 'offer' => apply_filters( 'bwfan_offer_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/exclusive-offer/' ) ), 'autonami' => apply_filters( 'bwfan_fka_sales_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/wordpress-marketing-automation-autonami/' ) ), 'support' => apply_filters( 'bwfan_support_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/support/' ) ), 'docs' => apply_filters( 'bwfan_docs_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/docs/autonami-2/' ) ), 'nxtgenbuilder' => apply_filters( 'bwfan_fka_nextgen_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/autonami-next-generation-automation-builder/' ) ), 'migratefromv1' => apply_filters( 'bwfan_fka_migrate_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/docs/autonami-2/automations/migrate-from-older-version' ) ), 'whatsnew' => apply_filters( 'bwfan_fka_whatsnew_link_append_utm_args', add_query_arg( $default_args, 'https://funnelkit.com/whats-new/' ) ), 'publicapi' => apply_filters( 'bwfan_fka_public_api_link_append_utm_args', add_query_arg( $default_args, 'https://developers.funnelkit.com/#introduction' ) ), ]; } /** * Get unsubscribe link * * @param $data * * @return string */ public static function get_unsubscribe_link( $data ) { if ( empty( self::$unsubscribe_page_link ) ) { $global_settings = self::get_global_settings(); if ( ! isset( $global_settings['bwfan_unsubscribe_page'] ) || empty( $global_settings['bwfan_unsubscribe_page'] ) ) { self::$unsubscribe_page_link = esc_url_raw( home_url() ); } else { $page = absint( $global_settings['bwfan_unsubscribe_page'] ); self::$unsubscribe_page_link = get_permalink( $page ); } } if ( empty( $data ) || ! is_array( $data ) ) { return self::$unsubscribe_page_link; } if ( empty( $data['uid'] ) && isset( $data['contact_id'] ) ) { $contact = new WooFunnels_Contact( '', '', '', $data['contact_id'] ); $uid = ( $contact->get_id() > 0 ) ? $contact->get_uid() : ''; if ( ! empty( $uid ) ) { $data['uid'] = $uid; } unset( $data['contact_id'] ); } $data['bwfan-action'] = 'unsubscribe'; return add_query_arg( $data, self::$unsubscribe_page_link ); } /** * Checking wc new order goal in automation * * @param $aid * * @return bool */ public static function is_wc_order_goal( $aid ) { global $wpdb; $query = $wpdb->prepare( "SELECT `ID` FROM {$wpdb->prefix}bwfan_automations WHERE ID = %d AND `benchmark` LIKE %s", $aid, '%"wc_new_order"%' ); return ( ! empty( $wpdb->get_var( $query ) ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } /** * Remove duplicate actions if found * * @return void */ public static function remove_duplicate_actions() { global $wpdb; $hooks = [ 'bwfan_delete_logs', 'bwfan_delete_expired_autonami_coupons', 'bwfan_mark_abandoned_lost_cart', 'bwfan_run_midnight_cron', 'bwfan_run_midnight_connectors_sync', 'bwfan_run_queue', 'bwfan_run_queue_v2', 'bwfcrm_broadcast_run_queue', 'bwfan_check_abandoned_carts', 'bwfan_5_minute_worker', 'bwfan_run_event_queue' ]; $placeholders = array_fill( 0, count( $hooks ), '%s' ); $placeholders_hooks = implode( ', ', $placeholders ); $query = "SELECT `hook`, count(`id`) as `count` FROM `{$wpdb->prefix}bwf_actions` WHERE `hook` IN ($placeholders_hooks) AND `status` = 0 GROUP BY `hook`;"; $query = $wpdb->prepare( $query, $hooks );// phpcs:ignore WordPress.DB.PreparedSQL $result = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $result ) ) { return; } $result = array_filter( $result, function ( $row ) { return $row['count'] > 1; } ); if ( empty( $result ) ) { return; } $hooks = array_column( $result, 'hook' ); sort( $hooks ); $placeholders = array_fill( 0, count( $hooks ), '%s' ); $placeholders_hooks = implode( ', ', $placeholders ); $query = $wpdb->prepare( "DELETE FROM `{$wpdb->prefix}bwf_actions` WHERE `hook` IN ($placeholders_hooks) AND `status` = 0", $hooks ); // phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders $wpdb->query( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( true === bwfan_is_autonami_pro_active() && in_array( 'bwfcrm_broadcast_run_queue', $hooks, true ) ) { /** Reschedule broadcast */ bwf_schedule_recurring_action( time(), 60, 'bwfcrm_broadcast_run_queue', array(), 'bwfcrm' ); } } /** * Save contact uid as cookie * * @param $optin_id * @param $posted_data * @param $bwf_contact WooFunnels_Contact * * @return void */ public static function set_uid_in_cookies( $optin_id, $posted_data, ?WooFunnels_Contact $bwf_contact = null ) { if ( headers_sent() ) { return; } /** If contact object available */ if ( ! is_null( $bwf_contact ) && $bwf_contact instanceof WooFunnels_Contact ) { $uid = $bwf_contact->get_uid(); if ( ! empty( $uid ) ) { BWFAN_Common::set_cookie( '_fk_contact_uid', $uid, time() + ( 10 * YEAR_IN_SECONDS ) ); return; } } if ( ! isset( $posted_data['cid'] ) || empty( $posted_data['cid'] ) ) { return; } $contact = new WooFunnels_Contact( '', '', '', $posted_data['cid'] ); if ( ! $contact instanceof WooFunnels_Contact ) { return; } $uid = $contact->get_uid(); if ( empty( $uid ) ) { return; } BWFAN_Common::set_cookie( '_fk_contact_uid', $uid, time() + ( 10 * YEAR_IN_SECONDS ) ); } /** * Returns block editor default settings * * @return array */ public static function get_block_editor_default_setting() { return [ 'site' => [ 'logo' => '', 'url' => '', 'logoAuto' => [ 'desktop' => true, ], 'logoSize' => [ 'desktop' => [ 'value' => 100, ], ], ], 'setting' => [ 'background' => [ 'desktop' => [ 'color' => '#f6f6f6', ], ], 'contentBackground' => [ 'desktop' => [ 'color' => '#ffffff', ], ], 'width' => [ 'desktop' => [ 'value' => 640, 'unit' => 'px', ], ], 'align' => [ 'desktop' => 'center', ], 'color' => [ 'desktop' => '#353030', ], 'font' => [ 'desktop' => [ 'family' => 'arial,helvetica,sans-serif', 'size' => 14, ], ], 'fontH1' => [ 'desktop' => [ 'size' => 36, ], ], 'fontH2' => [ 'desktop' => [ 'size' => 32, ], ], 'fontH3' => [ 'desktop' => [ 'size' => 28, ], ], 'fontH4' => [ 'desktop' => [ 'size' => 24, ], ], 'fontH5' => [ 'desktop' => [ 'size' => 20, ], ], 'fontH6' => [ 'desktop' => [ 'size' => 16, ], ], 'linkLineType' => [ 'desktop' => 'underline', ], 'linkColor' => [ 'desktop' => '#236fa1', ], 'linkLineColor' => [], 'buttonColor' => [ 'desktop' => '#ffffff', ], 'buttonBackground' => [ 'desktop' => [ 'color' => '#353030', 'gradient' => null, ], ], 'buttonSize' => [ 'desktop' => [ 'value' => 100, ], ], 'buttonAuto' => [ 'desktop' => true, ], 'buttonBorder' => [ 'desktop' => [ 'top-left' => '8', 'top-right' => '8', 'bottom-left' => '8', 'bottom-right' => '8', 'radius_unit' => 'px', ] ], 'buttonPadding' => [ 'desktop' => [ 'left' => '24', 'right' => '24', 'top' => '16', 'bottom' => '16', 'unit' => 'px', ] ], 'buttonFont' => [ 'desktop' => [ 'size' => 16, ], ], 'backupFont' => [ 'desktop' => [ 'family' => 'arial,helvetica,sans-serif', ], ], 'social' => [ [ 'iconName' => 'facebook', 'link' => '' ], [ 'iconName' => 'instagram', 'link' => '' ], [ 'iconName' => 'youtube', 'link' => '' ], [ 'iconName' => 'pinterest', 'link' => '' ], ], 'socialType' => 'circle', ], ]; } /** * Get block editor settings * * @return array|false|mixed|null */ public static function get_block_editor_settings() { if ( ! empty( self::$block_editor_settings ) ) { return self::$block_editor_settings; } $default = BWFAN_Common::get_block_editor_default_setting(); $saved_setting = get_option( 'bwf_global_block_editor_setting', $default ); if ( isset( $saved_setting['setting'] ) && isset( $default['setting'] ) ) { $new_settings = array_merge( $default['setting'], $saved_setting['setting'] ); $saved_setting['setting'] = $new_settings; } self::$block_editor_settings = ! empty( $saved_setting ) ? $saved_setting : $default; return self::$block_editor_settings; } /** * Check pro is deactivated or 3.0 * * @return bool */ public static function is_pro_3_0() { return ( ( ! bwfan_is_autonami_pro_active() ) || ( defined( 'BWFAN_PRO_VERSION' ) && version_compare( BWFAN_PRO_VERSION, '3.0.beta.27032024', '>=' ) ) ); } /** * Insert default fields * * @return void */ public static function insert_default_crm_fields() { global $wpdb; $crm_fields_table = $wpdb->prefix . 'bwfan_fields'; $default_fields = self::$crm_default_fields; $db_errors = []; foreach ( $default_fields as $field => $field_data ) { $already_exist = self::check_field_exist( $field ); if ( $already_exist ) { continue; } $data = [ 'name' => $field_data['name'], 'slug' => $field, 'type' => $field_data['type'], 'gid' => 0, 'meta' => wp_json_encode( $field_data['meta'] ), 'mode' => $field_data['mode'], 'vmode' => $field_data['vmode'], 'view' => $field_data['view'], 'search' => 1, 'created_at' => current_time( 'mysql', 1 ), ]; $wpdb->insert( $crm_fields_table, $data ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $field_id = $wpdb->insert_id; if ( ! empty( $wpdb->last_error ) ) { $db_errors[] = 'Error in default field creation: ' . $field_data['name'] . ' ' . $wpdb->last_error; } /** Check field column exist in contact_fields table **/ $exists = BWF_Model_Contact_Fields::column_already_exists( $field_id ); if ( empty( $exists ) ) { $column_added = BWF_Model_Contact_Fields::add_column_field( $field_id, 1 ); /** If column not added */ if ( true !== $column_added ) { BWFAN_Model_Fields::delete( $field_id ); $db_errors[] = 'Error in contact field column creation: ' . $column_added; } } } /** Log if any mysql errors */ if ( ! empty( $db_errors ) ) { BWFAN_Common::log_test_data( array_merge( [ __FUNCTION__ ], $db_errors ), 'field-creation-error' ); } } /** * Checking if field with slug exists or not * * @param $slug * * @return bool */ public static function check_field_exist( $slug ) { global $wpdb; $query = $wpdb->prepare( "SELECT `ID` FROM `{$wpdb->prefix}bwfan_fields` WHERE `slug` = %s LIMIT 0, 1", $slug ); $result = $wpdb->get_var( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL return ! empty( $result ); } /** * Get the complete phone number of a contact with a country code * * @param $contact_obj WooFunnels_Contact * * @return mixed|string|void */ public static function get_contact_full_number( $contact_obj ) { if ( ! $contact_obj instanceof WooFunnels_Contact || 0 === absint( $contact_obj->get_id() ) ) { return ''; } $phone = $contact_obj->get_contact_no(); if ( empty( $phone ) ) { return ''; } $country = $contact_obj->get_country(); if ( ! empty( $country ) ) { $phone = BWFAN_Phone_Numbers::add_country_code( $phone, $country ); } return $phone; } /** * @param $link * * @return void */ public static function wp_redirect( $link ) { remove_all_filters( 'wp_redirect' ); add_filter( 'allowed_redirect_hosts', function ( $allowed_hosts, $host ) use ( $link ) { /** Add link host in allowed hosts, because already checked link is valid or not */ if ( $host === wp_parse_url( $link, PHP_URL_HOST ) ) { $allowed_hosts[] = $host; } return $allowed_hosts; }, 10, 2 ); if ( ! headers_sent() ) { header( 'X-Robots-Tag: noindex, nofollow', true ); } wp_safe_redirect( $link ); exit; } /** * Get Contact id from contact object * * @param $email * @param $user_id * @param $phone * * @return int */ public static function get_cid_from_contact( $email = '', $user_id = 0, $phone = '' ) { if ( empty( $email ) && empty( $phone ) ) { return 0; } $contact = new WooFunnels_Contact( $user_id, $email, $phone ); if ( $contact->get_id() > 0 ) { return $contact->get_id(); } return 0; } /** * Return regex pattern * * @param int $type * * @return string */ public static function get_regex_pattern( $type = 1 ) { $type = (int) $type; switch ( $type ) { case 1: /** * [0] => href='https://google.com/?abcd=ss&utm_content=source' * [1] => https://google.com/?abcd=ss&utm_content=source */ return '/href=["\']?([^"\'>]+)["\']?/'; case 2: /** * [0] => */ return '/]+href=[^>]+>/i'; case 3: /** * [0] => https://... */ return '#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#'; default: return ''; } } /** * If url exists in excluded urls * * @param $url * * @return bool */ public static function is_exclude_url( $url ) { if ( empty( $url ) ) { return false; } $excluded_urls = [ 'fonts.googleapis.com', 'mailto:', 'tel:', 'whatsapp:', 'wa.me:', '//wa.me', 't.me', 'm.me', 'x.com', 'twitter.com', 'linkedin.com', 'instagram.com', 'pinterest.com', 'youtube.com', 'snapchat.com', 'reddit.com', 'tripadvisor.com', 'meetup.com', 'producthunt.com', 'tinder.com', 'tumblr.com', 'music.apple.com', 'open.spotify.com', 'soundcloud.com', 'yelp.com', 'medium.com', 'skype.com', 'flickr.com', 'github.com', 'discord.gg', 'tiktok.com', 'zoom.us' ]; $excluded_urls = apply_filters( 'bwfan_exclude_click_track_urls', $excluded_urls ); foreach ( $excluded_urls as $excluded_url ) { if ( $url === $excluded_url || false !== strpos( $url, $excluded_url ) ) { return true; } } return false; } public static function get_country_name( $country_code ) { $country_code = strtoupper( $country_code ); $countries = self::get_countries_data(); if ( isset( $countries[ $country_code ] ) ) { return $countries[ $country_code ]; } return $country_code; } /** countries data * @return mixed|null */ public static function get_countries_data() { $countries_json = file_get_contents( BWFAN_PLUGIN_DIR . '/includes/countries.json' ); $countries = json_decode( $countries_json, true ); return $countries; } /** * Conversions indexing * * @param $table_empty * * @return void */ public static function bwfan_conversions_index( $table_empty ) { $key = 'bwfan_conversions_index'; $order_ids = bwf_options_get( $key ); if ( empty( $order_ids ) || ! is_array( $order_ids ) || 0 === count( $order_ids ) ) { delete_option( $key ); bwf_unschedule_actions( 'bwfan_conversions_index' ); return; } $start_time = time(); $updated_orders = $order_ids; foreach ( $order_ids as $index => $order_id ) { if ( ( time() - $start_time ) > 10 ) { break; } $order = wc_get_order( $order_id ); if ( ! $order instanceof WC_Order ) { unset( $updated_orders[ $index ] ); continue; } /** Check order is already exists in table if table is not empty */ if ( empty( $table_empty ) ) { $already_exists = BWFAN_Model_Conversions::get_specific_rows( 'wcid', $order_id ); if ( ! empty( $already_exists ) ) { unset( $updated_orders[ $index ] ); continue; } } $cid = BWF_WC_Compatibility::get_order_meta( $order, '_woofunnel_cid' ); $oid = BWF_WC_Compatibility::get_order_meta( $order, '_bwfan_ab_cart_recovered_a_id' ); $data = array( 'wcid' => intval( $order_id ), 'cid' => intval( $cid ), 'oid' => intval( $oid ), 'otype' => 1, 'wctotal' => $order->get_total(), 'date' => $order->get_date_created()->date( 'Y-m-d H:i:s' ) ); BWFAN_Model_Conversions::insert( $data ); unset( $updated_orders[ $index ] ); } sort( $updated_orders ); if ( empty( $updated_orders ) ) { delete_option( $key ); bwf_unschedule_actions( 'bwfan_conversions_index' ); return; } bwf_options_update( $key, $updated_orders ); } /** * @return bool */ public static function is_conversion_empty() { global $wpdb; $query = "SELECT MAX(id) FROM {$wpdb->prefix}bwfan_conversions"; return empty( $wpdb->get_var( $query ) ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL } public static function get_skip_conversion_automations() { global $wpdb; $skip_events = apply_filters( 'bwfan_skip_conversion_automations', [ 'wcs_before_renewal' ] ); /** Create string placeholder */ $placeholder = array_fill( 0, count( $skip_events ), '%s' ); $placeholder = implode( ", ", $placeholder ); $query = $wpdb->prepare( "SELECT `ID` FROM {$wpdb->prefix}bwfan_automations WHERE 1 = 1 AND `event` IN ($placeholder) ", $skip_events );// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.PreparedSQLPlaceholders $query_res = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $query_res ) ) { return []; } return array_column( $query_res, 'ID' ); } /** * Include block editor shortcode before send mail * * @return void */ public static function bwfan_before_send_mail( $type = 'block' ) { if ( bwfan_is_autonami_pro_active() && version_compare( BWFAN_PRO_VERSION, '2.9.0', '>=' ) && in_array( $type, [ 5, 'block', '5', 7, '7' ] ) ) { include_once BWFAN_PRO_PLUGIN_DIR . '/crm/includes/class-bwfcrm-block-editor.php'; } } /** * Get product image url * * @param string|WC_Product $product * * @return string */ public static function get_product_image_url( $product = '', $size = 'thumbnail' ) { /** check for woocommerce active **/ if ( ! function_exists( 'bwfan_is_woocommerce_active' ) || false === bwfan_is_woocommerce_active() ) { return ''; } if ( ! empty( $product ) ) { if ( ! $product instanceof WC_Product || ( is_int( $product ) && intval( $product ) > 0 ) ) { $product = wc_get_product( $product ); } if ( $product ) { $product_img_id = $product->get_image_id(); if ( ! empty( $product_img_id ) ) { return wp_get_attachment_image_url( $product_img_id, $size ); } elseif ( $product->get_parent_id() ) { $parent_product = wc_get_product( $product->get_parent_id() ); if ( $parent_product ) { $image_id = $parent_product->get_image_id(); if ( ! empty( $image_id ) ) { return wp_get_attachment_image_url( $image_id, $size ); } } } } } return ''; } public static function bwfan_run_event_queue() { global $wpdb; $query = $wpdb->prepare( "SELECT `ID`, `args` FROM {$wpdb->prefix}bwfan_automation_events WHERE `execution_time` < %d ORDER BY `execution_time` ASC LIMIT 100", current_time( 'timestamp', 1 ) ); $results = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $results ) ) { return; } $events = []; foreach ( $results as $result ) { $events[ $result['ID'] ] = json_decode( $result['args'], true ); } $start_time = time(); $batch_size = 10; while ( count( $events ) > 0 && ( ( time() - $start_time ) < 15 ) ) { $selected_ids = ( count( $events ) > $batch_size ) ? array_slice( $events, 0, $batch_size, true ) : $events; foreach ( $selected_ids as $id => $args ) { unset( $events[ $id ] ); /** Delete row */ BWFAN_Model_Automation_Events::delete( $id ); if ( empty( $args ) ) { continue; } /** Order status change case */ if ( isset( $args['function_name'] ) && ( 'wc_order_status_changed' === $args['function_name'] ) ) { $order = wc_get_order( $args['order_id'] ); if ( $order instanceof WC_Order ) { do_action( 'bwfan_wc_order_status_changed', $order, $args['from'], $args['to'] ); } continue; }; /** Other events case */ BWFAN_Common::capture_async_helper( $args, false ); } } } /** * Set automation ended reason in data * * @param $reason * @param $data * * @return mixed */ public static function set_automation_ended_reason( $reason, $data ) { $decoded_data = ! empty( $data['data'] ) ? json_decode( $data['data'], true ) : []; $decoded_data['end_reason'] = $reason; $data['data'] = wp_json_encode( $decoded_data ); return $data; } /** * Get automaton end reason message * * @param $reason_data * * @return string */ public static function get_end_reason_message( $reason_data ) { if ( ! is_array( $reason_data ) || empty( $reason_data ) ) { return ''; } $messages = [ BWFAN_Automation_Controller::$MANUAL_END => __( "Manually ended by User #{user_id}", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$ACTION_END => __( "Ended by 'End automation' action (step #{step_id} of Automation #{automation_id})", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$BULK_ACTION_END => __( "Ended by Bulk Action #{id}", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$LINK_TRIGGER_END => __( "Ended by Link Trigger #{id}", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$GOAL_UPDATE_WITH_END => __( "Ended because goal step ( step #{step_id} ) is updated with end automation", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$GOAL_END => __( "Ended by Goal (Step #{step_id})", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$CART_RECOVERED_END => __( "Ended as Cart is Recovered", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$BEFORE_START_VALIDATION => __( "Ended as Event validation failed", 'wp-marketing-automations' ), BWFAN_Automation_Controller::$AUTOMATION_DATA_NOT_FOUND => __( "Automation data not found for event ({event_slug})", 'wp-marketing-automations' ), ]; $type = intval( $reason_data['type'] ); if ( ! isset( $messages[ $type ] ) ) { return ''; } $message = ''; switch ( $type ) { case BWFAN_Automation_Controller::$MANUAL_END: $message = str_replace( '{user_id}', intval( $reason_data['data']['user_id'] ), $messages[ $type ] ); break; case BWFAN_Automation_Controller::$ACTION_END: $message = str_replace( '{step_id}', intval( $reason_data['data']['sid'] ), $messages[ $type ] ); $aid = intval( $reason_data['data']['aid'] ); $link = "#$aid"; $message = str_replace( '#{automation_id}', $link, $message ); break; case BWFAN_Automation_Controller::$LINK_TRIGGER_END: case BWFAN_Automation_Controller::$BULK_ACTION_END: $id = intval( $reason_data['data']['id'] ); $action = ( $type === BWFAN_Automation_Controller::$BULK_ACTION_END ) ? 'bulk-action' : 'link-trigger'; $link = "#$id"; $message = str_replace( '#{id}', $link, $messages[ $type ] ); break; case BWFAN_Automation_Controller::$GOAL_END: case BWFAN_Automation_Controller::$GOAL_UPDATE_WITH_END: $message = str_replace( '{step_id}', intval( $reason_data['data']['sid'] ), $messages[ $type ] ); break; case BWFAN_Automation_Controller::$BEFORE_START_VALIDATION: case BWFAN_Automation_Controller::$CART_RECOVERED_END: $message = $messages[ $type ]; break; case BWFAN_Automation_Controller::$AUTOMATION_DATA_NOT_FOUND: $message = str_replace( '{event_slug}', $reason_data['data']['event_slug'], $messages[ $type ] ); break; } return $message; } /** * Get or create Tag / list if not exists * * @param $terms * @param $type * * @return array */ public static function get_or_create_terms( $terms, $type ) { $terms = array_map( function ( $term ) { if ( isset( $term['name'] ) ) { $term['value'] = $term['name']; } return $term; }, $terms ); $terms = self::check_for_comma_seperated( $terms ); $terms = BWFCRM_Term::get_or_create_terms( $terms, $type, true ); /** Preparing Data */ return array_map( function ( $term ) { $term_data = []; $term_data['id'] = $term->get_id(); $term_data['name'] = $term->get_name(); return $term_data; }, $terms ); } /** * Create or update contact on form submit event * * @param $automation_data */ public static function maybe_create_update_contact( $automation_data ) { if ( empty( $automation_data ) ) { return; } $email = $automation_data['email']; if ( ! is_email( trim( $email ) ) ) { return; } $contact = new WooFunnels_Contact( '', $email, '', '', '' ); $args = []; if ( isset( $automation_data['first_name'] ) && ! empty( $automation_data['first_name'] ) ) { $args['f_name'] = $automation_data['first_name']; } if ( isset( $automation_data['last_name'] ) && ! empty( $automation_data['last_name'] ) ) { $args['l_name'] = $automation_data['last_name']; } if ( isset( $automation_data['contact_phone'] ) && ! empty( $automation_data['contact_phone'] ) ) { $args['contact_no'] = $automation_data['contact_phone']; } if ( isset( $automation_data['mark_contact_subscribed'] ) && 1 === absint( $automation_data['mark_contact_subscribed'] ) ) { $args['status'] = 1; } /** checking if contact not exists than create otherwise update */ if ( ! $contact instanceof WooFunnels_Contact || 0 === absint( $contact->get_id() ) ) { new BWFCRM_Contact( $email, true, $args ); } else { // update first_name, last_name, phone and status $bwfcrm_contact = new BWFCRM_Contact( $contact, false, $args ); $bwfcrm_contact->update( $args ); if ( isset( $automation_data['mark_contact_subscribed'] ) && 1 === absint( $automation_data['mark_contact_subscribed'] ) ) { $bwfcrm_contact->resubscribe(); } } } /** * Get WP User object * * @param $user_login * @param $user * * @return false|WP_User|null */ public static function get_user( $user_login = false, $user = false ) { if ( ! empty( $user ) && $user instanceof WP_User ) { return $user; } if ( ! empty( $user_login ) ) { $user = get_user_by( 'login', $user_login ); if ( false === $user ) { $user = get_user_by( 'email', $user_login ); } if ( ! empty( $user ) && $user instanceof WP_User ) { return $user; } } if ( is_user_logged_in() ) { return wp_get_current_user(); } return false; } /** * Get paid orders count * * @param $renewal_orders * * @return int */ public static function get_paid_orders_count( $renewal_orders ) { if ( empty( $renewal_orders ) ) { return 0; } $paid_statuses = wc_get_is_paid_statuses(); if ( empty( $paid_statuses ) ) { return 0; } $orders = array_filter( $renewal_orders, function ( $order_id ) use ( $paid_statuses ) { $order = wc_get_order( $order_id ); return ( $order instanceof WC_ORDER && $order->has_status( $paid_statuses ) ); } ); return count( $orders ); } /** * Get order language * * @param $order * * @return array|mixed|string */ public static function get_order_language( $order ) { if ( ! $order instanceof WC_Order ) { return ''; } if ( function_exists( 'pll_current_language' ) && function_exists( 'pll_get_post_language' ) ) { $lang = pll_get_post_language( $order->get_id() ); return $lang && is_string( $lang ) ? $lang : ''; } $meta_key = ''; if ( class_exists( 'woocommerce_wpml' ) ) { $meta_key = 'wpml_language'; } elseif ( bwfan_is_translatepress_active() ) { $meta_key = 'trp_language'; } elseif ( function_exists( 'bwfan_is_weglot_active' ) && bwfan_is_weglot_active() ) { $meta_key = 'weglot_language'; } return $meta_key ? $order->get_meta( $meta_key ) : ''; } /** * Validate scheduled recurring actions * * @return void */ public static function validate_scheduled_recurring_actions() { $hooks = [ [ 'name' => 'bwfan_run_event_queue', 'time' => MINUTE_IN_SECONDS, 'args' => [], 'group_slug' => '' ], [ 'name' => 'bwfan_run_queue_v2', 'time' => MINUTE_IN_SECONDS, 'args' => [], 'group_slug' => '' ], [ 'name' => 'bwfcrm_broadcast_run_queue', 'time' => MINUTE_IN_SECONDS, 'args' => [], 'group_slug' => 'bwfcrm' ] ]; foreach ( $hooks as $hook ) { if ( bwf_has_action_scheduled( $hook['name'] ) ) { continue; } bwf_schedule_recurring_action( time(), $hook['time'], $hook['name'], $hook['args'], $hook['group_slug'] ); } } /** * Get contact status list * * @return array */ public static function get_contact_status_array_list() { return [ [ 'id' => 0, 'name' => __( 'Unverified', 'wp-marketing-automations' ), 'slug' => 'unverify', 'readableText' => __( 'Unverified', 'wp-marketing-automations' ), 'displaystatus' => 3, 'statusAction' => 'unverify', 'statusclass' => 'bwf-tags bwf-tag-gray', ], [ 'id' => 1, 'name' => __( 'Subscribed', 'wp-marketing-automations' ), 'slug' => 'resubscribe', 'readableText' => __( 'Opted In', 'wp-marketing-automations' ), 'displaystatus' => 1, 'statusAction' => 'resubscribe', 'statusclass' => 'bwf-tags bwf-tag-blue', ], [ 'id' => 2, 'name' => __( 'Bounced', 'wp-marketing-automations' ), 'slug' => 'bounced', 'readableText' => __( 'Bounced', 'wp-marketing-automations' ), 'displaystatus' => 4, 'statusAction' => 'bounced', 'statusclass' => 'bwf-tags bwf-tag-red', ], [ 'id' => 3, 'name' => __( 'Unsubscribed', 'wp-marketing-automations' ), 'slug' => 'unsubscribe', 'readableText' => __( 'Unsubscribed', 'wp-marketing-automations' ), 'displaystatus' => 2, 'statusAction' => 'unsubscribe', 'statusclass' => 'bwf-tags bwf-tag-orange', ], [ 'id' => 4, 'name' => __( 'Soft Bounced', 'wp-marketing-automations' ), 'slug' => 'softbounced', 'readableText' => __( 'Soft Bounced', 'wp-marketing-automations' ), 'displaystatus' => 5, 'statusAction' => 'softbounced', 'statusclass' => 'bwf-tags bwf-tag-red', ], [ 'id' => 5, 'name' => __( 'Complaint', 'wp-marketing-automations' ), 'slug' => 'complaint', 'readableText' => __( 'Complaint', 'wp-marketing-automations' ), 'displaystatus' => 6, 'statusAction' => 'complaint', 'statusclass' => 'bwf-tags bwf-tag-red', ] ]; } /** * Check if async http call timeout is high and status of the call is not 200 * * @param $force * * @return array|int[]|mixed */ public static function validate_core_worker( $force = false ) { $transient_val = get_transient( 'bwfan_core_worker_async' ); if ( false === $force && false !== $transient_val ) { return $transient_val; } $start_time = microtime( true ); $url = rest_url( '/woofunnels/v1/worker' ) . '?' . time(); $args = array( 'method' => 'GET', 'body' => array(), 'timeout' => 0.01, 'sslverify' => false, ); $request = wp_remote_post( $url, $args ); $end_time = microtime( true ); $data = []; if ( 0.2 < ( $end_time - $start_time ) ) { /** Taking more than 200ms */ $data = [ 'worker_async' => 1 ]; } /** Check for response code in case of firewall */ $status_code = wp_remote_retrieve_response_code( $request ); if ( ! empty( $status_code ) && $status_code != 200 ) { $data['response_code'] = $status_code; set_transient( 'bwfan_core_worker_async', $data, 6 * HOUR_IN_SECONDS ); return [ 'response_code' => $status_code ]; } set_transient( 'bwfan_core_worker_async', $data, 6 * HOUR_IN_SECONDS ); return $data; } public static function check_for_lks() { if ( ! is_null( self::$c_lk_p ) ) { return self::$c_lk_p; } $data = self::get_lk_data(); $s = isset( $data['s'] ) ? $data['s'] : 0; $e = isset( $data['e'] ) ? $data['e'] : ''; $ad = isset( $data['ad'] ) ? $data['ad'] : ''; if ( 2 === intval( $s ) ) { if ( $e === '' ) { self::$c_lk_p = true; return self::$c_lk_p; } $n = new DateTime(); $et = new DateTime( $e ); if ( $n > $et ) { $d = $n->diff( $et )->days; self::$c_lk_p = ( $d < 7 ); return self::$c_lk_p; } self::$c_lk_p = true; return self::$c_lk_p; } if ( 1 === intval( $s ) ) { if ( $ad !== '' ) { $n = new DateTime(); $adt = new DateTime( $ad ); $d = $n->diff( $adt )->days; if ( $d < 7 ) { self::$c_lk_p = true; return self::$c_lk_p; } } self::$c_lk_p = false; return self::$c_lk_p; } self::$c_lk_p = false; return self::$c_lk_p; } /** * Get last week date range * * @return array * @throws DateMalformedStringException */ public static function get_notification_week_range() { $dates = []; $date = new DateTime( current_time( 'mysql', true ) ); if ( 1 !== intval( $date->format( 'N' ) ) ) { $date->modify( 'last Monday' ); } $date->setTime( 0, 0, 0 ); $date = $date->modify( '-7 day' ); $dates['from_date'] = $date->format( 'Y-m-d' ); $date = $date->modify( '+6 day' ); $dates['to_date'] = $date->format( 'Y-m-d' ); $date = $date->modify( '-7 day' ); $dates['to_date_previous'] = $date->format( 'Y-m-d' ); $date = $date->modify( '-6 day' ); $dates['from_date_previous'] = $date->format( 'Y-m-d' ); return $dates; } /** * Get last month date range * * @return array * @throws DateMalformedStringException */ public static function get_notification_month_range() { $dates = []; $date = new DateTime( current_time( 'mysql', true ) ); $date->modify( 'last Month' ); $date->setDate( $date->format( 'Y' ), $date->format( 'm' ), 1 ); $date->setTime( 0, 0, 0 ); $dates['from_date'] = $date->format( 'Y-m-d' ); $last_month = clone $date; $date->modify( 'last day of this month' ); $dates['to_date'] = $date->format( 'Y-m-d' ); $last_month->modify( 'last Month' ); $last_month->setDate( $last_month->format( 'Y' ), $last_month->format( 'm' ), 1 ); $dates['from_date_previous'] = $last_month->format( 'Y-m-d' ); $last_month->modify( 'last day of this month' ); $dates['to_date_previous'] = $last_month->format( 'Y-m-d' ); return $dates; } /** * Get last day date range * * @return array * @throws DateMalformedStringException */ public static function get_notification_day_range() { $dates = []; $date = new DateTime( current_time( 'mysql', true ) ); $date->modify( '-1 day' ); $date->setTime( 0, 0, 0 ); $dates['from_date'] = $date->format( 'Y-m-d' ); $dates['to_date'] = $date->format( 'Y-m-d' ); $date->modify( '-1 day' ); $dates['from_date_previous'] = $date->format( 'Y-m-d' ); $dates['to_date_previous'] = $date->format( 'Y-m-d' ); return $dates; } /** * This function deletes engagement meta table's merge tag data from the "Tools" tab. * * @return void */ public static function delete_engagement_tracking_meta_tool_action() { $datetime = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); /** Fetched the last engagement ID of engagements from one day ago. */ $datetime->modify( '-1 day' ); $one_day_old = $datetime->format( 'Y-m-d H:i:s' ); global $wpdb; $query = "SELECT MAX(`ID`) FROM {$wpdb->prefix}bwfan_engagement_tracking WHERE `created_at` < %s"; //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL $last_id = $wpdb->get_var( $wpdb->prepare( $query, $one_day_old ) ); if ( empty( $last_id ) ) { bwf_unschedule_actions( 'bwfan_delete_engagement_tracking_meta_tool_action' ); return; } $start_time = time(); do { $query = "DELETE FROM {$wpdb->prefix}bwfan_engagement_trackingmeta WHERE `eid` <= %d AND `meta_key` = %s LIMIT 500"; //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL $rows_affected = $wpdb->query( $wpdb->prepare( $query, $last_id, 'merge_tags' ) ); /** If no rows deleted, we're done */ if ( $rows_affected === 0 ) { bwf_unschedule_actions( 'bwfan_delete_engagement_tracking_meta_tool_action' ); break; } } while ( ( time() - $start_time ) < 15 && ! BWFAN_Common::memory_exceeded() ); } /** * Schedule email notification daily * * @return void */ public static function schedule_notification() { $settings = BWFAN_Common::get_global_settings(); if ( empty( $settings['bwfan_enable_notification'] ) ) { return; } $ins = BWFAN_Notification_Email::get_instance(); $old_settings = $settings; $old_settings['bwfan_notification_time']['ampm'] = ( 'am' === $settings['bwfan_notification_time']['ampm'] ) ? 'pm' : 'am'; $ins->set_scheduler( $old_settings, $settings ); } public static function bwfan_get_date_format() { return ! empty( get_option( 'date_format' ) ) ? get_option( 'date_format' ) : 'Y-m-d'; } public static function bwfan_get_time_format() { return ! empty( get_option( 'time_format' ) ) ? get_option( 'time_format' ) : 'g:i a'; } public static function get_worker_delay_timestamp() { return ( 60 * apply_filters( 'bwfan_worker_notification_status_delay_var_in_min', 5 ) ); } /** * Get the UTC date time value from store date time value * * @param $store_date * @param $format * * @return string */ public static function get_utc_date_from_store_date( $store_date, $format = 'Y-m-d H:i:s' ) { if ( empty( $store_date ) ) { return ''; } try { $utc_date = get_gmt_from_date( $store_date, $format ); return $utc_date ?: ''; } catch ( Exception|Error $e ) { return ''; } } public static function get_user_menu_access() { $user_menu_access = apply_filters( 'bwfan_user_menu_access_data', [] ); $menu_data = []; if ( ! empty( $user_menu_access ) && isset( $user_menu_access[ get_current_user_id() ] ) ) { $menu_data = $user_menu_access[ get_current_user_id() ]; } return $menu_data; } /** * Check advance log enabled * * @param $log * * @return bool */ public static function is_log_enabled( $log ) { $global_settings = BWFAN_Common::get_global_settings(); return isset( $global_settings['bwfan_advance_logs'] ) && ! empty( $global_settings['bwfan_advance_logs'] ) && isset( $global_settings[ $log ] ) && ! empty( $global_settings[ $log ] ); } /** * Get formatted tag & list data if comma exists in value * * @param $data * * @return array|string[] */ public static function check_for_comma_seperated( $data ) { if ( empty( $data ) || ! is_array( $data ) ) { return []; } $formatted_data = []; foreach ( $data as $value ) { if ( ! empty( ( $value['id'] ) ) || false === strpos( $value['value'], ',' ) ) { $formatted_data[] = $value; continue; } $comma_separated_values = explode( ',', $value['value'] ); $comma_separated_values = array_map( function ( $single_value ) { return [ 'id' => 0, 'value' => trim( $single_value ) ]; }, $comma_separated_values ); $formatted_data = array_merge( $formatted_data, $comma_separated_values ); } return $formatted_data; } public static function minifyHtmlData( $content ) { if ( empty( $content ) ) { return ''; } // Remove unnecessary whitespaces and newlines between tags $htmlMinified = preg_replace( '/\s+/', ' ', $content ); $htmlMinified = preg_replace( '/> <', $htmlMinified ); // Remove space between tags // Call minifyCSS to handle embedded CSS inside ', $html, 1 ); return $html; } private static function mergeDuplicateMediaQueries( $style ) { // Extract all media queries and their rules $mediaQueries = []; $change_resolution = apply_filters( 'bwfan_change_media_query_resolution', '' ); preg_match_all( '/@media[^{]+\{([\s\S]*?)\}}/i', $style, $mediaMatches ); foreach ( $mediaMatches[0] as $mediaQuery ) { // Split the media query and its rules $parts = explode( '{', $mediaQuery, 2 ); $query = trim( $parts[0] ); $rules = trim( $parts[1] ); if ( ! empty( $change_resolution ) && intval( $change_resolution ) > 0 ) { // Update screen sizes from 768px to 480px $query = preg_replace( '/(\(max-width:\s*)768px(\s*\))/i', '${1}' . $change_resolution . 'px${2}', $query ); } // Store rules in the mediaQueries array if ( ! isset( $mediaQueries[ $query ] ) ) { $mediaQueries[ $query ] = []; } if ( str_ends_with( $rules, '}' ) ) { // Remove the last character (brace) from the string $rules = substr( $rules, 0, - 1 ); } $mediaQueries[ $query ][] = $rules; } // Combine the media query rules into a single string $combinedCSS = ''; foreach ( $mediaQueries as $query => $rules ) { $combinedCSS .= "{$query} { " . implode( ' ', $rules ) . " }\n"; } // Remove all media queries from the style $style = preg_replace( '/@media[^{]*{([^{}]*{[^{}]*})*[^{}]*}/', '', $style ); return $style . " " . $combinedCSS; } /** * Callback function for running v2 automation * * @param $request * * @return void */ public static function run_v2_worker_tasks( $request = '' ) { self::event_advanced_logs( "V2 worker callback received" ); self::worker_as_run(); /** Logs */ $cron_check = self::is_log_enabled( 'bwfan_cron_check_logging' ); if ( true === $cron_check || ( defined( 'BWF_CHECK_CRON_SCHEDULE' ) && true === BWF_CHECK_CRON_SCHEDULE ) ) { add_filter( 'bwf_logs_allowed', '__return_true', PHP_INT_MAX ); $logger_obj = BWF_Logger::get_instance(); $logger_obj->log( date_i18n( 'Y-m-d H:i:s' ) . ' - after worker run', 'fka-cron-check-v2', 'autonami' ); } wp_send_json( [ 'msg' => 'success', 'time' => date_i18n( 'Y-m-d H:i:s' ), 'datastore' => get_class( ActionScheduler_Store::instance() ), ] ); } /** * Validate redirect link by domain * * @param $link * @param $l_hash * @param $engagement_data * * @return mixed|string|null */ public static function validate_target_link( $link = '', $l_hash = '', $engagement_data = [] ) { /** Validate target link if all links not saved and l_hash empty */ if ( empty( get_option( 'bwfan_all_link_saved' ) ) && empty( $l_hash ) ) { return self::validate_old_target_link( $link, $engagement_data ); } /** Checking by cleaned url */ $cleaned_url = BWFAN_Core()->conversation->get_cleaned_url( $link ); /** Checking by l_hash & clean url */ if ( ! empty( $l_hash ) ) { $is_link_exists = BWFAN_Model_Links::is_link_hash_exists( $cleaned_url, $l_hash ); // if link entry not found return home url if ( empty( $is_link_exists ) ) { do_action( 'bwfan_invalid_tracking_link', $link ); return home_url(); } BWFAN_Email_Conversations::$link_id = $is_link_exists; return $link; } /** Checking by link exist in links table */ $is_link_exists = BWFAN_Model_Links::get_link_id_by_tid( $cleaned_url, $engagement_data[0] ?? [] ); if ( ! empty( $is_link_exists ) ) { BWFAN_Email_Conversations::$link_id = $is_link_exists; return $link; } /** If site url and redirect url host are same */ try { $link_host = wp_parse_url( urldecode( $link ), PHP_URL_HOST ); $site_url = home_url(); $site_url_host = wp_parse_url( $site_url, PHP_URL_HOST ); } catch ( Error|Exception $e ) { return $link; } if ( $link_host !== $site_url_host ) { do_action( 'bwfan_invalid_tracking_link', $link ); return home_url(); } return $link; } /** * Validate old target link if link is not saved * * @param $link * @param $e_data * * @return mixed|string|null */ public static function validate_old_target_link( $link, $e_data = [] ) { try { $link_host = wp_parse_url( urldecode( $link ), PHP_URL_HOST ); $site_url = home_url(); $site_url_host = wp_parse_url( $site_url, PHP_URL_HOST ); } catch ( Error|Exception $e ) { return $link; } /** Checking by cleaned url */ $cleaned_url = BWFAN_Core()->conversation->get_cleaned_url( urldecode( $link ) ); BWFAN_Email_Conversations::$link_id = BWFAN_Model_Links::get_link_id_by_tid( $cleaned_url, $e_data[0] ); /** If site url and redirect url host are same */ if ( $link_host === $site_url_host ) { return $link; } /** Allowed domains */ $allowed_domains = apply_filters( 'bwfan_allowed_redirect_domains', [] ); if ( empty( $allowed_domains ) ) { return $link; } /** Filter valid domains */ $allowed_domains = array_filter( array_map( function ( $domain ) { return ! empty( $domain ) && is_string( $domain ) ? wp_parse_url( $domain, PHP_URL_HOST ) : false; }, $allowed_domains ) ); return in_array( $link_host, $allowed_domains, true ) ? $link : $site_url; } /** * Store links * * @return void */ public static function bwfan_store_template_links() { $last_id = intval( get_option( 'bwfan_template_links' ) ); BWFAN_Common::log_test_data( 'Template link store process start', 'fk-store-link', true ); global $wpdb; $email_regex = BWFAN_Common::get_regex_pattern(); $sms_whatsapp_regex = BWFAN_Common::get_regex_pattern( 3 ); $start_time = time(); while ( ( time() - $start_time ) < 15 ) { $query = "SELECT et.`oid`,et.`sid`,et.`type`,et.`mode`,t.`ID`,t.`template` FROM {$wpdb->prefix}bwfan_templates AS t JOIN {$wpdb->prefix}bwfan_engagement_tracking AS et ON t.`ID`=et.`tid` WHERE tid > $last_id GROUP BY tid LIMIT 20"; $templates = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL if ( empty( $templates ) ) { bwf_unschedule_actions( 'bwfan_store_template_links' ); delete_option( 'bwfan_template_links' ); update_option( 'bwfan_all_link_saved', true, true ); BWFAN_Common::log_test_data( 'Template link store process complete', 'fk-store-link', true ); break; } $template_ids = array_column( $templates, 'ID' ); BWFAN_Common::log_test_data( 'Template ids :' . implode( ',', $template_ids ), 'fk-store-link', true ); foreach ( $templates as $template ) { $mode = intval( $template['mode'] ); $mode = $mode === BWFAN_Email_Conversations::$MODE_EMAIL ? 'email' : ( $mode === BWFAN_Email_Conversations::$MODE_SMS ? 'sms' : 'whatsapp' ); $regex_pattern = ( $mode === 'email' ) ? $email_regex : $sms_whatsapp_regex; preg_replace_callback( $regex_pattern, function ( $matches ) use ( $mode, $template ) { /** According to Href (1) regex, URL is at 1 index. And for Link (3) Regex, 0 index. */ $url = 'email' !== $mode ? $matches[0] : $matches[1]; BWFAN_Common::log_test_data( 'id:' . $template['ID'] . ' URL: ' . $url, 'fk-store-link', true ); if ( BWFAN_Common::is_exclude_url( $url ) ) { BWFAN_Common::log_test_data( 'exclude url', 'fk-store-link', true ); return $matches[0]; } /** Exclude click tracking for unsubscribe link and view email browser link*/ if ( false !== strpos( $url, 'bwfan-action=unsubscribe' ) || false !== strpos( $url, 'bwfan-action=view_in_browser' ) ) { BWFAN_Common::log_test_data( 'unsubscribe or view url', 'fk-store-link', true ); return 'email' !== $mode ? $url : str_replace( $matches[1], $url, $matches[0] ); } $data = [ 'type' => $template['type'], 'oid' => $template['oid'], 'step_id' => $template['sid'], 'template_id' => $template['ID'], ]; /** Save link in DB */ BWFAN_Core()->conversation->get_link_hash( $url, $data ); return 'email' !== $mode ? $url : str_replace( $matches[1], $url, $matches[0] ); }, $template['template'] ); $last_id = $template['ID']; } BWFAN_Common::log_test_data( 'Last process template id :' . $last_id, 'fk-store-link', true ); update_option( 'bwfan_template_links', $last_id ); } BWFAN_Common::log_test_data( 'Template link store process end :', 'fk-store-link', true ); } /** * Get mail replace string * * @return array */ public static function get_mail_replace_string() { if ( defined( 'BWFAN_PRO_VERSION' ) && version_compare( BWFAN_PRO_VERSION, '3.5.2', '<=' ) ) { return []; } return [ 'http-equiv' => md5( 'http-equiv' ), ]; } /** * Create contact if not created * * @param $user_id * * @return void */ public static function bwfan_register_user( $user_id ) { if ( did_action( 'woocommerce_before_checkout_process' ) ) { return; } $db_updater = WooFunnels_DB_Updater::get_instance(); $db_updater->do_profile_update_async_call( $user_id ); define( 'BWF_DISABLE_CONTACT_PROFILE_UPDATE', 1 ); } /** * @return string * */ public static function get_wc_tax_label_if_displayed() { if ( ! wc_tax_enabled() ) { return ''; } $tax_display_mode = get_option( 'woocommerce_tax_display_cart' ); $prices_include_tax = wc_prices_include_tax(); if ( $tax_display_mode === 'incl' && ! $prices_include_tax ) { return WC()->countries->inc_tax_or_vat(); } if ( $tax_display_mode === 'excl' && $prices_include_tax ) { return WC()->countries->ex_tax_or_vat(); } return ''; } /** * If constant define then get contact email by user id * * @param $user_id * @param $contact_id * * @return string */ public static function get_contact_email( $user_id = 0, $contact_id = 0 ) { if ( ! defined( 'BWFAN_GET_CONTACT_EMAIL' ) || true !== BWFAN_GET_CONTACT_EMAIL || ( empty( $user_id ) && empty( $contact_id ) ) ) { return ''; } $contact = new WooFunnels_Contact( $user_id, '', '', $contact_id ); return $contact->get_id() > 0 ? $contact->get_email() : ''; } /** * Check language support * * @return bool */ public static function should_skip_language_support() { if ( ! function_exists( 'icl_get_languages' ) && ! function_exists( 'pll_the_languages' ) && ( ! function_exists( 'bwfan_is_translatepress_active' ) || ! bwfan_is_translatepress_active() ) && ( ! function_exists( 'bwfan_is_weglot_active' ) || ! bwfan_is_weglot_active() ) && ( ! function_exists( 'bwfan_is_gtranslate_active' ) || ! bwfan_is_gtranslate_active() ) ) { return true; } return false; } /** * Get wp terms id and name array from ids, static query * * @param $term_ids * * @return array|object|stdClass[]|null */ public static function get_wp_term( $term_ids ) { if ( empty( $term_ids ) ) { return []; } global $wpdb; $placeholder = array_fill( 0, count( $term_ids ), '%d' ); $placeholder = implode( ', ', $placeholder ); $query = "SELECT `term_id` AS `id`,`name` FROM {$wpdb->prefix}terms WHERE `term_id` IN ($placeholder)"; //phpcs:ignore WordPress.DB.PreparedSQL $query = $wpdb->prepare( $query, $term_ids ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL return $wpdb->get_results( $query, ARRAY_A ); } /** * Get product names and id from ids, static query * * @param $product_ids * * @return array|object|stdClass[]|null */ public static function get_products_name( $product_ids ) { if ( empty( $product_ids ) ) { return []; } global $wpdb; $placeholder = array_fill( 0, count( $product_ids ), '%d' ); $placeholder = implode( ', ', $placeholder ); $query = "SELECT `ID` AS `id`, `post_title` AS `name`, `post_parent` FROM {$wpdb->prefix}posts WHERE `ID` IN ($placeholder)"; //phpcs:ignore WordPress.DB.PreparedSQL $query = $wpdb->prepare( $query, $product_ids ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL return $wpdb->get_results( $query, ARRAY_A ); } /** * Check server memory limit. * Using 75% max * * @return bool */ public static function memory_exceeded() { $memory_limit = self::get_memory_limit() * 0.9; $current_memory = memory_get_usage( true ); return ( $current_memory >= $memory_limit ); } /** * Get the memory limit in bytes. * If the memory limit is set to -1 or 'unlimited', it will return 32GB. * * @return int|mixed */ public static function get_memory_limit() { if ( function_exists( 'ini_get' ) ) { $memory_limit = ini_get( 'memory_limit' ); } else { $memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce } if ( ! $memory_limit || - 1 === $memory_limit || '-1' === $memory_limit ) { // Unlimited, set to 32GB. $memory_limit = '32G'; } return self::convert_hr_to_bytes( $memory_limit ); } /** * Converts a shorthand byte value to an integer byte value. * * @param $value * * @return int|mixed */ public static function convert_hr_to_bytes( $value ) { if ( function_exists( 'wp_convert_hr_to_bytes' ) ) { return wp_convert_hr_to_bytes( $value ); } $value = strtolower( trim( $value ) ); $bytes = (int) $value; if ( false !== strpos( $value, 'g' ) ) { $bytes *= GB_IN_BYTES; } elseif ( false !== strpos( $value, 'm' ) ) { $bytes *= MB_IN_BYTES; } elseif ( false !== strpos( $value, 'k' ) ) { $bytes *= KB_IN_BYTES; } // Deal with large (float) values which run into the maximum integer size. return min( $bytes, PHP_INT_MAX ); } /** * Get a list of attach actions/filters hook * * @param $hook * * @return array * @throws ReflectionException */ final public static function get_list_of_attach_actions( $hook ) { global $wp_filter; if ( ! isset( $wp_filter[ $hook ] ) || ! $wp_filter[ $hook ] instanceof WP_Hook ) { return []; } $output = []; $hooks = $wp_filter[ $hook ]->callbacks; foreach ( $hooks as $priority => $reference ) { if ( ! is_array( $reference ) || 0 === count( $reference ) ) { continue; } foreach ( $reference as $index => $calls ) { if ( isset( $calls['function'] ) && is_array( $calls['function'] ) && count( $calls['function'] ) > 0 ) { if ( is_object( $calls['function'][0] ) ) { $cls_name = get_class( $calls['function'][0] ); $output[] = [ 'type' => 'class', 'class' => $cls_name, 'function' => $calls['function'][1], 'class_path' => self::get_class_path( $cls_name ), 'index' => $index, 'priority' => $priority, ]; } else { $output[] = [ 'type' => 'static_class', 'class' => $calls['function'][0], 'function' => $calls['function'][1], 'class_path' => self::get_class_path( $calls['function'][0] ), 'index' => $index, 'priority' => $priority, ]; } } else { $output[] = [ 'type' => 'function', 'function' => $calls['function'], 'function_path' => self::get_function_path( $calls['function'] ), 'index' => $index, 'priority' => $priority, ]; } } } return $output; } /** * Get a class path * * @param $class * * @return string * @throws ReflectionException */ public static function get_class_path( $class = 'BWFAN_Core' ) { $reflector = new ReflectionClass( $class ); $file_name = $reflector->getFileName(); return dirname( $file_name ); } /** * Get a function path * * @param $function * * @return array|string|string[] */ public static function get_function_path( $function = '' ) { if ( empty( $function ) ) { return ''; } try { $reflector = new ReflectionFunction( $function ); $file_name = $reflector->getFileName(); $directory = dirname( $file_name ); if ( defined( 'WP_CONTENT_DIR' ) ) { $directory = str_replace( WP_CONTENT_DIR, '', $directory ); } } catch ( ReflectionException $exception ) { $directory = $exception->getMessage(); } return $directory; } }