1: <?php
2:
3: if ( ! class_exists( 'GFForms' ) ) {
4: die();
5: }
6:
7: 8: 9: 10: 11: 12:
13:
14: require_once( 'class-gf-addon.php' );
15:
16: abstract class GFFeedAddOn extends GFAddOn {
17:
18: 19: 20: 21:
22: protected $_multiple_feeds = true;
23:
24: 25: 26: 27:
28: protected $_single_feed_submission = false;
29:
30: 31: 32: 33:
34: protected $_single_submission_feed = false;
35:
36: 37: 38: 39:
40: protected $_supports_feed_ordering = false;
41:
42: 43: 44: 45: 46: 47:
48: protected $_async_feed_processing = false;
49:
50: 51: 52: 53: 54: 55: 56:
57: protected $_supports_frontend_feeds = false;
58:
59: 60: 61: 62:
63: protected $_bypass_feed_delay = false;
64:
65: 66: 67:
68: private $_feed_version = '0.14';
69: private $_feed_settings_fields = array();
70: private $_current_feed_id = false;
71:
72: 73: 74: 75:
76: private static $_frontend_feeds = array();
77:
78: 79: 80:
81: public function init() {
82:
83: parent::init();
84:
85: add_filter( 'gform_entry_post_save', array( $this, 'maybe_process_feed' ), 10, 2 );
86: add_action( 'gform_after_delete_form', array( $this, 'delete_feeds' ) );
87:
88:
89: if( $this->_supports_frontend_feeds && ! has_action( 'gform_register_init_scripts', array( __class__, 'register_frontend_feeds_init_script' ) ) ) {
90: add_action( 'gform_register_init_scripts', array( __class__, 'register_frontend_feeds_init_script' ) );
91: }
92:
93: }
94:
95: 96: 97:
98: public function init_ajax() {
99:
100: parent::init_ajax();
101:
102: add_action( "wp_ajax_gf_feed_is_active_{$this->_slug}", array( $this, 'ajax_toggle_is_active' ) );
103: add_action( 'wp_ajax_gf_save_feed_order', array( $this, 'ajax_save_feed_order' ) );
104:
105: }
106:
107: 108: 109:
110: public function init_admin() {
111:
112: parent::init_admin();
113:
114: add_filter( 'gform_notification_events', array( $this, 'notification_events' ), 10, 2 );
115: add_filter( 'gform_notes_avatar', array( $this, 'notes_avatar' ), 10, 2 );
116: add_action( 'gform_post_form_duplicated', array( $this, 'post_form_duplicated' ), 10, 2 );
117:
118: }
119:
120: 121: 122:
123: public function setup() {
124:
125: $installed_version = get_option( 'gravityformsaddon_feed-base_version' );
126: if ( $installed_version != $this->_feed_version ) {
127: $this->upgrade_base( $installed_version );
128: update_option( 'gravityformsaddon_feed-base_version', $this->_feed_version );
129: }
130:
131: parent::setup();
132: }
133:
134: private function upgrade_base( $previous_version ) {
135: global $wpdb;
136:
137: require_once( ABSPATH . '/wp-admin/includes/upgrade.php' );
138: if ( ! empty( $wpdb->charset ) ) {
139: $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
140: }
141: if ( ! empty( $wpdb->collate ) ) {
142: $charset_collate .= " COLLATE $wpdb->collate";
143: }
144:
145: $sql = "CREATE TABLE {$wpdb->prefix}gf_addon_feed (
146: id mediumint(8) unsigned not null auto_increment,
147: form_id mediumint(8) unsigned not null,
148: is_active tinyint(1) not null default 1,
149: feed_order mediumint(8) unsigned not null default 0,
150: meta longtext,
151: addon_slug varchar(50),
152: event_type varchar(20),
153: PRIMARY KEY (id),
154: KEY addon_form (addon_slug,form_id)
155: ) $charset_collate;";
156:
157: gf_upgrade()->dbDelta( $sql );
158:
159: }
160:
161: 162: 163: 164: 165: 166:
167: public function post_gravityforms_upgrade( $db_version, $previous_db_version, $force_upgrade ) {
168:
169:
170: if ( $force_upgrade ) {
171:
172: $installed_version = get_option( 'gravityformsaddon_feed-base_version' );
173:
174: $this->upgrade_base( $installed_version );
175:
176: update_option( 'gravityformsaddon_feed-base_version', $this->_feed_version );
177:
178: }
179:
180: parent::post_gravityforms_upgrade( $db_version, $previous_db_version, $force_upgrade );
181: }
182:
183: public function scripts() {
184:
185: $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
186: $scripts = array(
187: array(
188: 'handle' => 'gform_form_admin',
189: 'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
190: ),
191: array(
192: 'handle' => 'gform_gravityforms',
193: 'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
194: ),
195: array(
196: 'handle' => 'gform_forms',
197: 'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
198: ),
199: array(
200: 'handle' => 'json2',
201: 'enqueue' => array( array( 'admin_page' => array( 'form_settings' ) ) ),
202: ),
203: array(
204: 'handle' => 'gform_placeholder',
205: 'enqueue' => array(
206: array(
207: 'admin_page' => array( 'form_settings' ),
208: 'field_types' => array( 'feed_condition' ),
209: ),
210: )
211: ),
212: );
213:
214: if ( $this->_supports_feed_ordering ) {
215: $scripts[] = array(
216: 'handle' => 'gaddon_feedorder',
217: 'src' => $this->get_gfaddon_base_url() . "/js/gaddon_feedorder{$min}.js",
218: 'version' => GFCommon::$version,
219: 'deps' => array( 'jquery', 'jquery-ui-sortable' ),
220: 'in_footer' => false,
221: 'enqueue' => array(
222: array(
223: 'admin_page' => array( 'form_settings' )
224: ),
225: ),
226: );
227: }
228:
229: if( $this->_supports_frontend_feeds ) {
230: $scripts[] = array(
231: 'handle' => 'gaddon_frontend',
232: 'src' => $this->get_gfaddon_base_url() . "/js/gaddon_frontend{$min}.js",
233: 'deps' => array( 'jquery', 'gform_conditional_logic' ),
234: 'version' => GFCommon::$version,
235: 'enqueue' => array( array( $this, 'has_frontend_feeds' ) ),
236: );
237: }
238:
239: return array_merge( parent::scripts(), $scripts );
240: }
241:
242: public function uninstall() {
243: global $wpdb;
244: $sql = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}gf_addon_feed WHERE addon_slug=%s", $this->_slug );
245: $wpdb->query( $sql );
246:
247: }
248:
249:
250:
251: 252: 253: 254: 255: 256: 257: 258: 259:
260: public function maybe_process_feed( $entry, $form ) {
261:
262: if ( 'spam' === $entry['status'] ) {
263: $this->log_debug( "GFFeedAddOn::maybe_process_feed(): Entry #{$entry['id']} is marked as spam; not processing feeds for {$this->_slug}." );
264:
265: return $entry;
266: }
267:
268: $this->log_debug( __METHOD__ . "(): Checking for feeds to process for entry #{$entry['id']} for {$this->_slug}." );
269:
270: $feeds = false;
271:
272:
273: if ( $this->_single_feed_submission ) {
274: $feed = $this->get_single_submission_feed( $entry, $form );
275: if ( $feed ) {
276: $feeds = array( $feed );
277: }
278: } else {
279: $feeds = $this->get_feeds( $form['id'] );
280: }
281:
282:
283: $feeds = $this->pre_process_feeds( $feeds, $entry, $form );
284:
285:
286: if ( empty( $feeds ) ) {
287: $this->log_debug( __METHOD__ . "(): No feeds to process for entry #{$entry['id']}." );
288: return $entry;
289: }
290:
291:
292: $is_delayed = $this->maybe_delay_feed( $entry, $form );
293:
294:
295: $processed_feeds = array();
296:
297:
298: foreach ( $feeds as $feed ) {
299:
300:
301: $feed_name = rgempty( 'feed_name', $feed['meta'] ) ? rgar( $feed['meta'], 'feedName' ) : rgar( $feed['meta'], 'feed_name' );
302:
303:
304: if ( ! $feed['is_active'] ) {
305: $this->log_debug( "GFFeedAddOn::maybe_process_feed(): Feed is inactive, not processing feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']}." );
306: continue;
307: }
308:
309:
310: if ( ! $this->is_feed_condition_met( $feed, $form, $entry ) ) {
311: $this->log_debug( "GFFeedAddOn::maybe_process_feed(): Feed condition not met, not processing feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']}." );
312: continue;
313: }
314:
315:
316: if ( ! $is_delayed ) {
317:
318:
319: if ( $this->is_asynchronous( $feed, $entry, $form ) ) {
320:
321:
322: $this->log_debug( "GFFeedAddOn::maybe_process_feed(): Adding feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$this->_slug} to the processing queue." );
323:
324:
325: gf_feed_processor()->push_to_queue(
326: array(
327: 'addon' => $this,
328: 'feed' => $feed,
329: 'entry_id' => $entry['id'],
330: 'form_id' => $form['id'],
331: )
332: );
333:
334: } else {
335:
336:
337: $this->log_debug( "GFFeedAddOn::maybe_process_feed(): Starting to process feed (#{$feed['id']} - {$feed_name}) for entry #{$entry['id']} for {$this->_slug}" );
338: $returned_entry = $this->process_feed( $feed, $entry, $form );
339:
340:
341: if ( is_array( $returned_entry ) && rgar( $returned_entry, 'id' ) ) {
342: $entry = $returned_entry;
343: }
344:
345: 346: 347: 348: 349: 350: 351: 352: 353: 354:
355: do_action( 'gform_post_process_feed', $feed, $entry, $form, $this );
356: do_action( "gform_{$this->_slug}_post_process_feed", $feed, $entry, $form, $this );
357:
358:
359: $this->log_debug( 'GFFeedAddOn::maybe_process_feed(): Marking entry #' . $entry['id'] . ' as fulfilled for ' . $this->_slug );
360: gform_update_meta( $entry['id'], "{$this->_slug}_is_fulfilled", true );
361:
362:
363: $processed_feeds[] = $feed['id'];
364: }
365:
366: } else {
367:
368:
369: $this->log_debug( 'GFFeedAddOn::maybe_process_feed(): Feed processing is delayed, not processing feed for entry #' . $entry['id'] . ' for ' . $this->_slug );
370:
371:
372: $this->delay_feed( $feed, $entry, $form );
373:
374: }
375: }
376:
377:
378: if ( ! empty( $processed_feeds ) ) {
379:
380:
381: $meta = gform_get_meta( $entry['id'], 'processed_feeds' );
382:
383:
384: if ( empty( $meta ) ) {
385: $meta = array();
386: }
387:
388:
389: $meta[ $this->_slug ] = $processed_feeds;
390:
391:
392: gform_update_meta( $entry['id'], 'processed_feeds', $meta );
393:
394: }
395:
396:
397: return $entry;
398:
399: }
400:
401: 402: 403: 404: 405: 406: 407: 408: 409: 410:
411: public function maybe_delay_feed( $entry, $form ) {
412: if ( $this->_bypass_feed_delay ) {
413: return false;
414: }
415:
416: $is_delayed = false;
417: $slug = $this->get_slug();
418:
419: if ( $slug != 'gravityformspaypal' && class_exists( 'GFPayPal' ) && function_exists( 'gf_paypal' ) ) {
420: if ( gf_paypal()->is_payment_gateway( $entry['id'] ) ) {
421: $paypal_feed = gf_paypal()->get_single_submission_feed( $entry );
422: if ( $paypal_feed && $this->is_delayed( $paypal_feed ) ) {
423: $is_delayed = true;
424: }
425: }
426: }
427:
428: 429: 430: 431: 432: 433: 434: 435:
436: $is_delayed = apply_filters( 'gform_is_delayed_pre_process_feed', $is_delayed, $form, $entry, $slug );
437: $is_delayed = apply_filters( 'gform_is_delayed_pre_process_feed_' . $form['id'], $is_delayed, $form, $entry, $slug );
438:
439: return $is_delayed;
440: }
441:
442: 443: 444: 445: 446: 447: 448:
449: public function is_delayed( $paypal_feed ) {
450: $delay = rgar( $paypal_feed['meta'], 'delay_' . $this->_slug );
451:
452: return $delay;
453: }
454:
455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466:
467: public function is_asynchronous( $feed, $entry, $form ) {
468: if ( $this->_bypass_feed_delay ) {
469: return false;
470: }
471:
472: 473: 474: 475: 476: 477: 478: 479: 480: 481:
482: $is_asynchronous = gf_apply_filters( array( 'gform_is_feed_asynchronous', $form['id'], $feed['id'] ), $this->_async_feed_processing, $feed, $entry, $form );
483:
484: return $is_asynchronous;
485:
486: }
487:
488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499:
500: public function process_feed( $feed, $entry, $form ) {
501:
502: return;
503: }
504:
505: public function delay_feed( $feed, $entry, $form ) {
506:
507: return;
508: }
509:
510: public function is_feed_condition_met( $feed, $form, $entry ) {
511:
512: $feed_meta = $feed['meta'];
513: $is_condition_enabled = rgar( $feed_meta, 'feed_condition_conditional_logic' ) == true;
514: $logic = rgars( $feed_meta, 'feed_condition_conditional_logic_object/conditionalLogic' );
515:
516: if ( ! $is_condition_enabled || empty( $logic ) ) {
517: return true;
518: }
519:
520: return GFCommon::evaluate_conditional_logic( $logic, $form, $entry );
521: }
522:
523: 524: 525: 526: 527: 528: 529: 530:
531: public function create_feed_nonce() {
532:
533: $action = 'gform_' . $this->_slug . '_process_feed';
534: $i = wp_nonce_tick();
535:
536: return substr( wp_hash( $i . $action, 'nonce' ), - 12, 10 );
537:
538: }
539:
540: 541: 542: 543: 544: 545: 546: 547: 548:
549: public function verify_feed_nonce( $nonce ) {
550:
551: $action = 'gform_' . $this->_slug . '_process_feed';
552: $i = wp_nonce_tick();
553:
554:
555: if ( substr( wp_hash( $i . $action, 'nonce' ), - 12, 10 ) === $nonce ) {
556: return 1;
557: }
558:
559:
560: if ( substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), - 12, 10 ) === $nonce ) {
561: return 2;
562: }
563:
564:
565: $this->log_error( __METHOD__ . '(): Aborting. Unable to verify nonce.' );
566:
567: return false;
568:
569: }
570:
571: 572: 573: 574: 575: 576: 577:
578: public function supported_notification_events( $form ) {
579:
580: return array();
581:
582: }
583:
584: 585: 586: 587: 588: 589: 590: 591:
592: public function notification_events( $events, $form ) {
593:
594:
595: $supported_events = $this->supported_notification_events( $form );
596:
597:
598: if ( empty( $supported_events ) ) {
599: return $events;
600: }
601:
602: return array_merge( $events, $supported_events );
603:
604: }
605:
606:
607:
608: public function get_feeds( $form_id = null ) {
609: global $wpdb;
610:
611: $form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
612:
613: $sql = $wpdb->prepare(
614: "SELECT * FROM {$wpdb->prefix}gf_addon_feed
615: WHERE addon_slug=%s {$form_filter} ORDER BY `feed_order`, `id` ASC", $this->_slug
616: );
617:
618: $results = $wpdb->get_results( $sql, ARRAY_A );
619: foreach ( $results as &$result ) {
620: $result['meta'] = json_decode( $result['meta'], true );
621: }
622:
623: return $results;
624: }
625:
626: 627: 628: 629: 630: 631: 632: 633: 634:
635: public function get_active_feeds( $form_id = null ) {
636: global $wpdb;
637:
638: $form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
639:
640: $sql = $wpdb->prepare(
641: "SELECT * FROM {$wpdb->prefix}gf_addon_feed
642: WHERE addon_slug=%s AND is_active=1 {$form_filter} ORDER BY `feed_order`, `id` ASC", $this->_slug
643: );
644:
645: $results = $wpdb->get_results( $sql, ARRAY_A );
646: foreach ( $results as &$result ) {
647: $result['meta'] = json_decode( $result['meta'], true );
648: }
649:
650: return $results;
651: }
652:
653: public function get_feeds_by_slug( $slug, $form_id = null ) {
654: global $wpdb;
655:
656: $form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
657:
658: $sql = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gf_addon_feed
659: WHERE addon_slug=%s {$form_filter} ORDER BY `feed_order`, `id` ASC", $slug );
660:
661: $results = $wpdb->get_results( $sql, ARRAY_A );
662: foreach( $results as &$result ) {
663: $result['meta'] = json_decode( $result['meta'], true );
664: }
665:
666: return $results;
667: }
668:
669: public function get_current_feed() {
670: $feed_id = $this->get_current_feed_id();
671:
672: return empty( $feed_id ) ? false : $this->get_feed( $feed_id );
673: }
674:
675: public function get_current_feed_id() {
676: if ( $this->_current_feed_id ) {
677: return $this->_current_feed_id;
678: } elseif ( ! rgempty( 'gf_feed_id' ) ) {
679: return rgpost( 'gf_feed_id' );
680: } else {
681: return rgget( 'fid' );
682: }
683: }
684:
685: public function get_feed( $id ) {
686: global $wpdb;
687:
688: $sql = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gf_addon_feed WHERE id=%d", $id );
689:
690: $row = $wpdb->get_row( $sql, ARRAY_A );
691: if ( ! $row ) {
692: return false;
693: }
694:
695: $row['meta'] = json_decode( $row['meta'], true );
696:
697: return $row;
698: }
699:
700: public function get_feeds_by_entry( $entry_id ) {
701: $processed_feeds = gform_get_meta( $entry_id, 'processed_feeds' );
702: if ( ! $processed_feeds ) {
703: return false;
704: }
705:
706: return rgar( $processed_feeds, $this->_slug );
707: }
708:
709: public function has_feed( $form_id, $meets_conditional_logic = null ) {
710:
711: $feeds = $this->get_feeds( $form_id );
712: if ( ! $feeds ) {
713: return false;
714: }
715:
716: $has_active_feed = false;
717:
718: if ( $meets_conditional_logic ) {
719: $form = GFFormsModel::get_form_meta( $form_id );
720: $entry = GFFormsModel::create_lead( $form );
721: }
722:
723: foreach ( $feeds as $feed ) {
724: if ( ! $has_active_feed && $feed['is_active'] ) {
725: $has_active_feed = true;
726: }
727:
728: if ( $meets_conditional_logic && $feed['is_active'] && $this->is_feed_condition_met( $feed, $form, $entry ) ) {
729: return true;
730: }
731: }
732:
733: return $meets_conditional_logic ? false : $has_active_feed;
734: }
735:
736: public function get_single_submission_feed( $entry = false, $form = false ) {
737:
738: if ( ! $entry && ! $form ) {
739: return false;
740: }
741:
742: $feed = false;
743:
744: if ( ! empty( $this->_single_submission_feed ) && ( ! $form || $this->_single_submission_feed['form_id'] == $form['id'] ) ) {
745:
746: $feed = $this->_single_submission_feed;
747:
748: } elseif ( $entry['id'] ) {
749:
750: $feeds = $this->get_feeds_by_entry( $entry['id'] );
751:
752: if ( empty( $feeds ) ) {
753: $feed = $this->get_single_submission_feed_by_form( $form, $entry );
754: } else {
755: $feed = $this->get_feed( $feeds[0] );
756: }
757:
758: } elseif ( $form ) {
759:
760: $feed = $this->get_single_submission_feed_by_form( $form, $entry );
761: $this->_single_submission_feed = $feed;
762:
763: }
764:
765: return $feed;
766: }
767:
768: 769: 770: 771: 772: 773: 774: 775:
776: public function get_single_submission_feed_by_form( $form, $entry ) {
777: if ( $form ) {
778: $feeds = $this->get_feeds( $form['id'] );
779:
780: foreach ( $feeds as $_feed ) {
781: if ( $_feed['is_active'] && $this->is_feed_condition_met( $_feed, $form, $entry ) ) {
782:
783: return $_feed;
784: }
785: }
786: }
787:
788: return false;
789: }
790:
791: public function pre_process_feeds( $feeds, $entry, $form ) {
792:
793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803:
804: $feeds = apply_filters( 'gform_addon_pre_process_feeds', $feeds, $entry, $form );
805: $feeds = apply_filters( "gform_addon_pre_process_feeds_{$form['id']}", $feeds, $entry, $form );
806: $feeds = apply_filters( "gform_{$this->_slug}_pre_process_feeds", $feeds, $entry, $form );
807: $feeds = apply_filters( "gform_{$this->_slug}_pre_process_feeds_{$form['id']}", $feeds, $entry, $form );
808:
809: return $feeds;
810: }
811:
812: 813: 814: 815: 816: 817: 818: 819:
820: public function get_default_feed_name() {
821:
822: 823: 824: 825: 826:
827:
828:
829: $counter_to_use = 0;
830:
831:
832: $feeds_to_filter = $this->get_feeds_by_slug( $this->_slug );
833:
834:
835: if ( $feeds_to_filter ) {
836:
837:
838: foreach ( $feeds_to_filter as $check ) {
839:
840:
841: $name = rgars( $check, 'meta/feed_name' ) ? rgars( $check, 'meta/feed_name' ) : rgars( $check, 'meta/feedName' );
842: $name = trim( $name );
843:
844:
845: $pattern = '/(^Feed|^' . $this->_short_title . ' Feed)\s\d+/';
846:
847:
848: preg_match( $pattern,$name,$matches );
849:
850:
851: if ( $matches ) {
852:
853:
854: $last_space = strrpos( $matches[0], ' ' );
855:
856: $digit = substr( $matches[0], $last_space );
857:
858:
859: if ( $digit >= $counter_to_use ){
860: $counter_to_use = $digit;
861: }
862:
863: }
864:
865: }
866:
867: }
868:
869:
870: $value = $this->_short_title . ' Feed ' . ($counter_to_use + 1);
871:
872: return $value;
873:
874: }
875:
876: public function is_unique_feed_name( $name, $form_id ) {
877: $feeds = $this->get_feeds( $form_id );
878: foreach ( $feeds as $feed ) {
879: $feed_name = rgars( $feed, 'meta/feed_name' ) ? rgars( $feed, 'meta/feed_name' ) : rgars( $feed, 'meta/feedName' );
880: if ( strtolower( $feed_name ) === strtolower( $name ) ) {
881: return false;
882: }
883: }
884:
885: return true;
886: }
887:
888: public function update_feed_meta( $id, $meta ) {
889: global $wpdb;
890:
891: $meta = json_encode( $meta );
892: $wpdb->update( "{$wpdb->prefix}gf_addon_feed", array( 'meta' => $meta ), array( 'id' => $id ), array( '%s' ), array( '%d' ) );
893:
894: return $wpdb->rows_affected > 0;
895: }
896:
897: public function update_feed_active( $id, $is_active ) {
898: global $wpdb;
899: $is_active = $is_active ? '1' : '0';
900:
901: $wpdb->update( "{$wpdb->prefix}gf_addon_feed", array( 'is_active' => $is_active ), array( 'id' => $id ), array( '%d' ), array( '%d' ) );
902:
903: return $wpdb->rows_affected > 0;
904: }
905:
906: public function insert_feed( $form_id, $is_active, $meta ) {
907: global $wpdb;
908:
909: $meta = json_encode( $meta );
910: $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' ) );
911:
912: return $wpdb->insert_id;
913: }
914:
915: public function delete_feed( $id ) {
916: global $wpdb;
917:
918: $wpdb->delete( "{$wpdb->prefix}gf_addon_feed", array( 'id' => $id ), array( '%d' ) );
919: }
920:
921: public function delete_feeds( $form_id = null ) {
922: global $wpdb;
923:
924: $form_filter = is_numeric( $form_id ) ? $wpdb->prepare( 'AND form_id=%d', absint( $form_id ) ) : '';
925:
926: $sql = $wpdb->prepare(
927: "SELECT id FROM {$wpdb->prefix}gf_addon_feed
928: WHERE addon_slug=%s {$form_filter} ORDER BY `feed_order`, `id` ASC", $this->_slug
929: );
930:
931: $feed_ids = $wpdb->get_col( $sql );
932:
933: if ( ! empty( $feed_ids ) ) {
934: array_map( array( $this, 'delete_feed' ), $feed_ids );
935: }
936:
937: }
938:
939: 940: 941: 942: 943: 944: 945: 946: 947: 948: 949: 950: 951: 952: 953: 954:
955: public function duplicate_feed( $id, $new_form_id = false ) {
956:
957:
958: $original_feed = is_array( $id ) ? $id : $this->get_feed( $id );
959:
960:
961: if ( ! $original_feed || ! $this->can_duplicate_feed( $original_feed ) ) {
962: return;
963: }
964:
965:
966: $feed_name_key = rgars( $original_feed, 'meta/feed_name' ) ? 'feed_name' : 'feedName';
967:
968:
969: $count = 2;
970: $feed_name = rgars( $original_feed, 'meta/' . $feed_name_key ) . ' - ' . esc_html__( 'Copy 1', 'gravityforms' );
971: while ( ! $this->is_unique_feed_name( $feed_name, $original_feed['form_id'] ) ) {
972: $feed_name = rgars( $original_feed, 'meta/' . $feed_name_key ) . ' - ' . sprintf( esc_html__( 'Copy %d', 'gravityforms' ), $count );
973: $count++;
974: }
975:
976:
977: $meta = $original_feed['meta'];
978: $meta[ $feed_name_key ] = $feed_name;
979:
980: if ( ! $new_form_id ) {
981: $new_form_id = $original_feed['form_id'];
982: }
983:
984:
985: return $this->insert_feed( $new_form_id, $original_feed['is_active'], $meta );
986:
987: }
988:
989: 990: 991: 992: 993: 994:
995: public function post_form_duplicated( $form_id, $new_id ) {
996:
997: $feeds = $this->get_feeds( $form_id );
998:
999: if ( ! $feeds ) {
1000: return;
1001: }
1002:
1003: foreach ( $feeds as $feed ) {
1004: $this->duplicate_feed( $feed, $new_id );
1005: }
1006:
1007: }
1008:
1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016:
1017: public function save_feed_order( $feed_order ) {
1018:
1019: global $wpdb;
1020:
1021:
1022: $feed_order = array_combine( range( 1, count( $feed_order ) ), array_values( $feed_order ) );
1023:
1024:
1025: $feed_order = array_flip( $feed_order );
1026:
1027:
1028: foreach ( $feed_order as $feed_id => $position ) {
1029:
1030: $wpdb->update(
1031: $wpdb->prefix . 'gf_addon_feed',
1032: array( 'feed_order' => $position ),
1033: array( 'id' => $feed_id ),
1034: array( '%d' ),
1035: array( '%d' )
1036: );
1037:
1038: }
1039:
1040: }
1041:
1042:
1043:
1044: public function form_settings_init() {
1045: parent::form_settings_init();
1046: }
1047:
1048: public function ajax_toggle_is_active() {
1049: $feed_id = rgpost( 'feed_id' );
1050: $is_active = rgpost( 'is_active' );
1051:
1052: $this->update_feed_active( $feed_id, $is_active );
1053: die();
1054: }
1055:
1056: public function ajax_save_feed_order() {
1057: check_ajax_referer( 'gform_feed_order', 'nonce' );
1058:
1059: if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
1060: return;
1061: }
1062:
1063: $addon = sanitize_text_field( rgpost( 'addon' ) );
1064: $form_id = absint( rgpost( 'form_id' ) );
1065: $feed_order = rgpost( 'feed_order' ) ? rgpost( 'feed_order' ) : array();
1066: $feed_order = array_map( 'absint', $feed_order );
1067:
1068: if ( $addon == $this->_slug ) {
1069: $this->save_feed_order( $feed_order );
1070: }
1071: }
1072:
1073: public function form_settings_sections() {
1074: return array();
1075: }
1076:
1077: public function form_settings( $form ) {
1078: if ( ! $this->_multiple_feeds || $this->is_detail_page() ) {
1079:
1080:
1081: $feed_id = $this->_multiple_feeds ? $this->get_current_feed_id() : $this->get_default_feed_id( $form['id'] );
1082:
1083: $this->feed_edit_page( $form, $feed_id );
1084: } else {
1085:
1086: $this->feed_list_page( $form );
1087: }
1088: }
1089:
1090: public function is_feed_list_page() {
1091: return ! isset( $_GET['fid'] );
1092: }
1093:
1094: public function is_detail_page() {
1095: return ! $this->is_feed_list_page();
1096: }
1097:
1098: public function () {
1099: if ( $this->is_feed_list_page() ) {
1100: $title = $this->form_settings_title();
1101: $url = add_query_arg( array( 'fid' => 0 ) );
1102: return $title . " <a class='add-new-h2' href='" . esc_html( $url ) . "'>" . esc_html__( 'Add New', 'gravityforms' ) . '</a>';
1103: }
1104: }
1105:
1106: public function form_settings_title() {
1107: return sprintf( esc_html__( '%s Feeds', 'gravityforms' ), $this->get_short_title() );
1108: }
1109:
1110: public function feed_edit_page( $form, $feed_id ) {
1111:
1112: $title = '<h3><span>' . $this->feed_settings_title() . '</span></h3>';
1113:
1114: if ( ! $this->can_create_feed() ) {
1115: echo $title . '<div>' . $this->configure_addon_message() . '</div>';
1116:
1117: return;
1118: }
1119:
1120:
1121: $feed_id = $this->maybe_save_feed_settings( $feed_id, $form['id'] );
1122:
1123: $this->_current_feed_id = $feed_id;
1124:
1125: ?>
1126: <script type="text/javascript">
1127: <?php GFFormSettings::output_field_scripts() ?>
1128: </script>
1129: <?php
1130:
1131: echo $title;
1132:
1133: $feed = $this->get_feed( $feed_id );
1134: $this->set_settings( $feed['meta'] );
1135:
1136: GFCommon::display_admin_message();
1137:
1138: $this->render_settings( $this->get_feed_settings_fields( $form ) );
1139:
1140: }
1141:
1142: public function settings( $sections ) {
1143:
1144: parent::settings( $sections );
1145:
1146: ?>
1147: <input type="hidden" name="gf_feed_id" value="<?php echo esc_attr( $this->get_current_feed_id() ); ?>" />
1148: <?php
1149:
1150: }
1151:
1152: public function feed_settings_title() {
1153: return esc_html__( 'Feed Settings', 'gravityforms' );
1154: }
1155:
1156: public function feed_list_page( $form = null ) {
1157: $action = $this->get_bulk_action();
1158: if ( $action ) {
1159: check_admin_referer( 'feed_list', 'feed_list' );
1160: $this->process_bulk_action( $action );
1161: }
1162:
1163: $single_action = rgpost( 'single_action' );
1164: if ( ! empty( $single_action ) ) {
1165: check_admin_referer( 'feed_list', 'feed_list' );
1166: $this->process_single_action( $single_action );
1167: }
1168:
1169: ?>
1170:
1171: <h3><span><?php echo $this->feed_list_title() ?></span></h3>
1172: <form id="gform-settings" action="" method="post">
1173: <?php
1174: $feed_list = $this->get_feed_table( $form );
1175: $feed_list->prepare_items();
1176: $feed_list->display();
1177: ?>
1178:
1179: <!--Needed to save state after bulk operations-->
1180: <input type="hidden" value="gf_edit_forms" name="page">
1181: <input type="hidden" value="settings" name="view">
1182: <input type="hidden" value="<?php echo esc_attr( $this->_slug ); ?>" name="subview">
1183: <input type="hidden" value="<?php echo esc_attr( rgar( $form, 'id' ) ); ?>" name="id">
1184: <input id="single_action" type="hidden" value="" name="single_action">
1185: <input id="single_action_argument" type="hidden" value="" name="single_action_argument">
1186: <?php wp_nonce_field( 'feed_list', 'feed_list' ) ?>
1187: </form>
1188:
1189: <script type="text/javascript">
1190: <?php
1191:
1192: GFCommon::gf_vars();
1193:
1194: if ( $this->_supports_feed_ordering ) {
1195:
1196:
1197: $feed_order_options = array(
1198: 'addon' => $this->_slug,
1199: 'formId' => rgar( $form, 'id' ),
1200: 'nonce' => wp_create_nonce( 'gform_feed_order' ),
1201: );
1202:
1203: echo 'jQuery( document ).ready( function() {
1204: window.GFFeedOrderObj = new GFFeedOrder( ' . json_encode( $feed_order_options ) . ');
1205: } );';
1206:
1207: }
1208:
1209: ?>
1210: </script>
1211:
1212: <?php
1213: }
1214:
1215: public function get_feed_table( $form ) {
1216:
1217: $columns = $this->feed_list_columns();
1218: $column_value_callback = array( $this, 'get_column_value' );
1219: $feeds = $this->get_feeds( rgar( $form, 'id' ) );
1220: $bulk_actions = $this->get_bulk_actions();
1221: $action_links = $this->get_action_links();
1222: $no_item_callback = array( $this, 'feed_list_no_item_message' );
1223: $message_callback = array( $this, 'feed_list_message' );
1224:
1225: return new GFAddOnFeedsTable( $feeds, $this->_slug, $columns, $bulk_actions, $action_links, $column_value_callback, $no_item_callback, $message_callback, $this );
1226: }
1227:
1228: public function feed_list_title() {
1229: if ( ! $this->can_create_feed() ) {
1230: return $this->form_settings_title();
1231: }
1232:
1233: $url = add_query_arg( array( 'fid' => '0' ) );
1234: $url = esc_url( $url );
1235:
1236: return $this->form_settings_title() . " <a class='add-new-h2' href='{$url}'>" . esc_html__( 'Add New', 'gravityforms' ) . '</a>';
1237: }
1238:
1239: public function maybe_save_feed_settings( $feed_id, $form_id ) {
1240:
1241: if ( ! rgpost( 'gform-settings-save' ) ) {
1242: return $feed_id;
1243: }
1244:
1245: check_admin_referer( $this->_slug . '_save_settings', '_' . $this->_slug . '_save_settings_nonce' );
1246:
1247: if ( ! $this->current_user_can_any( $this->_capabilities_form_settings ) ) {
1248: GFCommon::add_error_message( esc_html__( "You don't have sufficient permissions to update the form settings.", 'gravityforms' ) );
1249: return $feed_id;
1250: }
1251:
1252:
1253: $feed = $this->get_feed( $feed_id );
1254: $this->set_previous_settings( $feed['meta'] );
1255:
1256: $settings = $this->get_posted_settings();
1257: $sections = $this->get_feed_settings_fields();
1258: $settings = $this->trim_conditional_logic_vales( $settings, $form_id );
1259:
1260: $is_valid = $this->validate_settings( $sections, $settings );
1261: $result = false;
1262:
1263: if ( $is_valid ) {
1264: $settings = $this->filter_settings( $sections, $settings );
1265: $feed_id = $this->save_feed_settings( $feed_id, $form_id, $settings );
1266: if ( $feed_id ) {
1267: GFCommon::add_message( $this->get_save_success_message( $sections ) );
1268: } else {
1269: GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
1270: }
1271: } else {
1272: GFCommon::add_error_message( $this->get_save_error_message( $sections ) );
1273: }
1274:
1275: return $feed_id;
1276: }
1277:
1278: public function trim_conditional_logic_vales( $settings, $form_id ) {
1279: if ( ! is_array( $settings ) ) {
1280: return $settings;
1281: }
1282: if ( isset( $settings['feed_condition_conditional_logic_object'] ) && is_array( $settings['feed_condition_conditional_logic_object'] ) ) {
1283: $form = GFFormsModel::get_form_meta( $form_id );
1284: $settings['feed_condition_conditional_logic_object'] = GFFormsModel::trim_conditional_logic_values_from_element( $settings['feed_condition_conditional_logic_object'], $form );
1285: }
1286:
1287: return $settings;
1288: }
1289:
1290: public function get_save_success_message( $sections ) {
1291: if ( ! $this->is_detail_page() )
1292: return parent::get_save_success_message( $sections );
1293:
1294: $save_button = $this->get_save_button( $sections );
1295:
1296: return isset( $save_button['messages']['success'] ) ? $save_button['messages']['success'] : esc_html__( 'Feed updated successfully.', 'gravityforms' );
1297: }
1298:
1299: public function get_save_error_message( $sections ) {
1300: if ( ! $this->is_detail_page() )
1301: return parent::get_save_error_message( $sections );
1302:
1303: $save_button = $this->get_save_button( $sections );
1304:
1305: 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' );
1306: }
1307:
1308: public function save_feed_settings( $feed_id, $form_id, $settings ) {
1309:
1310: if ( $feed_id ) {
1311: $this->update_feed_meta( $feed_id, $settings );
1312: $result = $feed_id;
1313: } else {
1314: $result = $this->insert_feed( $form_id, true, $settings );
1315: }
1316:
1317: return $result;
1318: }
1319:
1320: public function get_feed_settings_fields() {
1321:
1322: if ( ! empty( $this->_feed_settings_fields ) ) {
1323: return $this->_feed_settings_fields;
1324: }
1325:
1326: 1327: 1328: 1329: 1330: 1331: 1332: 1333: 1334: 1335:
1336: $feed_settings_fields = apply_filters( 'gform_addon_feed_settings_fields', $this->feed_settings_fields(), $this );
1337: $feed_settings_fields = apply_filters( "gform_{$this->_slug}_feed_settings_fields", $feed_settings_fields, $this );
1338:
1339: $this->_feed_settings_fields = $this->add_default_feed_settings_fields_props( $feed_settings_fields );
1340:
1341: return $this->_feed_settings_fields;
1342: }
1343:
1344: public function feed_settings_fields() {
1345: return array();
1346: }
1347:
1348: public function add_default_feed_settings_fields_props( $fields ) {
1349:
1350: foreach ( $fields as &$section ) {
1351: foreach ( $section['fields'] as &$field ) {
1352: switch ( $field['type'] ) {
1353:
1354: case 'hidden':
1355: $field['hidden'] = true;
1356: break;
1357: }
1358:
1359: if ( rgar( $field, 'name' ) === 'feedName' ) {
1360: $field['default_value'] = $this->get_default_feed_name();
1361: }
1362: }
1363: }
1364:
1365: return $fields;
1366: }
1367:
1368: private function get_bulk_action() {
1369: $action = rgpost( 'action' );
1370: if ( empty( $action ) || $action == '-1' ) {
1371: $action = rgpost( 'action2' );
1372: }
1373:
1374: return empty( $action ) || $action == '-1' ? false : $action;
1375: }
1376:
1377: 1378: 1379:
1380: public function get_bulk_actions() {
1381: $bulk_actions = array(
1382: 'delete' => esc_html__( 'Delete', 'gravityforms' ),
1383: );
1384:
1385: return $bulk_actions;
1386: }
1387:
1388: 1389: 1390: 1391: 1392:
1393: public function process_bulk_action( $action ) {
1394: if ( 'delete' === $action ) {
1395: $feeds = rgpost( 'feed_ids' );
1396: if ( is_array( $feeds ) ) {
1397: foreach ( $feeds as $feed_id ) {
1398: $this->delete_feed( $feed_id );
1399: }
1400: }
1401: }
1402: if ( 'duplicate' === $action ) {
1403: $feeds = rgpost( 'feed_ids' );
1404: if ( is_array( $feeds ) ) {
1405: foreach ( $feeds as $feed_id ) {
1406: $this->duplicate_feed( $feed_id );
1407: }
1408: }
1409: }
1410: }
1411:
1412: public function process_single_action( $action ) {
1413: if ( $action == 'delete' ) {
1414: $feed_id = absint( rgpost( 'single_action_argument' ) );
1415: $this->delete_feed( $feed_id );
1416: }
1417: if ( $action == 'duplicate' ) {
1418: $feed_id = absint( rgpost( 'single_action_argument' ) );
1419: $this->duplicate_feed( $feed_id );
1420: }
1421: }
1422:
1423: public function get_action_links() {
1424: $feed_id = '_id_';
1425: $edit_url = add_query_arg( array( 'fid' => $feed_id ) );
1426: $links = array(
1427: 'edit' => '<a href="' . esc_url( $edit_url ) . '">' . esc_html__( 'Edit', 'gravityforms' ) . '</a>',
1428: 'duplicate' => '<a href="#" onclick="gaddon.duplicateFeed(\'' . esc_js( $feed_id ) . '\');" onkeypress="gaddon.duplicateFeed(\'' . esc_js( $feed_id ) . '\');">' . esc_html__( 'Duplicate', 'gravityforms' ) . '</a>',
1429: 'delete' => '<a class="submitdelete" onclick="javascript: if(confirm(\'' . esc_js( __( 'WARNING: You are about to delete this item.', 'gravityforms' ) ) . esc_js( __( "'Cancel' to stop, 'OK' to delete.", 'gravityforms' ) ) . '\')){ gaddon.deleteFeed(\'' . esc_js( $feed_id ) . '\'); }" onkeypress="javascript: if(confirm(\'' . esc_js( __( 'WARNING: You are about to delete this item.', 'gravityforms' ) ) . esc_js( __( "'Cancel' to stop, 'OK' to delete.", 'gravityforms' ) ) . '\')){ gaddon.deleteFeed(\'' . esc_js( $feed_id ) . '\'); }" style="cursor:pointer;">' . esc_html__( 'Delete', 'gravityforms' ) . '</a>'
1430: );
1431:
1432: return $links;
1433: }
1434:
1435: public function feed_list_columns() {
1436: return array();
1437: }
1438:
1439: 1440: 1441: 1442:
1443: public function feed_list_no_item_message() {
1444: $url = add_query_arg( array( 'fid' => 0 ) );
1445: return sprintf( esc_html__( "You don't have any feeds configured. Let's go %screate one%s!", 'gravityforms' ), "<a href='" . esc_url( $url ) . "'>", '</a>' );
1446: }
1447:
1448: 1449: 1450: 1451:
1452: public function feed_list_message() {
1453: if ( ! $this->can_create_feed() ) {
1454: return $this->configure_addon_message();
1455: }
1456:
1457: return false;
1458: }
1459:
1460: public function configure_addon_message() {
1461:
1462: $settings_label = sprintf( __( '%s Settings', 'gravityforms' ), $this->get_short_title() );
1463: $settings_link = sprintf( '<a href="%s">%s</a>', esc_url( $this->get_plugin_settings_url() ), $settings_label );
1464:
1465: return sprintf( __( 'To get started, please configure your %s.', 'gravityforms' ), $settings_link );
1466:
1467: }
1468:
1469: 1470: 1471: 1472:
1473: public function can_create_feed() {
1474: return true;
1475: }
1476:
1477: 1478: 1479: 1480: 1481: 1482: 1483:
1484: public function can_duplicate_feed( $id ) {
1485: return false;
1486: }
1487:
1488: public function get_column_value( $item, $column ) {
1489: if ( is_callable( array( $this, "get_column_value_{$column}" ) ) ) {
1490: return call_user_func( array( $this, "get_column_value_{$column}" ), $item );
1491: } elseif ( isset( $item[ $column ] ) ) {
1492: return $item[ $column ];
1493: } elseif ( isset( $item['meta'][ $column ] ) ) {
1494: return $item['meta'][ $column ];
1495: }
1496: }
1497:
1498:
1499: public function update_form_settings( $form, $new_form_settings ) {
1500: $feed_id = rgar( $new_form_settings, 'id' );
1501: foreach ( $new_form_settings as $key => $value ) {
1502: $form[ $this->_slug ]['feeds'][ $feed_id ][ $key ] = $value;
1503: }
1504:
1505: return $form;
1506: }
1507:
1508: public function get_default_feed_id( $form_id ) {
1509: global $wpdb;
1510:
1511: $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 );
1512:
1513: $feed_id = $wpdb->get_var( $sql );
1514: if ( ! $feed_id ) {
1515: $feed_id = 0;
1516: }
1517:
1518: return $feed_id;
1519: }
1520:
1521: public function settings_feed_condition( $field, $echo = true ) {
1522:
1523: $conditional_logic = $this->get_feed_condition_conditional_logic();
1524: $checkbox_field = $this->get_feed_condition_checkbox( $field );
1525:
1526: $hidden_field = $this->get_feed_condition_hidden_field();
1527: $instructions = isset( $field['instructions'] ) ? $field['instructions'] : esc_html__( 'Process this feed if', 'gravityforms' );
1528: $html = $this->settings_checkbox( $checkbox_field, false );
1529: $html .= $this->settings_hidden( $hidden_field, false );
1530: $html .= '<div id="feed_condition_conditional_logic_container"><!-- dynamically populated --></div>';
1531: $html .= '<script type="text/javascript"> var feedCondition = new FeedConditionObj({' .
1532: 'strings: { objectDescription: "' . esc_attr( $instructions ) . '" },' .
1533: 'logicObject: ' . $conditional_logic .
1534: '}); </script>';
1535:
1536: if ( $this->field_failed_validation( $field ) ) {
1537: $html .= $this->get_error_icon( $field );
1538: }
1539:
1540: if ( $echo ) {
1541: echo $html;
1542: }
1543:
1544: return $html;
1545: }
1546:
1547: public function get_feed_condition_checkbox( $field ) {
1548: $checkbox_label = isset( $field['checkbox_label'] ) ? $field['checkbox_label'] : esc_html__( 'Enable Condition', 'gravityforms' );
1549:
1550: $checkbox_field = array(
1551: 'name' => 'feed_condition_conditional_logic',
1552: 'type' => 'checkbox',
1553: 'choices' => array(
1554: array(
1555: 'label' => $checkbox_label,
1556: 'name' => 'feed_condition_conditional_logic',
1557: ),
1558: ),
1559: 'onclick' => 'ToggleConditionalLogic( false, "feed_condition" );',
1560: );
1561:
1562: return $checkbox_field;
1563: }
1564:
1565: public function get_feed_condition_hidden_field() {
1566: $conditional_logic = $this->get_feed_condition_conditional_logic();
1567: $hidden_field = array(
1568: 'name' => 'feed_condition_conditional_logic_object',
1569: 'value' => $conditional_logic,
1570: );
1571: return $hidden_field;
1572: }
1573:
1574: public function get_feed_condition_conditional_logic() {
1575: $conditional_logic_object = $this->get_setting( 'feed_condition_conditional_logic_object' );
1576: if ( $conditional_logic_object ) {
1577: $form_id = rgget( 'id' );
1578: $form = GFFormsModel::get_form_meta( $form_id );
1579: $conditional_logic = json_encode( GFFormsModel::trim_conditional_logic_values_from_element( $conditional_logic_object, $form ) );
1580: } else {
1581: $conditional_logic = '{}';
1582: }
1583: return $conditional_logic;
1584: }
1585:
1586: public function validate_feed_condition_settings( $field, $settings ) {
1587: $checkbox_field = $this->get_feed_condition_checkbox( $field );
1588: $this->validate_checkbox_settings( $checkbox_field, $settings );
1589:
1590: if ( ! isset( $settings['feed_condition_conditional_logic_object'] ) ) {
1591: return;
1592: }
1593:
1594: $conditional_logic_object = $settings['feed_condition_conditional_logic_object'];
1595: if ( ! isset( $conditional_logic_object['conditionalLogic'] ) ) {
1596: return;
1597: }
1598: $conditional_logic = $conditional_logic_object['conditionalLogic'];
1599: $conditional_logic_safe = GFFormsModel::sanitize_conditional_logic( $conditional_logic );
1600: if ( serialize( $conditional_logic ) != serialize( $conditional_logic_safe ) ) {
1601: $this->set_field_error( $field, esc_html__( 'Invalid value', 'gravityforms' ) );
1602: }
1603: }
1604:
1605: public static function add_entry_meta( $form ) {
1606: $entry_meta = GFFormsModel::get_entry_meta( $form['id'] );
1607: $keys = array_keys( $entry_meta );
1608: foreach ( $keys as $key ) {
1609: array_push( $form['fields'], array( 'id' => $key, 'label' => $entry_meta[ $key ]['label'] ) );
1610: }
1611:
1612: return $form;
1613: }
1614:
1615: public function has_feed_condition_field() {
1616:
1617: $fields = $this->settings_fields_only( 'feed' );
1618:
1619: foreach ( $fields as $field ) {
1620: if ( $field['type'] == 'feed_condition' ) {
1621: return true;
1622: }
1623: }
1624:
1625: return false;
1626: }
1627:
1628: public function add_delayed_payment_support( $options ) {
1629: $this->delayed_payment_integration = $options;
1630:
1631: if ( is_admin() ) {
1632: add_filter( 'gform_gravityformspaypal_feed_settings_fields', array( $this, 'add_paypal_post_payment_actions' ) );
1633: }
1634:
1635: add_action( 'gform_paypal_fulfillment', array( $this, 'paypal_fulfillment' ), 10, 4 );
1636: }
1637:
1638: 1639: 1640: 1641: 1642: 1643: 1644:
1645: public function add_paypal_post_payment_actions( $feed_settings_fields ) {
1646:
1647: $form_id = absint( rgget( 'id' ) );
1648: if ( $this->has_feed( $form_id ) ) {
1649:
1650: $addon_label = rgar( $this->delayed_payment_integration, 'option_label' );
1651: $choice = array(
1652: 'label' => $addon_label ? $addon_label : sprintf( esc_html__( 'Process %s feed only when payment is received.', 'gravityforms' ), $this->get_short_title() ),
1653: 'name' => 'delay_' . $this->_slug,
1654: );
1655:
1656: $field_name = 'post_payment_actions';
1657: $field = $this->get_field( $field_name, $feed_settings_fields );
1658:
1659: if ( ! $field ) {
1660:
1661: $fields = array(
1662: array(
1663: 'name' => $field_name,
1664: 'label' => esc_html__( 'Post Payment Actions', 'gravityforms' ),
1665: 'type' => 'checkbox',
1666: 'choices' => array( $choice ),
1667: 'tooltip' => '<h6>' . esc_html__( 'Post Payment Actions', 'gravityforms' ) . '</h6>' . esc_html__( 'Select which actions should only occur after payment has been received.', 'gravityforms' )
1668: )
1669: );
1670:
1671: $feed_settings_fields = $this->add_field_after( 'options', $fields, $feed_settings_fields );
1672:
1673: } else {
1674:
1675: $field['choices'][] = $choice;
1676: $feed_settings_fields = $this->replace_field( $field_name, $field, $feed_settings_fields );
1677:
1678: }
1679: }
1680:
1681: return $feed_settings_fields;
1682: }
1683:
1684: public function paypal_fulfillment( $entry, $paypal_config, $transaction_id, $amount ) {
1685:
1686: $this->log_debug( 'GFFeedAddOn::paypal_fulfillment(): Checking PayPal fulfillment for transaction ' . $transaction_id . ' for ' . $this->_slug );
1687: $is_fulfilled = gform_get_meta( $entry['id'], "{$this->_slug}_is_fulfilled" );
1688: if ( $is_fulfilled || ! $this->is_delayed( $paypal_config ) ) {
1689: $this->log_debug( 'GFFeedAddOn::paypal_fulfillment(): Entry ' . $entry['id'] . ' is already fulfilled or feeds are not delayed. No action necessary.' );
1690: return false;
1691: }
1692:
1693: $form = RGFormsModel::get_form_meta( $entry['form_id'] );
1694: $this->_bypass_feed_delay = true;
1695: $this->maybe_process_feed( $entry, $form );
1696:
1697: }
1698:
1699:
1700: public function add_feed_error( $error_message, $feed, $entry, $form ) {
1701:
1702:
1703: $backtrace = debug_backtrace();
1704: $method = $backtrace[1]['class'] . '::' . $backtrace[1]['function'];
1705: $this->log_error( $method . '(): ' . $error_message );
1706:
1707:
1708: $feed_name = rgars( $feed, 'meta/feed_name' ) ? rgars( $feed, 'meta/feed_name' ) : rgars( $feed, 'meta/feedName' );
1709: $error_message = $feed_name . ': ' . $error_message;
1710:
1711:
1712: $this->add_note( $entry['id'], $error_message, 'error' );
1713:
1714:
1715: $slug = str_replace( 'gravityforms', '', $this->_slug );
1716:
1717:
1718: gf_do_action( array( "gform_{$slug}_error", $form['id'] ), $feed, $entry, $form );
1719:
1720: }
1721:
1722:
1723:
1724: public function get_paypal_feed( $form_id, $entry ) {
1725:
1726: if ( ! class_exists( 'GFPayPal' ) ) {
1727: return false;
1728: }
1729:
1730: if ( method_exists( 'GFPayPal', 'get_config_by_entry' ) ) {
1731: $feed = GFPayPal::get_config_by_entry( $entry );
1732: } elseif ( method_exists( 'GFPayPal', 'get_config' ) ) {
1733: $feed = GFPayPal::get_config( $form_id );
1734: } else {
1735: $feed = false;
1736: }
1737:
1738: return $feed;
1739: }
1740:
1741: public function has_paypal_payment( $feed, $form, $entry ) {
1742:
1743: $products = GFCommon::get_product_fields( $form, $entry );
1744:
1745: $payment_field = $feed['meta']['transactionType'] === 'product' ? $feed['meta']['paymentAmount'] : $feed['meta']['recurringAmount'];
1746: $setup_fee_field = rgar( $feed['meta'], 'setupFee_enabled' ) ? $feed['meta']['setupFee_product'] : false;
1747: $trial_field = rgar( $feed['meta'], 'trial_enabled' ) ? rgars( $feed, 'meta/trial_product' ) : false;
1748:
1749: $amount = 0;
1750: $line_items = array();
1751: $discounts = array();
1752: $fee_amount = 0;
1753: $trial_amount = 0;
1754: foreach ( $products['products'] as $field_id => $product ) {
1755:
1756: $quantity = $product['quantity'] ? $product['quantity'] : 1;
1757: $product_price = GFCommon::to_number( $product['price'] );
1758:
1759: $options = array();
1760: if ( is_array( rgar( $product, 'options' ) ) ) {
1761: foreach ( $product['options'] as $option ) {
1762: $options[] = $option['option_name'];
1763: $product_price += $option['price'];
1764: }
1765: }
1766:
1767: $is_trial_or_setup_fee = false;
1768:
1769: if ( ! empty( $trial_field ) && $trial_field === $field_id ) {
1770:
1771: $trial_amount = $product_price * $quantity;
1772: $is_trial_or_setup_fee = true;
1773:
1774: } elseif ( ! empty( $setup_fee_field ) && $setup_fee_field === $field_id ) {
1775:
1776: $fee_amount = $product_price * $quantity;
1777: $is_trial_or_setup_fee = true;
1778: }
1779:
1780:
1781: if ( is_numeric( $payment_field ) && $payment_field != $field_id ) {
1782: continue;
1783: }
1784:
1785:
1786: if ( $is_trial_or_setup_fee && ! is_numeric( $payment_field ) ) {
1787: continue;
1788: }
1789:
1790: $amount += $product_price * $quantity;
1791:
1792: }
1793:
1794:
1795: if ( ! empty( $products['shipping']['name'] ) && ! is_numeric( $payment_field ) ) {
1796: $line_items[] = array( 'id' => '',
1797: 'name' => $products['shipping']['name'],
1798: 'description' => '',
1799: 'quantity' => 1,
1800: 'unit_price' => GFCommon::to_number( $products['shipping']['price'] ),
1801: 'is_shipping' => 1
1802: );
1803: $amount += $products['shipping']['price'];
1804: }
1805:
1806: return $amount > 0;
1807: }
1808:
1809: public function is_delayed_payment( $entry, $form, $is_delayed ) {
1810: if ( $this->_slug == 'gravityformspaypal' ) {
1811: return false;
1812: }
1813:
1814: $paypal_feed = $this->get_paypal_feed( $form['id'], $entry );
1815: if ( ! $paypal_feed ) {
1816: return false;
1817: }
1818:
1819: $has_payment = self::get_paypal_payment_amount( $form, $entry, $paypal_feed ) > 0;
1820:
1821: return rgar( $paypal_feed['meta'], "delay_{$this->_slug}" ) && $has_payment && ! $is_delayed;
1822: }
1823:
1824: public static function get_paypal_payment_amount( $form, $entry, $paypal_config ) {
1825:
1826:
1827: $products = GFCommon::get_product_fields( $form, $entry, true );
1828: $recurring_field = rgar( $paypal_config['meta'], 'recurring_amount_field' );
1829: $total = 0;
1830: foreach ( $products['products'] as $id => $product ) {
1831:
1832: if ( $paypal_config['meta']['type'] != 'subscription' || $recurring_field == $id || $recurring_field == 'all' ) {
1833: $price = GFCommon::to_number( $product['price'] );
1834: if ( is_array( rgar( $product, 'options' ) ) ) {
1835: foreach ( $product['options'] as $option ) {
1836: $price += GFCommon::to_number( $option['price'] );
1837: }
1838: }
1839:
1840: $total += $price * $product['quantity'];
1841: }
1842: }
1843:
1844: if ( 'all' === $recurring_field && ! empty( $products['shipping']['price'] ) ) {
1845: $total += floatval( $products['shipping']['price'] );
1846: }
1847:
1848: return $total;
1849: }
1850:
1851:
1852:
1853: public function has_frontend_feeds( $form ) {
1854: $result = $this->register_frontend_feeds( $form );
1855: return ! empty( $result );
1856: }
1857:
1858: 1859: 1860: 1861: 1862: 1863: 1864: 1865: 1866:
1867: public function register_frontend_feeds( $form ) {
1868:
1869: if ( ! isset( self::$_frontend_feeds[ $form['id'] ] ) ) {
1870: self::$_frontend_feeds[ $form['id'] ] = array();
1871: }
1872:
1873: $feeds = $this->get_frontend_feeds( $form );
1874:
1875: $this->add_frontend_feeds( $form['id'], $feeds );
1876:
1877: return ! empty( $feeds );
1878: }
1879:
1880: 1881: 1882: 1883: 1884: 1885: 1886: 1887:
1888: public function add_frontend_feeds( $form_id, $feeds ) {
1889:
1890: foreach ( $feeds as $feed ) {
1891: $filter = array( 'feedId' => $feed['feedId'], 'addonSlug' => $feed['addonSlug'] );
1892: $found = wp_list_filter( self::$_frontend_feeds[ $form_id ], $filter );
1893:
1894: if ( empty( $found ) ) {
1895: self::$_frontend_feeds[ $form_id ][] = $feed;
1896: }
1897: }
1898: }
1899:
1900: 1901: 1902: 1903: 1904: 1905: 1906: 1907: 1908:
1909: public function get_frontend_feeds( $form ) {
1910:
1911: if ( ! $this->_supports_frontend_feeds ) {
1912: return array();
1913: }
1914:
1915: $feeds = $this->get_active_feeds( $form['id'] );
1916: if ( empty( $feeds ) ) {
1917: return array();
1918: }
1919:
1920: $frontend_feeds = array();
1921:
1922: foreach ( $feeds as $feed ) {
1923:
1924: $_feed = array(
1925: 'feedId' => $feed['id'],
1926: 'addonSlug' => $this->_slug,
1927: 'conditionalLogic' => rgars( $feed, 'meta/feed_condition_conditional_logic' ) === '0' ? false : rgars( $feed, 'meta/feed_condition_conditional_logic_object/conditionalLogic', false ),
1928: 'isSingleFeed' => $this->_single_feed_submission,
1929: );
1930:
1931: $_feed = apply_filters( 'gform_addon_frontend_feed', $_feed, $form, $feed );
1932: $_feed = apply_filters( "gform_addon_frontend_feed_{$form['id']}", $_feed, $form, $feed );
1933: $_feed = apply_filters( "gform_{$this->_slug}_frontend_feed", $_feed, $form, $feed );
1934: $_feed = apply_filters( "gform_{$this->_slug}_frontend_feed_{$form['id']}", $_feed, $form, $feed );
1935:
1936: $frontend_feeds[] = $_feed;
1937:
1938: }
1939:
1940: return $frontend_feeds;
1941: }
1942:
1943: 1944: 1945: 1946: 1947: 1948: 1949:
1950: public static function register_frontend_feeds_init_script( $form ) {
1951:
1952: $feeds = rgar( self::$_frontend_feeds, $form['id'] );
1953: if ( empty( $feeds ) ) {
1954: return;
1955: }
1956:
1957: $args = array(
1958: 'formId' => $form['id'],
1959: 'feeds' => $feeds,
1960: );
1961:
1962: $script = sprintf( '; new GFFrontendFeeds( %s );', json_encode( $args ) );
1963:
1964: GFFormDisplay::add_init_script( $form['id'], 'gaddon_frontend_feeds', GFFormDisplay::ON_PAGE_RENDER, $script );
1965:
1966: }
1967:
1968: }
1969:
1970: if ( ! class_exists( 'WP_List_Table' ) ) {
1971: require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
1972: }
1973:
1974: class GFAddOnFeedsTable extends WP_List_Table {
1975:
1976: private $_feeds;
1977: private $_slug;
1978: private $_columns;
1979: private $_bulk_actions;
1980: private $_action_links;
1981: private $_addon_class;
1982:
1983: private $_column_value_callback = array();
1984: private $_no_items_callback = array();
1985: private $_message_callback = array();
1986:
1987: function __construct( $feeds, $slug, $columns = array(), $bulk_actions, $action_links, $column_value_callback, $no_items_callback, $message_callback, $addon_class ) {
1988: $this->_bulk_actions = $bulk_actions;
1989: $this->_feeds = $feeds;
1990: $this->_slug = $slug;
1991: $this->_columns = $columns;
1992: $this->_column_value_callback = $column_value_callback;
1993: $this->_action_links = $action_links;
1994: $this->_no_items_callback = $no_items_callback;
1995: $this->_message_callback = $message_callback;
1996: $this->_addon_class = $addon_class;
1997:
1998: $standard_cols = array(
1999: 'cb' => esc_html__( 'Checkbox', 'gravityforms' ),
2000: 'is_active' => '',
2001: );
2002:
2003: $all_cols = array_merge( $standard_cols, $columns );
2004:
2005: $this->_column_headers = array(
2006: $all_cols,
2007: array(),
2008: array(),
2009: rgar( array_keys( $all_cols ), 2 ),
2010: );
2011:
2012: parent::__construct(
2013: array(
2014: 'singular' => esc_html__( 'feed', 'gravityforms' ),
2015: 'plural' => esc_html__( 'feeds', 'gravityforms' ),
2016: 'ajax' => false,
2017: )
2018: );
2019: }
2020:
2021: function prepare_items() {
2022: $this->items = isset( $this->_feeds ) ? $this->_feeds : array();
2023: }
2024:
2025: function get_columns() {
2026: return $this->_column_headers[0];
2027: }
2028:
2029: function get_bulk_actions() {
2030: return $this->_bulk_actions;
2031: }
2032:
2033: function no_items() {
2034: echo call_user_func( $this->_no_items_callback );
2035: }
2036:
2037: function display_rows_or_placeholder() {
2038: $message = call_user_func( $this->_message_callback );
2039:
2040: if ( $message !== false ) {
2041: ?>
2042: <tr class="no-items">
2043: <td class="colspanchange" colspan="<?php echo $this->get_column_count() ?>">
2044: <?php echo $message ?>
2045: </td>
2046: </tr>
2047: <?php
2048: } else {
2049: parent::display_rows_or_placeholder();
2050: }
2051:
2052: }
2053:
2054: function column_default( $item, $column ) {
2055:
2056: if ( is_callable( $this->_column_value_callback ) ) {
2057: $value = call_user_func( $this->_column_value_callback, $item, $column );
2058: }
2059:
2060:
2061: $columns = array_keys( $this->_columns );
2062: if ( is_array( $columns ) && count( $columns ) > 0 && $columns[0] == $column ) {
2063: $value = $this->add_action_links( $item, $column, $value );
2064: }
2065:
2066: return $value;
2067: }
2068:
2069: function column_cb( $item ) {
2070: $feed_id = rgar( $item, 'id' );
2071:
2072: return sprintf(
2073: '<input type="checkbox" name="feed_ids[]" value="%s" />', esc_attr( $feed_id )
2074: );
2075: }
2076:
2077: function add_action_links( $item, $column, $value ) {
2078:
2079: 2080: 2081: 2082: 2083: 2084: 2085:
2086: $actions = apply_filters( $this->_slug . '_feed_actions', $this->_action_links, $item, $column );
2087:
2088:
2089: foreach ( $actions as $action => &$link ) {
2090: $link = str_replace( '_id_', $item['id'], $link );
2091: }
2092:
2093: if ( ! $this->_addon_class->can_duplicate_feed( $item['id'] ) ) {
2094: unset( $actions['duplicate'] );
2095: }
2096:
2097: return sprintf( '%1$s %2$s', $value, $this->row_actions( $actions ) );
2098: }
2099:
2100: function _column_is_active( $item, $classes, $data, $primary ) {
2101:
2102:
2103: echo '<th scope="row" class="manage-column column-is_active">';
2104:
2105:
2106: $is_active = intval( rgar( $item, 'is_active' ) );
2107:
2108:
2109: $src = GFCommon::get_base_url() . "/images/active{$is_active}.png";
2110:
2111:
2112: $title = $is_active ? esc_attr__( 'Active', 'gravityforms' ) : esc_attr__( 'Inactive', 'gravityforms' );
2113:
2114:
2115: echo sprintf( '<img src="%s" title="%s" onclick="gaddon.toggleFeedActive(this, \'%s\', \'%s\');" onkeypress="gaddon.toggleFeedActive(this, \'%s\', \'%s\');" style="cursor:pointer";/>', $src, $title, esc_js( $this->_slug ), esc_js( $item['id'] ), esc_js( $this->_slug ), esc_js( $item['id'] ) );
2116:
2117:
2118: echo '</th>';
2119:
2120: }
2121:
2122: }
2123: