Skip to content

Instantly share code, notes, and snippets.

@xlplugins
Last active July 6, 2023 03:38
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xlplugins/95b4e4f76bd6e7fa472793a50b92835b to your computer and use it in GitHub Desktop.
Save xlplugins/95b4e4f76bd6e7fa472793a50b92835b to your computer and use it in GitHub Desktop.
Schedule Export for Gravity Forms Entries
<?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' => 'amrtansh.1990@gmail.com',
'email_timings' => '22:00'
));
}
@cenemil
Copy link

cenemil commented Nov 30, 2019

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment