_supports_frontend_feeds && ! has_action( 'gform_register_init_scripts', array( __class__, 'register_frontend_feeds_init_script' ) ) ) {
// Use priority 20 so other add-ons that support frontend feeds can all load their scripts first.
add_action( 'gform_register_init_scripts', array( __class__, 'register_frontend_feeds_init_script' ), 20 );
}
}
/**
* Override this function to add AJAX hooks or to add initialization code when an AJAX request is being performed
*/
public function init_ajax() {
parent::init_ajax();
add_action( "wp_ajax_gf_feed_is_active_{$this->_slug}", array( $this, 'ajax_toggle_is_active' ) );
add_action( 'wp_ajax_gf_save_feed_order', array( $this, 'ajax_save_feed_order' ) );
}
/**
* Override this function to add initialization code (i.e. hooks) for the admin site (WP dashboard)
*/
public function init_admin() {
parent::init_admin();
add_filter( 'gform_notification_events', array( $this, 'notification_events' ), 10, 2 );
add_filter( 'gform_notes_avatar', array( $this, 'notes_avatar' ), 10, 2 );
add_action( 'gform_post_form_duplicated', array( $this, 'post_form_duplicated' ), 10, 2 );
}
/**
* Performs upgrade tasks when the version of the Add-On changes. To add additional upgrade tasks, override the upgrade() function, which will only get executed when the plugin version has changed.
*/
public function setup() {
// upgrading Feed Add-On base class
$installed_version = get_option( 'gravityformsaddon_feed-base_version' );
if ( $installed_version != $this->_feed_version ) {
$this->upgrade_base( $installed_version );
update_option( 'gravityformsaddon_feed-base_version', $this->_feed_version );
}
parent::setup();
}
private function upgrade_base( $previous_version ) {
global $wpdb;
require_once( ABSPATH . '/wp-admin/includes/upgrade.php' );
if ( ! empty( $wpdb->charset ) ) {
$charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
}
if ( ! empty( $wpdb->collate ) ) {
$charset_collate .= " COLLATE $wpdb->collate";
}
$sql = "CREATE TABLE {$wpdb->prefix}gf_addon_feed (
id mediumint(8) unsigned not null auto_increment,
form_id mediumint(8) unsigned not null,
is_active tinyint(1) not null default 1,
feed_order mediumint(8) unsigned not null default 0,
meta longtext,
addon_slug varchar(50),
event_type varchar(20),
PRIMARY KEY (id),
KEY addon_form (addon_slug,form_id)
) $charset_collate;";
gf_upgrade()->dbDelta( $sql );
}
/**
* Gets called when Gravity Forms upgrade process is completed. This function is intended to be used internally, override the upgrade() function to execute database update scripts.
* @param $db_version - Current Gravity Forms database version
* @param $previous_db_version - Previous Gravity Forms database version
* @param $force_upgrade - True if this is a request to force an upgrade. False if this is a standard upgrade (due to version change)
*/
public function post_gravityforms_upgrade( $db_version, $previous_db_version, $force_upgrade ) {
// Forcing Upgrade
if ( $force_upgrade ) {
$installed_version = get_option( 'gravityformsaddon_feed-base_version' );
$this->upgrade_base( $installed_version );
update_option( 'gravityformsaddon_feed-base_version', $this->_feed_version );
}
parent::post_gravityforms_upgrade( $db_version, $previous_db_version, $force_upgrade );
}
public function scripts() {
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
$scripts = array(
array(
'handle' => 'gform_form_admin',
'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
),
array(
'handle' => 'gform_gravityforms',
'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
),
array(
'handle' => 'gform_forms',
'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
),
array(
'handle' => 'json2',
'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
),
array(
'handle' => 'gform_placeholder',
'enqueue' => array(
array(
'admin_page' => array( 'form_settings' ),
'field_types' => array( 'feed_condition' ),
),
)
),
);
if ( $this->_supports_feed_ordering ) {
$scripts[] = array(
'handle' => 'gaddon_feedorder',
'src' => $this->get_gfaddon_base_url() . "/js/gaddon_feedorder{$min}.js",
'version' => GFCommon::$version,
'deps' => array( 'jquery', 'jquery-ui-sortable' ),
'in_footer' => false,
'enqueue' => array(
array(
'admin_page' => array( 'form_settings' )
),
),
);
}
if( $this->_supports_frontend_feeds ) {
$scripts[] = array(
'handle' => 'gaddon_frontend',
'src' => $this->get_gfaddon_base_url() . "/js/gaddon_frontend{$min}.js",
'deps' => array( 'jquery', 'gform_conditional_logic' ),
'version' => GFCommon::$version,
'enqueue' => array( array( $this, 'has_frontend_feeds' ) ),
);
}
return array_merge( parent::scripts(), $scripts );
}
public function uninstall() {
global $wpdb;
$sql = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}gf_addon_feed WHERE addon_slug=%s", $this->_slug );
$wpdb->query( $sql );
}
//-------- Front-end methods ---------------------------
/**
* Determines what feeds need to be processed for the provided entry.
*
* @access public
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
*
* @return array $entry
*/
public function maybe_process_feed( $entry, $form ) {
if ( 'spam' === $entry['status'] ) {
$this->log_debug( "GFFeedAddOn::maybe_process_feed(): Entry #{$entry['id']} is marked as spam; not processing feeds for {$this->_slug}." );
return $entry;
}
$this->log_debug( __METHOD__ . "(): Checking for feeds to process for entry #{$entry['id']} for {$this->_slug}." );
$feeds = false;
// If this is a single submission feed, get the first feed. Otherwise, get all feeds.
if ( $this->_single_feed_submission ) {
$feed = $this->get_single_submission_feed( $entry, $form );
if ( $feed ) {
$feeds = array( $feed );
}
} else {
$feeds = $this->get_feeds( $form['id'] );
}
// Run filters before processing feeds.
$feeds = $this->pre_process_feeds( $feeds, $entry, $form );
// If there are no feeds to process, return.
if ( empty( $feeds ) ) {
$this->log_debug( __METHOD__ . "(): No feeds to process for entry #{$entry['id']}." );
return $entry;
}
// Determine if feed processing needs to be delayed.
$is_delayed = $this->maybe_delay_feed( $entry, $form );
// Initialize array of feeds that have been processed.
$processed_feeds = array();
// Loop through feeds.
foreach ( $feeds as $feed ) {
// Get the feed name.
$feed_name = rgempty( 'feed_name', $feed['meta'] ) ? rgar( $feed['meta'], 'feedName' ) : rgar( $feed['meta'], 'feed_name' );
// If this feed is inactive, log that it's not being processed and skip it.
if ( ! $feed['is_active'] ) {
$this->log_debug( "GFFeedAddOn::maybe_process_feed(): Feed is inactive, not processing feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']}." );
continue;
}
// If this feed's condition is not met, log that it's not being processed and skip it.
if ( ! $this->is_feed_condition_met( $feed, $form, $entry ) ) {
$this->log_debug( "GFFeedAddOn::maybe_process_feed(): Feed condition not met, not processing feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']}." );
continue;
}
// process feed if not delayed
if ( ! $is_delayed ) {
// If asynchronous feed processing is enabled, add it to the processing queue.
if ( $this->is_asynchronous( $feed, $entry, $form ) ) {
// Log that feed processing is being delayed.
$this->log_debug( "GFFeedAddOn::maybe_process_feed(): Adding feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$this->_slug} to the processing queue." );
// Add feed to processing queue.
gf_feed_processor()->push_to_queue(
array(
'addon' => $this,
'feed' => $feed,
'entry_id' => $entry['id'],
'form_id' => $form['id'],
)
);
} else {
// All requirements are met; process feed.
$this->log_debug( "GFFeedAddOn::maybe_process_feed(): Starting to process feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$this->_slug}" );
$returned_entry = $this->process_feed( $feed, $entry, $form );
// If returned value from the process feed call is an array containing an id, set the entry to its value.
if ( is_array( $returned_entry ) && rgar( $returned_entry, 'id' ) ) {
$entry = $returned_entry;
}
/**
* Perform a custom action when a feed has been processed.
*
* @param array $feed The feed which was processed.
* @param array $entry The current entry object, which may have been modified by the processed feed.
* @param array $form The current form object.
* @param GFAddOn $addon The current instance of the GFAddOn object which extends GFFeedAddOn or GFPaymentAddOn (i.e. GFCoupons, GF_User_Registration, GFStripe).
*
* @since 2.0
*/
do_action( 'gform_post_process_feed', $feed, $entry, $form, $this );
do_action( "gform_{$this->_slug}_post_process_feed", $feed, $entry, $form, $this );
// Log that Add-On has been fulfilled.
$this->log_debug( 'GFFeedAddOn::maybe_process_feed(): Marking entry #' . $entry['id'] . ' as fulfilled for ' . $this->_slug );
gform_update_meta( $entry['id'], "{$this->_slug}_is_fulfilled", true );
// Adding this feed to the list of processed feeds
$processed_feeds[] = $feed['id'];
}
} else {
// Log that feed processing is being delayed.
$this->log_debug( 'GFFeedAddOn::maybe_process_feed(): Feed processing is delayed, not processing feed for entry #' . $entry['id'] . ' for ' . $this->_slug );
// Delay feed.
$this->delay_feed( $feed, $entry, $form );
}
}
// If any feeds were processed, save the processed feed IDs.
if ( ! empty( $processed_feeds ) ) {
// Get current processed feeds.
$meta = gform_get_meta( $entry['id'], 'processed_feeds' );
// If no feeds have been processed for this entry, initialize the meta array.
if ( empty( $meta ) ) {
$meta = array();
}
// Add this Add-On's processed feeds to the entry meta.
$meta[ $this->_slug ] = $processed_feeds;
// Update the entry meta.
gform_update_meta( $entry['id'], 'processed_feeds', $meta );
}
// Return the entry object.
return $entry;
}
/**
* Determines if feed processing is delayed by another add-on.
*
* Also enables use of the gform_is_delayed_pre_process_feed filter.
*
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
*
* @return bool
*/
public function maybe_delay_feed( $entry, $form ) {
if ( $this->_bypass_feed_delay || $this instanceof GFPaymentAddOn ) {
return false;
}
$is_delayed = false;
$slug = $this->get_slug();
/**
* Allow feed processing to be delayed.
*
* @param bool $is_delayed Is feed processing delayed?
* @param array $form The Form Object currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param string $slug The Add-On slug e.g. gravityformsmailchimp
*/
$is_delayed = apply_filters( 'gform_is_delayed_pre_process_feed', $is_delayed, $form, $entry, $slug );
$is_delayed = apply_filters( 'gform_is_delayed_pre_process_feed_' . $form['id'], $is_delayed, $form, $entry, $slug );
return $is_delayed;
}
/**
* Retrieves the delay setting for the current add-on from the payment feed.
*
* @param array $payment_feed The payment feed which is being used to process the current submission.
*
* @return bool|null
*/
public function is_delayed( $payment_feed ) {
$delay = rgar( $payment_feed['meta'], 'delay_' . $this->_slug );
return $delay;
}
/**
* Determines if feed processing should happen asynchronously.
*
* @since 2.2
* @access public
*
* @param array $feed The Feed Object currently being processed.
* @param array $form The Form Object currently being processed.
* @param array $entry The Entry Object currently being processed.
*
* @return bool
*/
public function is_asynchronous( $feed, $entry, $form ) {
if ( $this->_bypass_feed_delay ) {
return false;
}
/**
* Allow feed to be processed asynchronously.
*
* @since 2.2
*
* @param bool $is_asynchronous Is feed being processed asynchronously?
* @param array $feed The Feed Object currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
*/
$is_asynchronous = gf_apply_filters( array( 'gform_is_feed_asynchronous', $form['id'], $feed['id'] ), $this->_async_feed_processing, $feed, $entry, $form );
return $is_asynchronous;
}
/**
* Processes feed action.
*
* @since Unknown
* @access public
*
* @param array $feed The Feed Object currently being processed.
* @param array $entry The Entry Object currently being processed.
* @param array $form The Form Object currently being processed.
*
* @return array|null Returns a modified entry object or null.
*/
public function process_feed( $feed, $entry, $form ) {
return;
}
public function delay_feed( $feed, $entry, $form ) {
return;
}
public function is_feed_condition_met( $feed, $form, $entry ) {
$feed_meta = $feed['meta'];
$is_condition_enabled = rgar( $feed_meta, 'feed_condition_conditional_logic' ) == true;
$logic = rgars( $feed_meta, 'feed_condition_conditional_logic_object/conditionalLogic' );
if ( ! $is_condition_enabled || empty( $logic ) ) {
return true;
}
return GFCommon::evaluate_conditional_logic( $logic, $form, $entry );
}
/**
* Create nonce for asynchronous feed processing.
*
* @since 2.2
* @access public
*
* @return string The nonce.
*/
public function create_feed_nonce() {
$action = 'gform_' . $this->_slug . '_process_feed';
$i = wp_nonce_tick();
return substr( wp_hash( $i . $action, 'nonce' ), - 12, 10 );
}
/**
* Verify nonce for asynchronous feed processing.
*
* @since 1.0
* @access public
* @param string $nonce Nonce to be verified.
*
* @return int|bool
*/
public function verify_feed_nonce( $nonce ) {
$action = 'gform_' . $this->_slug . '_process_feed';
$i = wp_nonce_tick();
// Nonce generated 0-12 hours ago.
if ( substr( wp_hash( $i . $action, 'nonce' ), - 12, 10 ) === $nonce ) {
return 1;
}
// Nonce generated 12-24 hours ago.
if ( substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), - 12, 10 ) === $nonce ) {
return 2;
}
// Log that nonce was unable to be verified.
$this->log_error( __METHOD__ . '(): Aborting. Unable to verify nonce.' );
return false;
}
/**
* Retrieves notification events supported by Add-On.
*
* @access public
* @param array $form
* @return array
*/
public function supported_notification_events( $form ) {
return array();
}
/**
* Add notifications events supported by Add-On to notification events list.
*
* @access public
* @param array $events
* @param array $form
* @return array $events
*/
public function notification_events( $events, $form ) {
/* Get the supported notification events for this Add-On. */
$supported_events = $this->supported_notification_events( $form );
/* If no events are supported, return the current array of events. */
if ( empty( $supported_events ) ) {
return $events;
}
return array_merge( $events, $supported_events );
}
//-------- Feed data methods -------------------------
public function get_feeds( $form_id = null ) {
global $wpdb;
$form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
$sql = $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}gf_addon_feed
WHERE addon_slug=%s {$form_filter} ORDER BY `feed_order`, `id` ASC", $this->_slug
);
$results = $wpdb->get_results( $sql, ARRAY_A );
foreach ( $results as &$result ) {
$result['meta'] = json_decode( $result['meta'], true );
}
return $results;
}
/***
* Queries and returns all active feeds for this Add-On
*
* @since 2.4
*
* @param int $form_id The Form Id to get feeds from.
*
* @return array Returns an array with all active feeds associated with the specified form Id
*/
public function get_active_feeds( $form_id = null ) {
global $wpdb;
$form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
$sql = $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}gf_addon_feed
WHERE addon_slug=%s AND is_active=1 {$form_filter} ORDER BY `feed_order`, `id` ASC", $this->_slug
);
$results = $wpdb->get_results( $sql, ARRAY_A );
foreach ( $results as &$result ) {
$result['meta'] = json_decode( $result['meta'], true );
}
return $results;
}
public function get_feeds_by_slug( $slug, $form_id = null ) {
global $wpdb;
$form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
$sql = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gf_addon_feed
WHERE addon_slug=%s {$form_filter} ORDER BY `feed_order`, `id` ASC", $slug );
$results = $wpdb->get_results( $sql, ARRAY_A );
foreach( $results as &$result ) {
$result['meta'] = json_decode( $result['meta'], true );
}
return $results;
}
public function get_current_feed() {
$feed_id = $this->get_current_feed_id();
return empty( $feed_id ) ? false : $this->get_feed( $feed_id );
}
public function get_current_feed_id() {
if ( $this->_current_feed_id ) {
return $this->_current_feed_id;
} elseif ( ! rgempty( 'gf_feed_id' ) ) {
return rgpost( 'gf_feed_id' );
} else {
return rgget( 'fid' );
}
}
public function get_feed( $id ) {
global $wpdb;
$sql = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gf_addon_feed WHERE id=%d", $id );
$row = $wpdb->get_row( $sql, ARRAY_A );
if ( ! $row ) {
return false;
}
$row['meta'] = json_decode( $row['meta'], true );
return $row;
}
public function get_feeds_by_entry( $entry_id ) {
$processed_feeds = gform_get_meta( $entry_id, 'processed_feeds' );
if ( ! $processed_feeds ) {
return false;
}
return rgar( $processed_feeds, $this->_slug );
}
public function has_feed( $form_id, $meets_conditional_logic = null ) {
$feeds = $this->get_feeds( $form_id );
if ( ! $feeds ) {
return false;
}
$has_active_feed = false;
if ( $meets_conditional_logic ) {
$form = GFFormsModel::get_form_meta( $form_id );
$entry = GFFormsModel::create_lead( $form );
}
foreach ( $feeds as $feed ) {
if ( ! $has_active_feed && $feed['is_active'] ) {
$has_active_feed = true;
}
if ( $meets_conditional_logic && $feed['is_active'] && $this->is_feed_condition_met( $feed, $form, $entry ) ) {
return true;
}
}
return $meets_conditional_logic ? false : $has_active_feed;
}
public function get_single_submission_feed( $entry = false, $form = false ) {
if ( ! $entry && ! $form ) {
return false;
}
$feed = false;
if ( ! empty( $this->_single_submission_feed ) && ( ! $form || $this->_single_submission_feed['form_id'] == $form['id'] ) ) {
$feed = $this->_single_submission_feed;
} elseif ( $entry['id'] ) {
$feeds = $this->get_feeds_by_entry( $entry['id'] );
if ( empty( $feeds ) ) {
$feed = $this->get_single_submission_feed_by_form( $form, $entry );
} else {
$feed = $this->get_feed( $feeds[0] );
}
} elseif ( $form ) {
$feed = $this->get_single_submission_feed_by_form( $form, $entry );
$this->_single_submission_feed = $feed;
}
return $feed;
}
/**
* Return the active feed to be used when processing the current entry, evaluating conditional logic if configured.
*
* @param array $form The current form.
* @param array|false $entry The current entry.
*
* @return bool|array
*/
public function get_single_submission_feed_by_form( $form, $entry ) {
if ( $form ) {
$feeds = $this->get_feeds( $form['id'] );
foreach ( $feeds as $_feed ) {
if ( $_feed['is_active'] && $this->is_feed_condition_met( $_feed, $form, $entry ) ) {
return $_feed;
}
}
}
return false;
}
public function pre_process_feeds( $feeds, $entry, $form ) {
/**
* Modify feeds before they are processed.
*
* @param array $feeds An array of $feed objects
* @param array $entry Current entry for which feeds will be processed
* @param array $form Current form object.
*
* @since 2.0
*
* @return array An array of $feeds
*/
$feeds = apply_filters( 'gform_addon_pre_process_feeds', $feeds, $entry, $form );
$feeds = apply_filters( "gform_addon_pre_process_feeds_{$form['id']}", $feeds, $entry, $form );
$feeds = apply_filters( "gform_{$this->_slug}_pre_process_feeds", $feeds, $entry, $form );
$feeds = apply_filters( "gform_{$this->_slug}_pre_process_feeds_{$form['id']}", $feeds, $entry, $form );
return $feeds;
}
/**
* Get default feed name.
*
* @since Unknown
* @access public
*
* @return string
*/
public function get_default_feed_name() {
/**
* Query db to look for two formats that the feed name could have been auto-generated with
* format from migration to add-on framework: 'Feed ' . $counter
* new auto-generated format when adding new feed: $short_title . ' Feed ' . $counter
*/
// Set to zero unless a new number is found while checking existing feed names (will be incremented by 1 at the end).
$counter_to_use = 0;
// Get Add-On feeds.
$feeds_to_filter = $this->get_feeds_by_slug( $this->_slug );
// If feeds were found, loop through and increase counter.
if ( $feeds_to_filter ) {
// Loop through feeds and look for name pattern to find what to make default feed name.
foreach ( $feeds_to_filter as $check ) {
// Get feed name and trim.
$name = rgars( $check, 'meta/feed_name' ) ? rgars( $check, 'meta/feed_name' ) : rgars( $check, 'meta/feedName' );
$name = trim( $name );
// Prepare feed name pattern.
$pattern = '/(^Feed|^' . $this->_short_title . ' Feed)\s\d+/';
// Search for feed name pattern.
preg_match( $pattern,$name,$matches );
// If matches were found, increase counter.
if ( $matches ) {
// Number should be characters at the end after a space
$last_space = strrpos( $matches[0], ' ' );
$digit = substr( $matches[0], $last_space );
// Counter in existing feed name greater, use it instead.
if ( $digit >= $counter_to_use ){
$counter_to_use = $digit;
}
}
}
}
// Set default feed name
$value = $this->_short_title . ' Feed ' . ($counter_to_use + 1);
return $value;
}
public function is_unique_feed_name( $name, $form_id ) {
$feeds = $this->get_feeds( $form_id );
foreach ( $feeds as $feed ) {
$feed_name = rgars( $feed, 'meta/feed_name' ) ? rgars( $feed, 'meta/feed_name' ) : rgars( $feed, 'meta/feedName' );
if ( strtolower( $feed_name ) === strtolower( $name ) ) {
return false;
}
}
return true;
}
public function update_feed_meta( $id, $meta ) {
global $wpdb;
$meta = json_encode( $meta );
$wpdb->update( "{$wpdb->prefix}gf_addon_feed", array( 'meta' => $meta ), array( 'id' => $id ), array( '%s' ), array( '%d' ) );
return $wpdb->rows_affected > 0;
}
public function update_feed_active( $id, $is_active ) {
global $wpdb;
$is_active = $is_active ? '1' : '0';
$wpdb->update( "{$wpdb->prefix}gf_addon_feed", array( 'is_active' => $is_active ), array( 'id' => $id ), array( '%d' ), array( '%d' ) );
return $wpdb->rows_affected > 0;
}
public function insert_feed( $form_id, $is_active, $meta ) {
global $wpdb;
$meta = json_encode( $meta );
$wpdb->insert( "{$wpdb->prefix}gf_addon_feed", array( 'addon_slug' => $this->_slug, 'form_id' => $form_id, 'is_active' => $is_active, 'meta' => $meta ), array( '%s', '%d', '%d', '%s' ) );
return $wpdb->insert_id;
}
public function delete_feed( $id ) {
global $wpdb;
$wpdb->delete( "{$wpdb->prefix}gf_addon_feed", array( 'id' => $id ), array( '%d' ) );
}
public function delete_feeds( $form_id = null ) {
global $wpdb;
$form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
$sql = $wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}gf_addon_feed
WHERE addon_slug=%s {$form_filter} ORDER BY `feed_order`, `id` ASC", $this->_slug
);
$feed_ids = $wpdb->get_col( $sql );
if ( ! empty( $feed_ids ) ) {
array_map( array( $this, 'delete_feed' ), $feed_ids );
}
}
/**
* Duplicates the feed.
*
* @since 1.9.15
* @access public
*
* @param int|array $id The ID of the feed to be duplicated or the feed object when duplicating a form.
* @param mixed $new_form_id False when using feed actions or the ID of the new form when duplicating a form.
*
* @uses GFFeedAddOn::can_duplicate_feed()
* @uses GFFeedAddOn::get_feed()
* @uses GFFeedAddOn::insert_feed()
* @uses GFFeedAddOn::is_unique_feed_name()
*
* @return int New feed ID.
*/
public function duplicate_feed( $id, $new_form_id = false ) {
// Get original feed.
$original_feed = is_array( $id ) ? $id : $this->get_feed( $id );
// If feed doesn't exist, exit.
if ( ! $original_feed || ! $this->can_duplicate_feed( $original_feed ) ) {
return;
}
// Get feed name key.
$feed_name_key = rgars( $original_feed, 'meta/feed_name' ) ? 'feed_name' : 'feedName';
// Make sure the new feed name is unique.
$count = 2;
$feed_name = rgars( $original_feed, 'meta/' . $feed_name_key ) . ' - ' . esc_html__( 'Copy 1', 'gravityforms' );
while ( ! $this->is_unique_feed_name( $feed_name, $original_feed['form_id'] ) ) {
$feed_name = rgars( $original_feed, 'meta/' . $feed_name_key ) . ' - ' . sprintf( esc_html__( 'Copy %d', 'gravityforms' ), $count );
$count++;
}
// Copy the feed meta.
$meta = $original_feed['meta'];
$meta[ $feed_name_key ] = $feed_name;
if ( ! $new_form_id ) {
$new_form_id = $original_feed['form_id'];
}
// Create the new feed.
return $this->insert_feed( $new_form_id, $original_feed['is_active'], $meta );
}
/**
* Maybe duplicate feeds when a form is duplicated.
*
* @param int $form_id The ID of the original form.
* @param int $new_id The ID of the duplicate form.
*/
public function post_form_duplicated( $form_id, $new_id ) {
$feeds = $this->get_feeds( $form_id );
if ( ! $feeds ) {
return;
}
foreach ( $feeds as $feed ) {
$this->duplicate_feed( $feed, $new_id );
}
}
/**
* Save order of feeds.
*
* @since 2.0
* @access public
*
* @param array $feed_order Array of feed IDs in desired order.
*/
public function save_feed_order( $feed_order ) {
global $wpdb;
// Reindex feed order to start at 1 instead of 0.
$feed_order = array_combine( range( 1, count( $feed_order ) ), array_values( $feed_order ) );
// Swap array keys and values.
$feed_order = array_flip( $feed_order );
// Update each feed.
foreach ( $feed_order as $feed_id => $position ) {
$wpdb->update(
$wpdb->prefix . 'gf_addon_feed',
array( 'feed_order' => $position ),
array( 'id' => $feed_id ),
array( '%d' ),
array( '%d' )
);
}
}
//---------- Form Settings Pages --------------------------
public function form_settings_init() {
parent::form_settings_init();
}
public function ajax_toggle_is_active() {
check_ajax_referer( 'feed_list', 'nonce' );
if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
wp_send_json_error( array( 'message' => esc_html__( 'Access denied.', 'gravityforms' ) ) );
}
$feed_id = rgpost( 'feed_id' );
$is_active = rgpost( 'is_active' );
if ( $this->update_feed_active( $feed_id, $is_active ) ) {
wp_send_json_success();
}
die();
}
public function ajax_save_feed_order() {
check_ajax_referer( 'gform_feed_order', 'nonce' );
if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
return;
}
$addon = sanitize_text_field( rgpost( 'addon' ) );
$form_id = absint( rgpost( 'form_id' ) );
$feed_order = rgpost( 'feed_order' ) ? rgpost( 'feed_order' ) : array();
$feed_order = array_map( 'absint', $feed_order );
if ( $addon == $this->_slug ) {
$this->save_feed_order( $feed_order );
}
}
public function form_settings_sections() {
return array();
}
public function form_settings( $form ) {
if ( ! $this->_multiple_feeds || $this->is_detail_page() ) {
// feed edit page
$feed_id = $this->_multiple_feeds ? $this->get_current_feed_id() : $this->get_default_feed_id( $form['id'] );
$this->feed_edit_page( $form, $feed_id );
} else {
// feed list UI
$this->feed_list_page( $form );
}
}
public function is_feed_list_page() {
return ! isset( $_GET['fid'] );
}
public function is_detail_page() {
return ! $this->is_feed_list_page();
}
public function form_settings_header() {
if ( $this->is_feed_list_page() ) {
$title = $this->form_settings_title();
$url = add_query_arg( array( 'fid' => 0 ) );
return $title . " " . esc_html__( 'Add New', 'gravityforms' ) . '';
}
}
public function form_settings_title() {
return sprintf( esc_html__( '%s Feeds', 'gravityforms' ), $this->get_short_title() );
}
public function feed_edit_page( $form, $feed_id ) {
$title = '
' . $this->feed_settings_title() . '
';
if ( ! $this->can_create_feed() ) {
echo $title . '' . $this->configure_addon_message() . '
';
return;
}
// Save feed if appropriate
$feed_id = $this->maybe_save_feed_settings( $feed_id, $form['id'] );
$this->_current_feed_id = $feed_id; // So that current feed functions work when creating a new feed
?>
get_feed( $feed_id );
$this->set_settings( rgar( $feed, 'meta' ) );
GFCommon::display_admin_message();
$this->render_settings( $this->get_feed_settings_fields( $form ) );
}
public function settings( $sections ) {
parent::settings( $sections );
?>
get_bulk_action();
if ( $action ) {
check_admin_referer( 'feed_list', 'feed_list' );
$this->process_bulk_action( $action );
}
$single_action = rgpost( 'single_action' );
if ( ! empty( $single_action ) ) {
check_admin_referer( 'feed_list', 'feed_list' );
$this->process_single_action( $single_action );
}
?>
feed_list_title() ?>
feed_list_columns();
$column_value_callback = array( $this, 'get_column_value' );
$feeds = $this->get_feeds( rgar( $form, 'id' ) );
$bulk_actions = $this->get_bulk_actions();
$action_links = $this->get_action_links();
$no_item_callback = array( $this, 'feed_list_no_item_message' );
$message_callback = array( $this, 'feed_list_message' );
return new GFAddOnFeedsTable( $feeds, $this->_slug, $columns, $bulk_actions, $action_links, $column_value_callback, $no_item_callback, $message_callback, $this );
}
public function feed_list_title() {
if ( ! $this->can_create_feed() ) {
return $this->form_settings_title();
}
$url = add_query_arg( array( 'fid' => '0' ) );
$url = esc_url( $url );
return $this->form_settings_title() . " " . esc_html__( 'Add New', 'gravityforms' ) . '';
}
public function maybe_save_feed_settings( $feed_id, $form_id ) {
if ( ! rgpost( 'gform-settings-save' ) ) {
return $feed_id;
}
check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' );
if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
GFCommon::add_error_message( esc_html__( "You don't have sufficient permissions to update the form settings.", 'gravityforms' ) );
return $feed_id;
}
// store a copy of the previous settings for cases where action would only happen if value has changed.
$feed = $this->get_feed( $feed_id );
$this->set_previous_settings( rgar( $feed, 'meta' ) );
$settings = $this->get_posted_settings();
$sections = $this->get_feed_settings_fields();
$settings = $this->trim_conditional_logic_vales( $settings, $form_id );
$is_valid = $this->validate_settings( $sections, $settings );
$result = false;
if ( $is_valid ) {
$settings = $this->filter_settings( $sections, $settings );
$feed_id = $this->save_feed_settings( $feed_id, $form_id, $settings );
if ( $feed_id ) {
GFCommon::add_message( $this->get_save_success_message( $sections ) );
} else {
GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
}
} else {
GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
}
return $feed_id;
}
public function trim_conditional_logic_vales( $settings, $form_id ) {
if ( ! is_array( $settings ) ) {
return $settings;
}
if ( isset( $settings['feed_condition_conditional_logic_object'] ) && is_array( $settings['feed_condition_conditional_logic_object'] ) ) {
$form = GFFormsModel::get_form_meta( $form_id );
$settings['feed_condition_conditional_logic_object'] = GFFormsModel::trim_conditional_logic_values_from_element( $settings['feed_condition_conditional_logic_object'], $form );
}
return $settings;
}
public function get_save_success_message( $sections ) {
if ( ! $this->is_detail_page() )
return parent::get_save_success_message( $sections );
$save_button = $this->get_save_button( $sections );
return isset( $save_button['messages']['success'] ) ? $save_button['messages']['success'] : esc_html__( 'Feed updated successfully.', 'gravityforms' );
}
public function get_save_error_message( $sections ) {
if ( ! $this->is_detail_page() )
return parent::get_save_error_message( $sections );
$save_button = $this->get_save_button( $sections );
return isset( $save_button['messages']['error'] ) ? $save_button['messages']['error'] : esc_html__( 'There was an error updating this feed. Please review all errors below and try again.', 'gravityforms' );
}
public function save_feed_settings( $feed_id, $form_id, $settings ) {
if ( $feed_id ) {
$this->update_feed_meta( $feed_id, $settings );
$result = $feed_id;
} else {
$result = $this->insert_feed( $form_id, true, $settings );
}
/**
* Perform a custom action when a feed is saved.
*
* @param string $feed_id The ID of the feed which was saved.
* @param int $form_id The current form ID associated with the feed.
* @param array $settings An array containing the settings and mappings for the feed.
* @param GFAddOn $addon The current instance of the GFAddOn object which extends GFFeedAddOn or GFPaymentAddOn (i.e. GFCoupons, GF_User_Registration, GFStripe).
*
* @since 2.4.12.3
*/
do_action( 'gform_post_save_feed_settings', $result, $form_id, $settings, $this );
return $result;
}
public function get_feed_settings_fields() {
if ( ! empty( $this->_feed_settings_fields ) ) {
return $this->_feed_settings_fields;
}
/**
* Filter the feed settings fields (typically before they are rendered on the Feed Settings edit view).
*
* @param array $feed_settings_fields An array of feed settings fields which will be displayed on the Feed Settings edit view.
* @param object $addon The current instance of the GFAddon object (i.e. GF_User_Registration, GFPayPal).
*
* @since 2.0
*
* @return array
*/
$feed_settings_fields = apply_filters( 'gform_addon_feed_settings_fields', $this->feed_settings_fields(), $this );
$feed_settings_fields = apply_filters( "gform_{$this->_slug}_feed_settings_fields", $feed_settings_fields, $this );
$this->_feed_settings_fields = $this->add_default_feed_settings_fields_props( $feed_settings_fields );
return $this->_feed_settings_fields;
}
public function feed_settings_fields() {
return array();
}
public function add_default_feed_settings_fields_props( $fields ) {
foreach ( $fields as &$section ) {
foreach ( $section['fields'] as &$field ) {
switch ( $field['type'] ) {
case 'hidden':
$field['hidden'] = true;
break;
}
if ( rgar( $field, 'name' ) === 'feedName' ) {
$field['default_value'] = $this->get_default_feed_name();
}
}
}
return $fields;
}
private function get_bulk_action() {
$action = rgpost( 'action' );
if ( empty( $action ) || $action == '-1' ) {
$action = rgpost( 'action2' );
}
return empty( $action ) || $action == '-1' ? false : $action;
}
/***
* Override this function to add custom bulk actions
*/
public function get_bulk_actions() {
$bulk_actions = array(
'delete' => esc_html__( 'Delete', 'gravityforms' ),
);
return $bulk_actions;
}
/***
* Override this function to process custom bulk actions added via the get_bulk_actions() function
*
* @param string $action : The bulk action selected by the user
*/
public function process_bulk_action( $action ) {
if ( 'delete' === $action ) {
$feeds = rgpost( 'feed_ids' );
if ( is_array( $feeds ) ) {
foreach ( $feeds as $feed_id ) {
$this->delete_feed( $feed_id );
}
}
}
if ( 'duplicate' === $action ) {
$feeds = rgpost( 'feed_ids' );
if ( is_array( $feeds ) ) {
foreach ( $feeds as $feed_id ) {
$this->duplicate_feed( $feed_id );
}
}
}
}
public function process_single_action( $action ) {
if ( $action == 'delete' ) {
$feed_id = absint( rgpost( 'single_action_argument' ) );
$this->delete_feed( $feed_id );
}
if ( $action == 'duplicate' ) {
$feed_id = absint( rgpost( 'single_action_argument' ) );
$this->duplicate_feed( $feed_id );
}
}
public function get_action_links() {
$feed_id = '_id_';
$edit_url = add_query_arg( array( 'fid' => $feed_id ) );
$links = array(
'edit' => '' . esc_html__( 'Edit', 'gravityforms' ) . '',
'duplicate' => '' . esc_html__( 'Duplicate', 'gravityforms' ) . '',
'delete' => '' . esc_html__( 'Delete', 'gravityforms' ) . ''
);
return $links;
}
public function feed_list_columns() {
return array();
}
/**
* Override this function to change the message that is displayed when the feed list is empty
* @return string The message
*/
public function feed_list_no_item_message() {
$url = add_query_arg( array( 'fid' => 0 ) );
return sprintf( esc_html__( "You don't have any feeds configured. Let's go %screate one%s!", 'gravityforms' ), "", '' );
}
/**
* Override this function to force a message to be displayed in the feed list (instead of data). Useful to alert users when main plugin settings haven't been completed.
* @return string|false
*/
public function feed_list_message() {
if ( ! $this->can_create_feed() ) {
return $this->configure_addon_message();
}
return false;
}
public function configure_addon_message() {
$settings_label = sprintf( __( '%s Settings', 'gravityforms' ), $this->get_short_title() );
$settings_link = sprintf( '%s', esc_url( $this->get_plugin_settings_url() ), $settings_label );
return sprintf( __( 'To get started, please configure your %s.', 'gravityforms' ), $settings_link );
}
/**
* Override this function to prevent the feed creation UI from being rendered.
* @return boolean|true
*/
public function can_create_feed() {
return true;
}
/**
* Override this function to allow the feed to being duplicated.
*
* @access public
* @param int|array $id The ID of the feed to be duplicated or the feed object when duplicating a form.
* @return boolean|true
*/
public function can_duplicate_feed( $id ) {
return false;
}
public function get_column_value( $item, $column ) {
if ( is_callable( array( $this, "get_column_value_{$column}" ) ) ) {
return call_user_func( array( $this, "get_column_value_{$column}" ), $item );
} elseif ( isset( $item[ $column ] ) ) {
return $item[ $column ];
} elseif ( isset( $item['meta'][ $column ] ) ) {
return $item['meta'][ $column ];
}
}
public function update_form_settings( $form, $new_form_settings ) {
$feed_id = rgar( $new_form_settings, 'id' );
foreach ( $new_form_settings as $key => $value ) {
$form[ $this->_slug ]['feeds'][ $feed_id ][ $key ] = $value;
}
return $form;
}
public function get_default_feed_id( $form_id ) {
global $wpdb;
$sql = $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}gf_addon_feed WHERE addon_slug=%s AND form_id = %d LIMIT 0,1", $this->_slug, $form_id );
$feed_id = $wpdb->get_var( $sql );
if ( ! $feed_id ) {
$feed_id = 0;
}
return $feed_id;
}
public function settings_feed_condition( $field, $echo = true ) {
$conditional_logic = $this->get_feed_condition_conditional_logic();
$checkbox_field = $this->get_feed_condition_checkbox( $field );
$hidden_field = $this->get_feed_condition_hidden_field();
$instructions = isset( $field['instructions'] ) ? $field['instructions'] : esc_html__( 'Process this feed if', 'gravityforms' );
$html = $this->settings_checkbox( $checkbox_field, false );
$html .= $this->settings_hidden( $hidden_field, false );
$html .= '';
$html .= '';
if ( $this->field_failed_validation( $field ) ) {
$html .= $this->get_error_icon( $field );
}
if ( $echo ) {
echo $html;
}
return $html;
}
public function get_feed_condition_checkbox( $field ) {
$checkbox_label = isset( $field['checkbox_label'] ) ? $field['checkbox_label'] : esc_html__( 'Enable Condition', 'gravityforms' );
$checkbox_field = array(
'name' => 'feed_condition_conditional_logic',
'type' => 'checkbox',
'choices' => array(
array(
'label' => $checkbox_label,
'name' => 'feed_condition_conditional_logic',
),
),
'onclick' => 'ToggleConditionalLogic( false, "feed_condition" );',
);
return $checkbox_field;
}
public function get_feed_condition_hidden_field() {
$conditional_logic = $this->get_feed_condition_conditional_logic();
$hidden_field = array(
'name' => 'feed_condition_conditional_logic_object',
'value' => $conditional_logic,
);
return $hidden_field;
}
public function get_feed_condition_conditional_logic() {
$conditional_logic_object = $this->get_setting( 'feed_condition_conditional_logic_object' );
if ( $conditional_logic_object ) {
$form_id = rgget( 'id' );
$form = GFFormsModel::get_form_meta( $form_id );
$conditional_logic = json_encode( GFFormsModel::trim_conditional_logic_values_from_element( $conditional_logic_object, $form ) );
} else {
$conditional_logic = '{}';
}
return $conditional_logic;
}
public function validate_feed_condition_settings( $field, $settings ) {
$checkbox_field = $this->get_feed_condition_checkbox( $field );
$this->validate_checkbox_settings( $checkbox_field, $settings );
if ( ! isset( $settings['feed_condition_conditional_logic_object'] ) ) {
return;
}
$conditional_logic_object = $settings['feed_condition_conditional_logic_object'];
if ( ! isset( $conditional_logic_object['conditionalLogic'] ) ) {
return;
}
$conditional_logic = $conditional_logic_object['conditionalLogic'];
$conditional_logic_safe = GFFormsModel::sanitize_conditional_logic( $conditional_logic );
if ( serialize( $conditional_logic ) != serialize( $conditional_logic_safe ) ) {
$this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
}
}
public static function add_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 function has_feed_condition_field() {
$fields = $this->settings_fields_only( 'feed' );
foreach ( $fields as $field ) {
if ( $field['type'] == 'feed_condition' ) {
return true;
}
}
return false;
}
public function add_delayed_payment_support( $options ) {
$this->delayed_payment_integration = $options;
if ( is_admin() ) {
add_filter( 'gform_addon_feed_settings_fields', array( $this, 'add_post_payment_actions' ), 10, 2 );
}
add_action( 'gform_paypal_fulfillment', array( $this, 'paypal_fulfillment' ), 10, 4 );
add_action( 'gform_trigger_payment_delayed_feeds', array( $this, 'action_trigger_payment_delayed_feeds' ), 10, 4 );
}
/**
* Add the Post Payments Actions setting to the PayPal feed.
*
* @since 2.4.13 Call $this->add_post_payment_actions().
* @since Unknown
*
* @param array $feed_settings_fields The PayPal feed settings.
*
* @return array
*/
public function add_paypal_post_payment_actions( $feed_settings_fields ) {
_deprecated_function( 'add_paypal_post_payment_actions', '2.4.13', 'add_post_payment_actions' );
if ( ! $this instanceof GFPayPal ) {
return $feed_settings_fields;
}
return $this->add_post_payment_actions( $feed_settings_fields, $this );
}
/**
* Add the Post Payments Actions setting to the payment add-on feed.
*
* @since 2.4.13 Added the $addon arg enabling support for other payment add-ons.
* @since Unknown
*
* @param array $feed_settings_fields The add-on feed settings.
* @param GFAddOn $addon The current instance of the add-on (i.e. GF_User_Registration, GFPayPal).
*
* @return array
*/
public function add_post_payment_actions( $feed_settings_fields, $addon ) {
if ( ! $addon instanceof GFPaymentAddOn ) {
return $feed_settings_fields;
}
$config = $addon->get_post_payment_actions_config( $this->get_slug() );
if ( empty( $config ) ) {
return $feed_settings_fields;
}
$form_id = absint( rgget( 'id' ) );
if ( $this->has_feed( $form_id ) ) {
$addon_label = rgar( $this->delayed_payment_integration, 'option_label' );
$choice = array(
'label' => $addon_label ? $addon_label : sprintf( esc_html__( 'Process %s feed only when payment is received.', 'gravityforms' ), $this->get_short_title() ),
'name' => 'delay_' . $this->_slug,
);
$field_name = 'post_payment_actions';
$field = $this->get_field( $field_name, $feed_settings_fields );
if ( ! $field ) {
$fields = array(
array(
'name' => $field_name,
'label' => esc_html__( 'Post Payment Actions', 'gravityforms' ),
'type' => 'checkbox',
'choices' => array( $choice ),
'tooltip' => '' . esc_html__( 'Post Payment Actions', 'gravityforms' ) . '
' . esc_html__( 'Select which actions should only occur after payment has been received.', 'gravityforms' )
)
);
$setting = rgar( $config, 'setting', 'options' );
if ( rgar( $config, 'position' ) === 'before' ) {
$feed_settings_fields = $this->add_field_before( $setting, $fields, $feed_settings_fields );
} else {
$feed_settings_fields = $this->add_field_after( $setting, $fields, $feed_settings_fields );
}
} else {
$field['choices'][] = $choice;
$feed_settings_fields = $this->replace_field( $field_name, $field, $feed_settings_fields );
}
}
return $feed_settings_fields;
}
/**
* Triggers processing of feeds delayed by the PayPal add-on.
*
* @since 2.4.13 Updated to use action_trigger_payment_delayed_feeds().
* @since unknown
*
* @param array $entry The entry currently being processed.
* @param array $paypal_config The payment feed which originated the transaction.
* @param string $transaction_id The transaction or subscription ID.
* @param string $amount The transaction amount.
*/
public function paypal_fulfillment( $entry, $paypal_config, $transaction_id, $amount ) {
$this->action_trigger_payment_delayed_feeds( $transaction_id, $paypal_config, $entry );
}
/**
* Triggers processing of feeds delayed by payment add-ons.
*
* @since 2.4.13
*
* @param string $transaction_id The transaction or subscription ID.
* @param array $payment_feed The payment feed which originated the transaction.
* @param array $entry The entry currently being processed.
* @param null|array $form The form currently being processed or null for the legacy PayPal integration.
*/
public function action_trigger_payment_delayed_feeds( $transaction_id, $payment_feed, $entry, $form = null ) {
$this->log_debug( __METHOD__ . '(): Checking fulfillment for transaction ' . $transaction_id . ' for ' . $payment_feed['addon_slug'] );
$is_fulfilled = gform_get_meta( $entry['id'], "{$this->_slug}_is_fulfilled" );
if ( $is_fulfilled || ! $this->is_delayed( $payment_feed ) ) {
$this->log_debug( __METHOD__ . '(): Entry ' . $entry['id'] . ' is already fulfilled or feeds are not delayed. No action necessary.' );
return;
}
if ( is_null( $form ) ) {
$form = GFFormsModel::get_form_meta( $entry['form_id'] );
}
$this->_bypass_feed_delay = true;
$this->maybe_process_feed( $entry, $form );
}
//--------------- Notes ------------------
/**
* Writes to the add-on log and adds an entry note when a feed processing error occurs.
*
* @since 1.9.12
*
* @param string $error_message The error message.
* @param array $feed The feed which was being processed when the error occurred.
* @param array $entry The entry which was being processed when the error occurred.
* @param array $form The form which was being processed when the error occurred.
*/
public function add_feed_error( $error_message, $feed, $entry, $form ) {
/* Log debug error before we prepend the error name. */
$backtrace = debug_backtrace();
$method = $backtrace[1]['class'] . '::' . $backtrace[1]['function'];
$this->log_error( $method . '(): ' . $error_message );
/* Prepend feed name to the error message. */
$feed_name = rgars( $feed, 'meta/feed_name' ) ? rgars( $feed, 'meta/feed_name' ) : rgars( $feed, 'meta/feedName' );
$note_error_message = $feed_name . ': ' . $error_message;
/* Add error note to the entry. */
$this->add_note( $entry['id'], $note_error_message, 'error' );
/* Get Add-On slug */
$slug = str_replace( 'gravityforms', '', $this->_slug );
/**
* Process any error actions.
*
* @since 1.9.12
* @since 2.4.15 Added $error_message as the fourth param.
*
* @param array $feed The feed which was being processed when the error occurred.
* @param array $entry The entry which was being processed when the error occurred.
* @param array $feed The form which was being processed when the error occurred.
* @param string $error_message The error message.
*/
gf_do_action( array( "gform_{$slug}_error", $form['id'] ), $feed, $entry, $form, $error_message );
}
// TODO: Review for Deprecation ------------------
public function get_paypal_feed( $form_id, $entry ) {
if ( ! class_exists( 'GFPayPal' ) ) {
return false;
}
if ( method_exists( 'GFPayPal', 'get_config_by_entry' ) ) {
$feed = GFPayPal::get_config_by_entry( $entry );
} elseif ( method_exists( 'GFPayPal', 'get_config' ) ) {
$feed = GFPayPal::get_config( $form_id );
} else {
$feed = false;
}
return $feed;
}
public function has_paypal_payment( $feed, $form, $entry ) {
$products = GFCommon::get_product_fields( $form, $entry );
$payment_field = $feed['meta']['transactionType'] === 'product' ? $feed['meta']['paymentAmount'] : $feed['meta']['recurringAmount'];
$setup_fee_field = rgar( $feed['meta'], 'setupFee_enabled' ) ? $feed['meta']['setupFee_product'] : false;
$trial_field = rgar( $feed['meta'], 'trial_enabled' ) ? rgars( $feed, 'meta/trial_product' ) : false;
$amount = 0;
$line_items = array();
$discounts = array();
$fee_amount = 0;
$trial_amount = 0;
foreach ( $products['products'] as $field_id => $product ) {
$quantity = $product['quantity'] ? $product['quantity'] : 1;
$product_price = GFCommon::to_number( $product['price'] );
$options = array();
if ( is_array( rgar( $product, 'options' ) ) ) {
foreach ( $product['options'] as $option ) {
$options[] = $option['option_name'];
$product_price += $option['price'];
}
}
$is_trial_or_setup_fee = false;
if ( ! empty( $trial_field ) && $trial_field === $field_id ) {
$trial_amount = $product_price * $quantity;
$is_trial_or_setup_fee = true;
} elseif ( ! empty( $setup_fee_field ) && $setup_fee_field === $field_id ) {
$fee_amount = $product_price * $quantity;
$is_trial_or_setup_fee = true;
}
// Do not add to line items if the payment field selected in the feed is not the current field.
if ( is_numeric( $payment_field ) && $payment_field != $field_id ) {
continue;
}
// Do not add to line items if the payment field is set to "Form Total" and the current field was used for trial or setup fee.
if ( $is_trial_or_setup_fee && ! is_numeric( $payment_field ) ) {
continue;
}
$amount += $product_price * $quantity;
}
if ( ! empty( $products['shipping']['name'] ) && ! is_numeric( $payment_field ) ) {
$line_items[] = array( 'id' => '',
'name' => $products['shipping']['name'],
'description' => '',
'quantity' => 1,
'unit_price' => GFCommon::to_number( $products['shipping']['price'] ),
'is_shipping' => 1
);
$amount += $products['shipping']['price'];
}
return $amount > 0;
}
public function is_delayed_payment( $entry, $form, $is_delayed ) {
if ( $this->_slug == 'gravityformspaypal' ) {
return false;
}
$paypal_feed = $this->get_paypal_feed( $form['id'], $entry );
if ( ! $paypal_feed ) {
return false;
}
$has_payment = self::get_paypal_payment_amount( $form, $entry, $paypal_feed ) > 0;
return rgar( $paypal_feed['meta'], "delay_{$this->_slug}" ) && $has_payment && ! $is_delayed;
}
public static function get_paypal_payment_amount( $form, $entry, $paypal_config ) {
// TODO: need to support old "paypal_config" format as well as new format when delayed payment suported feed addons are released
$products = GFCommon::get_product_fields( $form, $entry, true );
$recurring_field = rgar( $paypal_config['meta'], 'recurring_amount_field' );
$total = 0;
foreach ( $products['products'] as $id => $product ) {
if ( $paypal_config['meta']['type'] != 'subscription' || $recurring_field == $id || $recurring_field == 'all' ) {
$price = GFCommon::to_number( $product['price'] );
if ( is_array( rgar( $product, 'options' ) ) ) {
foreach ( $product['options'] as $option ) {
$price += GFCommon::to_number( $option['price'] );
}
}
$total += $price * $product['quantity'];
}
}
if ( 'all' === $recurring_field && ! empty( $products['shipping']['price'] ) ) {
$total += floatval( $products['shipping']['price'] );
}
return $total;
}
public function has_frontend_feeds( $form ) {
$result = $this->register_frontend_feeds( $form );
return ! empty( $result );
}
/***
* Registers front end feeds with the private $_frontend_feeds array.
*
* @since 2.4
*
* @param array $form The current Form Object.
*
* @return bool Returns true if one ore more feeds were registered, false if no feeds were registered
*/
public function register_frontend_feeds( $form ) {
// Don't register frontend feeds if $form ID is empty.
if ( empty( $form['id'] ) ) {
return false;
}
if ( ! isset( self::$_frontend_feeds[ $form['id'] ] ) ) {
self::$_frontend_feeds[ $form['id'] ] = array();
}
$feeds = $this->get_frontend_feeds( $form );
$this->add_frontend_feeds( $form['id'], $feeds );
return ! empty( $feeds );
}
/***
* Loads front end feeds into the private $_frontend_feeds array, making sure not to add duplicate feeds.
*
* @since 2.4
*
* @param int $form_id The current Form Id
* @param array $feeds An array of all feeds to be loaded into the $_frontend_feeds variable
*/
public function add_frontend_feeds( $form_id, $feeds ) {
foreach ( $feeds as $feed ) {
$filter = array( 'feedId' => $feed['feedId'], 'addonSlug' => $feed['addonSlug'] );
$found = wp_list_filter( self::$_frontend_feeds[ $form_id ], $filter );
if ( empty( $found ) ) {
self::$_frontend_feeds[ $form_id ][] = $feed;
}
}
}
/***
* Gets an array of all feeds eligible to be a Front End Feed.
*
* @since 2.4
*
* @param array $form The Form object to get Frontend Feeds from
*
* @return array An array with feeds eligible to be a Front End Feed. By default only feedId, addonSlug, conditionalLogic and isSingleFeed properties are returned in the array.
*/
public function get_frontend_feeds( $form ) {
if ( ! $this->_supports_frontend_feeds ) {
return array();
}
$feeds = $this->get_active_feeds( $form['id'] );
if ( empty( $feeds ) ) {
return array();
}
$frontend_feeds = array();
foreach ( $feeds as $feed ) {
$_feed = array(
'feedId' => $feed['id'],
'addonSlug' => $this->_slug,
'conditionalLogic' => rgars( $feed, 'meta/feed_condition_conditional_logic' ) === '0' ? false : rgars( $feed, 'meta/feed_condition_conditional_logic_object/conditionalLogic', false ),
'isSingleFeed' => $this->_single_feed_submission,
);
$_feed = apply_filters( 'gform_addon_frontend_feed', $_feed, $form, $feed );
$_feed = apply_filters( "gform_addon_frontend_feed_{$form['id']}", $_feed, $form, $feed );
$_feed = apply_filters( "gform_{$this->_slug}_frontend_feed", $_feed, $form, $feed );
$_feed = apply_filters( "gform_{$this->_slug}_frontend_feed_{$form['id']}", $_feed, $form, $feed );
$frontend_feeds[] = $_feed;
}
return $frontend_feeds;
}
/***
* Registers frontend feeds by rendering the GFFrontEndFeeds() JS object.
*
* @since 2.4
*
* @param array $form The current Form object
*/
public static function register_frontend_feeds_init_script( $form ) {
$feeds = rgar( self::$_frontend_feeds, $form['id'] );
if ( empty( $feeds ) ) {
return;
}
$args = array(
'formId' => $form['id'],
'feeds' => $feeds,
);
$script = sprintf( '; new GFFrontendFeeds( %s );', json_encode( $args ) );
GFFormDisplay::add_init_script( $form['id'], 'gaddon_frontend_feeds', GFFormDisplay::ON_PAGE_RENDER, $script );
}
}
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class GFAddOnFeedsTable extends WP_List_Table {
private $_feeds;
private $_slug;
private $_columns;
private $_bulk_actions;
private $_action_links;
private $_addon_class;
private $_column_value_callback = array();
private $_no_items_callback = array();
private $_message_callback = array();
function __construct( $feeds, $slug, $columns = array(), $bulk_actions, $action_links, $column_value_callback, $no_items_callback, $message_callback, $addon_class ) {
$this->_bulk_actions = $bulk_actions;
$this->_feeds = $feeds;
$this->_slug = $slug;
$this->_columns = $columns;
$this->_column_value_callback = $column_value_callback;
$this->_action_links = $action_links;
$this->_no_items_callback = $no_items_callback;
$this->_message_callback = $message_callback;
$this->_addon_class = $addon_class;
$standard_cols = array(
'cb' => esc_html__( 'Checkbox', 'gravityforms' ),
'is_active' => '',
);
$all_cols = array_merge( $standard_cols, $columns );
$this->_column_headers = array(
$all_cols,
array(),
array(),
rgar( array_keys( $all_cols ), 2 ),
);
parent::__construct(
array(
'singular' => esc_html__( 'feed', 'gravityforms' ),
'plural' => esc_html__( 'feeds', 'gravityforms' ),
'ajax' => false,
)
);
}
function prepare_items() {
$this->items = isset( $this->_feeds ) ? $this->_feeds : array();
}
function get_columns() {
return $this->_column_headers[0];
}
function get_bulk_actions() {
return $this->_bulk_actions;
}
function no_items() {
echo call_user_func( $this->_no_items_callback );
}
function display_rows_or_placeholder() {
$message = call_user_func( $this->_message_callback );
if ( $message !== false ) {
?>
|
_column_value_callback ) ) {
$value = call_user_func( $this->_column_value_callback, $item, $column );
}
// Adding action links to the first column of the list
$columns = array_keys( $this->_columns );
if ( is_array( $columns ) && count( $columns ) > 0 && $columns[0] == $column ) {
$value = $this->add_action_links( $item, $column, $value );
}
return $value;
}
function column_cb( $item ) {
$feed_id = rgar( $item, 'id' );
return sprintf(
'', esc_attr( $feed_id )
);
}
function add_action_links( $item, $column, $value ) {
/**
* Adds action links to feed items
*
* @param array $this->_action_links Action links to be filtered.
* @param array $item The feed item being filtered.
* @param string $column The column ID
*/
$actions = apply_filters( $this->_slug . '_feed_actions', $this->_action_links, $item, $column );
// Replacing _id_ merge variable with actual feed id
foreach ( $actions as $action => &$link ) {
$link = str_replace( '_id_', $item['id'], $link );
}
if ( ! $this->_addon_class->can_duplicate_feed( $item['id'] ) ) {
unset( $actions['duplicate'] );
}
return sprintf( '%1$s %2$s', $value, $this->row_actions( $actions ) );
}
function _column_is_active( $item, $classes, $data, $primary ) {
// Open cell as a table header.
echo '';
// Get feed active state.
$is_active = intval( rgar( $item, 'is_active' ) );
// Get active image URL.
$src = GFCommon::get_base_url() . "/images/active{$is_active}.png";
// Get image title tag.
$title = $is_active ? esc_attr__( 'Active', 'gravityforms' ) : esc_attr__( 'Inactive', 'gravityforms' );
// Display feed active button.
echo sprintf( '', $src, $title, esc_js( $this->_slug ), esc_js( $item['id'] ), esc_js( $this->_slug ), esc_js( $item['id'] ) );
// Close cell.
echo ' | ';
}
}