/** * Trigger string for custom events * * @param string $string * @param FUE_Email $email * @return string */ public function trigger_string($string, $email) { if ($email->trigger == 'before_tribe_event_starts' || $email->trigger == 'after_tribe_event_ends') { $type = $email->get_email_type(); $string = sprintf(__('%d %s %s'), $email->interval, Follow_Up_Emails::get_duration($email->duration), $type->get_trigger_name($email->trigger)); } return $string; }
public static function display() { $wpdb = Follow_Up_Emails::instance()->wpdb; $stats = array('total_emails_sent' => 0, 'emails_sent_today' => 0, 'emails_scheduled_total' => 0); $today = date('Y-m-d', current_time('timestamp')); $from = $today . ' 00:00:00'; $to = $today . ' 23:59:59'; $stats['total_emails_sent'] = FUE_Reports::count_emails_sent(); $stats['emails_sent_today'] = FUE_Reports::count_emails_sent(array($from, $to)); $stats['emails_scheduled_total'] = $wpdb->get_var("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders o, {$wpdb->posts} p\n WHERE o.is_sent = 0\n AND o.email_id = p.ID"); include FUE_TEMPLATES_DIR . '/dashboard-widget.php'; }
/** * Handle opt-in and opt-out requests */ public static function process_optout_request() { if (isset($_POST['fue_action']) && $_POST['fue_action'] == 'fue_save_myaccount') { $opted_out = isset($_POST['fue_opt_out']) && $_POST['fue_opt_out'] == 1 ? true : false; $user = wp_get_current_user(); if ($opted_out) { // unsubscribe this user using his/her email fue_add_user_opt_out($user->ID); } else { fue_remove_user_opt_out($user->ID); } wp_redirect(add_query_arg('fue_updated', 1, Follow_Up_Emails::get_account_url())); exit; } elseif (isset($_GET['fue_updated'])) { Follow_Up_Emails::show_message(__('Account updated', 'follow_up_emails')); } }
/** * Generate a JSON response given an array of data * * @since 4.1 * @param array $data the response data * @return string */ public function generate_response($data) { if (isset($_GET['_jsonp'])) { // JSONP enabled by default if (!apply_filters('fue_api_jsonp_enabled', true)) { Follow_Up_Emails::instance()->api->server->send_status(400); $data = array(array('code' => 'fue_api_jsonp_disabled', 'message' => __('JSONP support is disabled on this site', 'follow_up_emails'))); } // Check for invalid characters (only alphanumeric allowed) if (preg_match('/\\W/', $_GET['_jsonp'])) { Follow_Up_Emails::instance()->api->server->send_status(400); $data = array(array('code' => 'fue_api_jsonp_callback_invalid', __('The JSONP callback function is invalid', 'follow_up_emails'))); } // see http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ Follow_Up_Emails::instance()->api->server->header('X-Content-Type-Options', 'nosniff'); // Prepend '/**/' to mitigate possible JSONP Flash attacks return '/**/' . $_GET['_jsonp'] . '(' . json_encode($data) . ')'; } return json_encode($data); }
/** * Get an array of Category IDs included in the given $order * @param int|WC_Order $order * @return array */ protected function get_category_ids_from_order($order) { $wpdb = Follow_Up_Emails::instance()->wpdb; if (is_numeric($order)) { $order = WC_FUE_Compatibility::wc_get_order($order); } if (1 != get_post_meta($order->id, '_fue_recorded', true)) { FUE_Addon_Woocommerce::record_order($order); } $category_ids = $wpdb->get_col($wpdb->prepare("SELECT category_id\n FROM {$wpdb->prefix}followup_order_categories\n WHERE order_id = %d", $order->id)); return array_unique($category_ids); }
/** * List emails under the given campaign * * @since 4.1 * @param string $slug Campaign slug * @param array $filter * @param int $page * @return array */ public function get_campaign_emails($slug, $filter = array(), $page = 1) { $filter['campaign'] = $slug; return Follow_Up_Emails::instance()->api->FUE_API_Emails->get_emails($filter, $page); }
/** * Get replacement data for customer emails * * @param array $replacements * @param array $email_data * @param object $queue_item * @param FUE_Email $email * * @return array */ private function get_replacement_data_for_customer($replacements, $email_data, $queue_item, $email) { $wpdb = Follow_Up_Emails::instance()->wpdb; $order = WC_FUE_Compatibility::wc_get_order($queue_item->order_id); if ($email_data['user_id'] > 0) { $customer = $wpdb->get_row($wpdb->prepare("SELECT *\n FROM {$wpdb->prefix}followup_customers\n WHERE user_id = %d", $email_data['user_id'])); $last_order_date = $wpdb->get_var($wpdb->prepare("SELECT p.post_date\n FROM {$wpdb->posts} p, {$wpdb->prefix}followup_customer_orders co\n WHERE co.followup_customer_id = %d\n AND co.order_id = p.ID\n AND p.post_status = 'publish'\n ORDER BY p.ID\n DESC LIMIT 1", $email_data['user_id'])); $spent_order = strip_tags(woocommerce_price($order->order_total)); $spent_total = strip_tags(woocommerce_price($customer->total_purchase_price)); $num_orders = $customer->total_orders; $last_purchase = date(get_option('date_format'), strtotime($last_order_date)); } else { $customer = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}followup_customers WHERE email_address = %s", $email_data['email_to'])); $spent_total = strip_tags(woocommerce_price($customer->total_purchase_price)); $num_orders = $customer->total_orders; $last_order_date = $wpdb->get_var($wpdb->prepare("SELECT p.post_date FROM {$wpdb->posts} p, {$wpdb->postmeta} pm WHERE pm.meta_key = '_billing_email' AND pm.meta_value = %d AND pm.post_id = p.ID AND p.post_status = 'publish' ORDER BY p.ID DESC LIMIT 1", $email_data['email_to'])); $last_purchase = date(get_option('date_format'), strtotime($last_order_date)); } $spent_order = 0; if ($order) { $spent_order = strip_tags(woocommerce_price($order->order_total)); } $replacements['amount_spent_order'] = $spent_order; $replacements['amount_spent_total'] = $spent_total; $replacements['number_orders'] = $num_orders; $replacements['last_purchase_date'] = $last_purchase; return $replacements; }
<?php /* @var FUE_Email $email */ $durations = Follow_Up_Emails::get_durations(); foreach ($durations as $key => $value) { if ($key == 'date') { continue; } ?> <option class="interval_duration_<?php echo $key; ?> hideable" value="<?php echo esc_attr($key); ?> "><?php echo Follow_Up_Emails::get_duration($key, $value); ?> </option> <?php } ?> </select> </td> </tr> <?php do_action('fue_manual_email_form_before_message', $defaults); ?> <tr valign="top">
/** * Get the top performing emails based on the $event selected. * * @param string $event 'open', 'click' or 'ctor' (click to open rate) * @param int $length Number of emails to return * @return array */ public static function get_top_emails_by($event, $length = 5) { $wpdb = Follow_Up_Emails::instance()->wpdb; $top = array(); // look for stored reports if (!defined('FUE_DEBUG')) { $stored_emails = get_transient('fue_top_emails_' . $event); if ($stored_emails) { return $stored_emails; } } if ($event == 'click' || $event == 'open') { $emails = $wpdb->get_results("SELECT DISTINCT email_id, COUNT(email_id) AS occurence\n FROM {$wpdb->prefix}followup_email_tracking\n WHERE event_type = '" . esc_sql($event) . "'\n GROUP BY email_id\n ORDER BY occurence DESC"); foreach ($emails as $row) { $email_id = $row->email_id; $email_name = $wpdb->get_var($wpdb->prepare("SELECT email_name\n FROM {$wpdb->prefix}followup_email_logs\n WHERE email_id = %d LIMIT 1", $email_id)); if ($event == 'open') { $item = array($email_name, absint(self::count_emails_sent(array(), $email_id)), absint($row->occurence), absint(self::count_total_email_clicks(array('email_id' => $email_id)))); } else { $item = array($email_name, absint(self::count_emails_sent(array(), $email_id)), absint(self::count_opened_emails(array('email_id' => $email_id))), absint($row->occurence)); } $top[] = $item; if (count($top) >= $length) { break; } } } elseif ($event == 'ctor') { $clicks = $wpdb->get_results("SELECT email_id, COUNT(email_id) AS occurence\n FROM {$wpdb->prefix}followup_email_tracking\n WHERE event_type = 'click'\n GROUP BY email_id\n ORDER BY occurence DESC\n LIMIT 100", ARRAY_A); $opens = $wpdb->get_results("SELECT email_id, COUNT(email_id) AS occurence\n FROM {$wpdb->prefix}followup_email_tracking\n WHERE event_type = 'open'\n GROUP BY email_id\n ORDER BY occurence DESC\n LIMIT 100", ARRAY_A); $matched = array(); foreach ($clicks as $click) { foreach ($opens as $open) { if ($click['email_id'] == $open['email_id']) { $matched[] = array('email_id' => $click['email_id'], 'clicks' => $click['occurence'], 'opens' => $open['occurence'], 'ctor' => round($click['occurence'] / $open['occurence'] * 100, 1)); continue 2; } } } if (!empty($matched)) { $ctor = array(); foreach ($matched as $key => $match) { $ctor[$key] = $match['ctor']; } array_multisort($ctor, SORT_DESC, $matched); foreach ($matched as $match) { $email = new FUE_Email($match['email_id']); $item = array($email->name, absint($match['opens']), absint($match['clicks']), absint($match['ctor'])); $top[] = $item; if (count($top) >= $length) { break; } } } } if (!defined('FUE_DEBUG')) { // store for 10 minutes set_transient('fue_top_emails_' . $event, $top, 600); } return $top; }
/** * Get a single queue item * * @since 4.1 * @param int $id * @param array $fields * @return array */ public function get_queue_item($id, $fields = array()) { $id = $this->validate_request($id); // Return the validate error. if (is_wp_error($id)) { return $id; } $item = new FUE_Sending_Queue_Item($id); $email = Follow_Up_Emails::instance()->api->FUE_API_Emails->get_email($item->email_id); if (is_wp_error($email)) { $email = null; } $data = array('id' => $item->id, 'user_id' => $item->user_id, 'user_email' => $item->user_email, 'order_id' => $item->order_id, 'product_id' => $item->product_id, 'email_id' => $item->email_id, 'email' => $email, 'date_scheduled' => $this->server->format_datetime($item->send_on, true), 'is_cart' => $item->is_cart, 'is_sent' => $item->is_sent, 'date_sent' => $this->server->format_datetime($item->date_sent, true), 'email_trigger' => $item->email_trigger, 'meta' => $item->meta); return array('item' => apply_filters('fue_api_queue_response', $data, $item, $fields, $this->server)); }
/** * Return the scheduled date/time * @param array $item * @return string */ public function get_date_value($item) { $scheduler = Follow_Up_Emails::instance()->scheduler; $param = $scheduler->get_scheduler_parameters($item['id']); $send_on = wc_next_scheduled_action('sfn_followup_emails', $param, 'fue'); if (false === $send_on) { // attempt to schedule the email again $send_on = strtotime(get_gmt_from_date(date('Y-m-d H:i:s', $item['send_on']))); wc_schedule_single_action($send_on, 'sfn_followup_emails', $param, 'fue'); } return get_date_from_gmt(date('Y-m-d H:i:s', $send_on), get_option('date_format') . ' ' . get_option('time_format')); }
/** * Test will pass if the customer has bought from all of the categories specified * * @param $item * @param $condition * @return bool|WP_Error */ public function test_bought_categories_condition($item, $condition) { $wpdb = Follow_Up_Emails::instance()->wpdb; $categories = array_filter(array_map('absint', $condition['categories'])); $customer = fue_get_customer_from_order($item->order_id); $result = true; if (!$customer) { return new WP_Error('fue_email_conditions', sprintf(__('Customer data could not be found (Order #%d)', 'follow_up_emails'), $item->order_id)); } if (!empty($categories)) { foreach ($categories as $category) { if (!$this->fue_wc->customer_purchased_from_category($customer, $category)) { // no purchases found for this product $wc_category = get_term($category, 'product_cat'); return new WP_Error('fue_email_conditions', sprintf(__('Customer has not purchased from a required category (%s)', 'follow_up_emails'), $wc_category->name)); } } } return true; }
/** * Format the trigger string that is displayed in the email reports * * @param string $string * @param FUE_Email $email * * @return string */ public function trigger_string($string, $email) { if ($email->trigger == 'points_greater_than') { $email_type = $email->get_email_type(); $meta = maybe_unserialize($email->meta); $string = sprintf(__('%d %s %s %d'), $email->interval, Follow_Up_Emails::get_duration($email->duration, $email->interval), $email_type->get_trigger_name($email->trigger), $meta['points_greater_than']); } return $string; }
/** * Send emails that matches the provided triggers to the queue * @param int $booking_id * @param array $triggers */ private function create_email_order($booking_id, $triggers = array()) { /** * @var $booking WC_Booking * @var $order WC_Order */ $booking = get_wc_booking($booking_id); $last_status = get_post_meta($booking_id, '_last_status', true); $order = WC_FUE_Compatibility::wc_get_order($booking->order_id); $emails = fue_get_emails('wc_bookings', FUE_Email::STATUS_ACTIVE, array('meta_query' => array(array('key' => '_interval_type', 'value' => $triggers, 'compare' => 'IN')))); foreach ($emails as $email) { if (!empty($email->meta['bookings_last_status']) && $email->meta['bookings_last_status'] != $last_status) { continue; } if ($this->is_category_excluded($booking, $email)) { continue; } // A booking can have no order linked to it if ($order) { $customer = fue_get_customer_from_order($order); if (Follow_Up_Emails::instance()->fue_wc->wc_scheduler->exclude_customer_based_on_purchase_history($customer, $email)) { continue; } } if ($email->interval_type == 'before_booking_event') { $start = strtotime(get_post_meta($booking_id, '_booking_start', true)); $time = FUE_Sending_Scheduler::get_time_to_add($email->interval_num, $email->interval_duration); $send_on = $start - $time; } elseif ($email->interval_type == 'after_booking_event') { $start = strtotime(get_post_meta($booking_id, '_booking_end', true)); $time = FUE_Sending_Scheduler::get_time_to_add($email->interval_num, $email->interval_duration); $send_on = $start + $time; } else { $send_on = $email->get_send_timestamp(); } $insert = array('send_on' => $send_on, 'email_id' => $email->id, 'product_id' => $booking->product_id, 'order_id' => $booking->order_id, 'meta' => array('booking_id' => $booking_id)); if ($order) { $user_id = WC_FUE_Compatibility::get_order_user_id($order); if ($user_id) { $user = new WP_User($user_id); $insert['user_id'] = $user_id; $insert['user_email'] = $user->user_email; } } // Remove the nonce to avoid infinite loop because doing a // remove_action on WC_Bookings_Details_Meta_Box doesnt work unset($_POST['wc_bookings_details_meta_box_nonce']); if (!is_wp_error(FUE_Sending_Scheduler::queue_email($insert, $email))) { // Tell FUE that an email order has been created // to stop it from sending storewide emails if (!defined('FUE_ORDER_CREATED')) { define('FUE_ORDER_CREATED', true); } } } }
/** * Check if the given email address is already a subscriber * @param string $email * @return bool */ function fue_subscriber_email_exists($email) { $wpdb = Follow_Up_Emails::instance()->wpdb; $count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_subscribers\n WHERE email = %s", $email)); return $count > 0; }
$triggers = $email_type->triggers; } foreach ($durations as $key => $duration) { $selected = $email->duration == $key ? 'selected' : ''; ?> <option class="interval_duration_<?php echo $key; ?> hideable" value="<?php echo esc_attr($key); ?> " <?php echo $selected; ?> ><?php echo Follow_Up_Emails::get_duration($key, $email->interval); ?> </option> <?php } ?> </select> <span class="description signup signup_description hideable"><?php _e('after user signs up', 'follow_up_emails'); ?> </span> </p> <p class="form-field non-signup"> <label><?php
/** * Admin interface for managing opt-outs */ public static function optout_table() { $wpdb = Follow_Up_Emails::instance()->wpdb; include FUE_TEMPLATES_DIR . '/optout_table.php'; }
/** * Send a queue item that has no linked follow-up email. * Used in sending failed subscription payment notifications and daily summary emails * * @param FUE_Sending_Queue_Item $queue_item * @return bool|WP_Error */ private function send_adhoc_email($queue_item) { $wpdb = Follow_Up_Emails::instance()->wpdb; if (!empty($queue_item->meta['email'])) { $recipient_email = $queue_item->meta['email']; } else { $recipient_email = $queue_item->user_email; } $subject = apply_filters('fue_adhoc_email_subject', $queue_item->meta['subject'], $queue_item); $message = apply_filters('fue_adhoc_email_message', $queue_item->meta['message'], $queue_item); if (empty($message)) { $wpdb->update($wpdb->prefix . 'followup_email_orders', array('status' => -1), array('id' => $queue_item->id)); do_action('fue_adhoc_email_sent', $queue_item); return new WP_Error('fue_queue_error', __('Skipped sending because there was no message to be sent', 'follow_up_emails')); } self::mail($recipient_email, $subject, $message); // update the email order $now = get_date_from_gmt(date('Y-m-d H:i:s'), 'Y-m-d H:i:s'); $wpdb->update($wpdb->prefix . 'followup_email_orders', array('is_sent' => 1, 'date_sent' => $now), array('id' => $queue_item->id)); do_action('fue_adhoc_email_sent', $queue_item); return true; }
/** * Get orders matching the conditions of the customer email * @param FUE_Email $email * @return array */ private function get_orders_for_customer_email($email) { $wpdb = Follow_Up_Emails::instance()->wpdb; $orders = array(); if ($email->type != 'customer') { return $orders; } if ($email->trigger == 'after_last_purchase') { $customer_ids = $wpdb->get_col("SELECT DISTINCT followup_customer_id\n FROM {$wpdb->prefix}followup_customer_orders"); foreach ($customer_ids as $customer_id) { // get the last order of each customer $order_id = $wpdb->get_var($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_customer_orders co\n WHERE followup_customer_id = %d\n AND (\n SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = co.order_id\n AND email_id = %d\n ) = 0\n AND (\n SELECT meta_value\n FROM {$wpdb->postmeta}\n WHERE post_id = order_id\n AND meta_key = '_fue_recorded'\n ) != 1\n ORDER BY order_id DESC\n LIMIT 1", $customer_id, $email->id)); if ($order_id) { $orders[] = $order_id; } } } if ($email->trigger == 'order_total_above') { // get customer orders where the order total exceeds the value specified in the email $order_total_baseline = empty($email->meta['order_total_above']) ? 0 : $email->meta['order_total_above']; $orders = $wpdb->get_col($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_customer_orders co\n WHERE price > %d\n AND (\n SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = co.order_id\n AND email_id = %d\n ) = 0\n AND (\n SELECT meta_value\n FROM {$wpdb->postmeta}\n WHERE post_id = order_id\n AND meta_key = '_fue_recorded'\n ) != 1", $order_total_baseline, $email->id)); } if ($email->trigger == 'order_total_below') { // get customer orders where the order total is below the value specified in the email $order_total_baseline = empty($email->meta['order_total_below']) ? 0 : $email->meta['order_total_below']; $orders = $wpdb->get_col($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_customer_orders co\n WHERE price < %d\n AND (\n SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = co.order_id\n AND email_id = %d\n ) = 0\n AND (\n SELECT meta_value\n FROM {$wpdb->postmeta}\n WHERE post_id = order_id\n AND meta_key = '_fue_recorded'\n ) != 1", $order_total_baseline, $email->id)); } if ($email->trigger == 'purchase_above_one') { // Get the orders of customers with more than 1 order $customers = $wpdb->get_col("SELECT followup_customer_id\n FROM {$wpdb->prefix}followup_customer_orders\n GROUP BY followup_customer_id\n HAVING COUNT(followup_customer_id) > 1"); foreach ($customers as $customer_id) { $customer_orders = $wpdb->get_col($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_customer_orders\n WHERE followup_customer_id = %d\n ORDER BY order_id ASC", $customer_id)); if (count($customer_orders) > 0) { // drop the customer's first order $customer_orders = array_slice($customer_orders, 1); $queue_orders = $wpdb->get_col($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id IN (" . implode(',', $customer_orders) . ")\n AND email_id = %d", $email->id)); // exclude orders that are already in the queue foreach ($customer_orders as $customer_order) { if (!in_array($customer_order, $queue_orders)) { $orders[] = $customer_order; } } } } } if ($email->trigger == 'total_orders') { $total_orders_baseline = $email->meta['total_orders']; $operator = $email->meta['total_orders_mode'] == 'equal to' ? '=' : '>'; $customers = $wpdb->get_col($wpdb->prepare("SELECT followup_customer_id\n FROM {$wpdb->prefix}followup_customer_orders\n GROUP BY followup_customer_id\n HAVING COUNT(followup_customer_id) {$operator} %d", $total_orders_baseline)); foreach ($customers as $customer_id) { $order_id = $wpdb->get_var($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_customer_orders\n WHERE followup_customer_id = %d\n ORDER BY order_id DESC\n LIMIT 1", $customer_id)); if ($order_id) { $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $order_id, $email->id)); if ($in_queue) { continue; } $orders[] = $order_id; } } } if ($email->trigger == 'total_purchases') { $total_purchases_baseline = $email->meta['total_purchases']; $operator = $email->meta['total_purchases_mode'] == 'equal to' ? '=' : '>'; $customers = $wpdb->get_col($wpdb->prepare("SELECT followup_customer_id\n FROM {$wpdb->prefix}followup_customer_orders\n GROUP BY followup_customer_id\n HAVING SUM(price) {$operator} %d", $total_purchases_baseline)); foreach ($customers as $customer_id) { // get the customer's last order_id $order_id = $wpdb->get_var($wpdb->prepare("SELECT order_id\n FROM {$wpdb->prefix}followup_customer_orders\n WHERE followup_customer_id = %d\n ORDER BY order_id DESC\n LIMIT 1", $customer_id)); if ($order_id) { $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $order_id, $email->id)); if ($in_queue) { continue; } $orders[] = $order_id; } } } return $orders; }
/** * Order importer for WooCommerce. Process 10 orders at a time */ public static function wc_order_import() { $wpdb = Follow_Up_Emails::instance()->wpdb; if (empty($_POST['cmd'])) { self::send_response(array('error' => 'CMD is missing')); } $cmd = $_POST['cmd']; $email_id = !empty($_POST['email_id']) ? $_POST['email_id'] : ''; if ($email_id) { $fue_wc = Follow_Up_Emails::instance()->fue_wc; if ($cmd == 'start') { if (is_array($email_id)) { $total_orders = 0; foreach ($email_id as $id) { $email = new FUE_Email($id); $email_orders = $fue_wc->count_orders_for_email($email); $total_orders += $email_orders; if ($email_orders == 0) { delete_post_meta($id, '_import_order_flag'); } } self::send_response(array('total_orders' => $total_orders)); } else { $email = new FUE_Email($email_id); $total_orders = $fue_wc->count_orders_for_email($email); if ($total_orders == 0) { delete_post_meta($email_id, '_import_order_flag'); } self::send_response(array('total_orders' => $total_orders)); } } else { $email = new FUE_Email($email_id); $results = $fue_wc->import_orders_for_email($email, 10); if ($results['status'] == 'completed') { delete_post_meta($email_id, '_import_order_flag'); } self::send_response(array('status' => $results['status'] == 'running' ? 'partial' : 'completed', 'import_data' => $results['imported'], 'remaining_orders' => $results['remaining_orders'])); } } else { if ($cmd == 'start') { $tables = $wpdb->get_col("SHOW TABLES LIKE '{$wpdb->prefix}followup_order_items'"); if (empty($tables)) { self::send_response(array('error' => 'Database tables are not installed. Please deactivate then reactivate Follow Up Emails')); } if (!get_option('fue_orders_imported', false) && !get_transient('fue_importing_orders')) { // First run of the import script. Clear existing data for a fresh start $wpdb->query("DELETE FROM {$wpdb->prefix}followup_order_items"); $wpdb->query("DELETE FROM {$wpdb->prefix}followup_customers"); $wpdb->query("DELETE FROM {$wpdb->prefix}followup_order_categories"); $wpdb->query("DELETE FROM {$wpdb->prefix}followup_customer_orders"); } set_transient('fue_importing_orders', true, 86400); $sql = "SELECT COUNT( DISTINCT p.id )\n FROM {$wpdb->posts} p, {$wpdb->postmeta} pm\n WHERE p.ID = pm.post_id\n AND p.post_type = 'shop_order'\n AND (SELECT COUNT(*) FROM {$wpdb->postmeta} pm2 WHERE p.ID = pm2.post_id AND pm2.meta_key = '_fue_recorded') = 0"; $total_orders = $wpdb->get_var($sql); if ($total_orders == 0) { update_option('fue_orders_imported', true); delete_transient('fue_importing_orders'); } self::send_response(array('total_orders' => $total_orders)); } else { $sql = "SELECT DISTINCT p.ID\n FROM {$wpdb->posts} p, {$wpdb->postmeta} pm\n WHERE p.ID = pm.post_id\n AND p.post_type = 'shop_order'\n AND (SELECT COUNT(*) FROM {$wpdb->postmeta} pm2 WHERE p.ID = pm2.post_id AND pm2.meta_key = '_fue_recorded') = 0\n LIMIT 1"; $results = $wpdb->get_results($sql); if (count($results) == 0) { update_option('fue_orders_imported', true); delete_transient('fue_importing_orders'); self::send_response(array('status' => 'completed')); } else { $imported = array(); foreach ($results as $row) { $order = WC_FUE_Compatibility::wc_get_order($row->ID); FUE_Addon_Woocommerce::record_order($order); $imported[] = array('id' => $row->ID, 'status' => 'success'); } self::send_response(array('status' => 'partial', 'import_data' => $imported)); } } } }
/** * Schedule unsent emails to use action-scheduler * * @param int $pos * @param int $length * * @return bool|int */ public static function action_scheduler_import($pos = 0, $length = 0) { $wpdb = Follow_Up_Emails::instance()->wpdb; if ($length > 0) { $rows = $wpdb->get_results("SELECT id, send_on FROM {$wpdb->prefix}followup_email_orders WHERE is_sent = 0 ORDER BY id ASC LIMIT {$pos}, {$length}"); } else { $rows = $wpdb->get_results("SELECT id, send_on FROM {$wpdb->prefix}followup_email_orders WHERE is_sent = 0 ORDER BY id ASC"); } if (!$rows) { return false; } foreach ($rows as $row) { $data = array('email_order_id' => $row->id); $job_id = wc_schedule_single_action($row->send_on, 'sfn_followup_emails', $data, 'fue'); $pos++; } return $pos; }
/** * Get orders that match the $email's criteria * @param array $orders Matching Order IDs * @param FUE_Email $email * @return array */ public function get_orders_for_email($orders, $email) { $wpdb = Follow_Up_Emails::instance()->wpdb; $all_subscriptions = WC_Subscriptions_Manager::get_all_users_subscriptions(); $status_array = array('subs_activated' => 'active', 'subs_cancelled' => 'cancelled', 'subs_expired' => 'expired', 'subs_suspended' => 'suspended'); $status_triggers = array_keys($status_array); if (in_array($email->trigger, $status_triggers)) { $status = $status_array[$email->trigger]; foreach ($all_subscriptions as $user_id => $subscriptions) { foreach ($subscriptions as $subscription) { if ($subscription['status'] != $status) { continue; } $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $subscription['order_id'], $email->id)); if ($in_queue) { continue; } $orders[] = $subscription['order_id']; } } } elseif ($email->trigger == 'subs_renewed') { // get orders with active subscriptions AND renewals foreach ($all_subscriptions as $user_id => $subscriptions) { foreach ($subscriptions as $subscription) { if ($subscription['status'] == 'active' && count($subscription['completed_payments']) >= 2) { $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $subscription['order_id'], $email->id)); if ($in_queue) { continue; } $orders[] = $subscription['order_id']; } } } } elseif ($email->trigger == 'subs_reactivated') { // get active subscriptions with at least 1 suspension count foreach ($all_subscriptions as $user_id => $subscriptions) { foreach ($subscriptions as $subscription) { if ($subscription['status'] == 'active' && absint($subscription['suspension_count']) > 0) { $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $subscription['order_id'], $email->id)); if ($in_queue) { continue; } $orders[] = $subscription['order_id']; } } } } elseif ($email->trigger == 'subs_renewal_order') { $order_ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_parent > 0 AND post_type = 'shop_order' ORDER BY {$wpdb->posts}.post_date ASC"); foreach ($order_ids as $order_id) { $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $order_id, $email->id)); if ($in_queue) { continue; } $orders[] = $order_id; } } elseif ($email->trigger == 'subs_before_renewal' || $email->trigger == 'subs_before_expire') { foreach ($all_subscriptions as $user_id => $subscriptions) { foreach ($subscriptions as $subscription) { if ($subscription['status'] != 'active') { continue; } $in_queue = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)\n FROM {$wpdb->prefix}followup_email_orders\n WHERE order_id = %d\n AND email_id = %d", $subscription['order_id'], $email->id)); if ($in_queue) { continue; } $orders[] = $subscription['order_id']; } } } return $orders; }
/** * Load the addons */ public static function load_addons() { // Email Reporting, Tracking and Daily Summary require_once FUE_INC_DIR . '/reports/class-fue-reports.php'; if (self::is_woocommerce_installed()) { $fue = Follow_Up_Emails::instance(); $fue->fue_wc = new FUE_Addon_Woocommerce($fue, $fue->mailer, $fue->email_vars); } if (self::is_sensei_installed()) { require_once FUE_INC_DIR . '/addons/class-fue-addon-sensei.php'; } // Coming Soon Pro require_once FUE_INC_DIR . '/addons/class-fue-addon-coming-soon-pro.php'; do_action('fue_addons_loaded'); }
<?php if (isset($_GET['action']) && $_GET['action'] == 'install_template') { include FUE_TEMPLATES_DIR . '/add-ons/install.php'; } elseif (isset($_GET['action']) && $_GET['action'] == 'uninstall_template') { include FUE_TEMPLATES_DIR . '/add-ons/uninstall.php'; } else { ?> <h3><?php _e('Apps', 'follow_up_emails'); ?> </h3> <ul class="fue-addons"> <?php $fue_addons = new FUE_Addons(Follow_Up_Emails::instance()); $addons = $fue_addons->get_addons(); foreach ($addons as $id => $addon) { ?> <li><?php include FUE_TEMPLATES_DIR . '/add-ons/add-on-item.php'; ?> </li> <?php } ?> </ul> <h3><?php _e('Templates', 'follow_up_emails'); ?>
/** * Generate and serve the settings in a CSV format */ static function backup_settings() { check_admin_referer('fue_backup'); $contents = ''; $headers = array('meta_key', 'meta_value'); $contents .= self::array_to_csv($headers); $wpdb = Follow_Up_Emails::instance()->wpdb; $options = $wpdb->get_results("SELECT option_name, option_value\n FROM {$wpdb->options}\n WHERE option_name LIKE 'fue%'"); foreach ($options as $option) { $row = array($option->option_name, $option->option_value); $contents .= self::array_to_csv($row); } header('Content-Type: application/csv'); header('Content-Disposition:attachment;filename=follow_up_settings.csv'); header('Pragma: no-cache'); echo $contents; exit; }
/** * Return this emails FUE_Email_Type object * * @return FUE_Email_Type */ public function get_email_type() { return Follow_Up_Emails::get_email_type($this->get_type()); }
/** * Check that the API keys provided have the proper key-specific permissions to either read or write API resources * * @param WP_User $user * @throws Exception if the permission check fails */ public function check_api_key_permissions($user) { $key_permissions = $user->fue_api_key_permissions; if (!$key_permissions) { // try to load permissions from WC $key_permissions = $user->woocommerce_api_key_permissions; } switch (Follow_Up_Emails::instance()->api->server->method) { case 'HEAD': case 'GET': if ('read' !== $key_permissions && 'read_write' !== $key_permissions) { throw new Exception(__('The API key provided does not have read permissions', 'follow_up_emails'), 401); } break; case 'POST': case 'PUT': case 'PATCH': case 'DELETE': if ('write' !== $key_permissions && 'read_write' !== $key_permissions) { throw new Exception(__('The API key provided does not have write permissions', 'follow_up_emails'), 401); } break; } }
/** * Write the current values to the database * @return int The ID of the queue item */ public function save() { $wpdb = Follow_Up_Emails::instance()->wpdb; $fields = get_object_vars($this); $data = array(); $id = 0; if ($this->id) { $id = $this->id; } foreach ($fields as $field => $value) { if ($field == 'meta') { $data[$field] = maybe_serialize($this->{$field}); } else { $data[$field] = $this->{$field}; } } if ($id) { // updating unset($data['id']); $wpdb->update($wpdb->prefix . 'followup_email_orders', $data, array('id' => $id)); } else { $wpdb->insert($wpdb->prefix . 'followup_email_orders', $data); $this->id = $wpdb->insert_id; $id = $this->id; } return $id; }
/** * Get all the entries in the excludes list * * @param null $fields * @param array $filter * @param int $page * @return array */ public function get_excludes_report($fields = null, $filter = array(), $page = 1) { $args = array('type' => 'excludes', 'page' => $page, 'limit' => !empty($filter['limit']) ? absint($filter['limit']) : get_option('posts_per_page')); $exclude_reports = FUE_Reports::get_reports($args); $exclude_data = array(); $total_rows = Follow_Up_Emails::instance()->wpdb->get_var("SELECT FOUND_ROWS()"); foreach ($exclude_reports as $report) { $exclude_data[] = array('email_name' => $report->email_name, 'email_address' => $report->email, 'date' => $this->server->format_datetime($report->date_added, true)); } // set the pagination data $query = array('page' => $page, 'single' => count($exclude_data) == 1, 'total' => $total_rows, 'total_pages' => ceil($total_rows / $args['limit'])); $this->server->add_pagination_headers($query); return array('optouts' => apply_filters('fue_api_report_response', $exclude_data, $exclude_reports, $fields, $this->server)); }
/** * Reset coupon logs * @param array $data */ public function reset_reports($data) { $wpdb = Follow_Up_Emails::instance()->wpdb; if ($data['type'] == 'coupons' && $data['coupons_action'] == 'trash') { $coupon_ids_str = implode(',', $data['coupon_id']); /*foreach ( $data['coupon_id'] as $coupon_id ) { $wpdb->update( $wpdb->prefix . 'followup_coupons', array('usage_count' => 0), array('id' => $coupon_id) ); }*/ $wpdb->query("DELETE FROM {$wpdb->prefix}followup_coupon_logs WHERE id IN ({$coupon_ids_str})"); } }