File "hustle-migration.php"
Full Path: /home/londdqdw/public_html/06/wp-content/plugins/wordpress-popup/inc/hustle-migration.php
File size: 55.1 KB
MIME-type: text/x-php
Charset: utf-8
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
/**
* Hustle_Migration
*
* @package Hustle
*/
/**
* Class Hustle_Migration
*
* @class Hustle_Migration
*/
class Hustle_Migration {
/**
* Is multisite
*
* @var bool
*/
private $is_multisite = false;
/**
* Instance of Hustle_410_Migration.
*
* @since 4.1.0
* @var Hustle_410_Migration
*/
public $migration_410;
/**
* Instance of Hustle_430_Migration.
*
* @since 4.3.0
* @var Hustle_430_Migration
*/
private $migration_430;
/**
* Hustle_Migration instance.
*
* @since 4.1.0
* @var null
*/
private static $instance = null;
/**
* Whether any of the modules had custom css.
*
* @since 4.0
* @var boolean
*/
private $custom_css_migrated = false;
/**
* Tracking meta keys
*
* @var array
*/
private static $tracking_meta_keys = array(
'popup_view',
'popup_conversion',
'slidein_view',
'slidein_conversion',
'after_content_view',
'shortcode_view',
'floating_social_view',
'floating_social_conversion',
'widget_view',
'after_content_conversion',
'shortcode_conversion',
'widget_conversion',
'subscription',
);
/**
* Get an istance of this class.
*
* @since 4.1.0
*/
public static function get_instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
public function __construct() {
$this->is_multisite = is_multisite();
add_action( 'wp_ajax_hustle_migrate_tracking', array( $this, 'migrate_tracking_and_subscriptions' ) );
if ( $this->is_migration() ) {
add_action( 'init', array( $this, 'do_hustle_30_migration' ) );
}
$this->migration_410 = new Hustle_410_Migration();
$this->migration_430 = new Hustle_430_Migration();
}
/**
* Check whether we should run da migration.
*
* @since 4.0
* @return boolean
*/
private function is_migration() {
// If migration is being forced, do it.
if ( filter_input( INPUT_GET, 'reset_migration', FILTER_VALIDATE_BOOLEAN ) ) {
return true;
}
// If migration was already done, skip.
if ( self::is_migrated( 'hustle_30_migrated' ) ) {
return false;
}
// If it's a fresh install, no need to migrate.
return self::did_hustle_exist();
}
/**
* Get the previously installed version according to our flag.
*
* @since 4.2.1
*
* @return string|false
*/
public static function get_previous_installed_version() {
return get_site_option( 'hustle_previous_version', false );
}
/**
* Check if a spesific migration is passed
*
* @param string $key Migration key.
* @return bool
*/
public static function is_migrated( $key ) {
$keys = get_option( 'hustle_migrations', null );
if ( is_null( $keys ) ) {
self::change_migration_options();
$keys = get_option( 'hustle_migrations', array() );
}
return in_array( $key, $keys, true );
}
/**
* Save migration key
*
* @param string $key Migration key.
*/
public static function migration_passed( $key ) {
$keys = get_option( 'hustle_migrations', array() );
if ( ! in_array( $key, $keys, true ) ) {
$keys[] = $key;
update_option( 'hustle_migrations', $keys );
}
}
/**
* Remove the passed migration flag.
*
* @since 4.1.0
*
* @param string $flag Flag name.
*/
public static function remove_migration_passed_flag( $flag ) {
$keys = get_option( 'hustle_migrations', array() );
if ( in_array( $flag, $keys, true ) ) {
$key = array_search( $flag, $keys, true );
if ( false !== $key ) {
unset( $keys[ $key ] );
update_option( 'hustle_migrations', $keys );
}
}
}
/**
* Resave migration keys to a new format
*/
private static function change_migration_options() {
$keys = array(
'hustle_20_migrated',
'hustle_30_migrated',
'hustle_30_tracking_migrated',
);
foreach ( $keys as $key ) {
$option = get_option( $key );
if ( $option ) {
self::migration_passed( $key );
delete_option( $key );
}
}
}
/**
* Check whether the tracking and subscriptions data needs to be migrated.
*
* @since 4.0
* @return bool
*/
public static function check_tracking_needs_migration() {
// If migration was already done, skip.
if ( self::is_migrated( 'hustle_30_tracking_migrated' ) ) {
return false;
}
// If it's a fresh install, no need to migrate.
if ( ! self::did_hustle_exist() ) {
return false;
}
// If there isn't data to migrate, we're done.
return self::is_tracking_subscription_data_to_migrate();
}
/**
* Check whether this is a new 4.0 installation.
*
* @since 4.0
* @return bool
*/
public static function did_hustle_exist() {
$hustle_20_migrated = self::is_migrated( 'hustle_20_migrated' );
return $hustle_20_migrated;
}
/**
* Migrating from Hustle 3.x
*/
public function do_hustle_30_migration() {
// Update tables on migration.
Hustle_Db::maybe_create_tables( true );
// Migrate global settings.
$this->migrate_settings();
$modules = $this->get_all_hustle_modules();
if ( ! empty( $modules ) ) {
array_map( array( __CLASS__, 'migrate_hustle_30' ), $modules );
}
if ( ! $this->custom_css_migrated ) {
Hustle_Notifications::add_dismissed_notification( 'show_review_css_after_migration_notice' );
}
self::migration_passed( 'hustle_30_migrated' );
}
/**
* Migrate hustle 3.0
*
* @param object $old_module Old module.
*/
public function migrate_hustle_30( $old_module ) {
// Don't migrate the modules that don't belong to the blog requesting the migration (useful on MU).
if ( get_current_blog_id() !== (int) $old_module->blog_id ) {
return;
}
if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $old_module->module_type ) {
$this->migrate_non_sshare_module( $old_module );
} else {
$this->migrate_sshare_module( $old_module );
}
}
/**
* Get all hustle modules
*
* @return array
*/
public function get_all_hustle_modules() {
$module_collection_instance = Hustle_Module_Collection::instance();
return $module_collection_instance->get_hustle_30_modules( get_current_blog_id() );
}
/**
* Migrate Social Sharing module
*
* @param object $old_module Old module.
*/
private function migrate_sshare_module( $old_module ) {
if ( ! $this->is_multisite || is_main_site( get_current_blog_id() ) ) {
$module = new Hustle_SShare_Model( $old_module->module_id );
$module->save();
} else {
// The tables in multisite are no longer shared between the sites of the network.
// Instead, each site has its own tables, so they're empty and we should move the content there.
$module = new Hustle_SShare_Model();
$module->module_id = $old_module->module_id;
$module->active = $old_module->active;
$module->module_name = $old_module->module_name;
$module->module_type = $old_module->module_type;
$module->save_from_migration();
// Shortcode.
$module->update_meta( Hustle_Module_Model::KEY_SHORTCODE_ID, $old_module->meta['shortcode_id'] );
// Track types.
if ( isset( $old_module->meta['track_types'] ) ) {
// Change 'floating_social' track type to 4.0 'floating' one.
if ( isset( $old_module->meta['track_types']['floating_social'] ) ) {
$old_module->meta['track_types']['floating'] = $old_module->meta['track_types']['floating_social'];
unset( $old_module->meta['track_types']['floating_social'] );
}
$module->update_meta( Hustle_Module_Model::TRACK_TYPES, $old_module->meta['track_types'] );
}
}
// Services.
$content = $this->parse_sshare_content_meta( $module, $old_module );
// Display.
$display = $this->parse_sshare_display_meta( $module, $old_module );
// Appearance.
$design = $this->parse_sshare_design_meta( $module, $old_module );
// Visibility.
$visibility = $this->parse_visibility_meta( $module, $old_module );
// Edit roles.
$edit_roles = ! is_null( get_role( 'administrator' ) ) ? array( 'administrator' ) : array();
$data = array(
'id' => $module->id,
'content' => $content,
'design' => $design,
'display' => $display,
'visibility' => $visibility,
'edit_roles' => $edit_roles,
);
$module->update_module( $data );
}
/**
* Parse the old content to the new format.
*
* @since 4.0
*
* @param Hustle_SShare_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_sshare_content_meta( $module, $old_module ) {
$content = $module->get_content()->to_array();
if ( $this->is_multisite ) {
$content = array_merge( $content, $old_module->meta['content'] );
}
if ( 'native' !== $content['service_type'] || 'none' === $content['click_counter'] || '0' === $content['click_counter'] ) {
$content['counter_enabled'] = '0';
} else {
$content['counter_enabled'] = '1';
}
if ( isset( $content['social_icons'] ) && ! empty( $content['social_icons'] ) ) {
if ( isset( $content['social_icons']['google'] ) ) {
unset( $content['social_icons']['google'] );
}
$platforms_with_counter_endpoint = Hustle_SShare_Model::get_networks_counter_endpoint();
$social_platforms = Hustle_SShare_Model::get_social_platform_names();
foreach ( $content['social_icons'] as $platform => $data ) {
if ( 'native' === $content['click_counter'] ) {
// Set to 'native' only if the platform has a native counter.
$counter_type = in_array( $platform, $platforms_with_counter_endpoint, true ) ? 'native' : 'click';
} else {
// Applies for both 'click', '0', and 'none' click_counter.
$counter_type = 'click';
}
$data['platform'] = $platform;
$data['type'] = $counter_type;
$data['label'] = ! empty( $social_platforms[ $platform ] ) ? $social_platforms[ $platform ] : ucfirst( $platform );
$content['social_icons'][ $platform ] = $data;
}
}
return $content;
}
/**
* Parse the old design to the new one.
*
* @since 4.0
*
* @param Hustle_SShare_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_sshare_design_meta( $module, $old_module ) {
$design = $module->get_design()->to_array();
$old_design = $old_module->meta['design'];
if ( $this->is_multisite ) {
$design = array_merge( $design, $old_module->meta['design'] );
}
$design['floating_customize_colors'] = $this->is_true( $old_design['customize_colors'] ) ? '1' : '0';
$design['floating_icon_bg_color'] = $old_design['icon_bg_color'];
$design['floating_icon_color'] = $old_design['icon_color'];
$design['floating_bg_color'] = $old_design['floating_social_bg'];
$design['floating_animate_icons'] = $this->is_true( $old_design['floating_social_animate_icons'] ) ? '1' : '0';
$design['floating_drop_shadow'] = $this->is_true( $old_design['drop_shadow'] ) ? '1' : '0';
$design['floating_drop_shadow_x'] = $old_design['drop_shadow_x'];
$design['floating_drop_shadow_y'] = $old_design['drop_shadow_y'];
$design['floating_drop_shadow_blur'] = $old_design['drop_shadow_blur'];
$design['floating_drop_shadow_spread'] = $old_design['drop_shadow_spread'];
$design['floating_drop_shadow_color'] = $old_design['drop_shadow_color'];
$design['floating_inline_count'] = $this->is_true( $old_design['floating_inline_count'] ) ? '1' : '0';
$design['widget_customize_colors'] = $this->is_true( $old_design['customize_widget_colors'] ) ? '1' : '0';
// Same keys, making sure the value type is correct. String '1'|'0'.
$design['widget_animate_icons'] = $this->is_true( $old_design['widget_animate_icons'] ) ? '1' : '0';
$design['widget_drop_shadow'] = $this->is_true( $old_design['widget_drop_shadow'] ) ? '1' : '0';
$design['widget_inline_count'] = $this->is_true( $old_design['widget_inline_count'] ) ? '1' : '0';
return $design;
}
/**
* Parse ssharing specific display settings.
*
* @since 4.0
*
* @param Hustle_SShare_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_sshare_display_meta( $module, $old_module ) {
$display = $this->parse_display_meta( $module, $old_module );
$old_settings = $old_module->meta['settings'];
$test_types = isset( $old_module->meta['test_types'] ) ? $old_module->meta['test_types'] : array();
if ( ! $this->is_true( $old_settings['floating_social_enabled'] ) ) {
$display['float_desktop_enabled'] = '0';
$display['float_mobile_enabled'] = '0';
} elseif ( isset( $test_types['floating_social'] ) && $this->is_true( $test_types['floating_social'] ) ) {
$display['float_desktop_enabled'] = '0';
$display['float_mobile_enabled'] = '0';
}
// We didn't differentiate 'mobile' and 'desktop' floating in 3.x,
// so the old settings apply to both.
// We're removing old 'content' location since it never worked.
$location_type = 'selector' === $old_settings['location_type'] ? 'css_selector' : 'screen';
$display['float_desktop_offset'] = $location_type;
$display['float_mobile_offset'] = $location_type;
$display['float_desktop_css_selector'] = $old_settings['location_target'];
$display['float_mobile_css_selector'] = $old_settings['location_target'];
$display['float_desktop_position'] = $old_settings['location_align_x'];
$display['float_mobile_position'] = $old_settings['location_align_x'];
$display['float_desktop_position_y'] = $old_settings['location_align_y'];
$display['float_mobile_position_y'] = $old_settings['location_align_y'];
$offset_y = 'top' === $old_settings['location_align_y'] ? $old_settings['location_top'] : $old_settings['location_bottom'];
$display['float_desktop_offset_y'] = $offset_y;
$display['float_mobile_offset_y'] = $offset_y;
$offset_x = 'right' === $old_settings['location_align_x'] ? $old_settings['location_right'] : $old_settings['location_left'];
$display['float_desktop_offset_x'] = $offset_x;
$display['float_mobile_offset_x'] = $offset_x;
return $display;
}
/**
* Migrate the modules that are popups, slideins and embedded.
*
* @since 4.0
* @param object $old_module Old module.
*/
private function migrate_non_sshare_module( $old_module ) {
if ( ! $this->is_multisite || is_main_site( get_current_blog_id() ) ) {
$module = new Hustle_Module_Model( $old_module->module_id );
// Modules with 'test mode' enabled should be drafts.
if ( $this->is_true( $old_module->test_mode ) ) {
$module->active = '0';
}
// Add the new 'module_mode' property.
$module->module_mode = $this->get_module_mode( $old_module->meta['content'] );
$module->save();
} else {
// The tables in multisite are no longer shared between the sites of the network.
// Instead, each site has its own tables, so they're empty and we should move the content there.
$module = new Hustle_Module_Model();
// Modules with 'test mode' enabled should be drafts.
$module->active = ! $this->is_true( $old_module->test_mode ) ? $old_module->active : '0';
$module->module_id = $old_module->module_id;
$module->module_name = $old_module->module_name;
$module->module_type = $old_module->module_type;
$module->module_mode = $this->get_module_mode( $old_module->meta['content'] );
$module->save_from_migration();
// Shortcode.
$module->update_meta( Hustle_Module_Model::KEY_SHORTCODE_ID, $old_module->meta['shortcode_id'] );
// Track types.
if ( isset( $old_module->meta['track_types'] ) && ! empty( $old_module->meta['track_types'] ) ) {
// Change 'after_content' track type to 4.0 'inline' one.
if ( isset( $old_module->meta['track_types']['after_content'] ) ) {
$old_module->meta['track_types']['inline'] = $old_module->meta['track_types']['after_content'];
unset( $old_module->meta['track_types']['after_content'] );
}
$module->update_meta( Hustle_Module_Model::TRACK_TYPES, $old_module->meta['track_types'] );
}
}
// Handling metas.
// Content.
$content = $this->parse_content_meta( $module, $old_module );
// Emails.
$emails = $this->parse_email_meta( $module, $old_module );
// Integrations. For 'optins' only.
$integrations_settings = array();
if ( 'optin' === $module->module_mode ) {
$integrations_settings = $this->migrate_integrations( $module, $old_module );
}
// Appearance.
$design = $this->parse_design_meta( $module, $old_module );
// Display options. For Embedded modules only.
if ( Hustle_Module_Model::EMBEDDED_MODULE === $old_module->module_type ) {
$display = $this->parse_display_meta( $module, $old_module );
} else {
$display = array();
}
// Visibility.
$visibility = $this->parse_visibility_meta( $module, $old_module );
// Behavior.
$settings = $this->parse_settings_meta( $module, $old_module );
// Edit roles.
$edit_roles = ! is_null( get_role( 'administrator' ) ) ? array( 'administrator' ) : array();
$data = array(
'id' => $module->id,
'content' => $content,
'emails' => $emails,
'design' => $design,
'integrations_settings' => $integrations_settings,
'display' => $display,
'visibility' => $visibility,
'settings' => $settings,
'edit_roles' => $edit_roles,
);
$module->update_module( $data );
}
/**
* Get the module's mode according to the old content.
* 'optin' if email collection was enabled, 'informational' otherwise.
* Empty string for Social sharing modules that doesn't have email collection.
*
* @since 4.0
*
* @param array $content Content.
* @return string
*/
private function get_module_mode( $content ) {
$mode = 'informational';
if ( isset( $content['use_email_collection'] ) && $this->is_true( $content['use_email_collection'] ) ) {
$mode = 'optin';
}
return $mode;
}
/**
* Create the new 'content' settings according to the old module.
* The old data is used to replace the defaults.
* The old unused data is not being removed atm.
*
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_content_meta( $module, $old_module ) {
$content = $module->get_content()->to_array();
if ( $this->is_multisite ) {
$content = array_merge( $content, $old_module->meta['content'] );
}
if ( ! $this->is_true( $content['has_title'] ) ) {
$content['title'] = '';
$content['sub_title'] = '';
}
if ( ! $this->is_true( $content['use_feature_image'] ) ) {
$content['feature_image'] = '';
}
$content['show_cta'] = $this->is_true( $content['show_cta'] ) ? '1' : '0';
return $content;
}
/**
* Create the new 'emails' settings according to the old module.
*
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_email_meta( $module, $old_module ) {
$emails = $module->get_emails()->to_array();
$old_content = $old_module->meta['content'];
if ( ! isset( $old_content['form_elements'] ) ) {
return $emails;
}
$old_form_fields = $old_content['form_elements'];
if ( is_string( $old_form_fields ) ) {
$old_form_fields = json_decode( $old_form_fields, true );
}
foreach ( $old_form_fields as $name => $properties ) {
if ( true === $old_form_fields[ $name ]['required'] ) {
$old_form_fields[ $name ]['required'] = 'true';
}
if ( 'url' === $old_form_fields[ $name ]['type'] || 'email' === $old_form_fields[ $name ]['type'] ) {
$old_form_fields[ $name ]['validate'] = 'true';
}
if ( isset( $old_form_fields[ $name ]['delete'] ) ) {
$can_delete = $old_form_fields[ $name ]['delete'];
unset( $old_form_fields[ $name ]['delete'] );
} else {
$can_delete = true;
}
$old_form_fields[ $name ]['can_delete'] = $can_delete;
}
// Replace old 'f_name' by 'first_name' so we can stop doing legacy conversions along the plugin.
if ( isset( $old_form_fields['f_name'] ) ) {
$old_form_fields['f_name']['name'] = 'first_name';
$old_form_fields = Opt_In_Utils::replace_array_key( 'f_name', 'first_name', $old_form_fields );
}
// Replace old 'l_name' by 'last_name' so we can stop doing legacy conversions along the plugin.
if ( isset( $old_form_fields['l_name'] ) ) {
$old_form_fields['l_name']['name'] = 'last_name';
$old_form_fields = Opt_In_Utils::replace_array_key( 'l_name', 'last_name', $old_form_fields );
}
// Set the new recaptcha properties according to what was used in 3.x.
if ( isset( $old_form_fields['recaptcha'] ) ) {
$old_form_fields['recaptcha']['recaptcha_type'] = 'full';
$old_form_fields['recaptcha']['recaptcha_theme'] = 'light';
}
// Use the 4.0 error message.
if ( isset( $old_form_fields['submit'] ) ) {
$old_form_fields['submit']['error_message'] = __( 'Please fill out all required fields.', 'hustle' );
}
// Make gdpr a form field for optins.
if ( isset( $old_content['show_gdpr'] ) && $this->is_true( $old_content['show_gdpr'] ) ) {
$old_form_fields['gdpr'] = array(
'label' => 'gdpr',
'required' => 'true',
'css_classes' => '',
'type' => 'gdpr',
'name' => 'gdpr',
'can_delete' => 'true',
'placeholder' => '',
'gdpr_message' => $old_content['gdpr_message'],
);
}
$emails['form_elements'] = $module->sanitize_form_elements( $old_form_fields );
$emails['after_successful_submission'] = $old_content['after_successful_submission'];
$emails['success_message'] = $old_content['success_message'];
$emails['auto_close_success_message'] = $this->is_true( $old_content['auto_close_success_message'] ) ? '1' : '0';
if ( isset( $old_content['auto_close_time'] ) ) {
$emails['auto_close_time'] = $old_content['auto_close_time'];
}
if ( isset( $old_content['auto_close_unit'] ) ) {
$emails['auto_close_unit'] = $old_content['auto_close_unit'];
}
if ( isset( $old_content['redirect_url'] ) ) {
$emails['redirect_url'] = $old_content['redirect_url'];
}
return $emails;
}
/**
* Create the new 'design' settings according to the old module.
* The old data is used to replace the defaults.
* The old unused data is not being removed atm.
*
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_design_meta( $module, $old_module ) {
$design = $module->get_design()->to_array();
if ( $this->is_multisite ) {
$design = array_merge( $design, $old_module->meta['design'] );
}
$old_content = $old_module->meta['content'];
$design['feature_image_hide_on_mobile'] = $this->is_true( $old_content['feature_image_hide_on_mobile'] ) ? '1' : '0';
// There's a bug in 3.x that applied customized colors even when disabled.
// Turning on "customize_colors" to keep the same appearance in front after migration.
$design['customize_colors'] = '1';
$design['border'] = $this->is_true( $design['border'] ) ? '1' : '0';
$design['drop_shadow'] = $this->is_true( $design['drop_shadow'] ) ? '1' : '0';
$design['customize_size'] = $this->is_true( $design['customize_size'] ) ? '1' : '0';
$is_optin = 'optin' === $module->module_mode;
if ( $is_optin ) {
// When making a module 'optin' in 3.x, the selected palette remained as the informational one.
if ( in_array( $design['style'], Hustle_Palettes_Helper::get_palettes_names(), true ) ) {
$design['color_palette'] = $design['style'];
} else {
$design['color_palette'] = 'gray_slate';
}
if ( isset( $design['button_border_color'] ) ) {
$design['optin_submit_button_static_bo'] = $design['button_border_color'];
$design['optin_submit_button_active_bo'] = $design['button_border_color'];
$design['optin_submit_button_active_bo'] = $design['button_border_color'];
$design['optin_submit_button_hover_bo'] = $design['button_border_color'];
}
// When input's borders is disabled...
if ( ! $this->is_true( $design['form_fields_border'] ) ) {
// Always make the input's style "outlined" instead of "flat" in order
// to keep the input's borders highlighted on error.
$design['form_fields_border'] = '1';
// Make the borders invisible in all states, except for the error one.
$design['optin_input_static_bo'] = $design['optin_input_static_bg'];
$design['optin_input_hover_bo'] = $design['optin_input_hover_bg'];
$design['optin_input_active_bo'] = $design['optin_input_active_bg'];
// And make the border's attributes match the 3.x on error one.
$design['form_fields_border_radius'] = '0';
$design['form_fields_border_weight'] = '1';
$design['form_fields_border_type'] = 'solid';
} elseif ( isset( $design['form_fields_border_color'] ) ) {
$design['optin_input_static_bo'] = $design['form_fields_border_color'];
$design['optin_input_hover_bo'] = $design['form_fields_border_color'];
$design['optin_input_active_bo'] = $design['form_fields_border_color'];
}
if ( isset( $design['optin_input_icon'] ) ) {
$design['optin_input_icon_hover'] = $design['optin_input_icon'];
$design['optin_input_icon_focus'] = $design['optin_input_icon'];
}
if ( isset( $design['optin_check_radio_bg'] ) ) {
$design['optin_check_radio_bg_checked'] = $design['optin_check_radio_bg'];
}
// Modules before 3.0.3 don't have gdpr options.
if ( isset( $design['gdpr_border_color'] ) ) {
$design['gdpr_chechbox_border_static'] = $design['gdpr_border_color'];
$design['gdpr_chechbox_border_active'] = $design['gdpr_border_color'];
}
// When gdpr checkbox's border is disabled...
if ( isset( $design['gdpr_border'] ) && ! $this->is_true( $design['gdpr_border'] ) ) {
// Always make the input's style "outlined" instead of "flat" in order
// to keep the input's borders highlighted on error.
$design['gdpr_border'] = '1';
// Make the borders invisible in all states, except for the error one.
$design['gdpr_chechbox_border_static'] = $design['gdpr_chechbox_background_static'];
$design['gdpr_chechbox_border_active'] = $design['gdpr_checkbox_background_active'];
// And make the border's attributes match the 3.x on error one.
$design['gdpr_border_radius'] = '0';
$design['gdpr_border_weight'] = '2';
$design['gdpr_border_type'] = 'solid';
}
$design['optin_input_error_background'] = $design['optin_input_static_bg'];
$design['form_fields_style'] = empty( $design['form_fields_border'] ) || 'false' === $design['form_fields_border'] ? 'flat' : 'outlined';
$design['button_style'] = empty( $design['button_border'] ) || 'false' === $design['button_border'] ? 'flat' : 'outlined';
$design['gdpr_checkbox_style'] = empty( $design['gdpr_border'] ) || 'false' === $design['gdpr_border'] ? 'flat' : 'outlined';
} else {
$design['title_color_alt'] = $design['title_color'];
$design['subtitle_color_alt'] = $design['subtitle_color'];
}
if ( ! empty( trim( $design['custom_css'] ) ) ) {
$this->custom_css_migrated = true;
$new_css = $this->parse_custom_css( $design['custom_css'], $is_optin );
$design['custom_css'] = $new_css . ' /*' . $design['custom_css'] . '*/';
}
return $design;
}
/**
* Migrate the old providers to the new format.
*
* @uses Hustle_Provider_Abstract::migrate_30
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function migrate_integrations( $module, $old_module ) {
$old_content = $old_module->meta['content'];
$integrations_settings = array();
if ( $this->is_true( $old_content['save_local_list'] ) ) {
$local_list = Hustle_Provider_Utils::get_provider_by_slug( 'local_list' );
if ( isset( $old_content['local_list_name'] ) && ! empty( $old_content['local_list_name'] ) ) {
$list_name = $old_content['local_list_name'];
} else {
$list_name = __( 'List', 'hustle' ) . ' ' . $module->module_id;
}
$local_list_form_settings = $local_list->get_provider_form_settings( $module->module_id );
$local_list_form_settings->save_form_settings_values( array( 'local_list_name' => $list_name ) );
}
if ( ! empty( $old_content['email_services'] ) ) {
foreach ( $old_content['email_services'] as $slug => $data ) {
$provider = Hustle_Provider_Utils::get_provider_by_slug( $slug );
if ( $provider instanceof Hustle_Provider_Abstract ) {
$migrated = $provider->migrate_30( $module, $old_module );
if ( ! $migrated ) {
Opt_In_Utils::maybe_log( __METHOD__ . ': Module ' . $module->module_id . ' with email provider ' . $slug . ' could not be migrated.' );
}
}
}
$active_email_service = $old_content['active_email_service'];
if ( 'mailchimp' === $active_email_service ) {
$mailchimp_settings = $old_content['email_services']['mailchimp'];
if ( isset( $mailchimp_settings['allow_subscribed_users'] ) && 'allow' === $mailchimp_settings['allow_subscribed_users'] ) {
$integrations_settings['allow_subscribed_users'] = '1';
}
}
$integrations_settings['active_integrations'] = $active_email_service;
}
return $integrations_settings;
}
/**
* Create the new 'display options' settings according to the old module.
* Used by Embedded and Social sharing modules only.
*
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_display_meta( $module, $old_module ) {
$display = $module->get_display()->to_array();
$old_settings = $old_module->meta['settings'];
$test_types = isset( $old_module->meta['test_types'] ) ? $old_module->meta['test_types'] : array();
if ( isset( $old_settings['after_content_enabled'] ) && $this->is_true( $old_settings['after_content_enabled'] ) ) {
if ( ! isset( $test_types['after_content'] ) || ! $this->is_true( $test_types['after_content'] ) ) {
$display['inline_enabled'] = '1';
}
}
if ( isset( $old_settings['widget_enabled'] ) && ! $this->is_true( $old_settings['widget_enabled'] ) ) {
$display['widget_enabled'] = '0';
} elseif ( isset( $test_types['widget'] ) && $this->is_true( $test_types['widget'] ) ) {
$display['widget_enabled'] = '0';
}
if ( isset( $old_settings['shortcode_enabled'] ) && ! $this->is_true( $old_settings['shortcode_enabled'] ) ) {
$display['shortcode_enabled'] = '0';
} elseif ( isset( $test_types['shortcode'] ) && $this->is_true( $test_types['shortcode'] ) ) {
$display['shortcode_enabled'] = '0';
}
return $display;
}
/**
* Create the new 'settings' settings according to the old module.
* The old data is used to replace the defaults.
* The old unused data is not being removed atm.
*
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_settings_meta( $module, $old_module ) {
$settings = $module->get_settings()->to_array();
$old_settings = $old_module->meta['settings'];
$old_content = $old_module->meta['content'];
if ( $this->is_multisite ) {
$settings = array_merge( $settings, $old_settings );
}
if ( isset( $old_settings['allow_scroll_page'] ) ) {
$settings['allow_scroll_page'] = $this->is_true( $old_settings['allow_scroll_page'] ) ? '1' : '0';
}
if ( isset( $old_settings['not_close_on_background_click'] ) ) {
$settings['close_on_background_click'] = ! $this->is_true( $old_settings['not_close_on_background_click'] ) ? '1' : '0';
}
if ( isset( $old_settings['auto_hide'] ) ) {
$settings['auto_hide'] = $this->is_true( $old_settings['auto_hide'] ) ? '1' : '0';
}
// The 3.x default was an empty string, which behaved as "no_animation".
if ( isset( $old_settings['animation_in'] ) && '' === $old_settings['animation_in'] ) {
$settings['animation_in'] = 'no_animation';
}
// The 3.x default was an empty string, which behaved as "no_animation".
if ( isset( $old_settings['animation_out'] ) && '' === $old_settings['animation_out'] ) {
$settings['animation_out'] = 'no_animation';
}
// An old bug where this setting was empty, and the wrong option showed up selected in wizard.
if ( empty( $old_settings['after_close'] ) ) {
$settings['after_close'] = 'keep_show';
}
if ( isset( $old_content['after_subscription'] ) ) {
$settings['hide_after_subscription'] = $old_content['after_subscription'];
}
if ( Hustle_Module_Model::EMBEDDED_MODULE !== $module->module_type && isset( $old_settings['triggers'] ) ) {
// Check for click trigger.
if ( isset( $old_settings['triggers']['trigger'] ) && 'click' === $old_settings['triggers']['trigger'] ) {
$settings['triggers']['enable_on_click_shortcode'] = '1';
$settings['triggers']['enable_on_click_element'] = '1';
}
// The time trigger switch was removed, so make the time to show '0' if it was turend off.
if ( ! $this->is_true( $old_settings['triggers']['on_time'] ) ) {
$settings['triggers']['on_time_delay'] = '0';
}
// Same keys. Making sure the value's type is the same that we're using in 4.0.
if ( isset( $old_settings['triggers']['on_exit_intent_per_session'] ) ) {
$settings['triggers']['on_exit_intent_per_session'] = $this->is_true( $old_settings['triggers']['on_exit_intent_per_session'] ) ? '1' : '0';
}
if ( isset( $old_settings['triggers']['on_exit_intent_delayed'] ) ) {
$settings['triggers']['on_exit_intent_delayed'] = $this->is_true( $old_settings['triggers']['on_exit_intent_delayed'] ) ? '1' : '0';
}
if ( isset( $old_settings['on_adblock']['on_exit_intent_delayed'] ) ) {
$settings['triggers']['on_adblock'] = $this->is_true( $old_settings['triggers']['on_adblock'] ) ? '1' : '0';
}
}
return $settings;
}
/**
* Create the new 'visibility' settings according to the old module.
*
* @since 4.0
*
* @param Hustle_Module_Model $module Module.
* @param object $old_module Old module.
* @return array
*/
private function parse_visibility_meta( $module, $old_module ) {
$conditions = $module->get_visibility()->to_array();
$old_settings = $old_module->meta['settings'];
if ( isset( $old_settings['conditions'] ) ) {
$old_conditions = $old_settings['conditions'];
$group_id = substr( md5( wp_rand() ), 0, 10 );
$new_conditions = array();
// Visitor logged in status.
if ( isset( $old_conditions['visitor_logged_in'] ) && 'true' === $old_conditions['visitor_logged_in'] ) {
$new_conditions['visitor_logged_in_status']['show_to'] = 'logged_in';
} elseif ( isset( $old_conditions['visitor_not_logged_in'] ) && 'true' === $old_conditions['visitor_not_logged_in'] ) {
$new_conditions['visitor_logged_in_status']['show_to'] = 'logged_out';
}
// Visitor's device.
if ( isset( $old_conditions['only_on_mobile'] ) && 'true' === $old_conditions['only_on_mobile'] ) {
$new_conditions['visitor_device']['filter_type'] = 'mobile';
} elseif ( isset( $old_conditions['not_on_mobile'] ) && 'true' === $old_conditions['not_on_mobile'] ) {
$new_conditions['visitor_device']['filter_type'] = 'not_mobile';
}
// Referrer.
if ( isset( $old_conditions['from_specific_ref'] ) ) {
$new_conditions['from_referrer']['filter_type'] = 'true';
$new_conditions['from_referrer']['refs'] = $old_conditions['from_specific_ref']['refs'];
} elseif ( isset( $old_conditions['not_from_specific_ref'] ) ) {
$new_conditions['from_referrer']['filter_type'] = 'false';
$new_conditions['from_referrer']['refs'] = $old_conditions['from_specific_ref']['refs'];
}
// Source of arrival.
if ( isset( $old_conditions['not_from_internal_link'] ) || isset( $old_conditions['from_search_engine'] ) ) {
if ( isset( $old_conditions['not_from_internal_link'] ) && 'true' === $old_conditions['not_from_internal_link'] ) {
$new_conditions['source_of_arrival']['source_external'] = 'true';
}
if ( isset( $old_conditions['from_search_engine'] ) && 'true' === $old_conditions['from_search_engine'] ) {
$new_conditions['source_of_arrival']['source_search'] = 'true';
}
}
// On URL.
if ( isset( $old_conditions['on_specific_url'] ) ) {
$new_conditions['on_url']['filter_type'] = 'only';
$new_conditions['on_url']['urls'] = $old_conditions['on_specific_url']['urls'];
} elseif ( isset( $old_conditions['not_on_specific_url'] ) ) {
$new_conditions['on_url']['filter_type'] = 'except';
$new_conditions['on_url']['urls'] = $old_conditions['not_on_specific_url']['urls'];
}
// Visitor has commented.
if ( isset( $old_conditions['visitor_has_commented'] ) && 'true' === $old_conditions['visitor_has_commented'] ) {
$new_conditions['visitor_commented']['filter_type'] = 'true';
} elseif ( isset( $old_conditions['visitor_has_never_commented'] ) && 'true' === $old_conditions['visitor_has_never_commented'] ) {
$new_conditions['visitor_commented']['filter_type'] = 'false';
}
// Country.
if ( isset( $old_conditions['in_a_country'] ) ) {
$new_conditions['visitor_country']['filter_type'] = 'only';
$new_conditions['visitor_country']['countries'] = $old_conditions['in_a_country']['countries'];
} elseif ( isset( $old_conditions['not_in_a_country'] ) ) {
$new_conditions['visitor_country']['filter_type'] = 'except';
$new_conditions['visitor_country']['countries'] = $old_conditions['not_in_a_country']['countries'];
}
// 404.
if ( isset( $old_conditions['only_on_not_found'] ) && 'true' === $old_conditions['only_on_not_found'] ) {
$new_conditions['page_404']['show'] = 'true';
}
// Module shown less than.
if ( isset( $old_conditions['shown_less_than'] ) ) {
$new_conditions['shown_less_than']['filter_type'] = 'limited';
$new_conditions['shown_less_than']['less_than'] = $old_conditions['shown_less_than']['less_than'];
}
// Custom Post Types.
$post_types = Opt_In_Utils::get_post_types();
$cpts = wp_list_pluck( $post_types, 'label', 'name' );
foreach ( $cpts as $slug => $label ) {
if ( isset( $old_conditions[ $label ] ) ) {
$new_conditions[ $slug ] = $old_conditions[ $label ];
}
}
$regular_conditions_keys = array( 'pages', 'posts', 'categories', 'tags' );
foreach ( $regular_conditions_keys as $key ) {
if ( isset( $old_conditions[ $key ] ) ) {
$new_conditions[ $key ] = $old_conditions[ $key ];
}
}
$new_visibility = array();
$new_visibility[ $group_id ] = $new_conditions;
$new_visibility[ $group_id ]['group_id'] = $group_id;
$new_visibility[ $group_id ]['filter_type'] = 'any';
$visibility = array( 'conditions' => $new_visibility );
} else {
$visibility = array();
}
return $visibility;
}
/**
* Migrate global settings.
*
* @since 4.0
*/
private function migrate_settings() {
$current_settings = get_option( 'hustle_settings', array() );
// Email sender address and name settings.
$old_email_sender_settings = get_option( 'hustle_global_email_settings' );
if ( $old_email_sender_settings ) {
$current_settings['general']['sender_email_address'] = isset( $old_email_sender_settings['sender_email_address'] ) ? $old_email_sender_settings['sender_email_address'] : get_option( 'admin_email', '' );
$current_settings['general']['sender_email_name'] = isset( $old_email_sender_settings['sender_email_name'] ) ? $old_email_sender_settings['sender_email_name'] : get_option( 'blogname', '' );
}
// Unsubscription email and messages.
$old_unsubscription_settings = get_option( 'hustle_global_unsubscription_settings' );
if ( $old_unsubscription_settings ) {
$current_settings['unsubscribe']['messages'] = isset( $old_unsubscription_settings['messages'] ) ? $old_unsubscription_settings['messages'] : '';
$current_settings['unsubscribe']['email'] = isset( $old_unsubscription_settings['email'] ) ? $old_unsubscription_settings['email'] : '';
}
update_option( 'hustle_settings', $current_settings );
}
/**
* Take all classes and replace them with the new ones.
*
* @since 4.0
*
* @param string $custom_css Custom CSS.
* @param bool $is_optin Is optin or not.
* @return string
*/
private function parse_custom_css( $custom_css, $is_optin ) {
$replace_values = array(
'.wph-modal' => '', // Main wrapper (no need to migrate this, main wrapper "hustle-ui" it's automatically added on 4.0).
'.hustle-modal' => '.hustle-layout', // Content wrapper.
'.wph-modal-active' => '.hustle-show', // Active class.
'.hustle-modal-title' => '.hustle-title', // Title.
'.hustle-modal-subtitle' => '.hustle-subtitle', // Subtitle.
'section .hustle-modal-article' => '.hustle-content',
'.hustle-modal-article' => '.hustle-content',
'section' => '.hustle-content',
'.hustle-layout .hustle-modal-close' => '.hustle-modal-close', // .hustle-layout (previously .hustle-modal) is no longer a parent.
'.hustle-modal-close .hustle-icon' => '.hustle-button-close [class*="hustle-icon-"]', // Close button (icon).
'.hustle-modal-close' => '.hustle-button-close', // Close button.
'.hustle-modal-image' => '.hustle-image', // Feat. image.
'.hustle-modal-cta' => '.hustle-button-cta', // Call to action.
'.hustle-modal-image_only' => '.hustle-image-only', // Image only.
'.hustle-modal-mobile_hidden' => '.hustle-hide-until-sm', // Mobile hidden.
'.hustle-modal-content' => '.hustle-layout-content',
'.hustle-modal-footer' => '.hustle-layout-footer',
);
if ( $is_optin ) {
$extra_classes = array(
'.hustle-modal-body' => '.hustle-layout-body', // Body.
'footer' => '.hustle-layout-form', // Form container.
'.hustle-modal-optin_form' => '.hustle-layout-form', // Form container.
'.hustle-modal-optin_field' => '.hustle-field', // Form field(s).
'.hustle-modal-optin_group' => '.hustle-form-options', // Provider's extra options.
'.hustle-modal-optin_button button' => '.hustle-button-submit', // Submit button.
'.hustle-modal-optin_button' => '.hustle-button-submit', // Submit button.
'.hustle-modal-optin_field input' => '.hustle-input', // Inputs.
'.hustle-modal-provider-args-container' => '.hustle-form-options', // Provider's extra options.
'.hustle-modal-one' => '.hustle-optin--default', // Layout 1 - Default.
'.hustle-modal-two' => '.hustle-optin--compact', // Layout 2 - Compact.
'.hustle-modal-three' => '.hustle-optin--focus-optin', // Layout 3 (Optin Focus).
'.hustle-modal-four' => '.hustle-optin--focus-content', // Layout 4 (Content Focus).
'.hustle-layout .hustle-modal-success' => '.hustle-success',
'.hustle-modal-success' => '.hustle-success',
);
} else {
$extra_classes = array(
'.hustle-layout .hustle-modal-body' => '.hustle-layout', // Body.
'.hustle-modal-body' => '.hustle-layout', // Body.
'.hustle-modal-simple' => '.hustle-info--compact', // Simple - Compact.
'.hustle-modal-minimal' => '.hustle-info--default', // Minimal - Default.
'.hustle-modal-cabriolet' => '.hustle-info--stacked', // Cabriolet (Stacked).
'.hustle-modal-header' => '.hustle-layout-header',
);
}
$replace_values = array_merge( $replace_values, $extra_classes );
foreach ( $replace_values as $old => $new ) {
$custom_css = preg_replace( '/' . $old . '(?!-|[a-z])/m', $new, $custom_css );
}
return $custom_css;
}
/**
* Finish tracking subscription migration
*
* @param int $migrated_rows Migrated rows.
*/
private function finish_tracking_subscription_migration( $migrated_rows = 0 ) {
// Set the flag that we already migrated the tracking.
self::mark_tracking_migration_as_completed();
wp_send_json_success(
array(
'current_meta' => 'done',
'migrated_rows' => $migrated_rows,
)
);
}
/**
* Mark tracking migration as completed
*/
public static function mark_tracking_migration_as_completed() {
delete_option( 'hustle_30_migration_data' );
self::migration_passed( 'hustle_30_tracking_migrated' );
}
/**
* Check whether there's tracking and subscriptions data to be migrated.
*
* @since 4.0
*
* @return boolean
*/
public static function is_tracking_subscription_data_to_migrate() {
$migration_process_data = get_option( 'hustle_30_migration_data', array() );
if ( ! empty( $migration_process_data ) ) {
return true;
}
$blog_modules_id = Hustle_Module_Collection::instance()->get_30_modules_ids_by_blog( get_current_blog_id() );
// If we don't have modules, finish.
if ( empty( $blog_modules_id ) ) {
self::mark_tracking_migration_as_completed();
return false;
}
$total_entries = self::get_tracking_submissions_count( $blog_modules_id );
// If we don't have tracking nor submissions, finish.
if ( ! $total_entries ) {
self::mark_tracking_migration_as_completed();
return false;
}
return true;
}
/**
* Migrate tracking and subscription data.
* This is done via ajax in order to avoid timeouts.
*
* @since 4.0
*/
public function migrate_tracking_and_subscriptions() {
Opt_In_Utils::validate_ajax_call( 'hustle-migrate-tracking-and-subscriptions' );
global $wpdb;
$main_site_table = $wpdb->base_prefix . Hustle_Db::TABLE_HUSTLE_MODULES_META;
$batch_limit = intval( apply_filters( 'hustle_migration_tracking_batch_limit', 50 ) );
$migration_data = get_option( 'hustle_30_migration_data', array() );
// Things to get in the first run only.
if ( ! empty( $migration_data ) ) {
$blog_modules_id = $migration_data['blog_modules_id'];
$current_meta = $migration_data['current_meta'];
} else {
$blog_modules_id = Hustle_Module_Collection::instance()->get_30_modules_ids_by_blog( get_current_blog_id() );
// If we don't have modules, finish.
if ( empty( $blog_modules_id ) ) {
$this->finish_tracking_subscription_migration();
}
$total_entries = self::get_tracking_submissions_count( $blog_modules_id, $wpdb );
// If we don't have tracking nor submissions, finish.
if ( ! $total_entries ) {
$this->finish_tracking_subscription_migration();
}
$current_meta = 0;
// If there's enough data for 1 run only.
if ( $batch_limit > $total_entries ) {
$total_batches = 1;
} else {
$total_batches = round( intval( $total_entries ) / intval( $batch_limit ) );
}
$migration_data = array(
'blog_modules_id' => $blog_modules_id,
'current_meta' => $current_meta,
'total_entries' => $total_entries,
'migrated_rows' => 0,
'percentage_per_batch' => 100 / $total_batches,
'migrated_percentage' => 0,
);
update_option( 'hustle_30_migration_data', $migration_data );
}
$migrated_rows = $migration_data['migrated_rows'];
$metas = $this->get_paged_metas( $blog_modules_id, $current_meta, $batch_limit, $wpdb );
// If there aren't more metas, we finished.
if ( ! $metas ) {
$this->finish_tracking_subscription_migration( $migrated_rows );
}
foreach ( $metas as $meta ) {
$migrated_rows++;
// Store the new views, conversions, and subscriptions.
if ( false !== stripos( $meta->meta_key, 'view' ) ) {
$current_meta = $this->migrate_tracking( $meta, 'view' );
} elseif ( false !== stripos( $meta->meta_key, 'conversion' ) ) {
$current_meta = $this->migrate_tracking( $meta, 'conversion' );
} elseif ( 'subscription' === $meta->meta_key ) {
$current_meta = $this->migrate_subscription( $meta );
} elseif ( false !== stripos( $meta->meta_key, 'page_shares' ) ) {
$current_meta = $this->migrate_sshare_page_counter( $meta );
}
}
// If there aren't more metas, we finished.
if ( ! $current_meta ) {
$this->finish_tracking_subscription_migration( $migrated_rows );
}
// Update last the stored data of the last batch.
$migration_data['current_meta'] = $current_meta;
$migration_data['migrated_rows'] = $migrated_rows;
$migration_data['migrated_percentage'] += $migration_data['percentage_per_batch'];
update_option( 'hustle_30_migration_data', $migration_data );
$response = array(
'migrated_percentage' => round( $migration_data['migrated_percentage'], 2 ),
'migrated_rows' => $migrated_rows,
'total_entries' => $migration_data['total_entries'],
);
wp_send_json_success( $response );
}
/**
* Get the 3.x metas of a module, paginated.
* This just retrieves tracking (views and conversions) and subscriptions.
*
* @since 4.0
*
* @param array $modules_id Module IDs.
* @param int $current_meta Current meta.
* @param ont $limit Limit.
* @param boolean $wpdb WPDB.
* @return array
*/
private function get_paged_metas( $modules_id, $current_meta, $limit = 10, $wpdb = false ) {
if ( ! $wpdb ) {
global $wpdb;
}
$meta_keys_placeholders = implode( ', ', array_fill( 0, count( self::$tracking_meta_keys ), '%s' ) );
$meta_key_query = $wpdb->prepare(
"`meta_key` IN ({$meta_keys_placeholders})", // phpcs:ignore
self::$tracking_meta_keys
);
$modules_id_placeholders = implode( ', ', array_fill( 0, count( $modules_id ), '%d' ) );
$modules_id_query = $wpdb->prepare(
"`module_id` IN ({$modules_id_placeholders})", // phpcs:ignore
$modules_id
);
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$query = $wpdb->prepare(
'SELECT *
FROM `' . $wpdb->base_prefix . "hustle_modules_meta`
WHERE `meta_id` > %d
AND (({$modules_id_query}
AND {$meta_key_query})
OR `meta_key` LIKE %s)
ORDER BY `meta_id` ASC
LIMIT %d",
$current_meta,
'%page_shares',
$limit
);
// phpcs:enable
$metas = $wpdb->get_results( $query ); // phpcs:ignore
return $metas;
}
/**
* Get tracking submissions count
*
* @param array $modules_id Module ID.
* @param abject $wpdb WPDB.
* @return string
*/
private static function get_tracking_submissions_count( $modules_id, $wpdb = false ) {
if ( ! $wpdb ) {
global $wpdb;
}
$modules_id_placeholders = implode( ', ', array_fill( 0, count( $modules_id ), '%d' ) );
$modules_id_query = $wpdb->prepare( "`module_id` IN ({$modules_id_placeholders})", $modules_id );// phpcs:ignore
$meta_keys_placeholders = implode( ', ', array_fill( 0, count( self::$tracking_meta_keys ), '%s' ) );
$meta_keys_query = $wpdb->prepare( "`meta_key` IN ({$meta_keys_placeholders})", self::$tracking_meta_keys );// phpcs:ignore
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$query = $wpdb->prepare(
"SELECT COUNT(*)
FROM `{$wpdb->base_prefix}hustle_modules_meta`
WHERE ({$modules_id_query}
AND {$meta_keys_query})
OR `meta_key` LIKE %s",
'%page_shares'
);
// phpcs:enable
return $wpdb->get_var( $query ); // phpcs:ignore
}
/**
* Store the new tracking view.
*
* @since 4.0
* @param object $old_view Old view.
* @param string $tracking_type view|conversion.
*/
private function migrate_tracking( $old_view, $tracking_type ) {
$old_data = json_decode( $old_view->meta_value, true );
// Data coming from 2.x has 'optin_id' instead of 'module_id'.
$module_id = isset( $old_data['module_id'] ) ? $old_data['module_id'] : $old_data['optin_id'];
if ( isset( $old_data['module_type'] ) ) {
$module_type = $old_data['module_type'];
} else {
// Conversions didn't store the module_type. Try to get it without making a db call.
if ( false !== stripos( $old_view->meta_key, 'popup' ) ) {
$module_type = Hustle_Module_Model::POPUP_MODULE;
} elseif ( false !== stripos( $old_view->meta_key, 'slidein' ) ) {
$module_type = Hustle_Module_Model::SLIDEIN_MODULE;
} else {
// It can be either an embed or ssharing module. No way to know it unless retrieving it.
$module_type = $this->get_module_type_by_module_id( $module_id );
}
}
$meta_key = $old_view->meta_key;
$date_created = date_i18n( 'Y-m-d H:i:s', $old_data['date'] );
$module_sub_type = null;
// Define the subtype for embeds and social sharing modules.
if ( Hustle_Module_Model::EMBEDDED_MODULE === $module_type || Hustle_Module_Model::SOCIAL_SHARING_MODULE === $module_type ) {
// TODO: use constants here instead.
if ( false !== stripos( $meta_key, 'shortcode' ) ) {
$module_sub_type = 'shortcode';
} elseif ( false !== stripos( $meta_key, 'widget' ) ) {
$module_sub_type = 'widget';
} elseif ( false !== stripos( $meta_key, 'after_content' ) ) {
$module_sub_type = 'inline';
} elseif ( false !== stripos( $meta_key, 'floating' ) ) {
$module_sub_type = 'floating';
}
}
$tracking = Hustle_Tracking_Model::get_instance();
$tracking->save_tracking( $module_id, $tracking_type, $module_type, $old_data['page_id'], $module_sub_type, $date_created, $old_data['ip'] );
return $old_view->meta_id;
}
/**
* Migrate 3.x subscription.
*
* @since 4.0
*
* @param object $old_subscription Old subscription.
* @return int
*/
private function migrate_subscription( $old_subscription ) {
$data = json_decode( $old_subscription->meta_value, true );
$date_created = date_i18n( 'Y-m-d H:i:s', $data['time'] );
$entry = new Hustle_Entry_Model();
$entry->entry_type = $data['module_type'];
$entry->module_id = $old_subscription->module_id;
$entry->save( $date_created );
$entry_data = array();
foreach ( $data as $name => $value ) {
if ( 'time' === $name ) {
continue;
}
// Getting rid of legacy stuff by transforming it already.
if ( 'l_name' === $name ) {
$name = 'last_name';
} elseif ( 'f_name' === $name ) {
$name = 'first_name';
}
$entry_data[] = array(
// Remove trailing underscores. Used in 3.x when the fields' name had spaces.
'name' => preg_replace( '/_+$/', '', $name ),
'value' => $value,
);
}
$entry->set_fields( $entry_data, $date_created );
return $old_subscription->meta_id;
}
/**
* Migrate 3.x per page ssharing count.
*
* @since 4.0
*
* @param object $old_counter Old counter.
* @return int
*/
private function migrate_sshare_page_counter( $old_counter ) {
$page_id = $old_counter->module_id;
$count = $old_counter->meta_value;
$tracking = Hustle_Tracking_Model::get_instance();
$tracking->save_old_migrated_sshare_page_count( $page_id, $count );
return $old_counter->meta_id;
}
/**
* Get the module_type by the module_id.
*
* @since 4.0
*
* @param int $module_id Module.ID.
* @return string
*/
private function get_module_type_by_module_id( $module_id ) {
global $wpdb;
// TODO: This should be cached as long as the query is the same in the same load.
$module_type = $wpdb->get_var( $wpdb->prepare( 'SELECT `module_type` FROM ' . Hustle_Db::modules_table() . ' WHERE `module_id`=%d', $module_id ) ); // phpcs:ignore
return $module_type;
}
/**
* Helper function to check different values
* previously given to properties which all mean true.
*
* @param mixed $value Value.
* @return boolean
*/
private function is_true( $value ) {
if ( '1' === $value || 'true' === $value || 1 === $value || true === $value ) {
return true;
}
return false;
}
}