File "hustle-module-front-ajax.php"
Full Path: /home/londdqdw/public_html/06/wp-content/plugins/wordpress-popup/inc/front/hustle-module-front-ajax.php
File size: 39.96 KB
MIME-type: text/x-php
Charset: utf-8
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
/**
* Hustle_Module_Front_Ajax
*
* @package Hustle
*/
/**
* Class Hustle_Module_Front_Ajax
*/
class Hustle_Module_Front_Ajax {
/**
* Constructor
*/
public function __construct() {
// When module is viewed.
add_action( 'wp_ajax_hustle_module_viewed', array( $this, 'module_viewed' ) );
add_action( 'wp_ajax_nopriv_hustle_module_viewed', array( $this, 'module_viewed' ) );
// When module form is submitted.
add_action( 'wp_ajax_hustle_module_form_submit', array( $this, 'submit_form' ) );
add_action( 'wp_ajax_nopriv_hustle_module_form_submit', array( $this, 'submit_form' ) );
// Update the number of shares of each network.
add_action( 'wp_ajax_hustle_update_network_shares', array( $this, 'get_networks_native_shares' ) );
add_action( 'wp_ajax_nopriv_hustle_update_network_shares', array( $this, 'get_networks_native_shares' ) );
// When a conversion happens.
add_action( 'wp_ajax_hustle_module_converted', array( $this, 'log_module_conversion' ) );
add_action( 'wp_ajax_nopriv_hustle_module_converted', array( $this, 'log_module_conversion' ) );
// Update the stored click counter.
add_action( 'wp_ajax_hustle_sshare_click_counted', array( $this, 'update_sshare_click_counter' ) );
add_action( 'wp_ajax_nopriv_hustle_sshare_click_counted', array( $this, 'update_sshare_click_counter' ) );
// Handles unsubscribe form submisisons.
add_action( 'wp_ajax_hustle_unsubscribe_form_submission', array( $this, 'unsubscribe_submit_form' ) );
add_action( 'wp_ajax_nopriv_hustle_unsubscribe_form_submission', array( $this, 'unsubscribe_submit_form' ) );
// Check the schedule (avoiding pages static cache).
add_action( 'wp_ajax_hustle_module_display_despite_static_cache', array( $this, 'module_display_despite_static_cache' ) );
add_action( 'wp_ajax_nopriv_hustle_module_display_despite_static_cache', array( $this, 'module_display_despite_static_cache' ) );
}
/**
* Replace value if it's a dinamic one based on submited fields
*
* @param string $value The current value.
* @param array $form_data The submitted form data.
* @return string final value
*/
private function maybe_replace_to_field( $value, $form_data ) {
if ( ! empty( $value ) && '{' === $value[0] && '}' === substr( $value, -1 ) ) {
$field = trim( $value, '{}' );
$value = ! empty( $form_data[ $field ] ) ? $form_data[ $field ] : $value;
}
return $value;
}
/**
* Replace common placeholders and current field placeholders
*
* @param int $module_id Module ID.
* @param string $text Text.
* @param array $form_data Submitted data.
* @return string Replaced text
*/
private function replace_placeholders( $module_id, $text, $form_data ) {
preg_match_all( '/\{[^}]*\}/', $text, $matches );
if ( ! empty( $matches[0] ) && is_array( $matches[0] ) ) {
$site_placeholders = array(
'{site_url}' => site_url(),
'{site_title}' => get_bloginfo( 'name' ),
);
$module = new Hustle_Module_Model( $module_id );
$local_list_settings = ! is_wp_error( $module ) ? $module->get_provider_settings( 'local_list' ) : '';
if ( ! empty( $local_list_settings['local_list_name'] ) ) {
$site_placeholders['{local_list}'] = $local_list_settings['local_list_name'];
}
foreach ( $matches[0] as $placeholder ) {
// find common placeholders.
if ( key_exists( $placeholder, $site_placeholders ) ) {
$value = $site_placeholders[ $placeholder ];
} else {
// find field placeholders.
$value = $this->maybe_replace_to_field( $placeholder, $form_data );
}
if ( $value !== $placeholder ) {
// replace if we found something.
$text = str_replace( $placeholder, $value, $text );
}
}
}
return $text;
}
/**
* Check the schedule
*/
public function module_display_despite_static_cache() {
$module_id = filter_input( INPUT_POST, 'module_id', FILTER_VALIDATE_INT );
if ( ! $module_id ) {
wp_send_json_error( __( 'Invalid module ID!', 'hustle' ) );
}
$module = Hustle_Module_Collection::instance()->return_model_from_id( $module_id );
if ( is_wp_error( $module ) ) {
wp_send_json_error( __( 'Invalid module!', 'hustle' ) );
}
$is_scheduled = true;
// Check the schedule. Ssharing modules don't have schedules.
if ( Hustle_Module_Model::SOCIAL_SHARING_MODULE !== $module->module_type
&& ! $module->get_settings()->is_currently_scheduled() ) {
$is_scheduled = false;
}
if ( ! $is_scheduled ) {
wp_send_json_success( array( 'display' => false ) );
}
$avoid_static_cache = Opt_In_Utils::is_static_cache_enabled();
$passed_conditions = true;
if ( $avoid_static_cache ) {
$sub_type = filter_input( INPUT_POST, 'subType', FILTER_SANITIZE_SPECIAL_CHARS );
$module->sub_type = $sub_type;
// Check visibility conditions.
$passed_conditions = $module->is_condition_allow();
}
wp_send_json_success( array( 'display' => $passed_conditions ) );
}
/**
* Send auto email if it sets
*
* @param Hustle_Module_Model $module Module.
*/
public function send_automated_email( Hustle_Module_Model $module ) {
$module_id = $module->module_id;
$emails_settings = $module->get_emails()->to_array();
if ( empty( $emails_settings['automated_email'] ) || '1' !== $emails_settings['automated_email']
|| empty( $emails_settings['email_time'] ) ) {
return;
}
$recipient = ! empty( $emails_settings['recipient'] ) ? $emails_settings['recipient'] : '';
$email_subject = ! empty( $emails_settings['email_subject'] ) ? $emails_settings['email_subject'] : '';
$email_body = ! empty( $emails_settings['email_body'] ) ? $emails_settings['email_body'] : '';
$data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
parse_str( $data['form'], $form_data );
$to = apply_filters( 'hustle_automated_email_recipient', $recipient, $module_id, $data, $form_data );
$subject = apply_filters( 'hustle_automated_email_email_subject', $email_subject, $module_id, $data, $form_data );
$body = apply_filters( 'hustle_automated_email_email_body', $email_body, $module_id, $data, $form_data );
$to = $this->replace_placeholders( $module_id, $to, $form_data );
$body = $this->replace_placeholders( $module_id, $body, $form_data );
// Replace {hustle_unsubscribe_link} placeholder.
if ( false !== strpos( $body, '{hustle_unsubscribe_link}' ) ) {
if ( ! empty( $form_data['hustle_module_id'] ) ) {
$modules_id = array( $form_data['hustle_module_id'] );
$unsubscribe_url = Hustle_Mail::get_unsubscribe_link( $to, $modules_id );
} else {
$unsubscribe_url = '';
}
$body = str_replace( '{hustle_unsubscribe_link}', esc_url( $unsubscribe_url ), $body );
}
$subject = $this->replace_placeholders( $module_id, $subject, $form_data );
// Send the email right away if it's set as 'instant'.
if ( 'instant' === $emails_settings['email_time'] ) {
Hustle_Mail::send_email( $to, $subject, $body );
return;
}
// Adding the 4th parameter time() to prevent cron jobs from being ignored.
// According to wp_schedule_single_event docs:
// "Attempts to schedule an event after an event of the same name and $args will also be ignored".
$args = array( $to, $subject, $body, time() );
if ( 'delay' === $emails_settings['email_time'] ) {
$time = ! empty( $emails_settings['auto_email_time'] ) ? (int) $emails_settings['auto_email_time'] : '';
$unit = ! empty( $emails_settings['auto_email_unit'] ) ? $emails_settings['auto_email_unit'] : '';
// get delay rate.
switch ( $unit ) {
case 'days':
$rate = DAY_IN_SECONDS;
break;
case 'hours':
$rate = HOUR_IN_SECONDS;
break;
case 'minutes':
$rate = MINUTE_IN_SECONDS;
break;
default:
$rate = 1;
break;
}
$schedule_time = time() + $time * $rate;
} elseif ( 'schedule' === $emails_settings['email_time'] ) {
// time settings.
$time = ! empty( $emails_settings['time'] ) ? $emails_settings['time'] : '';
$day = ! empty( $emails_settings['day'] ) ? $emails_settings['day'] : '';
$time = $this->maybe_replace_to_field( $time, $form_data );
$day = $this->maybe_replace_to_field( $day, $form_data );
// delay settings.
$delay_time = ! empty( $emails_settings['schedule_auto_email_time'] ) ? (int) $emails_settings['schedule_auto_email_time'] : 0;
$delay_unit = ! empty( $emails_settings['schedule_auto_email_unit'] ) ? $emails_settings['schedule_auto_email_unit'] : '';
// get delay rate.
switch ( $delay_unit ) {
case 'days':
$delay_rate = DAY_IN_SECONDS;
break;
case 'hours':
$delay_rate = HOUR_IN_SECONDS;
break;
case 'minutes':
$delay_rate = MINUTE_IN_SECONDS;
break;
default:
$delay_rate = 1;
break;
}
// schedule time calculation.
$delay = $delay_time * $delay_rate;
// convert from local time to GMT.
$schedule_time = get_gmt_from_date( date( 'Y-m-d H:i:s', strtotime( $day . ' ' . $time ) ), 'U' );// phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
$schedule_time = $schedule_time + $delay;
if ( time() > $schedule_time ) {
return;
}
}
wp_schedule_single_event( $schedule_time, 'hustle_send_email', $args );
}
/**
* Submit form
*/
public function submit_form() {
Hustle_Provider_Autoload::initiate_providers();
if ( ! isset( $_POST['data']['module_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
return;
}
$module_id = sanitize_text_field( wp_unslash( $_POST['data']['module_id'] ) );// phpcs:ignore WordPress.Security.NonceVerification.Missing
// Action called before full form submit.
do_action( 'hustle_form_before_handle_submit', $module_id );
$response = $this->handle_form( $module_id );
// Filter submit form response.
$response = apply_filters( 'hustle_form_submit_response', $response, $module_id );
// Action called after full form submit.
do_action( 'hustle_form_after_handle_submit', $module_id, $response );
if ( is_array( $response ) && ! empty( $response ) ) {
if ( $response['success'] ) {
wp_send_json_success( $response );
}
}
wp_send_json_error( $response );
}
/**
* Handles the module's form submission process.
*
* @since 4.0
*
* @param int $module_id MOdule ID.
* @return array
*/
private function handle_form( $module_id ) {
$data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
parse_str( $data['form'], $form_data );
// Default error message response.
$response = array(
'message' => __( 'Error saving form', 'hustle' ),
'errors' => array(),
'success' => false,
'behavior' => array(),
);
$module = new Hustle_Module_Model( $module_id );
if ( is_wp_error( $module ) ) {
return $response;
}
$fields = $module->get_form_fields();
$field_data_array = array();
$placeholder_array = array();
$submit_errors = array();
$required_fields = array();
$fields_to_validate = array();
$entry = new Hustle_Entry_Model();
$entry->entry_type = $module->module_type;
$entry->module_id = $module_id;
if ( ! is_null( $fields ) ) {
// Verify recaptcha first.
if ( isset( $fields['recaptcha'] ) ) {
$submit_errors = $this->validate_recaptcha( $form_data, $fields['recaptcha'] );
if ( ! empty( $submit_errors ) ) {
// Recaptcha failed. No need to check the other fields.
$fields = array();
}
}
foreach ( $fields as $field_name => $field_data ) {
$ignored_field_types = Hustle_Entry_Model::ignored_fields();
if ( in_array( $field_data['type'], $ignored_field_types, true ) ) {
continue;
}
if ( 'true' === $field_data['required'] ) {
$required_fields[] = $field_name;
}
if ( isset( $field_data['validate'] ) && 'true' === $field_data['validate'] ) {
$fields_to_validate[] = $field_name;
}
if ( 'hidden' === $field_data['type'] ) {
$form_data = self::update_hidden_value( $field_data, $form_data );
}
if ( isset( $form_data[ $field_name ] ) ) {
$value = sanitize_text_field( $form_data[ $field_name ] );
$field_data_array[] = array(
'name' => $field_name,
'value' => $value,
);
$placeholder = '{' . $field_name . '}';
$placeholder_array[ $placeholder ] = $value;
}
}
if ( empty( $submit_errors ) ) {
$submit_errors = $this->validate_fields( $form_data, $required_fields, $fields_to_validate, $fields );
$response['errors'] = $submit_errors;
}
}
if ( ! empty( $field_data_array ) && empty( $submit_errors ) ) {
// $_POST doesn't contain everything we need to pass. So do this merge instead.
$submitted_data = array_merge( $data, $form_data );
// Do a pre-flight validation with the providers before submitting any data.
// As of 4.0 we're only checking whether the user is already subscribed if enabled.
$integrations_settings = $module->get_integrations_settings()->to_array();
$allow_subscribed = '1' === $integrations_settings['allow_subscribed_users'];
$formatted_submitted_data = Hustle_Provider_Utils::format_submitted_data_for_addon( $submitted_data );
// Do provider's validation.
$provider_error = $this->attach_addons_on_form_submit( $module_id, $formatted_submitted_data, $allow_subscribed );
if ( true !== $provider_error ) {
$response['errors'][] = $provider_error;
return $response;
}
$user_exists = Hustle_Entry_Model::is_email_subscribed_to_module_id( $module_id, $submitted_data['email'] );
if ( $user_exists ) {
$entry_id = Hustle_Entry_Model::get_email_subscribed_to_module_id( $module_id, $submitted_data['email'] );
$entry = new Hustle_Entry_Model( $entry_id );
$entry->entry_type = $module->module_type;
$entry->module_id = $module_id;
}
$active_integrations = array();
if ( isset( $integrations_settings['active_integrations'] ) && ! empty( $integrations_settings['active_integrations'] ) ) {
$active_integrations = explode( ',', $integrations_settings['active_integrations'] );
}
if ( in_array( 'local_list', $active_integrations, true ) ) {
if ( $user_exists || $entry->save() ) {
/**
* Check is tracking allowed
*/
$settings = Hustle_Settings_Admin::get_privacy_settings();
$ip_tracking = ! isset( $settings['ip_tracking'] ) || 'on' === $settings['ip_tracking'];
if ( $ip_tracking ) {
$field_data_array[] = array(
'name' => 'hustle_ip',
'value' => Opt_In_Geo::get_user_ip(),
);
}
$active_integrations = $this->get_module_active_integrations_to_store( $module_id );
$field_data_array[] = array(
'name' => 'active_integrations',
'value' => $active_integrations,
);
// Filter data before saving to db.
$field_data_array = apply_filters( 'hustle_form_submit_field_data', $field_data_array, $module_id );
// Action before saving to db.
do_action( 'hustle_form_submit_before_set_fields', $entry, $module_id, $field_data_array );
$added_data_array = $this->attach_addons_add_entry_fields( $module_id, $module, $formatted_submitted_data, $field_data_array );
$added_data_array = array_merge( $field_data_array, $added_data_array );
$entry->set_fields( $added_data_array );
}
} else {
$active_integrations = $this->get_module_active_integrations_to_store( $module_id );
$field_data_array[] = array(
'name' => 'active_integrations',
'value' => $active_integrations,
);
// Filter data before saving to db.
$field_data_array = apply_filters( 'hustle_form_submit_field_data', $field_data_array, $module_id );
// Action before saving to db.
do_action( 'hustle_form_submit_before_set_fields', $entry, $module_id, $field_data_array );
$this->attach_addons_add_entry_fields( $module_id, $module, $formatted_submitted_data, $field_data_array );
}
$this->send_automated_email( $module );
$post_id = sanitize_text_field( $form_data['post_id'] );
$module_sub_type = isset( $form_data['hustle_sub_type'] ) ? $form_data['hustle_sub_type'] : null;
$this->maybe_log_conversion( $module, $post_id, $module_sub_type );
$emails_settings = $module->get_emails()->to_array();
$fields_array = wp_list_pluck( $field_data_array, 'value', 'name' );
$success_message = $this->parse_message_with_fields_placeholders( $emails_settings['success_message'], $placeholder_array );
$success_message = apply_filters( 'hustle_parsed_success_message', $success_message, $module_id, $module_sub_type, $form_data );
$redirect_url = $this->parse_message_with_fields_placeholders( $emails_settings['redirect_url'], $placeholder_array );
/**
* Filters the URL to redirect to on success.
*
* @since 4.4.1
*
* @param string $redirect_url The URL to redirect to. Will be passed trough esc_url_raw().
* @param string $module_id ID of the current module.
* @param string $module_sub_type Subtype of the current module.
* @param array $form_data The submitted data.
*/
$redirect_url = apply_filters( 'hustle_success_redirect_url', $redirect_url, $module_id, $module_sub_type, $form_data );
/**
* Filters redirect tab on success
*
* @param string $redirect_tab Redirect tab ( sametab | newtab_thankyou | newtab_hide )
* @param string $module_id ID of the current module.
* @param string $module_sub_type Subtype of the current module.
* @param array $form_data The submitted data.
*/
$redirect_tab = apply_filters( 'hustle_success_redirect_tab', $emails_settings['redirect_tab'], $module_id, $module_sub_type, $form_data );
$response = array(
'message' => do_shortcode( wp_kses_post( $success_message ) ),
'success' => true,
'errors' => array(),
'behavior' => array(
'after_submit' => $emails_settings['after_successful_submission'],
'url' => esc_url_raw( $redirect_url ), // Using raw here to honor url params.
'redirect_tab' => $redirect_tab,
),
);
if ( ! empty( $emails_settings['automated_file'] ) && ! empty( $emails_settings['auto_download_file'] ) ) {
$explode = explode( DIRECTORY_SEPARATOR, $emails_settings['auto_download_file'] );
$file_name = end( $explode );
$response['behavior']['file'] = $emails_settings['auto_download_file'];
$response['behavior']['file_name'] = $file_name;
}
}
if ( ! empty( $submit_errors ) ) {
$response = array(
'message' => $this->get_invalid_form_message( $fields ),
'success' => false,
'errors' => $submit_errors,
'behavior' => array(),
);
}
return $response;
}
/**
* Update hidden value because it can be changed by user
*
* @param array $field_data Field settings.
* @param array $form_data Form data.
* @return array
*/
private static function update_hidden_value( $field_data, $form_data ) {
if ( ! empty( $field_data['name'] ) && ! empty( $field_data['default_value'] )
// skip some types because it returns wrong values on this state for them.
&& ! in_array( $field_data['default_value'], array( 'query_parameter', 'embed_url', 'refer_url' ), true ) ) {
$form_data[ $field_data['name'] ] = Hustle_Module_Renderer::get_hidden_value( $field_data );
}
return $form_data;
}
/**
* Do recaptcha backend validation.
*
* @since 4.0
* @param array $form_data Form data.
* @param array $recaptcha_field Recaptcha field.
* @return array
* @throws Exception When reCAPTCHA validation failed.
*/
private function validate_recaptcha( $form_data, $recaptcha_field ) {
$submit_errors = array();
$recaptcha_settings = Hustle_Settings_Admin::get_recaptcha_settings();
$recaptcha_version = empty( $recaptcha_field['version'] ) ? 'v2_checkbox' : $recaptcha_field['version'];
$recaptcha_secret = ! empty( $recaptcha_settings[ $recaptcha_version . '_secret_key' ] ) ? $recaptcha_settings[ $recaptcha_version . '_secret_key' ] : '';
$recaptcha_site = ! empty( $recaptcha_settings[ $recaptcha_version . '_site_key' ] ) ? $recaptcha_settings[ $recaptcha_version . '_site_key' ] : '';
$token = ! empty( $form_data['recaptcha-response'] ) ? $form_data['recaptcha-response'] : false;
if ( ! empty( $recaptcha_secret ) && ! empty( $recaptcha_site ) ) {
try {
$validation_message = ! empty( $recaptcha_field['validation_message'] )
? esc_html( $recaptcha_field['validation_message'] ) : '';
if ( ! $token ) {
throw new Exception(
! empty( $validation_message ) ? $validation_message
: esc_html__( 'reCAPTCHA must be verified to submit the form.', 'hustle' )
);
}
$remote_ip = filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED_FOR', FILTER_SANITIZE_SPECIAL_CHARS );
if ( ! $remote_ip ) {
$remote_ip = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_SPECIAL_CHARS );
}
$response = wp_remote_get(
add_query_arg(
array(
'secret' => $recaptcha_secret,
'response' => $token,
'remoteip' => $remote_ip,
),
'https://www.google.com/recaptcha/api/siteverify'
)
);
if ( is_wp_error( $response ) ) {
throw new Exception( $response->get_error_message() );
}
$response_body = ! empty( $response['body'] ) ? json_decode( $response['body'] ) : '';
if ( empty( $response_body ) || ! $response_body->success ) {
throw new Exception(
! empty( $validation_message ) ? $validation_message
: esc_html__( 'reCAPTCHA validation failed. Please try again.', 'hustle' )
);
}
if ( 'v3_recaptcha' === $recaptcha_version ) {
$selected_score = $recaptcha_field['threshold'];
if ( $selected_score > $response_body->score ) {
throw new Exception(
! empty( $validation_message ) ? $validation_message
: esc_html__( 'reCAPTCHA validation failed. The score is too low.', 'hustle' )
);
}
}
} catch ( Exception $e ) {
$submit_errors['recaptcha'] = $e->getMessage();
}
}
return $submit_errors;
}
/**
* Validate fields.
*
* @since 4.0
* @since 4.0.2 $fields_to_validate parameter added.
*
* @param array $form_data Form data.
* @param array $required_fields Rewuired Fields.
* @param array $fields_to_validate Fields to validate.
* @param array $fields Fields.
* @return array
*/
private function validate_fields( $form_data, $required_fields, $fields_to_validate, $fields ) {
$submit_errors = array();
// Check required fields.
foreach ( $required_fields as $slug ) {
if ( ! isset( $form_data[ $slug ] ) || empty( trim( sanitize_text_field( $form_data[ $slug ] ) ) ) ) {
$submit_errors[ $slug ] = $fields[ $slug ]['required_error_message'];
}
}
// Validate url and email fields.
if ( empty( $submit_errors ) ) {
foreach ( $fields_to_validate as $slug ) {
// Don't validate empty fields. These are validated under "required" if needed.
if ( empty( trim( $form_data[ $slug ] ) ) ) {
continue;
}
if ( 'email' === $fields[ $slug ]['type'] && ! is_email( $form_data[ $slug ] ) ||
'url' === $fields[ $slug ]['type'] && false === filter_var( $form_data[ $slug ], FILTER_VALIDATE_URL ) ||
'datepicker' === $fields[ $slug ]['type'] && false === $this->validate_date( $form_data[ $slug ], $fields[ $slug ]['date_format'] ) ) {
$submit_errors[ $slug ] = $fields[ $slug ]['validation_message'];
} elseif ( 'timepicker' === $fields[ $slug ]['type'] ) {
$time = str_replace( array( ' AM', ' PM' ), '', $form_data[ $slug ] );
$format = '12' === $fields[ $slug ]['time_format'] ? 'h:i' : 'H:i';
$created_time = DateTime::createFromFormat( $format, $time );
if ( ! $created_time || $created_time->format( $format ) !== $time ) {
$submit_errors[ $slug ] = $fields[ $slug ]['validation_message'];
}
}
}
}
return apply_filters( 'hustle_module_submit_errors_validated_fields', $submit_errors, $form_data, $required_fields, $fields_to_validate, $fields );
}
/**
* Get the generic error message.
*
* @since 4.0
*
* @param array $fields Fields.
* @return string
*/
private function get_invalid_form_message( $fields ) {
if ( isset( $fields['submit'] ) && isset( $fields['submit']['error_message'] ) && ! empty( $fields['submit']['error_message'] ) ) {
$message = $fields['submit']['error_message'];
} else {
$message = '';
}
return esc_html( $message );
}
/**
* Replace placeholders
*
* @param string $raw_message Message.
* @param array $submitted_data Submitted data.
* @return string
*/
private function parse_message_with_fields_placeholders( $raw_message, $submitted_data ) {
$message = str_replace(
array_keys( $submitted_data ),
array_values( $submitted_data ),
stripslashes( $raw_message )
);
return $message;
}
/**
* Log a conversion if tracking is enabled.
*
* @since 4.0
*
* @param int $module Module ID.
* @param int $page_id Page ID.
* @param string|null $module_sub_type Sub type.
* @param string|null $cta CTA.
*/
private function maybe_log_conversion( $module, $page_id, $module_sub_type = null, $cta = null ) {
$type = is_null( $module_sub_type ) ? $module->module_type : $module_sub_type;
if ( ! $module->is_tracking_enabled( $type ) ) {
return false;
}
$tracking = Hustle_Tracking_Model::get_instance();
if ( 'social_sharing' === $module->module_type ) {
$action = 'conversion';
} elseif ( $cta ) {
$action = $cta . '_conversion';
} else {
$action = 'optin_conversion';
}
$tracking->save_tracking( $module->id, $action, $module->module_type, $page_id, $module_sub_type );
return true;
}
/**
* Get an array with the connected integrations to show in entries.
*
* @since 4.0
*
* @param int $module_id Module ID.
* @return array
*/
private function get_module_active_integrations_to_store( $module_id ) {
$active_integrations = array();
$connected_addons = Hustle_Provider_Utils::get_addons_instance_connected_with_module( $module_id );
foreach ( $connected_addons as $addon ) {
// Local list is not really an integration to be shown here.
if ( 'local_list' === $addon->get_slug() ) {
continue;
}
$active_integrations[ $addon->get_slug() ] = $addon->get_title();
}
return $active_integrations;
}
/**
* Executor on form submit for attached addons.
*
* @see Hustle_Provider_Form_Hooks_Abstract::on_form_submit()
* @since 4.0
*
* @param int $module_id Module ID.
* @param array $submitted_data Data submitted by the user.
* @param bool $allow_subscribed Allow already subscribed.
* @return bool true on success|string error message from addon otherwise
*/
private function attach_addons_on_form_submit( $module_id, $submitted_data, $allow_subscribed ) {
// Find is_form_connected.
$connected_addons = Hustle_Provider_Utils::get_addons_instance_connected_with_module( $module_id );
$submitted_data = Opt_In_Utils::validate_and_sanitize_fields( $submitted_data );
foreach ( $connected_addons as $connected_addon ) {
try {
$slug = $connected_addon->get_slug();
$formatted_submitted_data = apply_filters( 'hustle_format_submitted_data', $submitted_data, $slug );
$form_hooks = $connected_addon->get_addon_form_hooks( $module_id );
if ( $form_hooks instanceof Hustle_Provider_Form_Hooks_Abstract ) {
$addon_return = $form_hooks->on_form_submit( $formatted_submitted_data, $allow_subscribed );
if ( true !== $addon_return ) {
return $form_hooks->get_submit_form_error_message();
}
}
} catch ( Exception $e ) {
Opt_In_Utils::maybe_log( $connected_addon->get_slug(), 'failed to attach_addons_on_form_submit', $e->getMessage() );
}
}
return true;
}
/**
* Executor to add more entry fields for attached addons.
*
* @see Hustle_Provider_Form_Hooks_Abstract::add_entry_fields()
*
* @since 4.0
*
* @param int $module_id Module ID.
* @param Hustle_Module_Model $module Module.
* @param array $submitted_data Data submitted by the user.
* @param array $current_entry_fields Entry fields.
* @return array fields to be added to entry
*/
private function attach_addons_add_entry_fields( $module_id, Hustle_Module_Model $module, $submitted_data, $current_entry_fields ) {
$additional_fields_data = array();
$connected_addons = Hustle_Provider_Utils::get_addons_instance_connected_with_module( $module_id );
foreach ( $connected_addons as $connected_addon ) {
try {
$slug = $connected_addon->get_slug();
$formatted_submitted_data = apply_filters( 'hustle_format_submitted_data', $submitted_data, $slug );
$form_hooks = $connected_addon->get_addon_form_hooks( $module_id );
if ( $form_hooks instanceof Hustle_Provider_Form_Hooks_Abstract ) {
$addon_fields = $form_hooks->add_entry_fields( $formatted_submitted_data );
// log errors.
if (
! empty( $addon_fields[0] ) && ! empty( $addon_fields[0]['value'] ) &&
isset( $addon_fields[0]['value']['is_sent'] ) &&
false === $addon_fields[0]['value']['is_sent']
) {
$error = ! empty( $addon_fields[0]['value']['description'] ) ?
$addon_fields[0]['value']['description']
: __( 'Something went wrong.', 'hustle' );
$error = $connected_addon->get_title() . ' ' . $error;
Opt_In_Utils::maybe_log( $error );
}
$account_settings = $connected_addon->get_settings_values();
if ( ! empty( $connected_addon->selected_global_multi_id ) ) {
$addon_fields[0]['value']['account_name'] = isset( $account_settings[ $connected_addon->selected_global_multi_id ]['name'] )
? $account_settings[ $connected_addon->selected_global_multi_id ]['name'] . ' (' . $connected_addon->selected_global_multi_id . ')'
: $connected_addon->selected_global_multi_id;
}
// Reformat additional fields.
$addon_fields = self::format_addon_additional_fields( $connected_addon, $addon_fields );
$additional_fields_data = array_merge( $additional_fields_data, $addon_fields );
}
} catch ( Exception $e ) {
Opt_In_Utils::maybe_log( $connected_addon->get_slug(), 'failed to add_entry_fields', $e->getMessage() );
}
}
return $additional_fields_data;
}
/**
* Format additional fields from provider.
* Format used is `hustle_provider_{$slug}_{$field_name}`
*
* @since 4.0
*
* @param Hustle_Provider_Abstract $addon Addon.
* @param array $additional_fields Additional fields.
* @return array
*/
private static function format_addon_additional_fields( Hustle_Provider_Abstract $addon, $additional_fields ) {
// to `name` and `value` basis.
$formatted_additional_fields = array();
if ( ! is_array( $additional_fields ) ) {
return array();
}
foreach ( $additional_fields as $additional_field ) {
if ( ! isset( $additional_field['name'] ) || ! isset( $additional_field['value'] ) ) {
continue;
}
$formatted_additional_fields[] = array(
'name' => 'hustle_provider_' . $addon->get_slug() . '_' . $additional_field['name'],
'value' => $additional_field['value'],
);
}
return $formatted_additional_fields;
}
/**
* Handles the unsubscribe form submission.
*
* @since 3.0.5
*/
public function unsubscribe_submit_form() {
parse_str( $_POST['data'], $submitted_data ); // phpcs:ignore
$sanitized_data = Opt_In_Utils::validate_and_sanitize_fields( $submitted_data );
$messages = Hustle_Settings_Admin::get_unsubscribe_messages();
$email = isset( $sanitized_data['email'] ) ? filter_var( $sanitized_data['email'], FILTER_VALIDATE_EMAIL ) : '';
// Check if we got the email address and if it's valid.
if ( $email ) {
$modules_id = self::get_module_ids( $email, $sanitized_data, $messages );
// Handle 'choose_list' form step.
if ( isset( $sanitized_data['form_step'] ) && 'choose_list' === $sanitized_data['form_step'] ) {
if ( ! empty( $sanitized_data['skip_confirmation'] ) ) {
$sanitized_data['lists_id'] = $modules_id;
}
// If the lists are defined, submit the email with the nonce.
if ( ! empty( $sanitized_data['lists_id'] ) && isset( $sanitized_data['current_url'] ) ) {
// Do the process to send the unsubscription email.
$email_processed = Hustle_Mail::handle_unsubscription_user_email( $email, $sanitized_data['lists_id'], $sanitized_data['current_url'] );
if ( $email_processed ) {
$html = $messages['email_submitted'];
$wrapper = '.hustle-form-body';
$response = array(
'html' => apply_filters( 'hustle_unsubscribe_email_processed_html', $html, $sanitized_data ),
'wrapper' => apply_filters( 'hustle_unsubscribe_email_processed_wrapper', $wrapper, $sanitized_data ),
);
wp_send_json_success( $response );
}
}
$html = apply_filters( 'hustle_unsubscribe_email_not_processed_html', $messages['email_not_processed'], $sanitized_data );
wp_send_json_error( array( 'html' => $html ) );
} elseif ( isset( $sanitized_data['form_step'] ) && 'enter_email' === $sanitized_data['form_step'] ) {
$modules_id = self::get_module_ids( $email, $sanitized_data, $messages );
$module = new Hustle_Module_Model();
$params = array(
'ajax_step' => true,
'modules_id' => $modules_id,
'module' => $module,
'email' => $email,
'current_url' => $sanitized_data['current_url'],
'messages' => $messages,
);
$renderer = new Hustle_Layout_Helper();
$html = $renderer->render( 'general/unsubscribe-form', $params, true );
$wrapper = '.hustle-form-body';
$response = array(
'html' => apply_filters( 'hustle_render_unsubscribe_lists_html', $html, $modules_id, $email ),
'wrapper' => apply_filters( 'hustle_render_unsubscribe_list_wrapper', $wrapper, $modules_id, $email ),
);
wp_send_json_success( $response );
}
} else {
// Return an error if the email is missing or is invalid.
$html = apply_filters( 'hustle_unsubscribe_invalid_email_address_message', $messages['invalid_email'], $sanitized_data );
wp_send_json_error( array( 'html' => $html ) );
}
wp_send_json_success( $sanitized_data );
}
/**
* Get module ids
*
* @param atring $email Email.
* @param array $sanitized_data Data.
* @param array $messages Message texts.
* @return array
*/
private static function get_module_ids( $email, $sanitized_data, $messages ) {
$entry = new Hustle_Entry_Model();
$modules_id = $entry->get_modules_id_by_email_in_local_list( $email );
// The lists are not defined yet. Show the list for the user to select them.
// If not showing all, show only the ones defined in the shortcode.
if ( ! empty( $sanitized_data['form_module_id'] ) && '-1' !== $sanitized_data['form_module_id'] ) {
$form_modules_id = array_map( 'trim', explode( ',', $sanitized_data['form_module_id'] ) );
$modules_id = array_intersect( $form_modules_id, $modules_id );
}
// If the email is not in any of the selected lists.
if ( empty( $modules_id ) ) {
$html = $messages['email_not_found'];
$wrapper = '.hustle-form-body';
$response = array(
'html' => apply_filters( 'hustle_unsubscribe_email_not_found_html', $html, $modules_id, $email ),
'wrapper' => apply_filters( 'hustle_unsubscribe_email_not_found_wrapper', $wrapper, $modules_id, $email ),
);
wp_send_json_success( $response );
}
return $modules_id;
}
/**
* Retrieve the number of shares from the network's native APIs.
*
* @since 3.0.3
* @since 4.0 Get the networks' names from frontend.
*/
public function get_networks_native_shares() {
// TODO: check the networks are the ones that have APIs, and sanitize.
$networks = filter_input( INPUT_POST, 'networks', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY );
$post_id = filter_input( INPUT_POST, 'postId', FILTER_VALIDATE_INT );
if ( ! $networks || false === $post_id || is_null( $post_id ) ) {
wp_send_json_error();
}
$module_instance = new Hustle_SShare_Model();
$networks_shares = $module_instance->retrieve_networks_shares( $networks, $post_id );
wp_send_json_success(
array(
'networks' => $networks_shares,
'shorten' => array(
'thousand' => esc_html__( 'K', 'hustle' ),
'million' => esc_html__( 'M', 'hustle' ),
),
)
);
}
/**
* Log module conversion
*
* @return null
*/
public function log_module_conversion() {
$data = json_decode( file_get_contents( 'php://input' ) );
$data = $data ? get_object_vars( $data ) : array();
if ( ! is_array( $data ) || empty( $data ) ) {
return;
}
$module_id = $data['module_id'];
if ( empty( $module_id ) ) {
wp_send_json_error( __( 'Invalid Request!', 'hustle' ) . $module_id );
}
$module = Hustle_Module_Collection::instance()->return_model_from_id( $module_id );
if ( is_wp_error( $module ) ) {
wp_send_json_error( __( 'Invalid module!', 'hustle' ) );
}
if ( $module->id ) {
$page_id = $data['page_id'];
$module_sub_type = ( isset( $data['module_sub_type'] ) && ! empty( $data['module_sub_type'] ) ) ? $data['module_sub_type'] : null;
$cta = ! empty( $data['cta'] ) ? $data['cta'] : null;
$res = $this->maybe_log_conversion( $module, $page_id, $module_sub_type, $cta );
} else {
$res = false;
}
if ( ! $res ) {
wp_send_json_error( __( 'Error saving stats', 'hustle' ) );
} else {
wp_send_json_success( __( 'Stats Successfully saved', 'hustle' ) );
}
}
/**
* Module view
*
* @return null
*/
public function module_viewed() {
$data = json_decode( file_get_contents( 'php://input' ) );
$data = $data ? get_object_vars( $data ) : array();
if ( ! is_array( $data ) || empty( $data ) ) {
return;
}
$module_id = $data['module_id'];
if ( empty( $module_id ) ) {
wp_send_json_error( __( 'Invalid Request: Module id invalid', 'hustle' ) );
}
$module = new Hustle_Module_Model( $module_id );
if ( is_wp_error( $module ) ) {
wp_send_json_error( __( 'Invalid module!', 'hustle' ) );
}
if ( $module->id ) {
$module_type = $data['module_type'];
$page_id = $data['page_id'];
$module_sub_type = isset( $data['module_sub_type'] ) ? $data['module_sub_type'] : null;
$tracking = Hustle_Tracking_Model::get_instance();
$res = $tracking->save_tracking( $module_id, 'view', $module_type, $page_id, $module_sub_type );
} else {
$res = false;
}
if ( ! $res ) {
wp_send_json_error( __( 'Error saving stats', 'hustle' ) );
} else {
wp_send_json_success( __( 'Stats Successfully saved', 'hustle' ) );
}
}
/**
* Update the click counter after an icon is clicked.
*
* @since 4.0
*/
public function update_sshare_click_counter() {
$module_id = filter_input( INPUT_POST, 'moduleId', FILTER_VALIDATE_INT );
$module = Hustle_Module_Collection::instance()->return_model_from_id( $module_id );
if ( ! is_wp_error( $module ) ) {
$network = filter_input( INPUT_POST, 'network', FILTER_SANITIZE_SPECIAL_CHARS );
$content = $module->get_content()->to_array();
if ( isset( $content['social_icons'][ $network ] ) ) {
$content['social_icons'][ $network ]['counter'] = intval( $content['social_icons'][ $network ]['counter'] ) + 1;
$module->update_meta( Hustle_Module_Model::KEY_CONTENT, $content );
wp_send_json_success();
}
}
wp_send_json_error();
}
/**
* Validate date field.
*
* @param string $date date.
* @param string $format date format.
* @since 4.0.2
*/
private function validate_date( $date, $format ) {
$format = $this->validate_format( $format );
$d = DateTime::createFromFormat( $format, $date );
return ( $d && $d->format( $format ) === $date );
}
/**
* Changes the date format from JS one to PHP version.
*
* @param string $format date format.
* @since 4.0.2
*/
private function validate_format( $format ) {
// Formats based on https://api.jqueryui.com/datepicker/#utility-formatDate.
$format_translate = array(
'dd' => 'd',
'mm' => 'm',
'yy' => 'Y',
'MM' => 'F',
'oo' => 'z', // PHP doesn't have format like this, using the version without leading zeros.
'DD' => 'l',
'd' => 'j',
'o' => 'z',
'm' => 'n',
'@' => 'U',
);
$format = strtr( $format, $format_translate );
return $format;
}
}