KOKINIO - MANAGER
Edit File: class-hustle-provider-admin-ajax.php
<?php /** * File for Hustle_Provider_Admin_Ajax class. * * @package Hustle * @since 3.0.5 */ if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Class Hustle_Provider_Admin_Ajax. * Handles the AJAX actions for providers. * * @since 4.0.0 */ class Hustle_Provider_Admin_Ajax { /** * Default nonce action. * * @since 4.0.0 * @var string */ private static $nonce_action = 'hustle_provider_action'; /** * Instance of this class. * * @since 4.2.0 * @var Hustle_Provider_Admin_Ajax */ private static $instance = null; /** * Instance of Hustle_Layout_Helper. * * @since 4.2.0 * @var Hustle_Layout_Helper */ private $renderer = null; /** * Returns an instance of this class. * * @since 4.2.0 * @return Hustle_Provider_Admin_Ajax */ public static function get_instance() { if ( is_null( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Class constructor. * * @since 4.0.0 */ public function __construct() { $this->renderer = new Hustle_Layout_Helper(); add_action( 'wp_ajax_hustle_provider_get_providers', array( $this, 'get_addons' ) ); add_action( 'wp_ajax_hustle_provider_get_form_providers', array( $this, 'get_form_addons' ) ); add_action( 'wp_ajax_hustle_provider_deactivate', array( $this, 'deactivate' ) ); add_action( 'wp_ajax_hustle_provider_is_on_module', array( $this, 'is_on_module' ) ); add_action( 'wp_ajax_hustle_provider_settings', array( $this, 'settings' ) ); add_action( 'wp_ajax_hustle_provider_form_settings', array( $this, 'form_settings' ) ); add_action( 'wp_ajax_hustle_provider_form_deactivate', array( $this, 'form_deactivate' ) ); add_action( 'wp_ajax_hustle_refresh_email_lists', array( $this, 'refresh_email_lists' ) ); add_action( 'wp_ajax_hustle_provider_insert_local_list', array( $this, 'insert_local_list' ) ); add_action( 'wp_ajax_hustle_provider_migrate_aweber', array( $this, 'migrate_aweber' ) ); add_action( 'wp_ajax_hustle_provider_migrate_constantcontact', array( $this, 'migrate_constantcontact' ) ); add_action( 'wp_ajax_hustle_provider_migrate_infusionsoft', array( $this, 'migrate_infusionsoft' ) ); add_action( 'wp_ajax_hustle_provider_migrate_convertkit', array( $this, 'migrate_convertkit' ) ); add_action( 'wp_ajax_hustle_provider_migrate_hubspot', array( $this, 'migrate_hubspot' ) ); } /** * Validates the Ajax request. * * @since 4.0.0 */ private function validate_ajax() { Opt_In_Utils::validate_ajax_call( self::$nonce_action ); } /** * Executes the deactivation of the global instance of a provider. * * @since 4.0.0 */ public function deactivate() { $this->validate_ajax(); Opt_In_Utils::is_user_allowed_ajax( 'hustle_edit_integrations' ); $post_data = ! empty( $_POST['data'] ) ? wp_unslash( $_POST['data'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug' ) ); $slug = $data['slug']; $addon = Hustle_Provider_Utils::get_provider_by_slug( $slug ); // . Hustle_Provider_Utils::maybe_attach_addon_hook( $addon ). $title = $addon->get_title(); // Handling multi_id. if ( isset( $data['global_multi_id'] ) ) { $multi_id_label = ''; $multi_ids = $addon->get_global_multi_ids(); foreach ( $multi_ids as $key => $multi_id ) { if ( isset( $multi_id['id'] ) && $multi_id['label'] ) { if ( $multi_id['id'] === $data['global_multi_id'] ) { $multi_id_label = $multi_id['label']; break; } } } if ( ! empty( $multi_id_label ) ) { $title .= ' - ' . $multi_id_label; } } $deactivated = Hustle_Providers::get_instance()->deactivate_addon( $slug, $data ); if ( ! $deactivated ) { wp_send_json_error( array( 'message' => Hustle_Providers::get_instance()->get_last_error_message(), 'data' => array( 'notification' => array( 'type' => 'error', 'text' => Hustle_Providers::get_instance()->get_last_error_message(), ), ), ) ); } wp_send_json_success( array( 'message' => __( 'Addon Deactivated', 'hustle' ), 'data' => array( 'notification' => array( 'type' => 'success', 'text' => '<strong>' . $title . '</strong> ' . __( 'Successfully disconnected' ), ), ), ) ); } /** * Get Addons list, grouped by connected status * * @since 4.0 */ public function get_addons() { $this->validate_ajax(); $providers = Hustle_Provider_Utils::get_registered_addons_grouped_by_connected(); $connected_html = $this->renderer->render( 'admin/integrations/page-table-connected', array( 'providers' => $providers['connected'] ), true ); $not_connected_html = $this->renderer->render( 'admin/integrations/page-table-not-connected', array( 'providers' => $providers['not_connected'] ), true ); wp_send_json_success( array( 'connected' => $connected_html, 'not_connected' => $not_connected_html, ) ); } /** * Refresh email lists * * @since 4.0.2 */ public function refresh_email_lists() { $this->validate_ajax(); $module_id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT ); $slug = filter_input( INPUT_POST, 'slug', FILTER_SANITIZE_SPECIAL_CHARS ); $type = filter_input( INPUT_POST, 'type', FILTER_SANITIZE_SPECIAL_CHARS ); $provider = Hustle_Provider_Utils::get_provider_by_slug( $slug ); if ( ! $provider ) { wp_send_json_error( esc_html__( 'Provider not found', 'hustle' ) ); } $class_name = $provider->get_form_settings_class_name(); if ( empty( $class_name ) || ! class_exists( $class_name ) ) { wp_send_json_error( esc_html__( 'Settings class not found', 'hustle' ) ); } $form_settings_instance = new $class_name( $provider, $module_id ); $lists = $form_settings_instance->get_global_multi_lists( true, $module_id, $type ); $list_id = empty( $type ) || 'forms' !== $type ? 'list_id' : 'form_id'; $options = array( 'list' => array( 'id' => $list_id, 'type' => 'select', 'name' => $list_id, 'default' => '', 'options' => $lists, 'value' => '', 'selected' => '', 'class' => 'sui-select', ), ); $select = Hustle_Provider_Utils::get_html_for_options( $options ); wp_send_json_success( array( 'select' => $select, ) ); } /** * Get providers list, grouped by connected status with module * * @since 4.0.0 */ public function get_form_addons() { $this->validate_ajax(); $post_data = ! empty( $_POST['data'] ) ? wp_unslash( $_POST['data'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $sanitized_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'moduleId' => 'moduleId' ) ); $module_id = isset( $sanitized_data['moduleId'] ) ? $sanitized_data['moduleId'] : ''; $providers = Hustle_Provider_Utils::get_registered_addons_grouped_by_form_connected( $module_id ); $connected_html = $this->renderer->render( 'admin/integrations/wizard-table-connected', array( 'providers' => $providers['connected'], 'module_id' => $module_id, ), true ); $not_connected_html = $this->renderer->render( 'admin/integrations/wizard-table-not-connected', array( 'providers' => $providers['not_connected'], 'module_id' => $module_id, ), true ); $list_connected = array(); if ( ! empty( $providers ) && isset( $providers['connected'] ) ) { foreach ( $providers['connected'] as $key => $value ) { $list_connected[] = $value['slug']; } } wp_send_json_success( array( 'connected' => $connected_html, 'not_connected' => $not_connected_html, 'list_connected' => implode( ',', $list_connected ), 'list_connected_total' => count( $list_connected ), ) ); } /** * Handles the provider's wizard for the global configuration. * * @since 4.0.0 */ public function settings() { $this->validate_ajax(); Opt_In_Utils::is_user_allowed_ajax( 'hustle_edit_integrations' ); $sanitized_post_data = $this->get_sanitized_submitted_data(); $check_required_fields_missing = $this->check_required_fields( $sanitized_post_data, array( 'slug', 'step', 'current_step' ) ); if ( ! empty( $check_required_fields_missing ) ) { wp_send_json_error( array( 'message' => __( 'Please check the required fields.', 'hustle' ), 'errors' => $check_required_fields_missing, ) ); } $slug = $sanitized_post_data['slug']; $step = $sanitized_post_data['step']; $current_step = $sanitized_post_data['current_step']; $module_id = 0; if ( isset( $sanitized_post_data['module_id'] ) ) { $module_id = $sanitized_post_data['module_id']; // Module_id could be unset from $sanitized_post_data when the providers don't expect it anymore within they params. } $provider = Hustle_Provider_Utils::get_provider_by_slug( $slug ); if ( ! $provider ) { wp_send_json_error( __( 'Provider not found', 'hustle' ) ); } if ( ! $provider->is_settings_available() ) { wp_send_json_error( array( 'data' => $provider->get_empty_wizard( __( 'This provider does not have settings available', 'hustle' ) ), ) ); } Hustle_Provider_Utils::maybe_attach_addon_hook( $provider ); unset( $sanitized_post_data['slug'] ); unset( $sanitized_post_data['current_step'] ); unset( $sanitized_post_data['step'] ); $wizard = $provider->get_settings_wizard( $sanitized_post_data, $module_id, $current_step, $step, true ); wp_send_json_success( array( 'data' => $wizard, ) ); } /** * Handles the provider's wizard for the per module configuration. * * @since 4.0.0 */ public function form_settings() { $this->validate_ajax(); $sanitized_post_data = $this->get_sanitized_submitted_data( array( 'module_id' => FILTER_VALIDATE_INT ) ); $check_required_fields_missing = $this->check_required_fields( $sanitized_post_data, array( 'slug', 'step', 'current_step', 'module_id' ) ); if ( ! empty( $check_required_fields_missing ) ) { wp_send_json_error( array( 'message' => __( 'Please check the required fields.', 'hustle' ), 'errors' => $check_required_fields_missing, ) ); } $slug = $sanitized_post_data['slug']; $step = (int) $sanitized_post_data['step']; $current_step = (int) $sanitized_post_data['current_step']; $module_id = $sanitized_post_data['module_id']; $provider = Hustle_Provider_Utils::get_provider_by_slug( $slug ); if ( ! $provider ) { wp_send_json_error( __( 'Provider not found', 'hustle' ) ); } if ( ! $provider->is_form_settings_available( $module_id ) ) { wp_send_json_success( array( 'data' => $provider->get_empty_wizard( __( 'This provider does not have form settings available', 'hustle' ) ), ) ); } Hustle_Provider_Utils::maybe_attach_addon_hook( $provider ); unset( $sanitized_post_data['slug'] ); unset( $sanitized_post_data['current_step'] ); unset( $sanitized_post_data['step'] ); unset( $sanitized_post_data['module_id'] ); $wizard = $provider->get_form_settings_wizard( $sanitized_post_data, $module_id, $current_step, $step ); if ( ! $wizard['opt_in_provider_has_next_step'] ) { $module = Hustle_Module_Model::new_instance( $module_id ); if ( ! is_wp_error( $module ) ) { $module->connect_integration( $slug ); } } wp_send_json_success( array( 'data' => $wizard, ) ); } /** * Handles the provider's deactivation from modules. * * @since 4.0.0 */ public function form_deactivate() { $this->validate_ajax(); $sanitized_data = Opt_In_Utils::validate_and_sanitize_fields( $_POST['data'], array( 'slug', 'module_id' ) );// phpcs:ignore $slug = $sanitized_data['slug']; $module_id = $sanitized_data['module_id']; $provider = Hustle_Provider_Utils::get_provider_by_slug( $slug ); $provider_title = $provider->get_title(); if ( ! $provider ) { $response = array( 'message' => __( 'Addon not found', 'hustle' ), 'data' => array( 'notification' => array( 'type' => 'error', 'text' => '<strong>' . $slug . '</strong> ' . __( 'integration not found', 'hustle' ), ), ), ); wp_send_json_error( $response ); } $form_settings = $provider->get_provider_form_settings( $module_id ); if ( $form_settings instanceof Hustle_Provider_Form_Settings_Abstract ) { unset( $sanitized_data['slug'] ); unset( $sanitized_data['module_id'] ); // Handling multi_id. if ( isset( $sanitized_data['multi_id'] ) ) { $multi_id_label = ''; $multi_ids = $form_settings->get_multi_ids(); foreach ( $multi_ids as $key => $multi_id ) { if ( isset( $multi_id['id'] ) && $multi_id['label'] ) { if ( $multi_id['id'] === $sanitized_data['multi_id'] ) { $multi_id_label = $multi_id['label']; break; } } } if ( ! empty( $multi_id_label ) ) { $provider_title .= ' [' . $multi_id_label . '] '; } } $form_settings->disconnect_form( $sanitized_data ); $response = array( 'message' => /* translators: provider title */ sprintf( __( 'Successfully disconnected %s from this form', 'hustle' ), $provider_title ), 'data' => array( 'notification' => array( 'type' => 'success', 'text' => '<strong>' . $provider_title . '</strong> ' . __( 'successfully disconnected from this form', 'hustle' ), ), ), ); wp_send_json_success( $response ); } else { $response = array( /* translators: provider title */ 'message' => sprintf( __( 'Failed to disconnect %1$s from this form', 'hustle' ), $provider_title ), 'data' => array( 'notification' => array( 'type' => 'error', 'text' => '<strong>' . $provider->get_title() . '</strong> ' . __( 'Failed to disconnected from this form', 'hustle' ), ), ), ); wp_send_json_error( $response ); } } /** * Insert local list into module * * @since 4.0.1 */ public function insert_local_list() { $this->validate_ajax(); $id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT ); $module = Hustle_Module_Model::new_instance( $id ); if ( 0 < $id && ! is_wp_error( $module ) ) { $module->update_meta( 'local_list_provider_settings', array( 'local_list_name' => 'hustle-' . wp_rand() ) ); $integrations_settings = $module->get_integrations_settings()->to_array(); $integrations_settings['active_integrations'] = 'local_list'; $module->update_meta( Hustle_Module_Model::KEY_INTEGRATIONS_SETTINGS, $integrations_settings ); wp_send_json_success(); } if ( is_wp_error( $module ) ) { wp_send_json_error( sprintf( __( 'Invalid module!', 'hustle' ) ) ); } wp_send_json_error(); } /** * Migrate aweber integration from oAuth1 to oAuth2 * * @since 4.1.1 */ public function migrate_aweber() { $this->validate_ajax(); if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {// phpcs:ignore $post_data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); } else { $post_data = filter_input( INPUT_POST, 'data' ); } $sanitized_post_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug', 'api_key', 'global_multi_id' ) ); $aweber = Hustle_Aweber::get_instance()->configure_migrated_api_key( $sanitized_post_data ); if ( $aweber ) { wp_send_json_error(); } wp_send_json_success(); } /** * Migrate constant contact integration from oAuth1 to oAuth2 * * @since 4.1.1 */ public function migrate_constantcontact() { $this->validate_ajax(); // Check if site connected to Hub. if ( Opt_In_Utils::get_hub_api_key() ) { wp_send_json_success(); } if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {// phpcs:ignore $post_data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); } else { $post_data = filter_input( INPUT_POST, 'data' ); } $sanitized_post_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug', 'api_key', 'global_multi_id' ) ); if ( isset( $sanitized_post_data['errors'] ) ) { wp_send_json_error(); } $instance = Hustle_ConstantContact::get_instance(); // Update API key and enable migration mode. $instance->update_api_key( $sanitized_post_data['api_key'] ); $result = array( 'next_step' => array( 'nonce' => wp_create_nonce( 'hustle_provider_action' ), 'module_id' => 0, 'multi_id' => 0, 'action' => 'hustle_provider_settings', 'global_multi_id' => 0, 'slug' => 'constantcontact', 'step' => 2, ), ); wp_send_json_success( $result ); } /** * Migrate Infusionsoft integration from to OAuth2 * * @since 7.8.9 */ public function migrate_infusionsoft() { // Validate the AJAX request. $this->validate_ajax(); if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {// phpcs:ignore $post_data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); } else { $post_data = filter_input( INPUT_POST, 'data' ); } $sanitized_post_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug', 'api_key', 'private_key', 'global_multi_id' ) ); if ( isset( $sanitized_post_data['errors'] ) ) { wp_send_json_error(); } $instance = Hustle_Infusion_Soft::get_instance(); // Update API key. $instance->configure_migrated_api_keys( $sanitized_post_data ); $redirect_url = $instance ->get_oauth() ->get_authorization_uri( 0, true, Hustle_Data::INTEGRATIONS_PAGE ); $result = array( 'redirect' => $redirect_url, ); wp_send_json_success( $result ); } /** * Migrate ConvertKit integration to V4 * * @since 7.8.11 */ public function migrate_convertkit() { $this->validate_ajax(); if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {// phpcs:ignore $post_data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); } else { $post_data = filter_input( INPUT_POST, 'data' ); } $sanitized_post_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug', 'api_key', 'global_multi_id' ) ); $convertkit = Hustle_ConvertKit::get_instance()->configure_api_key( $sanitized_post_data ); if ( ! empty( $convertkit['errors'] ) ) { wp_send_json_error(); } $integration_id = filter_var( $sanitized_post_data['global_multi_id'], FILTER_SANITIZE_SPECIAL_CHARS ); wp_send_json_success( array( 'redirect' => add_query_arg( array( 'page' => Hustle_Data::INTEGRATIONS_PAGE, 'migration' => true, 'slug' => 'convertkit', 'nonce' => wp_create_nonce( 'hustle_provider_external_redirect' ), 'action' => 'external-redirect', 'integration_id' => $integration_id, ), admin_url( 'admin.php' ) ), ) ); } /** * Configure HubSpot integration with the new API key and enable migration mode. * * @since 7.8.13 */ public function migrate_hubspot() { $this->validate_ajax(); if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {// phpcs:ignore $post_data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); } else { $post_data = filter_input( INPUT_POST, 'data' ); } $sanitized_post_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug', 'api_key', 'global_multi_id' ) ); if ( isset( $sanitized_post_data['errors'] ) ) { wp_send_json_error(); } $instance = Hustle_HubSpot::get_instance(); $instance->remove_wp_options(); // Update API key. $instance->configure_migrated_api_keys( $sanitized_post_data ); wp_send_json_success( array( 'next_step' => array( 'slug' => 'hubspot', ), ) ); } /** * Check if is active on module * * @since 4.0.1 */ public function is_on_module() { $this->validate_ajax(); $data = Opt_In_Utils::validate_and_sanitize_fields( $_POST['data'], array( 'slug' ) );// phpcs:ignore $slug = $data['slug']; $provider = Hustle_Provider_Utils::get_provider_by_slug( $slug ); $is_multi_on_global = $provider->is_allow_multi_on_global(); $is_multi_on_form = $provider->is_allow_multi_on_form(); $global_multi_id = filter_var( $_POST['data']['globalMultiId'], FILTER_SANITIZE_SPECIAL_CHARS );// phpcs:ignore $global_multi_id = ( $is_multi_on_global && ! $is_multi_on_form && ! empty( $global_multi_id ) ) ? $global_multi_id : false; $modules = Hustle_Provider_Utils::get_modules_by_active_provider( $slug, $global_multi_id ); $module_data = array(); foreach ( $modules as $module ) { $meta = $module->get_meta( 'integrations_settings' ); $module_data[ $module->module_id ] = array( 'edit_url' => esc_url_raw( $module->get_edit_url( 'integrations' ) ), 'name' => $module->module_name, 'type' => $module->module_type, 'active' => json_decode( $meta ), ); } if ( ! empty( $module_data ) ) { wp_send_json_success( $module_data ); } if ( is_wp_error( $modules ) ) { wp_send_json_error( sprintf( __( 'Invalid module!', 'hustle' ) ) ); } wp_send_json_error(); } /** * Sanitizes the incoming $_POST['data']. * * It uses FILTER_SANITIZE_SPECIAL_CHARS for all keys except the predefined ones. * * @since 4.1.0 * * @param array $extra_base_filters Additional default filters to be used. * * @return array */ private function get_sanitized_submitted_data( $extra_base_filters = array() ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated if ( ! empty( $_POST ) && ! is_array( $_POST['data'] ) ) { $string_data = filter_input( INPUT_POST, 'data' ); parse_str( $string_data, $data ); } else { $data = filter_input( INPUT_POST, 'data', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY ); } // Required and shared fields along all providers' requests. $base_filters = array_merge( array( 'slug' => FILTER_SANITIZE_SPECIAL_CHARS, 'step' => FILTER_VALIDATE_INT, 'current_step' => FILTER_VALIDATE_INT, ), $extra_base_filters ); // Let's not kill submitted arrays. $arrays_filters = array(); $submitted_arrays = array_filter( $data, 'is_array' ); if ( ! empty( $submitted_arrays ) ) { $array_args = array( 'filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_REQUIRE_ARRAY, ); $arrays_filters = array_fill_keys( array_keys( $submitted_arrays ), $array_args ); } // Implement trim for all incoming fields. foreach ( $data as $data_key => $data_value ) { // Check we are not trimming array value. if ( is_array( $data_value ) ) { continue; } $data[ $data_key ] = trim( $data_value ); } // Implement FILTER_SANITIZE_SPECIAL_CHARS for all the other incoming fields. $generic_filters = array_fill_keys( array_keys( $data ), FILTER_SANITIZE_SPECIAL_CHARS ); // Merge both generic filters with the pre-defined and arrays ones. $filters = array_merge( $generic_filters, $arrays_filters, $base_filters ); // Aand filter. $sanitized_data = filter_var_array( $data, $filters ); if ( ! empty( $sanitized_data['name'] ) ) { $sanitized_data['name'] = wp_strip_all_tags( $sanitized_data['name'] ); } return $sanitized_data; } /** * Check that the required fields are set and not empty. * * @since 4.1.0 * * @param array $data Data to check. * @param array $required_fields Key of the required fields to look for. * * @return array|bool Array on missing required fields. False otherwise. */ private function check_required_fields( $data, $required_fields ) { $errors = array(); foreach ( $required_fields as $required_field ) { if ( ! isset( $data[ $required_field ] ) || ( empty( trim( $data[ $required_field ] ) ) && 0 !== $data[ $required_field ] ) ) { /* translators: required field name */ $errors[ $required_field ] = sprintf( __( 'Field %s is required.', 'hustle' ), $required_field ); continue; } } if ( ! empty( $errors ) ) { return $errors; } return false; } }