Last active
July 6, 2023 03:38
-
-
Save xlplugins/95b4e4f76bd6e7fa472793a50b92835b to your computer and use it in GitHub Desktop.
Schedule Export for Gravity Forms Entries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @package Gravity XL Scheduled Entries Export | |
* @version 1.0 | |
* @name gravityxl -scheduled-entries-export | |
* @author Gravity XL | |
*/ | |
/** | |
* Schedule gform Entry export | |
* | |
*/ | |
class Gravity_XL_Scheduled_Entries_Export | |
{ | |
public $field_type = null; | |
public static $args = null; | |
public static $default_meta_keys = array('created_by', 'id', 'date_created', 'source_url', 'transaction_id', 'payment_amount', 'payment_date', 'payment_status', 'post_id', 'user_agent', 'ip'); | |
/** | |
* Class construct to initiate all hooks & loading dependencies | |
*/ | |
public function __construct($configs) | |
{ | |
// make sure we're running the required minimum version of Gravity Forms | |
if (!property_exists('GFCommon', 'version') || !version_compare(GFCommon::$version, '1.8', '>=')) | |
return; | |
self::$args = wp_parse_args($configs, array( | |
'form_id' => false, | |
'frequency' => 'daily', | |
'day_of_week' => '', | |
'day_of_month' => '', | |
'options' => 'all', | |
'email_to' => false, | |
'email_from_name' => '', | |
'email_from_email' => get_bloginfo('admin_email'), | |
'email_timings' => '00:00', | |
'email_subject' => __('Your lead export report is ready.'), | |
'email_body' => ("Here are your leads export(s) from {start_date} to {end_date}. <br/> <br/> Please Find the attachments."), | |
)); | |
add_action('init', array(__CLASS__, 'initHooks')); | |
add_action('wp', array(__CLASS__, 'maybe_initiate_crons')); | |
} | |
public static function maybe_initiate_crons() | |
{ | |
if (isset(self::$args['form_id']) && self::$args['form_id'] !== false && !wp_next_scheduled('gxl_scheduled_entry_export_' . self::$args['form_id'])) { | |
wp_schedule_event(self::crontimings(self::$args), 'daily', 'gxl_scheduled_entry_export_' . self::$args['form_id'], array(self::$args)); | |
} | |
//try and run it | |
self::maybe_init_scheduled_export(self::$args); | |
} | |
public static function crontimings($args) | |
{ | |
$local_timestamp = strtotime(date("Y-m-d") . " " . self::get_timing($args)); | |
$gmt_timestamp = self::get_gmt_timestamp($local_timestamp); | |
return $gmt_timestamp; | |
} | |
public static function initHooks() | |
{ | |
add_action('gxl_scheduled_entry_export_' . self::$args['form_id'], array(__CLASS__, 'maybe_init_scheduled_export')); | |
} | |
/** | |
* Controller function | |
* @param $args | |
*/ | |
public static function maybe_init_scheduled_export($args) | |
{ | |
if (!self::maybe_run_export($args)) { | |
return; | |
} | |
$form = RGFormsModel::get_form_meta($args['form_id']); | |
$options = self::prepere_options_and_fields($form, $args); | |
ob_start(); | |
if (!empty($options)) { | |
self::start_export($form, $options, $args); | |
} | |
$expected_csv_data = ob_get_clean(); | |
$get_file = self::try_and_savefile($expected_csv_data, $args); | |
self::send_mail($args['email_from_email'], $args['email_to'], "", "", $args['email_subject'], self::parse_body($args['email_body'], $args, $options), $args['email_from_name'], "html", $get_file); | |
} | |
public static function parse_body($body, $args, $data) | |
{ | |
$body = str_replace("{start_date}", $data['export_date_start'], $body); | |
$body = str_replace("{end_date}", $data['export_date_end'], $body); | |
return $body; | |
} | |
public static function prepere_options_and_fields($form, $args) | |
{ | |
$data_return = array(); | |
$data_return['export_field'] = array(); | |
if (!empty($form['fields']) && $args['options'] == "all") { | |
foreach ($form['fields'] as $fields) { | |
if ($fields->displayOnly === true) { | |
continue; | |
} | |
array_push($data_return['export_field'], $fields->id); | |
} | |
} | |
if ($args['options'] == "all") { | |
foreach (self::$default_meta_keys as $keys) { | |
array_push($data_return['export_field'], $keys); | |
} | |
} else { | |
foreach ($args['options'] as $keys) { | |
array_push($data_return['export_field'], $keys); | |
} | |
} | |
$data_return = array_merge($data_return, self::get_dates($args)); | |
return $data_return; | |
} | |
private static function try_and_savefile($data, $args) | |
{ | |
$path = self::get_upload_root(); | |
if (!file_exists($path)) { | |
wp_mkdir_p($path); | |
touch($path . 'index.php'); | |
} | |
$file = fopen($path . self::get_file_name($args), 'w'); | |
fwrite($file, $data); | |
fclose($file); | |
return self::get_upload_root() . self::get_file_name($args); | |
} | |
private static function get_file_name($args) | |
{ | |
$form = RGFormsModel::get_form_meta($args['form_id']); | |
$filename = sanitize_title_with_dashes($form['title']) . '-' . gmdate('Y-m-d', GFCommon::get_local_timestamp(time())) . '.csv'; | |
return $filename; | |
} | |
private static function get_upload_root_url() | |
{ | |
$dir = wp_upload_dir(); | |
if ($dir['error']) { | |
return null; | |
} | |
return $dir['baseurl'] . '/gxl_scheduled_entries_export/'; | |
} | |
private static function get_upload_root() | |
{ | |
$dir = wp_upload_dir(); | |
if ($dir['error']) { | |
return null; | |
} | |
return $dir['basedir'] . '/gxl_scheduled_entries_export/'; | |
} | |
public static function start_export($form, $data, $args) | |
{ | |
$form_id = $form['id']; | |
$fields = $data['export_field']; | |
$start_date = empty($data['export_date_start']) ? '' : self::get_gmt_date($data['export_date_start'] . ' ' . self::get_timing($args)); | |
$end_date = empty($data['export_date_end']) ? '' : self::get_gmt_date($data['export_date_end'] . ' ' . self::get_timing($args)); | |
$search_criteria['status'] = 'active'; | |
$search_criteria['field_filters'] = GFCommon::get_field_filters_from_post($form); | |
if (!empty($start_date)) { | |
$search_criteria['start_date'] = $start_date; | |
} | |
if (!empty($end_date)) { | |
$search_criteria['end_date'] = $end_date; | |
} | |
$sorting = array('key' => 'date_created', 'direction' => 'DESC', 'type' => 'info'); | |
$form = self::add_default_export_fields($form); | |
$entry_count = GFAPI::count_entries($form_id, $search_criteria); | |
$page_size = 100; | |
$offset = 0; | |
//Adding BOM marker for UTF-8 | |
$lines = chr(239) . chr(187) . chr(191); | |
// set the separater | |
$separator = gf_apply_filters(array('gform_export_separator', $form_id), ',', $form_id); | |
$field_rows = self::get_field_row_count($form, $fields, $entry_count); | |
//writing header | |
$headers = array(); | |
foreach ($fields as $field_id) { | |
$field = RGFormsModel::get_field($form, $field_id); | |
$label = gf_apply_filters(array('gform_entries_field_header_pre_export', $form_id, $field_id), GFCommon::get_label($field, $field_id), $form, $field); | |
$value = str_replace('"', '""', $label); | |
if (strpos($value, '=') === 0) { | |
// Prevent Excel formulas | |
$value = "'" . $value; | |
} | |
$headers[$field_id] = $value; | |
$subrow_count = isset($field_rows[$field_id]) ? intval($field_rows[$field_id]) : 0; | |
if ($subrow_count == 0) { | |
$lines .= '"' . $value . '"' . $separator; | |
} else { | |
for ($i = 1; $i <= $subrow_count; $i++) { | |
$lines .= '"' . $value . ' ' . $i . '"' . $separator; | |
} | |
} | |
} | |
$lines = substr($lines, 0, strlen($lines) - 1) . "\n"; | |
//paging through results for memory issues | |
while ($entry_count > 0) { | |
$paging = array( | |
'offset' => $offset, | |
'page_size' => $page_size, | |
); | |
$leads = GFAPI::get_entries($form_id, $search_criteria, $sorting, $paging); | |
$leads = gf_apply_filters(array('gform_leads_before_export', $form_id), $leads, $form, $paging); | |
foreach ($leads as $lead) { | |
foreach ($fields as $field_id) { | |
switch ($field_id) { | |
case 'date_created' : | |
$lead_gmt_time = mysql2date('G', $lead['date_created']); | |
$lead_local_time = GFCommon::get_local_timestamp($lead_gmt_time); | |
$value = date_i18n('Y-m-d H:i:s', $lead_local_time, true); | |
break; | |
default : | |
$field = RGFormsModel::get_field($form, $field_id); | |
$value = is_object($field) ? $field->get_value_export($lead, $field_id, false, true) : rgar($lead, $field_id); | |
$value = apply_filters('gform_export_field_value', $value, $form_id, $field_id, $lead); | |
GFCommon::log_debug("GFExport::start_export(): Value for field ID {$field_id}: {$value}"); | |
break; | |
} | |
if (isset($field_rows[$field_id])) { | |
$list = empty($value) ? array() : unserialize($value); | |
foreach ($list as $row) { | |
$row_values = array_values($row); | |
$row_str = implode('|', $row_values); | |
if (strpos($row_str, '=') === 0) { | |
// Prevent Excel formulas | |
$row_str = "'" . $row_str; | |
} | |
$lines .= '"' . str_replace('"', '""', $row_str) . '"' . $separator; | |
} | |
//filling missing subrow columns (if any) | |
$missing_count = intval($field_rows[$field_id]) - count($list); | |
for ($i = 0; $i < $missing_count; $i++) { | |
$lines .= '""' . $separator; | |
} | |
} else { | |
$value = maybe_unserialize($value); | |
if (is_array($value)) { | |
$value = implode('|', $value); | |
} | |
if (strpos($value, '=') === 0) { | |
// Prevent Excel formulas | |
$value = "'" . $value; | |
} | |
$lines .= '"' . str_replace('"', '""', $value) . '"' . $separator; | |
} | |
} | |
$lines = substr($lines, 0, strlen($lines) - 1); | |
$lines .= "\n"; | |
} | |
$offset += $page_size; | |
$entry_count -= $page_size; | |
if (!seems_utf8($lines)) { | |
$lines = utf8_encode($lines); | |
} | |
$lines = apply_filters('gform_export_lines', $lines); | |
echo $lines; | |
$lines = ''; | |
} | |
} | |
public static function maybe_run_export($args) | |
{ | |
if (!isset($args['frequency'])) { | |
return false; | |
} | |
$maybe_run = false; | |
switch ($args['frequency']) { | |
case "daily": | |
$maybe_run = true; | |
break; | |
case "weekly": | |
if (strtolower(date('l')) == strtolower($args['day_of_week'])) { | |
$maybe_run = true; | |
} | |
break; | |
case "monthly": | |
if ((date('D')) == ($args['day_of_month']) || (date('d')) == $args['day_of_month']) { | |
$maybe_run = true; | |
} | |
break; | |
} | |
return $maybe_run; | |
} | |
private static function get_dates($args) | |
{ | |
$dates = array(); | |
$dates['export_date_start'] = ''; | |
$dates['export_date_end'] = ''; | |
switch ($args['frequency']) { | |
case "daily": | |
$dates['export_date_end'] = date('Y-m-d'); | |
$phpDateTime = new DateTime(); | |
$phpDateTime->setTimestamp(time()); | |
$phpDateTime->modify("-1 day"); | |
$dates['export_date_start'] = $phpDateTime->format('Y-m-d'); | |
break; | |
case "weekly": | |
if (strtolower(date('l')) == strtolower($args['day_of_week'])) { | |
$dates['export_date_end'] = date('Y-m-d'); | |
$phpDateTime = new DateTime(); | |
$phpDateTime->setTimestamp(time()); | |
$phpDateTime->modify("-6 days"); | |
$dates['export_date_start'] = $phpDateTime->format('Y-m-d'); | |
} | |
break; | |
case "monthly": | |
if (date('D') == $args['day_of_month'] || date('d') == $args['day_of_month']) { | |
$dates['export_date_end'] = date('Y-m-d'); | |
$phpDateTime = new DateTime(); | |
$phpDateTime->setTimestamp(time()); | |
$phpDateTime->modify("-29 days"); | |
$dates['export_date_start'] = $phpDateTime->format('Y-m-d'); | |
} | |
break; | |
} | |
return $dates; | |
} | |
public static function get_gmt_timestamp($local_timestamp) | |
{ | |
return $local_timestamp - (get_option('gmt_offset') * 3600); | |
} | |
public static function get_gmt_date($local_date) | |
{ | |
$local_timestamp = strtotime($local_date); | |
$gmt_timestamp = self::get_gmt_timestamp($local_timestamp); | |
$date = gmdate('Y-m-d H:i:s', $gmt_timestamp); | |
return $date; | |
} | |
public static function add_default_export_fields($form) | |
{ | |
//adding default fields | |
array_push($form['fields'], array('id' => 'created_by', 'label' => __('Created By (User Id)', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'id', 'label' => __('Entry Id', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'date_created', 'label' => __('Entry Date', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'source_url', 'label' => __('Source Url', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'transaction_id', 'label' => __('Transaction Id', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'payment_amount', 'label' => __('Payment Amount', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'payment_date', 'label' => __('Payment Date', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'payment_status', 'label' => __('Payment Status', 'gravityforms'))); | |
//array_push($form['fields'],array('id' => 'payment_method' , 'label' => __('Payment Method', 'gravityforms'))); //wait until all payment gateways have been released | |
array_push($form['fields'], array('id' => 'post_id', 'label' => __('Post Id', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'user_agent', 'label' => __('User Agent', 'gravityforms'))); | |
array_push($form['fields'], array('id' => 'ip', 'label' => __('User IP', 'gravityforms'))); | |
$form = self::get_entry_meta($form); | |
$form = apply_filters('gform_export_fields', $form); | |
$form = GFFormsModel::convert_field_objects($form); | |
return $form; | |
} | |
private static function get_entry_meta($form) | |
{ | |
$entry_meta = GFFormsModel::get_entry_meta($form['id']); | |
$keys = array_keys($entry_meta); | |
foreach ($keys as $key) { | |
array_push($form['fields'], array('id' => $key, 'label' => $entry_meta[$key]['label'])); | |
} | |
return $form; | |
} | |
public static function get_field_row_count($form, $exported_field_ids, $entry_count) | |
{ | |
$list_fields = GFAPI::get_fields_by_type($form, array('list'), true); | |
//only getting fields that have been exported | |
$field_ids = ''; | |
foreach ($list_fields as $field) { | |
if (in_array($field->id, $exported_field_ids) && $field->enableColumns) { | |
$field_ids .= $field->id . ','; | |
} | |
} | |
if (empty($field_ids)) { | |
return array(); | |
} | |
$field_ids = substr($field_ids, 0, strlen($field_ids) - 1); | |
$page_size = 200; | |
$offset = 0; | |
$row_counts = array(); | |
global $wpdb; | |
$go_to_next_page = true; | |
while ($go_to_next_page) { | |
$sql = "SELECT d.field_number as field_id, ifnull(l.value, d.value) as value | |
FROM {$wpdb->prefix}rg_lead_detail d | |
LEFT OUTER JOIN {$wpdb->prefix}rg_lead_detail_long l ON d.id = l.lead_detail_id | |
WHERE d.form_id={$form['id']} AND cast(d.field_number as decimal) IN ({$field_ids}) | |
LIMIT {$offset}, {$page_size}"; | |
$results = $wpdb->get_results($sql, ARRAY_A); | |
foreach ($results as $result) { | |
$list = unserialize($result['value']); | |
$current_row_count = isset($row_counts[$result['field_id']]) ? intval($row_counts[$result['field_id']]) : 0; | |
if (is_array($list) && count($list) > $current_row_count) { | |
$row_counts[$result['field_id']] = count($list); | |
} | |
} | |
$offset += $page_size; | |
$go_to_next_page = count($results) == $page_size; | |
} | |
return $row_counts; | |
} | |
private static function send_mail($from, $to, $bcc, $reply_to, $subject, $message, $from_name = '', $message_format = 'html', $attachments = '', $entry = false, $notification = false) | |
{ | |
global $phpmailer; | |
$to = str_replace(' ', '', $to); | |
$bcc = str_replace(' ', '', $bcc); | |
$error = false; | |
if (!GFCommon::is_valid_email($from)) { | |
$from = get_bloginfo('admin_email'); | |
} | |
if (!GFCommon::is_valid_email_list($to)) { | |
$error = new WP_Error('invalid_to', 'Cannot send email because the TO address is invalid.'); | |
} else if (empty($subject) && empty($message)) { | |
$error = new WP_Error('missing_subject_and_message', 'Cannot send email because there is no SUBJECT and no MESSAGE.'); | |
} else if (!GFCommon::is_valid_email($from)) { | |
$error = new WP_Error('invalid_from', 'Cannot send email because the FROM address is invalid.'); | |
} | |
if (is_wp_error($error)) { | |
GFCommon::log_error('GFCommon::send_email(): ' . $error->get_error_message()); | |
GFCommon::log_error(print_r(compact('to', 'subject', 'message'), true)); | |
/** | |
* Fires when an email from Gravity Forms has failed to send | |
* | |
* @since 1.8.10 | |
* | |
* @param string $error The Error message returned after the email fails to send | |
* @param array $details The details of the message that failed | |
* @param array $entry The Entry object | |
* | |
*/ | |
do_action('gform_send_email_failed', $error, compact('from', 'to', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'attachments'), $entry); | |
return; | |
} | |
$content_type = $message_format == 'html' ? 'text/html' : 'text/plain'; | |
$name = empty($from_name) ? $from : $from_name; | |
$headers = array(); | |
$headers['From'] = "From: \"" . wp_strip_all_tags($name, true) . "\" <{$from}>"; | |
if (GFCommon::is_valid_email_list($reply_to)) { | |
$headers['Reply-To'] = "Reply-To: {$reply_to}"; | |
} | |
if (GFCommon::is_valid_email_list($bcc)) { | |
$headers['Bcc'] = "Bcc: $bcc"; | |
} | |
$headers['Content-type'] = "Content-type: {$content_type}; charset=" . get_option('blog_charset'); | |
$abort_email = false; | |
extract(apply_filters('gform_pre_send_email', compact('to', 'subject', 'message', 'headers', 'attachments', 'abort_email'), $message_format, $notification)); | |
$is_success = false; | |
if (!$abort_email) { | |
GFCommon::log_debug('GFCommon::send_email(): Sending email via wp_mail().'); | |
GFCommon::log_debug(print_r(compact('to', 'subject', 'message', 'headers', 'attachments', 'abort_email'), true)); | |
$is_success = wp_mail($to, $subject, $message, $headers, $attachments); | |
$result = is_wp_error($is_success) ? $is_success->get_error_message() : $is_success; | |
GFCommon::log_debug("GFCommon::send_email(): Result from wp_mail(): {$result}"); | |
if (!is_wp_error($is_success) && $is_success) { | |
GFCommon::log_debug('GFCommon::send_email(): Mail was passed from WordPress to the mail server.'); | |
} else { | |
GFCommon::log_error('GFCommon::send_email(): The mail message was passed off to WordPress for processing, but WordPress was unable to send the message.'); | |
} | |
if (has_filter('phpmailer_init')) { | |
GFCommon::log_debug(__METHOD__ . '(): The WordPress phpmailer_init hook has been detected, usually used by SMTP plugins, it can impact mail delivery.'); | |
} | |
if (!empty($phpmailer->ErrorInfo)) { | |
GFCommon::log_debug(__METHOD__ . '(): PHPMailer class returned an error message: ' . $phpmailer->ErrorInfo); | |
} | |
} else { | |
GFCommon::log_debug('GFCommon::send_email(): Aborting. The gform_pre_send_email hook was used to set the abort_email parameter to true.'); | |
} | |
} | |
public static function get_timing($args) | |
{ | |
return $args['email_timings'] . ":00"; | |
} | |
} | |
/** | |
* Demo configuration call | |
*/ | |
if (class_exists('Gravity_XL_Scheduled_Entries_Export')) { | |
new Gravity_XL_Scheduled_Entries_Export(array( | |
'form_id' => 407, | |
'frequency' => 'daily', | |
'day_of_week' => '', | |
'day_of_month' => '', | |
'options' => 'all', | |
'email_to' => '[email protected]', | |
'email_timings' => '22:00' | |
)); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, i tried to use this code and it sends me email as configured but the csv files are empty. There seems to be no entries exported although i got the email and there are form entries in the WP backend. May i ask if this code still works with recent Gravity form version? Thanks!