post_title : null; $postTitle = self::extract('postTitle', $context); $postUrl = self::extract('postUrl', $context); $name = self::extract('name', $identity); $family = self::extract('family', $identity); $displayName = self::extract('displayName', $identity ); if ( empty( $displayName ) ) { if ( !empty( $name ) && !empty( $family ) ) { $displayName = $name . ' ' . $family; } elseif ( !empty( $name ) ) { $displayName = $name; } elseif ( !empty( $family ) ) { $displayName = $family; } else { $displayName = ""; } } $leadId = empty( $lead ) ? null : $lead->ID; $isNew = empty( $leadId ) ? true : false; // extra fields $fields = array(); foreach( $identity as $itemName => $itemValue ) { if ( in_array( $itemName, array( 'email', 'name', 'family', 'displayName' ) ) ) continue; if ( 'image' === $itemName ) $itemName = 'externalImage'; $fields[trim( $itemName, '{}') ] = array('value' => $itemValue, 'custom' => ( strpos($itemName, '{') === 0 ) ? 1 : 0 ); } // counts the number of confirmed emails (subscription) if ( $subscriptionConfirmed && $leadId && !$lead->lead_subscription_confirmed ) { require_once OPANDA_BIZPANDA_DIR . '/admin/includes/stats.php'; OPanda_Stats::countMetrict( $itemId, $postId, 'email-confirmed'); } if ( !$leadId ) { // counts the number of new recivied emails OPanda_Stats::countMetrict( $itemId, $postId, 'email-received'); $postTitle = html_entity_decode($postTitle); $postTitle = urldecode($postTitle); $postTitle = preg_replace('/[^A-Za-z0-9\s\-\.\,]/', '', $postTitle); $data = array( 'lead_display_name' => $displayName, 'lead_name' => $name, 'lead_family' => $family, 'lead_email' => $email, 'lead_date' => time(), 'lead_item_id' => $itemId, 'lead_post_id' => $postId, 'lead_item_title' => $itemTitle, 'lead_post_title' => $postTitle, 'lead_referer' => $postUrl, 'lead_email_confirmed' => $emailConfirmed ? 1 : 0, 'lead_subscription_confirmed' => $subscriptionConfirmed ? 1 : 0, 'lead_ip' => self::getIP(), 'lead_temp' => !empty( $temp ) ? json_encode( $temp ) : null ); // else inserts a new lead $result = $wpdb->insert( $wpdb->prefix . 'opanda_leads', $data, array( '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%s', '%s', '%s', '%d', '%s', '%s' )); // sends a notification if ( get_option('opanda_notify_leads', false) ) { $receiver = trim ( get_option('opanda_leads_email_receiver') ); $subject = trim ( get_option('opanda_leads_email_subject') ); $message = trim ( get_option('opanda_leads_email_body') ); $post = get_post( $postId ); $locker = get_post( $itemId ); $eventContext = array( sprintf ( __( 'Locker: %s', 'bizpanda' ), $locker->post_title ), sprintf ( __( 'Where: %s', 'bizpanda' ), get_permalink( $postId ), $post->post_title ), sprintf ( __( 'IP: %s', 'bizpanda' ), self::getIP() ) ); $eventContext = apply_filters('opanda_leads_notification_context', $eventContext); $eventDetails = array( sprintf ( __( 'Name: %s', 'bizpanda' ), $data['lead_display_name'] ), sprintf ( __( 'Email: %s', 'bizpanda' ), $data['lead_email'] ) ); if ( count( $fields ) > 0 ) { foreach( $fields as $fieldName => $field ) { if ( !$field['custom'] ) continue; $eventDetails[] = $fieldName . ': ' . $field['value']; } } $eventDetails = apply_filters('opanda_leads_notification_details', $eventDetails, $data ); $replacements = array( 'sitename' => get_bloginfo('name'), 'siteurl' => get_bloginfo('url'), 'details' => implode('
', $eventDetails), 'context' => implode('
', $eventContext) ); foreach( $replacements as $name => $replacement ) { $subject = str_replace('{'. $name . '}', $replacement, $subject); $message = str_replace('{'. $name . '}', $replacement, $message); } $headers = array(); $headers[] = 'content-type: text/html'; $subject = apply_filters('opanda_leads_notification_subject', $subject, $data ); $message = apply_filters('opanda_leads_notification_message', $message, $data ); wp_mail( $receiver, $subject, $message, $headers ); } if ( $result ) $leadId = $wpdb->insert_id; } else { $data = array( 'lead_display_name' => $displayName, 'lead_email' => $email, 'lead_name' => $name, 'lead_family' => $family, 'lead_email_confirmed' => $emailConfirmed ? 1 : 0, 'lead_subscription_confirmed' => $subscriptionConfirmed ? 1 : 0, 'lead_temp' => !empty( $temp ) ? json_encode( $temp ) : null ); $formats = array( 'lead_display_name' => '%s', 'lead_email' => '%s', 'lead_name' => '%s', 'lead_family' => '%s', 'lead_email_confirmed' => '%d', 'lead_subscription_confirmed' => '%d', 'lead_temp' => '%s' ); // to void claring the temp data in sign in locker // when several actions save a lead if ( empty( $data['lead_temp'] ) ) { unset( $data['lead_temp'] ); unset( $formats['lead_temp'] ); } if ( empty( $displayName ) ) { unset( $data['lead_display_name'] ); unset( $formats['lead_display_name'] ); } if ( empty( $name ) ) { unset( $data['lead_display_name'] ); unset( $formats['lead_display_name'] ); } if ( empty( $family ) ) { unset( $data['lead_display_name'] ); unset( $formats['lead_display_name'] ); } if ( !$emailConfirmed || $lead->lead_email_confirmed ) { unset( $data['lead_email_confirmed'] ); unset( $formats['lead_email_confirmed'] ); } if ( !$subscriptionConfirmed || $lead->lead_subscription_confirmed ) { unset( $data['lead_subscription_confirmed'] ); unset( $formats['lead_subscription_confirmed'] ); } if ( !empty( $data ) ) { $where = array( 'ID' => $leadId ); $wpdb->update( $wpdb->prefix . 'opanda_leads', $data, $where, array_values( $formats ), array( '%s' )); } } // saving extra fields foreach( $fields as $fieldName => $fieldData ) { $sql = $wpdb->prepare(" INSERT INTO {$wpdb->prefix}opanda_leads_fields ( lead_id, field_name, field_value, field_custom ) VALUES ( %d, %s, %s, %d ) ON DUPLICATE KEY UPDATE field_value = VALUES(field_value) ", $leadId, $fieldName, $fieldData['value'], $fieldData['custom'] ); $wpdb->query( $sql ); } self::pushLeadToZapier( $leadId, $isNew ); return $leadId; } /** * Sets a confirmation code for the lead. */ public static function setConfirmationCode( $lead, $code ) { if ( empty( $lead ) ) return; global $wpdb; $sql = $wpdb->prepare(" UPDATE {$wpdb->prefix}opanda_leads SET lead_confirmation_code = %s WHERE ID = %d ", $code, $lead->ID ); $wpdb->query($sql); } /** * Confirms a lead. */ public static function confirm( $emailOrID, $code, $push = false ) { if ( empty( $emailOrID ) ) return; if ( is_numeric($emailOrID) ) { $lead = OPanda_Leads::getById($emailOrID); } else { $lead = OPanda_Leads::getByEmail($emailOrID); } if ( !$lead || $lead->lead_subscription_confirmed ) return; if ( empty( $lead ) ) return; if ( $code !== $lead->lead_confirmation_code ) return; $temp = !empty( $lead->lead_temp ) ? json_decode( $lead->lead_temp, true ) : null; $itemId = isset( $temp['context']['itemId'] ) ? $temp['context']['itemId'] : null; $postId = isset( $temp['context']['postId'] ) ? $temp['context']['postId'] : null; if ( $push ) { try { require_once OPANDA_BIZPANDA_DIR . '/admin/includes/subscriptions.php'; $serviceReady = isset( $temp['serviceReady'] ) ? $temp['serviceReady'] : null; $context = isset( $temp['context'] ) ? $temp['context'] : null; $listId = isset( $temp['listId'] ) ? $temp['listId'] : null; $verified = isset( $temp['verified'] ) ? $temp['verified'] : null; $service = OPanda_SubscriptionServices::getCurrentService(); if ( empty( $service) ) { throw new Exception( sprintf( 'The subscription service is not set.' )); } $service->subscribe( $serviceReady, $listId, false, $context, $verified ); } catch (Exception $ex) { printf ( __( "Error: %s", 'bizpanda' ), $ex->getMessage() ); exit; } } global $wpdb; $sql = $wpdb->prepare(" UPDATE {$wpdb->prefix}opanda_leads SET lead_email_confirmed = 1, lead_subscription_confirmed = 1 WHERE ID = %d ", $lead->ID ); self::pushLeadToZapier( $lead->ID, false ); $wpdb->query($sql); // counts the number of confirmed emails (subscription) if ( $lead->ID && !$lead->lead_subscription_confirmed && $itemId && $postId ) { require_once OPANDA_BIZPANDA_DIR . '/admin/includes/stats.php'; OPanda_Stats::countMetrict( $itemId, $postId, 'email-confirmed'); } } /** * Sends data to Zapier if needed. */ public static function pushLeadToZapier( $leadId, $isNew ) { global $wpdb; $newLeadHookUrl = trim( get_option('opanda_zapier_hook_new_leads', "" ) ); if ( empty( $newLeadHookUrl )) return; if ( empty( $leadId ) ) return; $lead = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}opanda_leads WHERE ID = %d", $leadId ) ); if ( empty( $lead ) ) return; $fields = self::getCustomFields( $leadId ); $onlyNewLeads = get_option('opanda_zapier_only_new', false ); $onlyConfirmed = get_option('opanda_zapier_only_confirmed', false ); if ( !(( $onlyNewLeads && $isNew ) || !$onlyNewLeads ) ) return; if ( !(( $onlyConfirmed && $lead->lead_subscription_confirmed ) || !$onlyConfirmed ) ) return; $zapierData = array( 'lead_email' => $lead->lead_email, 'lead_name' => $lead->lead_name, 'lead_family' => $lead->lead_family, 'lead_display_name' => $lead->lead_display_name, 'lead_ip' => $lead->lead_ip, 'post_title' => $lead->lead_post_title, 'post_url' => $lead->lead_referer ); if ( !empty( $fields ) ) { foreach( $fields as $name => $value ) { $zapierData['custom_' . $name] = $value; } } $zapierData = apply_filters('opanda_zapier_data', $zapierData ); $response = wp_remote_post( $newLeadHookUrl, array( 'method' => 'POST', 'timeout' => 10, 'headers' => array( 'Content-Type' => 'application/json', 'Accept' => 'application/json' ), 'body' => json_encode($zapierData) )); } public static function setTempData( $lead, $temp ) { global $wpdb; $sql = $wpdb->prepare(" UPDATE {$wpdb->prefix}opanda_leads SET lead_temp = %s WHERE ID = %d ", json_encode($temp), $lead->ID ); $wpdb->query($sql); } private static $_leads = array(); /** * Returns a lead. */ public static function get( $leadId ) { if ( isset( self::$_leads[$leadId] ) ) return self::$_leads[$leadId]; global $wpdb; $lead = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}opanda_leads WHERE ID = %d", $leadId ) ); self::$_leads[$leadId] = $lead; return $lead; } /** * Returns custom fields */ public static function getCustomFields( $leadId = null ) { if ( !empty( $leadId )) { global $wpdb; $data = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}opanda_leads_fields WHERE lead_id = %d AND field_custom = 1", $leadId ), ARRAY_A ); $customFields = array(); foreach( $data as $item ) { $name = $item['field_name']; if ( strpos( $name, '_' ) === 0 ) continue; $customFields[$item['field_name']] = $item['field_value']; $fields[$name] = strip_tags( $item['field_value'] ); } return $customFields; } else { global $wpdb; $fields = $wpdb->get_results( "SELECT field_name FROM {$wpdb->prefix}opanda_leads_fields WHERE field_custom = 1 GROUP BY field_name" ); return $fields; } } private static $_fields = array(); /** * Returns all fields of a given lead. * * @since 1.0.7 * @param int $leadId An id of a lead which contains fields to return. * @return string[] */ public static function getLeadFields( $leadId ) { if ( isset( self::$_fields[$leadId] ) ) return self::$_fields[$leadId]; global $wpdb; $data = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}opanda_leads_fields WHERE lead_id = %d", $leadId ), ARRAY_A ); $fields = array(); foreach( $data as $item ) { $fields[$item['field_name']] = $item['field_value']; } self::$_fields[$leadId] = $fields; return $fields; } /** * Returns a given field of a lead. * * @since 1.0.7 * @param int $leadId An id of a lead which contains fields to return. * @param string $fieldName A field name to return. * @param mixed $default A default value to return if the field is not found in the database. * @return string */ public static function getLeadField( $leadId, $fieldName, $default = null ) { $fields = self::getLeadFields( $leadId ); return isset( $fields[$fieldName] ) ? $fields[$fieldName] : $default; } /** * Removes a field of a given lead. * * @since 1.0.7 * @param int $leadId An id of a lead which contains a field to remove. * @param string $fieldName A field name to remove. * @return void */ public static function removeLeadField( $leadId, $fieldName ) { self::updateLeadField( $leadId, $fieldName, null ); } /** * Updates a field of a given lead. * * @since 1.0.7 * @param int $leadId An id of a lead which contains a field to update. * @param string $fieldName A field name to update. * @param string $fieldValue A field value to set. * @return void */ public static function updateLeadField( $leadId, $fieldName, $fieldValue ) { global $wpdb; if ( !isset( self::$_fields[$leadId] ) ) { self::$_fields[$leadId] = self::getLeadFields( $leadId ); } if ( empty( $fieldValue ) ) { $wpdb->query( $wpdb->prepare(" DELETE FROM {$wpdb->prefix}opanda_leads_fields WHERE lead_id = %d AND field_name = %s ", $leadId, $fieldName )); unset( self::$_fields[$leadId][$fieldName] ); return; } $wpdb->query( $wpdb->prepare(" INSERT INTO {$wpdb->prefix}opanda_leads_fields ( lead_id, field_name, field_value ) VALUES ( %d, %s, %s ) ON DUPLICATE KEY UPDATE field_value = VALUES(field_value) ", $leadId, $fieldName, $fieldValue )); self::$_fields[$leadId][$fieldName] = $fieldValue; } /** * Return an URL of the image to use as an avatar. * * @since 1.0.7 * @param int $leadId A lead ID for which we need to return the URL of the avatar. * @param int $size A size of the avatar (px). * @return string */ public static function getAvatarUrl( $leadId, $email = null, $size = 40 ) { $imageSource = OPanda_Leads::getLeadField( $leadId, 'externalImage', null ); $image = OPanda_Leads::getLeadField( $leadId, '_image' . $size, null ); // getting an avatar from cache if ( !empty( $image ) ) { $upload_dir = wp_upload_dir(); $path = $upload_dir['path'] . '/bizpanda/avatars/' . $image; $url = $upload_dir['url'] . '/bizpanda/avatars/' . $image; if ( file_exists( $path ) ) return $url; self::removeLeadField($leadId, '_image' . $size); } // trying to process an external image if ( !empty( $imageSource ) && function_exists('wp_get_image_editor') ) { return admin_url('admin-ajax.php?action=opanda_avatar&opanda_lead_id=' . $leadId) . '&opanda_size=' . $size; } // else return a gravatar $gravatar = get_avatar( $email, $size ); if ( preg_match('/https?\:\/\/[^\'"]+/i', $gravatar, $match) ) { return $match[0]; } return null; } /** * Return a HTML code markup to display avatar. * * @since 1.0.7 * @param int $leadId A lead ID for which we need to return the URL of the avatar. * @param int $size A size of the avatar (px). * @return string HTML */ public static function getAvatar( $leadId, $email = null, $size = 40 ) { $url = self::getAvatarUrl( $leadId, $email, $size ); if ( empty( $url ) ) return null; $alt = __('User Avatar', 'bizpanda'); return "$alt"; } /** * Returns an URL of the social profile of the lead. * * @since 1.0.7 * @param int $leadId A lead ID for which we need to return an URL of the social profile. * @return string|false An URL of the social profile of the lead. */ public static function getSocialUrl( $leadId ) { $fields = self::getLeadFields( $leadId ); if ( isset( $fields['facebookUrl'] )) return $fields['facebookUrl']; if ( isset( $fields['twitterUrl'] )) return $fields['twitterUrl']; if ( isset( $fields['googleUrl'] )) return $fields['googleUrl']; if ( isset( $fields['linkedinUrl'] )) return $fields['linkedinUrl']; return false; } /** * Returns the following array: * * 'confirmed' => the number of leads (int), * 'not-fonfirmed' => the number of leads (int) * * @since 1.0.7 */ public static function getCountByStatus() { global $wpdb; $rows = $wpdb->get_results( "SELECT COUNT(*) as status_count, lead_email_confirmed FROM {$wpdb->prefix}opanda_leads GROUP BY lead_email_confirmed", ARRAY_A ); $result = array(); foreach( $rows as $row ) { $status = $row['lead_email_confirmed'] == 1 ? 'confirmed' : 'not-confirmed'; $result[$status] = intval( $row['status_count'] ); } if ( !isset( $result['confirmed'] )) $result['confirmed'] = 0; if ( !isset( $result['not-confirmed'] )) $result['not-confirmed'] = 0; return $result; } /** * Returns a lead by email or null. */ public static function getByEmail( $email ) { global $wpdb; return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}opanda_leads WHERE lead_email = %s", $email )); } /** * Returns a lead by ID or null. */ public static function getById( $id ) { global $wpdb; return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}opanda_leads WHERE ID = %s", $id )); } protected static function extract( $name, $source, $default = null ) { $value = isset( $source[$name] ) ? trim( $source[$name] ) : $default; if ( empty( $value ) ) $value = $default; return $value; } public static function getCount( $cache = true ) { global $wpdb; $count = null; if ( $cache ) { $count = get_transient('opanda_subscribers_count'); if ( $count === '0' || !empty( $count ) ) return intval( $count ); } if( $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}opanda_leads'") === $wpdb->prefix . 'opanda_leads' ) { $count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}opanda_leads" ); set_transient('opanda_subscribers_count', $count, 60 * 5); } return $count; } public static function updateCount() { self::getCount( false ); } public static function getIP( ) { $ip = ''; foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){ if ( array_key_exists($key, $_SERVER) !== true) continue; foreach (explode(',', $_SERVER[$key]) as $ip){ $ip = trim($ip); if ( !self::validateIP($ip) ) continue; return $ip; } } return $ip; } public static function validateIP($ip) { if (strtolower($ip) === 'unknown') return false; // generate ipv4 network address $ip = ip2long($ip); // if the ip is set and not equivalent to 255.255.255.255 if ($ip !== false && $ip !== -1) { // make sure to get unsigned long representation of ip // due to discrepancies between 32 and 64 bit OSes and // signed numbers (ints default to signed in PHP) $ip = sprintf('%u', $ip); // do private network range checking if ($ip >= 0 && $ip <= 50331647) return false; if ($ip >= 167772160 && $ip <= 184549375) return false; if ($ip >= 2130706432 && $ip <= 2147483647) return false; if ($ip >= 2851995648 && $ip <= 2852061183) return false; if ($ip >= 2886729728 && $ip <= 2887778303) return false; if ($ip >= 3221225984 && $ip <= 3221226239) return false; if ($ip >= 3232235520 && $ip <= 3232301055) return false; if ($ip >= 4294967040) return false; } return true; } }