HubSpot – Free Marketing Plugin for WordPress - Version 2.0.2

Version Description

(2014.09.09) =

  • Bug fixes
  • Fix inconsistent sources on stats widgets and contact timeline widgets
  • Onboarding tooltip popup for setting up settings now works correctly
  • Parse out get vars for traffic sources in the contact timeline
Download this release

Release Info

Developer AndyGCook
Plugin Icon 128x128 HubSpot – Free Marketing Plugin for WordPress
Version 2.0.2
Comparing to
See all releases

Code changes from version 2.0.1 to 2.0.2

admin/inc/class-leadin-list-table.php CHANGED
@@ -404,7 +404,7 @@ class LI_List_Table extends WP_List_Table {
404
  COUNT(DISTINCT p.pageview_id) AS lead_pageviews,
405
  LOWER(DATE_FORMAT(MAX(p.pageview_date), %s)) AS last_visit,
406
  ( SELECT COUNT(DISTINCT pageview_id) FROM $wpdb->li_pageviews WHERE lead_hashkey = l.hashkey AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS visits,
407
- ( SELECT MAX(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = l.hashkey AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS pageview_source
408
  FROM
409
  $wpdb->li_leads l
410
  LEFT JOIN $wpdb->li_submissions s ON l.hashkey = s.lead_hashkey
404
  COUNT(DISTINCT p.pageview_id) AS lead_pageviews,
405
  LOWER(DATE_FORMAT(MAX(p.pageview_date), %s)) AS last_visit,
406
  ( SELECT COUNT(DISTINCT pageview_id) FROM $wpdb->li_pageviews WHERE lead_hashkey = l.hashkey AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS visits,
407
+ ( SELECT MIN(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = l.hashkey AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS pageview_source
408
  FROM
409
  $wpdb->li_leads l
410
  LEFT JOIN $wpdb->li_submissions s ON l.hashkey = s.lead_hashkey
admin/inc/class-leadin-pointers.php CHANGED
@@ -22,6 +22,7 @@ class LI_Pointers {
22
  // Hooks & Filters
23
  //=============================================
24
 
 
25
  add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
26
  }
27
 
@@ -30,13 +31,19 @@ class LI_Pointers {
30
  */
31
  function enqueue ()
32
  {
 
 
33
  if ( !current_user_can( 'manage_options' ) )
34
- return;
 
 
35
 
36
  $options = get_option('leadin_options');
37
-
38
  if ( !isset($options['ignore_settings_popup']) || !$options['ignore_settings_popup'] )
39
  {
 
 
40
  wp_enqueue_style( 'wp-pointer' );
41
  wp_enqueue_script( 'jquery-ui' );
42
  wp_enqueue_script( 'wp-pointer' );
@@ -50,7 +57,7 @@ class LI_Pointers {
50
  * Shows a popup that asks for permission to allow tracking.
51
  */
52
  function li_settings_popup() {
53
- $id = '#toplevel_page_leadin_contacts';
54
  $nonce = wp_create_nonce( 'wpseo_activate_tracking' );
55
 
56
  $content = '<h3>' . __( 'Finish setting up LeadIn', 'leadin' ) . '</h3>';
@@ -111,6 +118,7 @@ class LI_Pointers {
111
  $(document).ready(setup);
112
  })(jQuery);
113
  //]]>
 
114
  </script>
115
  <?php
116
  }
22
  // Hooks & Filters
23
  //=============================================
24
 
25
+
26
  add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
27
  }
28
 
31
  */
32
  function enqueue ()
33
  {
34
+
35
+
36
  if ( !current_user_can( 'manage_options' ) )
37
+ return;
38
+
39
+
40
 
41
  $options = get_option('leadin_options');
42
+
43
  if ( !isset($options['ignore_settings_popup']) || !$options['ignore_settings_popup'] )
44
  {
45
+ leadin_log_debug('isset');
46
+
47
  wp_enqueue_style( 'wp-pointer' );
48
  wp_enqueue_script( 'jquery-ui' );
49
  wp_enqueue_script( 'wp-pointer' );
57
  * Shows a popup that asks for permission to allow tracking.
58
  */
59
  function li_settings_popup() {
60
+ $id = '#toplevel_page_leadin_stats';
61
  $nonce = wp_create_nonce( 'wpseo_activate_tracking' );
62
 
63
  $content = '<h3>' . __( 'Finish setting up LeadIn', 'leadin' ) . '</h3>';
118
  $(document).ready(setup);
119
  })(jQuery);
120
  //]]>
121
+
122
  </script>
123
  <?php
124
  }
admin/inc/class-stats-dashboard.php CHANGED
@@ -121,7 +121,7 @@ class LI_StatsDashboard {
121
  lead_id,
122
  lead_email,
123
  ( SELECT COUNT(*) FROM $wpdb->li_pageviews WHERE lead_hashkey = lh ) as pageviews,
124
- ( SELECT MAX(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = lh AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS lead_source
125
  FROM
126
  $wpdb->li_leads ll, $wpdb->li_pageviews lpv
127
  WHERE
@@ -142,7 +142,7 @@ class LI_StatsDashboard {
142
  lead_id,
143
  lead_email,
144
  ( SELECT COUNT(*) FROM $wpdb->li_pageviews WHERE lead_hashkey = lh ) as pageviews,
145
- ( SELECT MAX(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = lh AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS lead_source
146
  FROM
147
  $wpdb->li_leads ll, li_pageviews lpv
148
  WHERE
@@ -158,7 +158,7 @@ class LI_StatsDashboard {
158
  global $wpdb;
159
 
160
  $q = "SELECT hashkey lh,
161
- ( SELECT MAX(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = lh AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS lead_source
162
  FROM
163
  $wpdb->li_leads
164
  WHERE
121
  lead_id,
122
  lead_email,
123
  ( SELECT COUNT(*) FROM $wpdb->li_pageviews WHERE lead_hashkey = lh ) as pageviews,
124
+ ( SELECT MIN(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = lh AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS lead_source
125
  FROM
126
  $wpdb->li_leads ll, $wpdb->li_pageviews lpv
127
  WHERE
142
  lead_id,
143
  lead_email,
144
  ( SELECT COUNT(*) FROM $wpdb->li_pageviews WHERE lead_hashkey = lh ) as pageviews,
145
+ ( SELECT MIN(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = lh AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS lead_source
146
  FROM
147
  $wpdb->li_leads ll, li_pageviews lpv
148
  WHERE
158
  global $wpdb;
159
 
160
  $q = "SELECT hashkey lh,
161
+ ( SELECT MIN(pageview_source) AS pageview_source FROM $wpdb->li_pageviews WHERE lead_hashkey = lh AND pageview_session_start = 1 AND pageview_deleted = 0 ) AS lead_source
162
  FROM
163
  $wpdb->li_leads
164
  WHERE
admin/leadin-admin.php CHANGED
@@ -212,11 +212,11 @@ class WPLeadInAdmin {
212
  if ( !isset($_GET['page']) || $_GET['page'] != 'leadin_settings' )
213
  {
214
  $options = get_option('leadin_options');
215
- //if ( !isset($options['ignore_settings_popup']) || !$options['ignore_settings_popup'] )
216
-
217
  }
218
 
219
- $li_pointers = new LI_Pointers();
220
  }
221
 
222
  //=============================================
212
  if ( !isset($_GET['page']) || $_GET['page'] != 'leadin_settings' )
213
  {
214
  $options = get_option('leadin_options');
215
+ if ( !isset($options['ignore_settings_popup']) || !$options['ignore_settings_popup'] )
216
+ $li_pointers = new LI_Pointers();
217
  }
218
 
219
+
220
  }
221
 
222
  //=============================================
assets/js/build/leadin-subscribe.js CHANGED
@@ -423,7 +423,7 @@ function bind_leadin_subscribe_widget ()
423
  '<h3>Thanks!<br>You should receive a confirmation email in your inbox shortly.</h3>' +
424
  '<div>' +
425
  '<span class="powered-by">Powered by LeadIn</span>' +
426
- '<a href="http://leadin.com/wordpress-subscribe-widget/?utm_campaign=subscribe_widget&utm_medium=email&utm_source=' + window.location.host + '"><img alt="LeadIn" height="20px" width="99px" src="http://leadin.com/wp-content/themes/LeadIn-WP-Theme/library/images/logos/Leadin_logo@2x.png" alt="leadin.com"/></a>' +
427
  '</div>'
428
  ).css('text-align', 'center').fadeIn(250);
429
  });
423
  '<h3>Thanks!<br>You should receive a confirmation email in your inbox shortly.</h3>' +
424
  '<div>' +
425
  '<span class="powered-by">Powered by LeadIn</span>' +
426
+ '<a href="http://leadin.com/wordpress-subscribe-widget/?utm_campaign=subscribe_widget&utm_medium=email&utm_source=' + window.location.host + '"><img alt="LeadIn" height="20px" width="99px" src="' + document.location.protocol + '//leadin.com/wp-content/themes/LeadIn-WP-Theme/library/images/logos/Leadin_logo@2x.png" alt="leadin.com"/></a>' +
427
  '</div>'
428
  ).css('text-align', 'center').fadeIn(250);
429
  });
assets/js/build/leadin-subscribe.min.js CHANGED
@@ -1 +1 @@
1
- function bind_leadin_subscribe_widget(){!function(){var $=jQuery,subscribe={};subscribe.vex=void 0,subscribe.init=function(){$(window).scroll(function(){$(window).scrollTop()+$(window).height()>$(document).height()/2&&subscribe.open()})},subscribe.open=function(){return subscribe.vex?subscribe._open():(subscribe.vex=vex.dialog.open({showCloseButton:!0,className:"leadin-subscribe "+$("#leadin-subscribe-vex-class").val(),message:$("#leadin-subscribe-heading").val(),input:'<input id="leadin-subscribe-email" name="email" type="email" placeholder="Email address" />'+(0==$("#leadin-subscribe-name-fields").val()?"":'<input id="leadin-subscribe-fname" name="fname" type="text" placeholder="First Name" /><input id="leadin-subscribe-lname" name="lname" type="text" placeholder="Last Name" />')+(0==$("#leadin-subscribe-phone-field").val()?"":'<input id="leadin-subscribe-phone" name="phone" type="tel" placeholder="Phone" />'),buttons:[$.extend({},vex.dialog.buttons.YES,{text:$("#leadin-subscribe-btn-label").val()?$("#leadin-subscribe-btn-label").val():"SUBSCRIBE"})],onSubmit:function(){$subscribe_form=$(this),$subscribe_form.find("input.error").removeClass("error");var form_validated=!0;return $subscribe_form.find("input").each(function(){var $input=$(this);$input.val()||($input.addClass("error"),form_validated=!1)}),form_validated?($(".vex-dialog-form").fadeOut(300,function(){$(".vex-dialog-form").html('<div class="vex-close"></div><h3>Thanks!<br>You should receive a confirmation email in your inbox shortly.</h3><div><span class="powered-by">Powered by LeadIn</span><a href="http://leadin.com/wordpress-subscribe-widget/?utm_campaign=subscribe_widget&utm_medium=email&utm_source='+window.location.host+'"><img alt="LeadIn" height="20px" width="99px" src="http://leadin.com/wp-content/themes/LeadIn-WP-Theme/library/images/logos/Leadin_logo@2x.png" alt="leadin.com"/></a></div>').css("text-align","center").fadeIn(250)}),leadin_submit_form($(".leadin-subscribe form"),$),$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date}),!1):!1},callback:function(data){data===!1&&$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date}),$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date})}}),void $(".leadin-subscribe form.vex-dialog-form").append('<a href="http://leadin.com/pop-subscribe-form-plugin-wordpress/?utm_campaign=subscribe_widget&utm_medium=widget&utm_source='+document.URL+'" id="leadin-subscribe-powered-by" class="leadin-subscribe-powered-by">Powered by LeadIn</a>'))},subscribe._open=function(){subscribe.vex.parent().removeClass("vex-closing")},subscribe.close=function(){subscribe.vex&&subscribe.vex.parent().addClass("vex-closing")},subscribe.init(),window.subscribe=subscribe}()}function leadin_subscribe_check_mobile($){var is_mobile=!1;return"none"==$("#leadin-subscribe-mobile-check").css("display")&&(is_mobile=!0),is_mobile}function leadin_subscribe_show(){jQuery.ajax({type:"POST",url:li_ajax.ajax_url,data:{action:"leadin_subscribe_show"},success:function(){},error:function(){}})}(function(){var vexFactory;vexFactory=function($){var animationEndSupport,vex;return animationEndSupport=!1,$(function(){var s;return s=(document.body||document.documentElement).style,animationEndSupport=void 0!==s.animation||void 0!==s.WebkitAnimation||void 0!==s.MozAnimation||void 0!==s.MsAnimation||void 0!==s.OAnimation,$(window).bind("keyup.vex",function(event){return 27===event.keyCode?vex.closeByEscape():void 0})}),vex={globalID:1,animationEndEvent:"animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend",baseClassNames:{vex:"vex",content:"vex-content",overlay:"vex-overlay",close:"vex-close",closing:"vex-closing",open:"vex-open"},defaultOptions:{content:"",showCloseButton:!0,escapeButtonCloses:!0,overlayClosesOnClick:!0,appendLocation:"body",className:"",css:{},overlayClassName:"",overlayCSS:{},contentClassName:"",contentCSS:{},closeClassName:"",closeCSS:{}},open:function(options){return options=$.extend({},vex.defaultOptions,options),options.id=vex.globalID,vex.globalID+=1,options.$vex=$("<div>").addClass(vex.baseClassNames.vex).addClass(options.className).css(options.css).data({vex:options}),options.$vexOverlay=$("<div>").addClass(vex.baseClassNames.overlay).addClass(options.overlayClassName).css(options.overlayCSS).data({vex:options}),options.overlayClosesOnClick&&options.$vexOverlay.bind("click.vex",function(e){return e.target===this?vex.close($(this).data().vex.id):void 0}),options.$vex.append(options.$vexOverlay),options.$vexContent=$("<div>").addClass(vex.baseClassNames.content).addClass(options.contentClassName).css(options.contentCSS).append(options.content).data({vex:options}),options.$vex.append(options.$vexContent),options.showCloseButton&&(options.$closeButton=$("<div>").addClass(vex.baseClassNames.close).addClass(options.closeClassName).css(options.closeCSS).data({vex:options}).bind("click.vex",function(){return vex.close($(this).data().vex.id)}),options.$vexContent.append(options.$closeButton)),$(options.appendLocation).append(options.$vex),vex.setupBodyClassName(options.$vex),options.afterOpen&&options.afterOpen(options.$vexContent,options),setTimeout(function(){return options.$vexContent.trigger("vexOpen",options)},0),options.$vexContent},getAllVexes:function(){return $("."+vex.baseClassNames.vex+':not(".'+vex.baseClassNames.closing+'") .'+vex.baseClassNames.content)},getVexByID:function(id){return vex.getAllVexes().filter(function(){return $(this).data().vex.id===id})},close:function(id){var $lastVex;if(!id){if($lastVex=vex.getAllVexes().last(),!$lastVex.length)return!1;id=$lastVex.data().vex.id}return vex.closeByID(id)},closeAll:function(){var ids;return ids=vex.getAllVexes().map(function(){return $(this).data().vex.id}).toArray(),(null!=ids?ids.length:void 0)?($.each(ids.reverse(),function(index,id){return vex.closeByID(id)}),!0):!1},closeByID:function(id){var $vex,$vexContent,beforeClose,close,options;return $vexContent=vex.getVexByID(id),$vexContent.length?($vex=$vexContent.data().vex.$vex,options=$.extend({},$vexContent.data().vex),beforeClose=function(){return options.beforeClose?options.beforeClose($vexContent,options):void 0},close=function(){return $vexContent.trigger("vexClose",options),$vex.remove(),options.afterClose?options.afterClose($vexContent,options):void 0},animationEndSupport?(beforeClose(),$vex.unbind(vex.animationEndEvent).bind(vex.animationEndEvent,function(){return close()}).addClass(vex.baseClassNames.closing)):(beforeClose(),close()),!0):void 0},closeByEscape:function(){var $lastVex,id,ids;return ids=vex.getAllVexes().map(function(){return $(this).data().vex.id}).toArray(),(null!=ids?ids.length:void 0)?(id=Math.max.apply(Math,ids),$lastVex=vex.getVexByID(id),$lastVex.data().vex.escapeButtonCloses!==!0?!1:vex.closeByID(id)):!1},setupBodyClassName:function($vex){return $vex.bind("vexOpen.vex",function(){return $("body").addClass(vex.baseClassNames.open)}).bind("vexClose.vex",function(){return vex.getAllVexes().length?void 0:$("body").removeClass(vex.baseClassNames.open)})},hideLoading:function(){return $(".vex-loading-spinner").remove()},showLoading:function(){return vex.hideLoading(),$("body").append('<div class="vex-loading-spinner '+vex.defaultOptions.className+'"></div>')}}},"function"==typeof define&&define.amd?define(["jquery"],vexFactory):"object"==typeof exports?module.exports=vexFactory(require("jquery")):window.vex=vexFactory(jQuery)}).call(this),function(){var vexDialogFactory;vexDialogFactory=function($,vex){var $formToObject,dialog;return null==vex?$.error("Vex is required to use vex.dialog"):($formToObject=function($form){var object;return object={},$.each($form.serializeArray(),function(){return object[this.name]?(object[this.name].push||(object[this.name]=[object[this.name]]),object[this.name].push(this.value||"")):object[this.name]=this.value||""}),object},dialog={},dialog.buttons={YES:{text:"OK",type:"submit",className:"vex-dialog-button-primary"},NO:{text:"Cancel",type:"button",className:"vex-dialog-button-secondary",click:function($vexContent){return $vexContent.data().vex.value=!1,vex.close($vexContent.data().vex.id)}}},dialog.defaultOptions={callback:function(){},afterOpen:function(){},message:"Message",input:'<input name="vex" type="hidden" value="_vex-empty-value" />',value:!1,buttons:[dialog.buttons.YES,dialog.buttons.NO],showCloseButton:!1,onSubmit:function(event){var $form,$vexContent;return $form=$(this),$vexContent=$form.parent(),event.preventDefault(),event.stopPropagation(),$vexContent.data().vex.value=dialog.getFormValueOnSubmit($formToObject($form)),vex.close($vexContent.data().vex.id)},focusFirstInput:!0},dialog.defaultAlertOptions={message:"Alert",buttons:[dialog.buttons.YES]},dialog.defaultConfirmOptions={message:"Confirm"},dialog.open=function(options){var $vexContent;return options=$.extend({},vex.defaultOptions,dialog.defaultOptions,options),options.content=dialog.buildDialogForm(options),options.beforeClose=function($vexContent){return options.callback($vexContent.data().vex.value)},$vexContent=vex.open(options),options.focusFirstInput&&$vexContent.find('input[type="submit"], textarea, input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"]').first().focus(),$vexContent},dialog.alert=function(options){return"string"==typeof options&&(options={message:options}),options=$.extend({},dialog.defaultAlertOptions,options),dialog.open(options)},dialog.confirm=function(options){return"string"==typeof options?$.error("dialog.confirm(options) requires options.callback."):(options=$.extend({},dialog.defaultConfirmOptions,options),dialog.open(options))},dialog.prompt=function(options){var defaultPromptOptions;return"string"==typeof options?$.error("dialog.prompt(options) requires options.callback."):(defaultPromptOptions={message:'<label for="vex">'+(options.label||"Prompt:")+"</label>",input:'<input name="vex" type="text" class="vex-dialog-prompt-input" placeholder="'+(options.placeholder||"")+'" value="'+(options.value||"")+'" />'},options=$.extend({},defaultPromptOptions,options),dialog.open(options))},dialog.buildDialogForm=function(options){var $form,$input,$message;return $form=$('<form class="vex-dialog-form" />'),$message=$('<div class="vex-dialog-message" />'),$input=$('<div class="vex-dialog-input" />'),$form.append($message.append(options.message)).append($input.append(options.input)).append(dialog.buttonsToDOM(options.buttons)).bind("submit.vex",options.onSubmit),$form},dialog.getFormValueOnSubmit=function(formData){return formData.vex||""===formData.vex?"_vex-empty-value"===formData.vex?!0:formData.vex:formData},dialog.buttonsToDOM=function(buttons){var $buttons;return $buttons=$('<div class="vex-dialog-buttons" />'),$.each(buttons,function(index,button){return $buttons.append($('<input type="'+button.type+'" />').val(button.text).addClass(button.className+" vex-dialog-button "+(0===index?"vex-first ":"")+(index===buttons.length-1?"vex-last ":"")).bind("click.vex",function(e){return button.click?button.click($(this).parents("."+vex.baseClassNames.content),e):void 0}))}),$buttons},dialog)},"function"==typeof define&&define.amd?define(["jquery","vex"],vexDialogFactory):"object"==typeof exports?module.exports=vexDialogFactory(require("jquery"),require("vex")):window.vex.dialog=vexDialogFactory(window.jQuery,window.vex)}.call(this);var ignore_date=new Date;ignore_date.setTime(ignore_date.getTime()+12096e5),jQuery(document).ready(function($){var li_subscribe_flag=$.cookie("li_subscribe");leadin_subscribe_check_mobile($)||(li_subscribe_flag?"show"==li_subscribe_flag&&bind_leadin_subscribe_widget():leadin_check_visitor_status($.cookie("li_hash"),function(data){"vex_set"!=data?($.cookie("li_subscribe","show",{path:"/",domain:""}),bind_leadin_subscribe_widget()):$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date})}))});
1
+ function bind_leadin_subscribe_widget(){!function(){var $=jQuery,subscribe={};subscribe.vex=void 0,subscribe.init=function(){$(window).scroll(function(){$(window).scrollTop()+$(window).height()>$(document).height()/2&&subscribe.open()})},subscribe.open=function(){return subscribe.vex?subscribe._open():(subscribe.vex=vex.dialog.open({showCloseButton:!0,className:"leadin-subscribe "+$("#leadin-subscribe-vex-class").val(),message:$("#leadin-subscribe-heading").val(),input:'<input id="leadin-subscribe-email" name="email" type="email" placeholder="Email address" />'+(0==$("#leadin-subscribe-name-fields").val()?"":'<input id="leadin-subscribe-fname" name="fname" type="text" placeholder="First Name" /><input id="leadin-subscribe-lname" name="lname" type="text" placeholder="Last Name" />')+(0==$("#leadin-subscribe-phone-field").val()?"":'<input id="leadin-subscribe-phone" name="phone" type="tel" placeholder="Phone" />'),buttons:[$.extend({},vex.dialog.buttons.YES,{text:$("#leadin-subscribe-btn-label").val()?$("#leadin-subscribe-btn-label").val():"SUBSCRIBE"})],onSubmit:function(){$subscribe_form=$(this),$subscribe_form.find("input.error").removeClass("error");var form_validated=!0;return $subscribe_form.find("input").each(function(){var $input=$(this);$input.val()||($input.addClass("error"),form_validated=!1)}),form_validated?($(".vex-dialog-form").fadeOut(300,function(){$(".vex-dialog-form").html('<div class="vex-close"></div><h3>Thanks!<br>You should receive a confirmation email in your inbox shortly.</h3><div><span class="powered-by">Powered by LeadIn</span><a href="http://leadin.com/wordpress-subscribe-widget/?utm_campaign=subscribe_widget&utm_medium=email&utm_source='+window.location.host+'"><img alt="LeadIn" height="20px" width="99px" src="'+document.location.protocol+'//leadin.com/wp-content/themes/LeadIn-WP-Theme/library/images/logos/Leadin_logo@2x.png" alt="leadin.com"/></a></div>').css("text-align","center").fadeIn(250)}),leadin_submit_form($(".leadin-subscribe form"),$),$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date}),!1):!1},callback:function(data){data===!1&&$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date}),$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date})}}),void $(".leadin-subscribe form.vex-dialog-form").append('<a href="http://leadin.com/pop-subscribe-form-plugin-wordpress/?utm_campaign=subscribe_widget&utm_medium=widget&utm_source='+document.URL+'" id="leadin-subscribe-powered-by" class="leadin-subscribe-powered-by">Powered by LeadIn</a>'))},subscribe._open=function(){subscribe.vex.parent().removeClass("vex-closing")},subscribe.close=function(){subscribe.vex&&subscribe.vex.parent().addClass("vex-closing")},subscribe.init(),window.subscribe=subscribe}()}function leadin_subscribe_check_mobile($){var is_mobile=!1;return"none"==$("#leadin-subscribe-mobile-check").css("display")&&(is_mobile=!0),is_mobile}function leadin_subscribe_show(){jQuery.ajax({type:"POST",url:li_ajax.ajax_url,data:{action:"leadin_subscribe_show"},success:function(){},error:function(){}})}(function(){var vexFactory;vexFactory=function($){var animationEndSupport,vex;return animationEndSupport=!1,$(function(){var s;return s=(document.body||document.documentElement).style,animationEndSupport=void 0!==s.animation||void 0!==s.WebkitAnimation||void 0!==s.MozAnimation||void 0!==s.MsAnimation||void 0!==s.OAnimation,$(window).bind("keyup.vex",function(event){return 27===event.keyCode?vex.closeByEscape():void 0})}),vex={globalID:1,animationEndEvent:"animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend",baseClassNames:{vex:"vex",content:"vex-content",overlay:"vex-overlay",close:"vex-close",closing:"vex-closing",open:"vex-open"},defaultOptions:{content:"",showCloseButton:!0,escapeButtonCloses:!0,overlayClosesOnClick:!0,appendLocation:"body",className:"",css:{},overlayClassName:"",overlayCSS:{},contentClassName:"",contentCSS:{},closeClassName:"",closeCSS:{}},open:function(options){return options=$.extend({},vex.defaultOptions,options),options.id=vex.globalID,vex.globalID+=1,options.$vex=$("<div>").addClass(vex.baseClassNames.vex).addClass(options.className).css(options.css).data({vex:options}),options.$vexOverlay=$("<div>").addClass(vex.baseClassNames.overlay).addClass(options.overlayClassName).css(options.overlayCSS).data({vex:options}),options.overlayClosesOnClick&&options.$vexOverlay.bind("click.vex",function(e){return e.target===this?vex.close($(this).data().vex.id):void 0}),options.$vex.append(options.$vexOverlay),options.$vexContent=$("<div>").addClass(vex.baseClassNames.content).addClass(options.contentClassName).css(options.contentCSS).append(options.content).data({vex:options}),options.$vex.append(options.$vexContent),options.showCloseButton&&(options.$closeButton=$("<div>").addClass(vex.baseClassNames.close).addClass(options.closeClassName).css(options.closeCSS).data({vex:options}).bind("click.vex",function(){return vex.close($(this).data().vex.id)}),options.$vexContent.append(options.$closeButton)),$(options.appendLocation).append(options.$vex),vex.setupBodyClassName(options.$vex),options.afterOpen&&options.afterOpen(options.$vexContent,options),setTimeout(function(){return options.$vexContent.trigger("vexOpen",options)},0),options.$vexContent},getAllVexes:function(){return $("."+vex.baseClassNames.vex+':not(".'+vex.baseClassNames.closing+'") .'+vex.baseClassNames.content)},getVexByID:function(id){return vex.getAllVexes().filter(function(){return $(this).data().vex.id===id})},close:function(id){var $lastVex;if(!id){if($lastVex=vex.getAllVexes().last(),!$lastVex.length)return!1;id=$lastVex.data().vex.id}return vex.closeByID(id)},closeAll:function(){var ids;return ids=vex.getAllVexes().map(function(){return $(this).data().vex.id}).toArray(),(null!=ids?ids.length:void 0)?($.each(ids.reverse(),function(index,id){return vex.closeByID(id)}),!0):!1},closeByID:function(id){var $vex,$vexContent,beforeClose,close,options;return $vexContent=vex.getVexByID(id),$vexContent.length?($vex=$vexContent.data().vex.$vex,options=$.extend({},$vexContent.data().vex),beforeClose=function(){return options.beforeClose?options.beforeClose($vexContent,options):void 0},close=function(){return $vexContent.trigger("vexClose",options),$vex.remove(),options.afterClose?options.afterClose($vexContent,options):void 0},animationEndSupport?(beforeClose(),$vex.unbind(vex.animationEndEvent).bind(vex.animationEndEvent,function(){return close()}).addClass(vex.baseClassNames.closing)):(beforeClose(),close()),!0):void 0},closeByEscape:function(){var $lastVex,id,ids;return ids=vex.getAllVexes().map(function(){return $(this).data().vex.id}).toArray(),(null!=ids?ids.length:void 0)?(id=Math.max.apply(Math,ids),$lastVex=vex.getVexByID(id),$lastVex.data().vex.escapeButtonCloses!==!0?!1:vex.closeByID(id)):!1},setupBodyClassName:function($vex){return $vex.bind("vexOpen.vex",function(){return $("body").addClass(vex.baseClassNames.open)}).bind("vexClose.vex",function(){return vex.getAllVexes().length?void 0:$("body").removeClass(vex.baseClassNames.open)})},hideLoading:function(){return $(".vex-loading-spinner").remove()},showLoading:function(){return vex.hideLoading(),$("body").append('<div class="vex-loading-spinner '+vex.defaultOptions.className+'"></div>')}}},"function"==typeof define&&define.amd?define(["jquery"],vexFactory):"object"==typeof exports?module.exports=vexFactory(require("jquery")):window.vex=vexFactory(jQuery)}).call(this),function(){var vexDialogFactory;vexDialogFactory=function($,vex){var $formToObject,dialog;return null==vex?$.error("Vex is required to use vex.dialog"):($formToObject=function($form){var object;return object={},$.each($form.serializeArray(),function(){return object[this.name]?(object[this.name].push||(object[this.name]=[object[this.name]]),object[this.name].push(this.value||"")):object[this.name]=this.value||""}),object},dialog={},dialog.buttons={YES:{text:"OK",type:"submit",className:"vex-dialog-button-primary"},NO:{text:"Cancel",type:"button",className:"vex-dialog-button-secondary",click:function($vexContent){return $vexContent.data().vex.value=!1,vex.close($vexContent.data().vex.id)}}},dialog.defaultOptions={callback:function(){},afterOpen:function(){},message:"Message",input:'<input name="vex" type="hidden" value="_vex-empty-value" />',value:!1,buttons:[dialog.buttons.YES,dialog.buttons.NO],showCloseButton:!1,onSubmit:function(event){var $form,$vexContent;return $form=$(this),$vexContent=$form.parent(),event.preventDefault(),event.stopPropagation(),$vexContent.data().vex.value=dialog.getFormValueOnSubmit($formToObject($form)),vex.close($vexContent.data().vex.id)},focusFirstInput:!0},dialog.defaultAlertOptions={message:"Alert",buttons:[dialog.buttons.YES]},dialog.defaultConfirmOptions={message:"Confirm"},dialog.open=function(options){var $vexContent;return options=$.extend({},vex.defaultOptions,dialog.defaultOptions,options),options.content=dialog.buildDialogForm(options),options.beforeClose=function($vexContent){return options.callback($vexContent.data().vex.value)},$vexContent=vex.open(options),options.focusFirstInput&&$vexContent.find('input[type="submit"], textarea, input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"]').first().focus(),$vexContent},dialog.alert=function(options){return"string"==typeof options&&(options={message:options}),options=$.extend({},dialog.defaultAlertOptions,options),dialog.open(options)},dialog.confirm=function(options){return"string"==typeof options?$.error("dialog.confirm(options) requires options.callback."):(options=$.extend({},dialog.defaultConfirmOptions,options),dialog.open(options))},dialog.prompt=function(options){var defaultPromptOptions;return"string"==typeof options?$.error("dialog.prompt(options) requires options.callback."):(defaultPromptOptions={message:'<label for="vex">'+(options.label||"Prompt:")+"</label>",input:'<input name="vex" type="text" class="vex-dialog-prompt-input" placeholder="'+(options.placeholder||"")+'" value="'+(options.value||"")+'" />'},options=$.extend({},defaultPromptOptions,options),dialog.open(options))},dialog.buildDialogForm=function(options){var $form,$input,$message;return $form=$('<form class="vex-dialog-form" />'),$message=$('<div class="vex-dialog-message" />'),$input=$('<div class="vex-dialog-input" />'),$form.append($message.append(options.message)).append($input.append(options.input)).append(dialog.buttonsToDOM(options.buttons)).bind("submit.vex",options.onSubmit),$form},dialog.getFormValueOnSubmit=function(formData){return formData.vex||""===formData.vex?"_vex-empty-value"===formData.vex?!0:formData.vex:formData},dialog.buttonsToDOM=function(buttons){var $buttons;return $buttons=$('<div class="vex-dialog-buttons" />'),$.each(buttons,function(index,button){return $buttons.append($('<input type="'+button.type+'" />').val(button.text).addClass(button.className+" vex-dialog-button "+(0===index?"vex-first ":"")+(index===buttons.length-1?"vex-last ":"")).bind("click.vex",function(e){return button.click?button.click($(this).parents("."+vex.baseClassNames.content),e):void 0}))}),$buttons},dialog)},"function"==typeof define&&define.amd?define(["jquery","vex"],vexDialogFactory):"object"==typeof exports?module.exports=vexDialogFactory(require("jquery"),require("vex")):window.vex.dialog=vexDialogFactory(window.jQuery,window.vex)}.call(this);var ignore_date=new Date;ignore_date.setTime(ignore_date.getTime()+12096e5),jQuery(document).ready(function($){var li_subscribe_flag=$.cookie("li_subscribe");leadin_subscribe_check_mobile($)||(li_subscribe_flag?"show"==li_subscribe_flag&&bind_leadin_subscribe_widget():leadin_check_visitor_status($.cookie("li_hash"),function(data){"vex_set"!=data?($.cookie("li_subscribe","show",{path:"/",domain:""}),bind_leadin_subscribe_widget()):$.cookie("li_subscribe","ignore",{path:"/",domain:"",expires:ignore_date})}))});
images/power-up-icon-constant-contact-list-sync_small.png DELETED
Binary file
images/power-up-icon-mailchimp-list-sync.png DELETED
Binary file
images/power-up-icon-mailchimp-list-sync_small.png DELETED
Binary file
inc/class-leadin.php CHANGED
@@ -5,68 +5,72 @@
5
  //=============================================
6
  class WPLeadIn {
7
 
8
- var $power_ups;
9
- /**
10
- * Class constructor
11
- */
12
- function __construct ()
13
- {
14
- leadin_set_wpdb_tables();
15
-
16
- $this->power_ups = self::get_available_power_ups();
17
  add_action('admin_bar_menu', array($this, 'add_leadin_link_to_admin_bar'), 999);
18
-
19
- if ( is_admin() )
20
- {
21
- if ( ! defined('DOING_AJAX') || ! DOING_AJAX )
22
- {
23
- if ( current_user_can('manage_options') )
24
- $li_wp_admin = new WPLeadInAdmin($this->power_ups);
25
- }
26
- }
27
- else
28
- {
29
-
30
- add_action('wp_enqueue_scripts', array($this, 'add_leadin_frontend_scripts'));
31
- // Get all the power-ups and instantiate them
32
- }
33
- }
34
-
35
- //=============================================
36
- // Scripts & Styles
37
- //=============================================
38
-
39
- /**
40
- * Adds front end javascript + initializes ajax object
41
- */
42
- function add_leadin_frontend_scripts ()
43
- {
44
- wp_register_script('leadin-tracking', LEADIN_PATH . '/assets/js/build/leadin-tracking.min.js', array ('jquery'), FALSE, TRUE);
45
- wp_enqueue_script('leadin-tracking');
46
-
47
- // replace https with http for admin-ajax calls for SSLed backends
48
- //wp_localize_script('leadin-tracking', 'li_ajax', array('ajax_url' => str_replace('https:', 'http:', admin_url('admin-ajax.php'))));
49
- wp_localize_script('leadin-tracking', 'li_ajax', array('ajax_url' => get_admin_url(NULL,'') . '/admin-ajax.php'));
50
- }
51
-
52
- /**
53
- * Adds LeadIn link to top-level admin bar
54
  */
55
- function add_leadin_link_to_admin_bar( $wp_admin_bar ) {
56
- global $wp_version;
 
 
 
 
 
 
 
 
 
 
 
57
 
58
- $args = array(
59
- 'id' => 'leadin-admin-menu',
60
- 'title' => '<span class="ab-icon" '. ( $wp_version < 3.8 && !is_plugin_active('mp6/mp6.php') ? ' style="margin-top: 3px;"' : ''). '><img src="/wp-content/plugins/leadin/images/leadin-svg-icon.svg" style="height:16px; width:16px;"></span><span class="ab-label">LeadIn</span>', // alter the title of existing node
61
- 'parent' => FALSE, // set parent to false to make it a top level (parent) node
62
- 'href' => get_bloginfo('wpurl') . '/wp-admin/admin.php?page=leadin_stats',
63
- 'meta' => array('title' => 'LeadIn')
64
- );
 
 
 
 
 
 
65
 
66
- $wp_admin_bar->add_node( $args );
67
- }
68
 
69
- /**
70
  * List available power-ups
71
  */
72
  public static function get_available_power_ups ( $min_version = FALSE, $max_version = FALSE ) {
5
  //=============================================
6
  class WPLeadIn {
7
 
8
+ var $power_ups;
9
+ /**
10
+ * Class constructor
11
+ */
12
+ function __construct ()
13
+ {
14
+ leadin_set_wpdb_tables();
15
+
16
+ $this->power_ups = self::get_available_power_ups();
17
  add_action('admin_bar_menu', array($this, 'add_leadin_link_to_admin_bar'), 999);
18
+
19
+ if ( is_admin() )
20
+ {
21
+ if ( ! defined('DOING_AJAX') || ! DOING_AJAX )
22
+ {
23
+ if ( current_user_can('manage_options') )
24
+ $li_wp_admin = new WPLeadInAdmin($this->power_ups);
25
+ }
26
+ }
27
+ else
28
+ {
29
+
30
+ add_action('wp_enqueue_scripts', array($this, 'add_leadin_frontend_scripts'));
31
+ // Get all the power-ups and instantiate them
32
+ }
33
+ }
34
+
35
+ //=============================================
36
+ // Scripts & Styles
37
+ //=============================================
38
+
39
+ /**
40
+ * Adds front end javascript + initializes ajax object
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  */
42
+ function add_leadin_frontend_scripts ()
43
+ {
44
+ wp_register_script('leadin-tracking', LEADIN_PATH . '/assets/js/build/leadin-tracking.min.js', array ('jquery'), FALSE, TRUE);
45
+ wp_enqueue_script('leadin-tracking');
46
+
47
+ // replace https with http for admin-ajax calls for SSLed backends
48
+ $admin_url = admin_url('admin-ajax.php');
49
+ wp_localize_script(
50
+ 'leadin-tracking',
51
+ 'li_ajax',
52
+ array('ajax_url' => ( is_ssl() ? str_replace('http:', 'https:', $admin_url) : str_replace('https:', 'http:', $admin_url) ))
53
+ );
54
+ }
55
 
56
+ /**
57
+ * Adds LeadIn link to top-level admin bar
58
+ */
59
+ function add_leadin_link_to_admin_bar( $wp_admin_bar ) {
60
+ global $wp_version;
61
+
62
+ $args = array(
63
+ 'id' => 'leadin-admin-menu',
64
+ 'title' => '<span class="ab-icon" '. ( $wp_version < 3.8 && !is_plugin_active('mp6/mp6.php') ? ' style="margin-top: 3px;"' : ''). '><img src="/wp-content/plugins/leadin/images/leadin-svg-icon.svg" style="height:16px; width:16px;"></span><span class="ab-label">LeadIn</span>', // alter the title of existing node
65
+ 'parent' => FALSE, // set parent to false to make it a top level (parent) node
66
+ 'href' => get_bloginfo('wpurl') . '/wp-admin/admin.php?page=leadin_stats',
67
+ 'meta' => array('title' => 'LeadIn')
68
+ );
69
 
70
+ $wp_admin_bar->add_node( $args );
71
+ }
72
 
73
+ /**
74
  * List available power-ups
75
  */
76
  public static function get_available_power_ups ( $min_version = FALSE, $max_version = FALSE ) {
leadin.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: LeadIn
4
  Plugin URI: http://leadin.com
5
  Description: LeadIn is an easy-to-use marketing automation and lead tracking plugin for WordPress that helps you better understand your web site visitors.
6
- Version: 2.0.1
7
  Author: Andy Cook, Nelson Joyce
8
  Author URI: http://leadin.com
9
  License: GPL2
@@ -26,7 +26,7 @@ if ( !defined('LEADIN_DB_VERSION') )
26
  define('LEADIN_DB_VERSION', '2.0.0');
27
 
28
  if ( !defined('LEADIN_PLUGIN_VERSION') )
29
- define('LEADIN_PLUGIN_VERSION', '2.0.1');
30
 
31
  if ( !defined('MIXPANEL_PROJECT_TOKEN') )
32
  define('MIXPANEL_PROJECT_TOKEN', 'a9615503ec58a6bce2c646a58390eac1');
3
  Plugin Name: LeadIn
4
  Plugin URI: http://leadin.com
5
  Description: LeadIn is an easy-to-use marketing automation and lead tracking plugin for WordPress that helps you better understand your web site visitors.
6
+ Version: 2.0.2
7
  Author: Andy Cook, Nelson Joyce
8
  Author URI: http://leadin.com
9
  License: GPL2
26
  define('LEADIN_DB_VERSION', '2.0.0');
27
 
28
  if ( !defined('LEADIN_PLUGIN_VERSION') )
29
+ define('LEADIN_PLUGIN_VERSION', '2.0.2');
30
 
31
  if ( !defined('MIXPANEL_PROJECT_TOKEN') )
32
  define('MIXPANEL_PROJECT_TOKEN', 'a9615503ec58a6bce2c646a58390eac1');
power-ups/constant-contact-connect.php CHANGED
@@ -5,7 +5,7 @@
5
  * Power-up Menu Text:
6
  * Power-up Slug: constant_contact_connect
7
  * Power-up Menu Link: settings
8
- * Power-up URI: http://leadin.com/mailchimp-list-sync
9
  * Power-up Description: Push your contacts to Constant Contact email lists.
10
  * Power-up Icon: power-up-icon-constant-contact-connect
11
  * Power-up Icon Small: power-up-icon-constant-contact-connect_small
5
  * Power-up Menu Text:
6
  * Power-up Slug: constant_contact_connect
7
  * Power-up Menu Link: settings
8
+ * Power-up URI: http://leadin.com/mailchimp-connect
9
  * Power-up Description: Push your contacts to Constant Contact email lists.
10
  * Power-up Icon: power-up-icon-constant-contact-connect
11
  * Power-up Icon Small: power-up-icon-constant-contact-connect_small
power-ups/constant-contact-connect/inc/li_constant_contact.php CHANGED
@@ -681,36 +681,40 @@ end;
681
  $entries[] = $response['feed']['entry'];
682
  else
683
  $entries = $response['feed']['entry'];
684
- foreach ($entries as $data)
 
685
  {
686
- $my_data = Array();
687
- $my_data = $data['content']['ContactList'];
688
- $d = Array();
689
- //$d['ListID'] = $this->id_from_url($my_data['attr']['id']);
690
- $d['ListID'] = $my_data['attr']['id'];
 
 
691
 
692
- // Exclude the default lists like active, do-not-mail and removed
693
- if ( ! is_numeric($this->id_from_url($my_data['attr']['id'])) )
694
- continue;
695
 
696
- unset($my_data['attr']);
697
- foreach ($my_data as $dkey => $dval)
698
- {
699
- if ( isset($dval['value']) )
700
- $d[$dkey] = $dval['value'];
701
- }
702
-
703
- if ($key)
704
- {
705
- if ($unique)
706
- $ret[$d[$key]] = $d;
 
 
 
707
  else
708
- $ret[$d[$key]][] = $d;
709
  }
710
- else
711
- $ret[] = $d;
712
  }
713
- return $ret;
714
  }
715
 
716
  /**
681
  $entries[] = $response['feed']['entry'];
682
  else
683
  $entries = $response['feed']['entry'];
684
+
685
+ if ( count($entries) )
686
  {
687
+ foreach ($entries as $data)
688
+ {
689
+ $my_data = Array();
690
+ $my_data = $data['content']['ContactList'];
691
+ $d = Array();
692
+ //$d['ListID'] = $this->id_from_url($my_data['attr']['id']);
693
+ $d['ListID'] = $my_data['attr']['id'];
694
 
695
+ // Exclude the default lists like active, do-not-mail and removed
696
+ if ( ! is_numeric($this->id_from_url($my_data['attr']['id'])) )
697
+ continue;
698
 
699
+ unset($my_data['attr']);
700
+ foreach ($my_data as $dkey => $dval)
701
+ {
702
+ if ( isset($dval['value']) )
703
+ $d[$dkey] = $dval['value'];
704
+ }
705
+
706
+ if ($key)
707
+ {
708
+ if ($unique)
709
+ $ret[$d[$key]] = $d;
710
+ else
711
+ $ret[$d[$key]][] = $d;
712
+ }
713
  else
714
+ $ret[] = $d;
715
  }
716
+ return $ret;
 
717
  }
 
718
  }
719
 
720
  /**
power-ups/constant-contact-list-sync/admin/constant-contact-list-sync-admin.php DELETED
@@ -1,268 +0,0 @@
1
- <?php
2
- //=============================================
3
- // WPLeadInAdmin Class
4
- //=============================================
5
- class WPConstantContactListSyncAdmin extends WPLeadInAdmin {
6
-
7
- var $power_up_settings_section = 'leadin_cc_options_section';
8
- var $power_up_icon;
9
- var $bad_api_call;
10
- var $constant_contact;
11
- var $lists;
12
- var $options;
13
- var $authed = FALSE;
14
-
15
- /**
16
- * Class constructor
17
- */
18
- function __construct ( $power_up_icon_small )
19
- {
20
- global $pagenow;
21
-
22
- //=============================================
23
- // Hooks & Filters
24
- //=============================================
25
-
26
- if ( is_admin() )
27
- {
28
- $this->power_up_icon = $power_up_icon_small;
29
- add_action('admin_init', array($this, 'leadin_cc_build_settings_page'));
30
- $this->options = get_option('leadin_cc_options');
31
- if ( isset($this->options['li_cc_email']) && isset($this->options['li_cc_password']) && $this->options['li_cc_email'] && $this->options['li_cc_password'] )
32
- $this->authed = TRUE;
33
- }
34
- }
35
-
36
- //=============================================
37
- // Settings Page
38
- //=============================================
39
-
40
- /**
41
- * Creates settings options
42
- */
43
- function leadin_cc_build_settings_page ()
44
- {
45
- global $leadin_constant_contact_list_sync_wp;
46
-
47
- register_setting('leadin_settings_options', 'leadin_cc_options', array($this, 'sanitize'));
48
-
49
- // If the creds are set, check if they are any good by hitting the API
50
- if ( $this->authed )
51
- {
52
- // Try to make a request using the authentication credentials
53
- $this->lists = $this->li_cc_get_email_lists(LEADIN_CONSTANT_CONTACT_API_KEY, $this->options['li_cc_email'], $this->options['li_cc_password']);
54
-
55
- if ( $this->constant_contact->cc_exception )
56
- {
57
- $this->bad_api_call = TRUE;
58
- }
59
- }
60
-
61
- add_settings_section($this->power_up_settings_section, $this->power_up_icon . "Constant Contact", array($this, 'cc_section_callback'), LEADIN_ADMIN_PATH);
62
-
63
- if ( $this->authed && ! $this->bad_api_call )
64
- add_settings_field('li_print_synced_lists', 'Synced tags', array($this, 'li_print_synced_lists'), LEADIN_ADMIN_PATH, $this->power_up_settings_section);
65
- else
66
- {
67
- add_settings_field('li_cc_email', 'Email', array($this, 'li_cc_email_callback'), LEADIN_ADMIN_PATH, $this->power_up_settings_section);
68
- add_settings_field('li_cc_password', 'Password', array($this, 'li_cc_password_callback'), LEADIN_ADMIN_PATH, $this->power_up_settings_section);
69
- }
70
- }
71
-
72
- function cc_section_callback ( )
73
- {
74
- if ( ! $this->authed )
75
- echo '<div class="leadin-section">Sign into your Constant Contact account below to setup Contact Sync</div>';
76
- else if ( $this->bad_api_call )
77
- echo '<div class="leadin-section"><p style="color: #f33f33; font-weight: bold;">' . $this->constant_contact->cc_exception . '</p></div>';
78
-
79
- $this->print_hidden_settings_fields();
80
- }
81
-
82
- function print_hidden_settings_fields ()
83
- {
84
- // Hacky solution to solve the Settings API overwriting the default values
85
- $li_cc_email = ( $this->options['li_cc_email'] ? $this->options['li_cc_email'] : '' );
86
- $li_cc_password = ( $this->options['li_cc_password'] ? $this->options['li_cc_password'] : '' );
87
-
88
- if ( $li_cc_email )
89
- {
90
- printf(
91
- '<input id="li_cc_email" type="hidden" name="leadin_cc_options[li_cc_email]" value="%s"/>',
92
- $li_cc_email
93
- );
94
- }
95
-
96
- if ( $li_cc_password )
97
- {
98
- printf(
99
- '<input id="li_cc_password" type="hidden" name="leadin_cc_options[li_cc_password]" value="%s"/>',
100
- $li_cc_password
101
- );
102
- }
103
- }
104
-
105
- /**
106
- * Sanitize each setting field as needed
107
- *
108
- * @param array $input Contains all settings fields as array keys
109
- */
110
- public function sanitize ( $input )
111
- {
112
- $new_input = array();
113
-
114
- if( isset( $input['li_cc_email'] ) )
115
- $new_input['li_cc_email'] = sanitize_text_field( $input['li_cc_email'] );
116
-
117
- if( isset( $input['li_cc_password'] ) )
118
- $new_input['li_cc_password'] = sanitize_text_field( $input['li_cc_password'] );
119
-
120
- if( isset( $input['li_cc_subscribers_to_list'] ) )
121
- $new_input['li_cc_subscribers_to_list'] = sanitize_text_field( $input['li_cc_subscribers_to_list'] );
122
-
123
- return $new_input;
124
- }
125
-
126
- /**
127
- * Prints email input for settings page
128
- */
129
- function li_cc_email_callback ()
130
- {
131
- $li_cc_email = ( $this->options['li_cc_email'] ? $this->options['li_cc_email'] : '' ); // Get header from options, or show default
132
-
133
- printf(
134
- '<input id="li_cc_email" type="text" id="title" name="leadin_cc_options[li_cc_email]" value="%s" size="50"/>',
135
- $li_cc_email
136
- );
137
- }
138
-
139
- /**
140
- * Prints password input for settings page
141
- */
142
- function li_cc_password_callback ()
143
- {
144
- $li_cc_password = ( $this->options['li_cc_password'] ? $this->options['li_cc_password'] : '' ); // Get header from options, or show default
145
-
146
- printf(
147
- '<input id="li_cc_password" type="password" id="title" name="leadin_cc_options[li_cc_password]" value="%s" size="50"/>',
148
- $li_cc_password
149
- );
150
- }
151
-
152
- /**
153
- * Prints email input for settings page
154
- */
155
- function li_cc_subscribers_to_list_callback ()
156
- {
157
- $li_cc_subscribers_to_list = ( isset($this->options['li_cc_subscribers_to_list']) ? $this->options['li_cc_subscribers_to_list'] : '' ); // Get header from options, or show default
158
-
159
- echo '<select id="li_cc_subscribers_to_list" name="leadin_cc_options[li_cc_subscribers_to_list]" ' . ( ! count($this->lists) ? 'disabled' : '' ) . '>';
160
-
161
- if ( count($this->lists) )
162
- {
163
- $list_set = FALSE;
164
-
165
- foreach ( $this->lists as $list )
166
- {
167
- // Skip over default lists
168
- if ( $list['Name'] == 'Active' || $list['Name'] == 'Do Not Mail' || $list['Name'] == 'Removed' )
169
- continue;
170
-
171
- if ( urldecode($list['ListID']) == $li_cc_subscribers_to_list && !$list_set )
172
- $list_set = TRUE;
173
-
174
- echo '<option ' . ( urldecode($list['ListID']) == $li_cc_subscribers_to_list ? 'selected' : '' ) . ' value="' . urldecode($list['ListID']) . '">' . $list['Name'] . '</option>';
175
- }
176
-
177
- if ( !$list_set )
178
- echo '<option selected value="">No list set...</option>';
179
- }
180
- else
181
- {
182
- echo '<option value="No lists...">No lists...</option>';
183
- }
184
-
185
- echo '</select>';
186
- echo '<p><a href="https://login.constantcontact.com/login/login.sdo?goto=https://ui.constantcontact.com/rnavmap/distui/contacts" target="_blank">Create a new list on ConstantContact.com</a></p>';
187
- }
188
-
189
- function li_cc_get_email_lists ( $api_key, $username, $password )
190
- {
191
- $this->constant_contact = new LI_ConstantContact($username, $password, $api_key, FALSE);
192
- $lists = $this->constant_contact->get_lists();
193
-
194
- if ( count($lists) )
195
- return $lists;
196
- else
197
- return FALSE;
198
- }
199
-
200
- /**
201
- * Prints synced lists with tag name
202
- */
203
- function li_print_synced_lists ()
204
- {
205
- $synced_lists = $this->li_get_synced_list_for_esp('constant_contact');
206
- $list_value_pairs = array();
207
- $synced_list_count = 0;
208
-
209
- echo '<table>';
210
- foreach ( $synced_lists as $synced_list )
211
- {
212
- foreach ( stripslashes_deep(unserialize($synced_list->tag_synced_lists)) as $tag_synced_list )
213
- {
214
- if ( $tag_synced_list['esp'] == 'constant_contact' )
215
- {
216
- echo '<tr class="synced-list-row">';
217
- echo '<td class="synced-list-cell"><span class="icon-tag"></span> ' . $synced_list->tag_text . '</td>';
218
- echo '<td class="synced-list-cell"><span class="synced-list-arrow">&#8594;</span></td>';
219
- echo '<td class="synced-list-cell"><span class="icon-envelope"></span> ' . $tag_synced_list['list_name'] . '</td>';
220
- echo '<td class="synced-list-edit"><a href="' . get_bloginfo('wpurl') . '/wp-admin/admin.php?page=leadin_contacts&action=edit_tag&tag=' . $synced_list->tag_id . '">edit</a></td>';
221
- echo '</tr>';
222
-
223
- $synced_list_count++;
224
- }
225
- }
226
- }
227
- echo '</table>';
228
-
229
- if ( ! $synced_list_count )
230
- echo "<p>You don't have any Constant Contact lists synced with LeadIn yet...</p>";
231
-
232
- echo '<p><a href="' . get_bloginfo('wpurl') . '/wp-admin/admin.php?page=leadin_contacts&action=manage_tags' . '">Manage tags</a></p>';
233
-
234
- echo '<p style="padding-top: 10px;"><a href="https://login.constantcontact.com/login/login.sdo?goto=https://ui.constantcontact.com/rnavmap/distui/contacts" target="_blank">Create a new list on ConstantContact.com</a></p>';
235
- }
236
-
237
- function li_get_synced_list_for_esp ( $esp_name, $output_type = 'OBJECT' )
238
- {
239
- global $wpdb;
240
-
241
- $q = $wpdb->prepare("SELECT * FROM $wpdb->li_tags WHERE tag_synced_lists LIKE '%%%s%%' AND tag_deleted = 0", $esp_name);
242
- $synced_lists = $wpdb->get_results($q, $output_type);
243
-
244
- return $synced_lists;
245
- }
246
-
247
- function li_get_lists ( )
248
- {
249
- $lists = $this->li_cc_get_email_lists(LEADIN_CONSTANT_CONTACT_API_KEY, $this->options['li_cc_email'], $this->options['li_cc_password']);
250
-
251
- $sanitized_lists = array();
252
- if ( count($lists) )
253
- {
254
- foreach ( $lists as $list )
255
- {
256
- $list_obj = (Object)NULL;
257
- $list_obj->id = $list['ListID'];
258
- $list_obj->name = $list['Name'];
259
-
260
- array_push($sanitized_lists, $list_obj);;
261
- }
262
- }
263
-
264
- return $sanitized_lists;
265
- }
266
- }
267
-
268
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
power-ups/constant-contact-list-sync/inc/li_constant_contact.php DELETED
@@ -1,1123 +0,0 @@
1
- <?php
2
-
3
- global $cc_exception;
4
-
5
- class LI_ConstantContact
6
- {
7
- var $auth;
8
- var $api;
9
- var $debug;
10
- var $cc_exception;
11
-
12
- /**
13
- * The ConstantContact contructor
14
- *
15
- * @param String $username - Your username
16
- * @param String $password - Your password
17
- * @param String $api_key - Your API Key
18
- * @param Boolean $debug - Whether or not debugging output is displayed
19
- * @param String $debug_style - Options are "cli" or "html". All it does is print "\n" or "<br>" for debugging output.
20
- */
21
-
22
- public function __construct ( $username = '', $password = '', $api_key = '', $debug_enabled = FALSE, $debug_style = 'html' )
23
- {
24
- $this->debug['enabled'] = $debug_enabled;
25
- $this->debug['style'] = $debug_style;
26
- $this->debug['last_response'] = 0;
27
- $this->auth['username'] = $username;
28
- $this->auth['password'] = $password;
29
- $this->auth['api_key'] = $api_key;
30
- $this->api['url'] = 'https://api.constantcontact.com/ws/customers/'.$username.'/';
31
- $this->api['inner_url'] = 'http://api.constantcontact.com/ws/customers/'.$username.'/';
32
- $this->api['relative_url'] = '/ws/customers/'.$username.'/';
33
- }
34
-
35
- //Main Functions
36
-
37
- /**
38
- * Print debugging output
39
- *
40
- * @param String $string - String to print
41
- */
42
- private function debug_print($string)
43
- {
44
- if($this->debug['enabled'])
45
- {
46
- $line_end = "\n";
47
- if ($this->debug['style'] == 'html')
48
- $line_end = "<br>";
49
- print "ConstantContact Debug: $string{$line_end}";
50
- }
51
- }
52
-
53
- /**
54
- * Fetch a URI from ConstantContact
55
- *
56
- * @param String $url - URL to connect to
57
- * @param String $post - POST data to include
58
- * @param String $fetch_as - Either array or xml for the return object
59
- * @param String $call_type - NORMAL,PUT,DELETE
60
- * @return Respose
61
- */
62
- private function fetch($url,$post,$fetch_as='array',$call_type='NORMAL')
63
- {
64
- $this->debug_print("------------------ fetch ------------------");
65
-
66
- $credentials=$this->auth['api_key'].'%'.$this->auth['username'].':'.$this->auth['password'];
67
-
68
- $this->debug_print("Connecting to '".$url."'");
69
- $this->debug_print("With Credentials '".$credentials."'");
70
-
71
- $ch=curl_init();
72
-
73
- curl_setopt($ch, CURLOPT_URL, $url);
74
- curl_setopt($ch, CURLOPT_USERPWD, $credentials);
75
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
76
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION ,1);
77
- curl_setopt($ch, CURLOPT_TIMEOUT, 30);
78
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
79
-
80
- if(strlen(trim($post))>0)
81
- {
82
- if ($this->debug['style'] == 'cli')
83
- $this->debug_print("And Posting:\n\n---START---\n".$post."\n---END---\n\n");
84
- elseif ($this->debug['style'] == 'html')
85
- $this->debug_print("And Posting:<pre>\n\n---START---\n".htmlspecialchars($post)."\n---END---\n\n</pre>");
86
- if ($call_type == 'PUT')
87
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
88
- elseif ($call_type == 'DELETE')
89
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
90
- else
91
- curl_setopt($ch, CURLOPT_POST, 1);
92
-
93
- curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
94
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/atom+xml'));
95
- }
96
- else
97
- {
98
- $this->debug_print("Not posting");
99
- curl_setopt($ch, CURLOPT_POST, 0);
100
- if ($call_type == 'PUT')
101
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
102
- elseif ($call_type == 'DELETE')
103
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
104
- }
105
-
106
- curl_setopt($ch, CURLOPT_HEADER, 0);
107
-
108
-
109
-
110
- $response = curl_exec($ch);
111
- $response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
112
- $this->debug_print("HTTP Response Code '".$response_code."'");
113
-
114
- if ( ! in_array($response_code, array('201', '200', '204')) )
115
- {
116
- if ( $response_code == 401 )
117
- {
118
- $this->cc_exception = "Sorry, that username and password combination isn't right";
119
- }
120
- else if ( $response_code == 403 )
121
- {
122
- $this->cc_exception = "Your account is locked due to too many bad logins. You can try <a href='https://login.constantcontact.com/login/pwreset.sdo' target='_blank'>resetting your Constant Contact password</a> to unlock your account";
123
- }
124
- }
125
-
126
- $this->debug['last_response'] = $response_code;
127
-
128
- if ($this->debug['style'] == 'cli')
129
- $this->debug_print("Received:\n\n---START---\n".$response."\n---END---\n\n");
130
- elseif ($this->debug['style'] == 'html')
131
- $this->debug_print("Received:<pre>\n\n---START---\n".htmlspecialchars($response)."\n---END---\n\n</pre>");
132
-
133
- curl_close($ch);
134
-
135
- if ($fetch_as == 'array')
136
- return $this->xml_to_array($response);
137
- else
138
- return $response;
139
- }
140
-
141
- /**
142
- * Converts XML data into a nested array
143
- *
144
- * @param String $contents - XML string
145
- * @param Integers $get_attributes - Include attributes (default 1)
146
- * @return Nested associative array
147
- */
148
- public function xml_to_array($contents, $get_attributes=1)
149
- {
150
- if (!$contents)
151
- return array();
152
-
153
- if (!function_exists('xml_parser_create'))
154
- {
155
- $this->debug_print("ERROR: xml_parser_create function doesn't exist!");
156
- return array();
157
- }
158
-
159
- $parser = xml_parser_create();
160
- xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 );
161
- xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 );
162
- xml_parse_into_struct( $parser, $contents, $xml_values );
163
- xml_parser_free( $parser );
164
-
165
- if (!$xml_values)
166
- {
167
- $this->debug_print("WARN: Could not parse xml_values!");
168
- return;
169
- }
170
-
171
- $xml_array = array();
172
- $parents = array();
173
- $opened_tags = array();
174
- $arr = array();
175
-
176
- $current = &$xml_array;
177
-
178
- foreach( $xml_values as $data)
179
- {
180
- unset($attributes,$value);
181
- extract($data);
182
-
183
- $result = '';
184
- if ($get_attributes)
185
- {
186
- $result = array();
187
- if (isset($value))
188
- $result['value'] = $value;
189
- if (isset($attributes))
190
- {
191
- foreach ($attributes as $attr => $val)
192
- {
193
- if ($get_attributes == 1)
194
- $result['attr'][$attr] = $val;
195
- }
196
- }
197
- }
198
- elseif (isset($value))
199
- $result = $value;
200
-
201
- if ($type == "open")
202
- {
203
- $parent[$level-1] = &$current;
204
- if (!is_array($current) || !in_array($tag, array_keys($current)))
205
- {
206
- $current[$tag] = $result;
207
- $current = &$current[$tag];
208
- }
209
- else
210
- {
211
- if (isset($current[$tag][0]))
212
- array_push($current[$tag], $result);
213
- else
214
- $current[$tag] = array($current[$tag],$result);
215
-
216
- $last = count($current[$tag]) - 1;
217
- $current = &$current[$tag][$last];
218
- }
219
- }
220
- elseif ($type == "complete")
221
- {
222
- if (!isset($current[$tag]))
223
- $current[$tag] = $result;
224
- else
225
- {
226
- if ((is_array($current[$tag]) and $get_attributes == 0) || (isset($current[$tag][0]) and is_array($current[$tag][0]) and $get_attributes == 1))
227
- array_push($current[$tag],$result);
228
- else
229
- $current[$tag] = array($current[$tag],$result);
230
- }
231
- }
232
- elseif ($type == 'close')
233
- $current = &$parent[$level-1];
234
- }
235
- return($xml_array);
236
- }
237
-
238
- /**
239
- * Converts id URL to numeric id
240
- *
241
- * @param String $url - ID URL
242
- * @return Numeric ID
243
- */
244
- public function id_from_url($url)
245
- {
246
- $temp = Array();
247
- $temp = explode('/',trim($url));
248
- return trim($temp[count($temp)-1]);
249
- }
250
-
251
- /**
252
- * Retrieves the XML service document
253
- *
254
- * @return XML service document
255
- */
256
- public function get_service_doc_xml()
257
- {
258
- $url=$this->api_url;
259
- $post='';
260
- $response=$this->fetch($url,$post,'xml');
261
- return $response;
262
- }
263
-
264
-
265
- //Contact Functions
266
-
267
- /**
268
- * Formats a contact array into the format we always return as
269
- * Note:
270
- * I like to do this because the atom specification has so much extraneous data
271
- * that I just don't care about. This makes a sane array out of what is
272
- * incredibly overcomplicated in my opinion.
273
- *
274
- * @param Array - Contact array as returned from fetch/xml_to_array
275
- * @return Associative array in the format returned by this api
276
- */
277
- public function format_contact($response)
278
- {
279
- $my_data = Array();
280
- $my_data = $response['entry']['content']['Contact'];
281
- $d = Array();
282
- $d['ContactID'] = $this->id_from_url($my_data['attr']['id']);
283
- unset($my_data['attr']);
284
- foreach ($my_data as $dkey => $dval)
285
- {
286
- if ($dkey != 'ContactLists')
287
- $d[$dkey] = $dval['value'];
288
- else
289
- {
290
- $entries = Array();
291
- if (isset($dval['ContactList']['link']))
292
- $entries[] = $dval['ContactList'];
293
- else
294
- $entries = $dval['ContactList'];
295
-
296
- foreach ($entries as $entry)
297
- {
298
- $e = Array();
299
- $e['ListID'] = $this->id_from_url($entry['attr']['id']);
300
- unset($entry['attr']);
301
- unset($entry['link']);
302
- foreach ($entry as $ekey => $eval)
303
- $e[$ekey] = $eval['value'];
304
- $d[$dkey][] = $e;
305
- }
306
- }
307
- }
308
- return $d;
309
- }
310
-
311
- /**
312
- * Return your list of contacts.
313
- *
314
- * @param String $key - Optionally specify a key to use for the array
315
- * @param Boolean $unique - Whether the key you specified is unique
316
- * @return Associative array containing your contacts indexed by whatever key specified.
317
- */
318
- public function get_contacts($key='',$unique=true)
319
- {
320
- $ret = Array();
321
-
322
- $url = $this->api['url'].'contacts';
323
- $post = '';
324
- $response = Array();
325
- $response = $this->fetch($url,$post);
326
-
327
- $entries = Array();
328
- if (isset($response['feed']['entry']['link']))
329
- $entries[] = $response['feed']['entry'];
330
- else
331
- $entries = $response['feed']['entry'];
332
- foreach ($entries as $data)
333
- {
334
- $my_data = Array();
335
- $my_data = $data['content']['Contact'];
336
- $d = Array();
337
- $d['ContactID'] = $this->id_from_url($my_data['attr']['id']);
338
- unset($my_data['attr']);
339
- foreach ($my_data as $dkey => $dval)
340
- $d[$dkey] = $dval['value'];
341
-
342
- if ($key)
343
- {
344
- if ($unique)
345
- $ret[$d[$key]] = $d;
346
- else
347
- $ret[$d[$key]][] = $d;
348
- }
349
- else
350
- $ret[] = $d;
351
- }
352
- return $ret;
353
- }
354
-
355
- /**
356
- * Add a contact
357
- * See Contact Data Format at http://developer.constantcontact.com/doc/contactCollection for all fields
358
- *
359
- * @param Array $data - An associative array containing all the contact data to add
360
- * @param Array $lists - An array of list_ids to add this contact to
361
- * @return Integer - ContactID for the new entry
362
- */
363
- public function add_contact($data,$lists)
364
- {
365
-
366
- $updated = date('Y-m-d\TH:i:s\Z');
367
- $xml_string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><entry xmlns='http://www.w3.org/2005/Atom'></entry>";
368
- $xml_object = simplexml_load_string($xml_string);
369
- $xml_object->addChild("title");
370
- $xml_object->addChild("updated",$updated);
371
- $author_node = $xml_object->addChild("author");
372
- $author_node->addChild("name", ("CTCT Samples"));
373
- $xml_object->addChild("id", 'data:,none');
374
- $summary_node = $xml_object->addChild("summary");
375
- $summary_node->addAttribute("type", "text");
376
- $content_node = $xml_object->addChild("content");
377
- $content_node->addAttribute("type", "application/vnd.ctct+xml");
378
- $contact_node = $content_node->addChild("Contact");
379
- $contact_node->addAttribute("xmlns", "http://ws.constantcontact.com/ns/1.0/");
380
- $contact_node->addChild("OptInSource", 'ACTION_BY_CUSTOMER');
381
-
382
- foreach ( $data as $key => $val )
383
- {
384
- $contact_node->addChild($key, $val);
385
- }
386
-
387
- $contactlists_node = $contact_node->addChild("ContactLists");
388
- foreach ( $lists as $list )
389
- {
390
- $listNode = $contactlists_node->addChild("ContactList");
391
- $listNode->addAttribute("id", $list);
392
- }
393
-
394
- $entry = $xml_object->asXML();
395
-
396
- $url= $this->api['url'].'contacts';
397
-
398
- $response = Array();
399
- $response = $this->fetch($url, $entry);
400
- if ( $this->debug['last_response'] <= 204 )
401
- return $this->id_from_url($response['entry']['id']['value']);
402
- else
403
- return false;
404
- }
405
-
406
- /**
407
- * Returns detailed info for a particular contact.
408
- *
409
- * @param Integer $id - Contact ID of the contact requested.
410
- * @return Associative array containing the contact's details
411
- */
412
- public function get_contact($id)
413
- {
414
- $url = $this->api['url'].'contacts/'.$id;
415
- $post = '';
416
- $contact = Array();
417
- $contact = $this->format_contact($this->fetch($url,$post));
418
-
419
- if ($this->debug['last_response'] <= 204)
420
- return $contact;
421
- else
422
- return false;
423
- }
424
-
425
- /**
426
- * Edit a contact
427
- * See Contact Data Format at http://developer.constantcontact.com/doc/contactCollection for all fields
428
- *
429
- * @param Integer $id - Contact ID of the contact to edit
430
- * @param Array $data - An associative array containing all the contact data to edit
431
- * @return Boolean - True on success and false on failure
432
- */
433
- public function edit_contact($id,$data)
434
- {
435
- //Get the old xml from get_contact() and then post after replacing values that need replacing
436
- $url = $this->api['url'].'contacts/'.$id;
437
- $post = '';
438
- $post = $this->fetch($url,$post,'xml');
439
-
440
- foreach ($data as $key => $val)
441
- $post = preg_replace("/<$key>.*?<\/{$key}>/s","<$key>$val</$key>",$post);
442
-
443
- $this->fetch($url,$post,'array','PUT');
444
-
445
- if ($this->debug['last_response'] <= 204)
446
- return true;
447
- else
448
- return false;
449
- }
450
-
451
- /**
452
- * Delete a contact
453
- *
454
- * @param Integer $id - Contact ID of the contact to delete
455
- * @return Boolean - True on success and false on failure
456
- */
457
- public function delete_contact($id)
458
- {
459
- //Get the old xml from get_contact() and then post after replacing values that need replacing
460
- $url = $this->api['url'].'contacts/'.$id;
461
- $post = '';
462
- $this->fetch($url,$post,'array','DELETE');
463
-
464
- if ($this->debug['last_response'] <= 204)
465
- return true;
466
- else
467
- return false;
468
- }
469
-
470
-
471
- /**
472
- * Search for a contact by email
473
- * See Contact Data Format at http://developer.constantcontact.com/doc/contactCollection for all fields
474
- *
475
- * @param String $email - Email address of the contact to search for
476
- * @param Boolean $id_only - If true will return ContactID found otherwise will return all contact info
477
- * @return Integer of found ContactID or Associative Array of contact info for found contact
478
- */
479
- public function search_contact_by_email($email,$id_only=true)
480
- {
481
- //Get the old xml from get_contact() and then post after replacing values that need replacing
482
- $url = $this->api['url'].'contacts?email='.urlencode(strtolower($email));
483
- $post = '';
484
- $response = Array();
485
- $response = $this->fetch($url,$post);
486
-
487
- if ($this->debug['last_response'] <= 204)
488
- {
489
- if ($id_only)
490
- {
491
- return $this->id_from_url($response['feed']['entry']['id']['value']);
492
- }
493
- else
494
- {
495
- return $this->get_contact($this->id_from_url($response['feed']['entry']['id']['value']));
496
- }
497
- }
498
- else
499
- return false;
500
- }
501
-
502
- /**
503
- * Returns contacts updated since date your list of contacts.
504
- *
505
- * @param Date $date - Date should be in the format "Y-m-d H:i:s" (this is the datetime mysql spec)
506
- * @param String $list_type - Type of contact to query for: active,removed,do-not-mail
507
- * @param String $key - Optionally specify a key to use for the array
508
- * @param Boolean $unique - Whether the key you specified is unique
509
- * @return Associative array containing your contacts indexed by whatever key specified.
510
- */
511
- public function search_contacts_by_date($date,$list_type='active',$key='',$unique=true)
512
- {
513
- //Format date to UTC atom spec
514
- $atom_date = date('Y-m-d\TH:i:s\Z',strtotime($date)+date("Z"));
515
-
516
- $ret = Array();
517
-
518
- $url = $this->api['url'].'contacts?updatedsince='.$atom_date.'&listtype='.$list_type;
519
- $post = '';
520
- $response = Array();
521
- $response = $this->fetch($url,$post);
522
-
523
- $entries = Array();
524
- if (isset($response['feed']['entry']['link']))
525
- $entries[] = $response['feed']['entry'];
526
- else
527
- $entries = $response['feed']['entry'];
528
- foreach ($entries as $data)
529
- {
530
- $my_data = Array();
531
- $my_data = $data['content']['Contact'];
532
- $d = Array();
533
- $d['ContactID'] = $this->id_from_url($my_data['attr']['id']);
534
- unset($my_data['attr']);
535
- foreach ($my_data as $dkey => $dval)
536
- $d[$dkey] = $dval['value'];
537
-
538
- if ($key)
539
- {
540
- if ($unique)
541
- $ret[$d[$key]] = $d;
542
- else
543
- $ret[$d[$key]][] = $d;
544
- }
545
- else
546
- $ret[] = $d;
547
- }
548
- return $ret;
549
- }
550
-
551
- //List Functions
552
-
553
- /**
554
- * Formats a list array into the format we always return as
555
- * Note:
556
- * I like to do this because the atom specification has so much extraneous data
557
- * that I just don't care about it. This makes a sane array out of what is
558
- * incredibly overcomplicated in my opinion.
559
- *
560
- * @param Array - Contact array as returned from fetch/xml_to_array
561
- * @return Associative array in the format returned by this api
562
- */
563
- public function format_list($response)
564
- {
565
- $my_data = Array();
566
- $my_data = $response['entry']['content']['ContactList'];
567
- $d = Array();
568
- $d['ListID'] = $this->id_from_url($my_data['attr']['id']);
569
- unset($my_data['attr']);
570
- unset($my_data['Members']);
571
- foreach ($my_data as $key => $val)
572
- $d[$key] = $val['value'];
573
- return $d;
574
- }
575
-
576
- /**
577
- * Add a list
578
- * See List Data Format at http://developer.constantcontact.com/doc/contactLists for all fields
579
- *
580
- * @param Array $data - An associative array containing all the contact data to add
581
- * @return Integer - ListID for the new entry
582
- */
583
- public function add_list($data)
584
- {
585
- $updated = date('Y-m-d\TH:i:s\Z');
586
- $post = <<<end
587
- <entry xmlns="http://www.w3.org/2005/Atom">
588
- <title type="text"> </title>
589
- <updated>{$updated}</updated>
590
- <author></author>
591
- <id>data:,none</id>
592
- <summary type="text">Contact</summary>
593
- <content type="application/vnd.ctct+xml">
594
- <ContactList xmlns="http://ws.constantcontact.com/ns/1.0/">
595
-
596
- end;
597
-
598
- foreach ($data as $key => $val)
599
- $post .= "\t\t\t<$key>{$val}</$key>\n";
600
-
601
- $post .= <<<end
602
- </ContactList>
603
- </content>
604
- </entry>
605
- end;
606
-
607
-
608
- $url= $this->api['url'].'lists';
609
-
610
- $response = Array();
611
- $response = $this->fetch($url,$post);
612
- if ($this->debug['last_response'] <= 204)
613
- return $this->id_from_url($response['entry']['id']['value']);
614
- else
615
- return false;
616
- }
617
-
618
- /**
619
- * Returns detailed info for a particular list.
620
- *
621
- * @param Integer $id - ListID of the list requested.
622
- * @return Associative array containing the list's details
623
- */
624
- public function get_list($id)
625
- {
626
- $url = $this->api['url'].'lists/'.$id;
627
- $post = '';
628
- $list = Array();
629
- $list = $this->format_list($this->fetch($url,$post));
630
-
631
- if ($this->debug['last_response'] <= 204)
632
- return $list;
633
- else
634
- return false;
635
- }
636
-
637
- /**
638
- * Edit a list
639
- * See List Data Format at http://developer.constantcontact.com/doc/contactLists for all fields
640
- *
641
- * @param Integer $id - List ID of the list to edit
642
- * @param Array $data - An associative array containing all the list data to edit
643
- * @return Boolean - True on success and false on failure
644
- */
645
- public function edit_list($id,$data)
646
- {
647
- //Get the old xml from get_list() and then post after replacing values that need replacing
648
- $url = $this->api['url'].'lists/'.$id;
649
- $post = '';
650
- $post = $this->fetch($url,$post,'xml');
651
-
652
- foreach ($data as $key => $val)
653
- $post = preg_replace("/<$key>.*?<\/{$key}>/s","<$key>$val</$key>",$post);
654
-
655
- $this->fetch($url,$post,'array','PUT');
656
-
657
- if ($this->debug['last_response'] <= 204)
658
- return true;
659
- else
660
- return false;
661
- }
662
-
663
- /**
664
- * Return your lists.
665
- *
666
- * @param String $key - Optionally specify a key to use for the array
667
- * @param Boolean $unique - Whether the key you specified is unique
668
- * @return Associative array containing your lists indexed by whatever key specified.
669
- */
670
- public function get_lists($key='',$unique=true)
671
- {
672
- $ret = Array();
673
-
674
- $url = $this->api['url'].'lists';
675
- $post = '';
676
- $response = Array();
677
- $response = $this->fetch($url,$post);
678
-
679
- $entries = Array();
680
- if (isset($response['feed']['entry']['link']))
681
- $entries[] = $response['feed']['entry'];
682
- else
683
- $entries = $response['feed']['entry'];
684
- foreach ($entries as $data)
685
- {
686
- $my_data = Array();
687
- $my_data = $data['content']['ContactList'];
688
- $d = Array();
689
- //$d['ListID'] = $this->id_from_url($my_data['attr']['id']);
690
- $d['ListID'] = $my_data['attr']['id'];
691
-
692
- // Exclude the default lists like active, do-not-mail and removed
693
- if ( ! is_numeric($this->id_from_url($my_data['attr']['id'])) )
694
- continue;
695
-
696
- unset($my_data['attr']);
697
- foreach ($my_data as $dkey => $dval)
698
- {
699
- if ( isset($dval['value']) )
700
- $d[$dkey] = $dval['value'];
701
- }
702
-
703
- if ($key)
704
- {
705
- if ($unique)
706
- $ret[$d[$key]] = $d;
707
- else
708
- $ret[$d[$key]][] = $d;
709
- }
710
- else
711
- $ret[] = $d;
712
- }
713
- return $ret;
714
- }
715
-
716
- /**
717
- * Delete a list
718
- *
719
- * @param Integer $id - ListID of the list to delete
720
- * @return Boolean - True on success and false on failure
721
- */
722
- public function delete_list($id)
723
- {
724
- //Get the old xml from get_list() and then post after replacing values that need replacing
725
- $url = $this->api['url'].'lists/'.$id;
726
- $post = '';
727
- $this->fetch($url,$post,'array','DELETE');
728
-
729
- if ($this->debug['last_response'] <= 204)
730
- return true;
731
- else
732
- return false;
733
- }
734
-
735
- //Subscription Functions
736
-
737
- /**
738
- * Add a subscription for an existing contact to a list
739
- * See Contact Data Format at http://developer.constantcontact.com/doc/contactCollection for all fields
740
- *
741
- * @param Integer $contact_id - Contact ID of the contact to use
742
- * @param Integer $list_id - List ID of the list to add the contact to
743
- * @param String $optin_source - ACTION_BY_CUSTOMER or ACTION_BY_CLIENT depending on if this person is filling out a form for subscription in realtime
744
- * @return Boolean - True on success and false on failure
745
- */
746
- public function add_subscription($contact_id,$list_id,$optin_source='ACTION_BY_CUSTOMER')
747
- {
748
- //Get the old xml from get_contact() and then post after replacing values that need replacing
749
- $url = $this->api['url'].'contacts/'.$contact_id;
750
- $post = '';
751
- $post = $this->fetch($url,$post,'xml');
752
-
753
- if (!strstr($post,'</ContactLists>'))
754
- $post = str_replace('</Contact>',"<ContactLists></ContactLists></Contact>",$post);
755
-
756
- if (!strstr($post,'<OptInSource>'))
757
- $post = str_replace('</Confirmed>',"</Confirmed>\n<OptInSource>$optin_source</OptInSource>",$post);
758
-
759
- if (!strstr($post,'<ContactList id="'.$this->api['inner_url'].'lists/'.$list_id.'">'))
760
- $post = str_replace('</ContactLists>','<ContactList id="'.$this->api['inner_url'].'lists/'.$list_id.'"></ContactList></ContactLists>',$post);
761
-
762
- $this->fetch($url,$post,'array','PUT');
763
-
764
- if ($this->debug['last_response'] <= 204)
765
- return true;
766
- else
767
- return false;
768
- }
769
-
770
- /**
771
- * Remove a subscription for an existing contact to a list
772
- * See Contact Data Format at http://developer.constantcontact.com/doc/contactCollection for all fields
773
- *
774
- * @param Integer $contact_id - Contact ID of the contact to use
775
- * @param Integer $list_id - List ID of the list to add the contact to
776
- * @return Boolean - True on success and false on failure
777
- */
778
- public function remove_subscription($contact_id,$list_id)
779
- {
780
- //Get the old xml from get_contact() and then post after replacing values that need replacing
781
- $url = $this->api['url'].'contacts/'.$contact_id;
782
- $post = '';
783
- $post = $this->fetch($url,$post,'xml');
784
-
785
- $post = preg_replace('/<ContactList id="'.str_replace('/','\/',$this->api['inner_url']).'lists\/'.$list_id.'">.*?<\/ContactList>/s','',$post);
786
-
787
- $this->fetch($url,$post,'array','PUT');
788
-
789
- if ($this->debug['last_response'] <= 204)
790
- return true;
791
- else
792
- return false;
793
- }
794
-
795
- //Campaign Functions
796
-
797
- /**
798
- * Formats a campaign array into the format we always return as
799
- * Note:
800
- * I like to do this because the atom specification has so much extraneous data
801
- * that I just don't care about it. This makes a sane array out of what is
802
- * incredibly overcomplicated in my opinion.
803
- *
804
- * @param Array - Contact array as returned from fetch/xml_to_array
805
- * @return Associative array in the format returned by this api
806
- */
807
- public function format_campaign($response)
808
- {
809
- $my_data = Array();
810
- $my_data = $response['entry']['content']['Campaign'];
811
- $d = Array();
812
- $d['CampaignID'] = $this->id_from_url($my_data['attr']['id']);
813
- $d['FromID'] = $this->id_from_url($my_data['FromEmail']['Email']['attr']['id']);
814
- $d['FromEmail'] = $my_data['FromEmail']['EmailAddress']['value'];
815
- unset($my_data['FromEmail']);
816
- unset($my_data['ReplyToEmail']);
817
-
818
- unset($my_data['attr']);
819
- foreach ($my_data as $dkey => $dval)
820
- {
821
- if ($dkey != 'ContactLists')
822
- $d[$dkey] = $dval['value'];
823
- else
824
- {
825
- $entries = Array();
826
- if (isset($dval['ContactList']['link']))
827
- $entries[] = $dval['ContactList'];
828
- else
829
- $entries = $dval['ContactList'];
830
-
831
- foreach ($entries as $entry)
832
- {
833
- $e = Array();
834
- $e['ListID'] = $this->id_from_url($entry['attr']['id']);
835
- unset($entry['attr']);
836
- unset($entry['link']);
837
- foreach ($entry as $ekey => $eval)
838
- $e[$ekey] = $eval['value'];
839
- $d[$dkey][] = $e;
840
- }
841
- }
842
- }
843
- return $d;
844
- }
845
-
846
- /**
847
- * Return your campaigns.
848
- *
849
- * @param String $key - Optionally specify a key to use for the array
850
- * @param Boolean $unique - Whether the key you specified is unique
851
- * @return Associative array containing your lists indexed by whatever key specified.
852
- */
853
- public function get_campaigns($key='',$unique=true)
854
- {
855
- $ret = Array();
856
-
857
- $url = $this->api['url'].'campaigns';
858
- $post = '';
859
- $response = Array();
860
- $response = $this->fetch($url,$post);
861
-
862
- $entries = Array();
863
- if (isset($response['feed']['entry']['link']))
864
- $entries[] = $response['feed']['entry'];
865
- else
866
- $entries = $response['feed']['entry'];
867
- foreach ($entries as $data)
868
- {
869
- $my_data = Array();
870
- $my_data = $data['content']['Campaign'];
871
- $d = Array();
872
- $d['CampaignID'] = $this->id_from_url($my_data['attr']['id']);
873
- unset($my_data['attr']);
874
- foreach ($my_data as $dkey => $dval)
875
- $d[$dkey] = $dval['value'];
876
-
877
- if ($key)
878
- {
879
- if ($unique)
880
- $ret[$d[$key]] = $d;
881
- else
882
- $ret[$d[$key]][] = $d;
883
- }
884
- else
885
- $ret[] = $d;
886
- }
887
- return $ret;
888
- }
889
-
890
- /**
891
- * Add a campaign
892
- * See Campaign Data Format at http://developer.constantcontact.com/doc/manageCampaigns for all fields
893
- *
894
- * @param Array $data - An associative array containing all the campaign data to add
895
- * @param Array $lists - An array of ListIDs to have this campaign send to
896
- * @param Array $from_id - FromID to use as the from email address
897
- * @return Integer - CampaignID for the new entry
898
- */
899
- public function add_campaign($data,$lists,$from_id)
900
- {
901
- $updated = date('Y-m-d\TH:i:s\Z');
902
- $post = <<<end
903
- <entry xmlns="http://www.w3.org/2005/Atom">
904
- <link href="{$this->api['relative_url']}campaigns" rel="edit" />
905
- <id>{$this->api['inner_url']}campaigns</id>
906
- <title type="text">{$data['Name']}</title>
907
- <updated>{$updated}</updated>
908
- <author>
909
- <name>Constant Contact</name>
910
- </author>
911
- <content type="application/vnd.ctct+xml">
912
- <Campaign xmlns="http://ws.constantcontact.com/ns/1.0/" id="{$this->api['inner_url']}campaigns/">
913
-
914
- end;
915
-
916
- foreach ($data as $key => $val)
917
- {
918
- if ($key == 'Date')
919
- $val = date('Y-m-d\TH:i:s\Z',strtotime($val)+date("Z"));
920
- elseif ($key == 'EmailContent' || $key == 'StyleSheet' || $key == 'PermissionReminderText')
921
- $val = urlencode($val);
922
- elseif ($key == 'TextContent')
923
- $val = urlencode('<Text>'.$val.'</Text>');
924
-
925
- $post .= "\t\t\t<$key>{$val}</$key>\n";
926
- }
927
-
928
- $post .= "\t\t\t<ContactLists>\n";
929
- foreach ($lists as $list_id)
930
- $post .= "\t\t\t\t<ContactList id=\"{$this->api['inner_url']}lists/{$list_id}\" />\n";
931
-
932
- $temp = Array();
933
- $temp = get_from($from_id);
934
- $email = $temp['EmailAddress'];
935
-
936
- $post .= <<<end
937
- </ContactLists>
938
- <FromEmail>
939
- <Email id="{$this->api['inner_url']}emailaddresses/$from_id">
940
- <link xmlns="http://www.w3.org/2005/Atom" href="{$this->api['inner_url']}emailaddresses/$from_id" rel="self" />
941
- </Email>
942
- <EmailAddress>$email</EmailAddress>
943
- </FromEmail>
944
- <ReplyToEmail>
945
- <Email id="{$this->api['inner_url']}emailaddresses/$from_id">
946
- <link xmlns="http://www.w3.org/2005/Atom" href="{$this->api['inner_url']}emailaddresses/$from_id" rel="self" />
947
- </Email>
948
- <EmailAddress>$email</EmailAddress>
949
- </ReplyToEmail>
950
-
951
- end;
952
-
953
- $post .= <<<end
954
- </Campaign>
955
- </content>
956
- </entry>
957
- end;
958
-
959
-
960
- $url= $this->api['url'].'contacts';
961
-
962
- $response = Array();
963
- $response = $this->fetch($url,$post);
964
- if ($this->debug['last_response'] <= 204)
965
- return $this->id_from_url($response['entry']['id']['value']);
966
- else
967
- return false;
968
- }
969
-
970
- /**
971
- * Returns detailed info for a particular campaign.
972
- *
973
- * @param Integer $id - Campaign ID of the campaign requested.
974
- * @return Associative array containing the campaign's details
975
- */
976
- public function get_campaign($id)
977
- {
978
- $url = $this->api['url'].'campaigns/'.$id;
979
- $post = '';
980
- $campaign = Array();
981
- $campaign = $this->format_campaign($this->fetch($url,$post));
982
-
983
- if ($this->debug['last_response'] <= 204)
984
- return $campaign;
985
- else
986
- return false;
987
- }
988
-
989
- /**
990
- * Edit a campaign
991
- * See Campaign Data Format at http://developer.constantcontact.com/doc/manageCampaigns for all fields
992
- *
993
- * @param Integer $id - Campaign ID of the list to edit
994
- * @param Array $data - An associative array containing all the campaign data to edit
995
- * @return Boolean - True on success and false on failure
996
- */
997
- public function edit_campaign($id,$data)
998
- {
999
- //Get the old xml from get_campaign() and then post after replacing values that need replacing
1000
- $url = $this->api['url'].'campaigns/'.$id;
1001
- $post = '';
1002
- $post = $this->fetch($url,$post,'xml');
1003
-
1004
- foreach ($data as $key => $val)
1005
- $post = preg_replace("/<$key>.*?<\/{$key}>/s","<$key>$val</$key>",$post);
1006
-
1007
- $this->fetch($url,$post,'array','PUT');
1008
-
1009
- if ($this->debug['last_response'] <= 204)
1010
- return true;
1011
- else
1012
- return false;
1013
- }
1014
-
1015
- /**
1016
- * Delete a campaign
1017
- *
1018
- * @param Integer $id - CampaignID of the list to delete
1019
- * @return Boolean - True on success and false on failure
1020
- */
1021
- public function delete_campaign($id)
1022
- {
1023
- //Get the old xml from get_campaign() and then post after replacing values that need replacing
1024
- $url = $this->api['url'].'campaigns/'.$id;
1025
- $post = '';
1026
- $this->fetch($url,$post,'array','DELETE');
1027
-
1028
- if ($this->debug['last_response'] <= 204)
1029
- return true;
1030
- else
1031
- return false;
1032
- }
1033
-
1034
- //From Functions
1035
-
1036
- /**
1037
- * Formats a list array into the format we always return as
1038
- * Note:
1039
- * I like to do this because the atom specification has so much extraneous data
1040
- * that I just don't care about. This makes a sane array out of what is
1041
- * incredibly overcomplicated in my opinion.
1042
- *
1043
- * @param Array - Contact array as returned from fetch/xml_to_array
1044
- * @return Associative array in the format returned by this api
1045
- */
1046
- public function format_from($response)
1047
- {
1048
- $my_data = Array();
1049
- $my_data = $response['entry']['content']['Email'];
1050
- $d = Array();
1051
- $d['FromID'] = $this->id_from_url($my_data['attr']['id']);
1052
- unset($my_data['attr']);
1053
- foreach ($my_data as $key => $val)
1054
- $d[$key] = $val['value'];
1055
- return $d;
1056
- }
1057
-
1058
- /**
1059
- * Returns detailed info for a particular list.
1060
- *
1061
- * @param Integer $id - FromID of the from email requested.
1062
- * @return Associative array containing the from's details
1063
- */
1064
- public function get_from($id)
1065
- {
1066
- $url = $this->api['url'].'settings/emailaddresses/'.$id;
1067
- $post = '';
1068
- $from = Array();
1069
- $from = $this->format_from($this->fetch($url,$post));
1070
-
1071
- if ($this->debug['last_response'] <= 204)
1072
- return $from;
1073
- else
1074
- return false;
1075
- }
1076
-
1077
- /**
1078
- * Return your from email addresses.
1079
- *
1080
- * @param String $key - Optionally specify a key to use for the array
1081
- * @param Boolean $unique - Whether the key you specified is unique
1082
- * @return Associative array containing your lists indexed by whatever key specified.
1083
- */
1084
- public function get_froms($key='',$unique=true)
1085
- {
1086
- $ret = Array();
1087
-
1088
- $url = $this->api['url'].'settings/emailaddresses';
1089
- $post = '';
1090
- $response = Array();
1091
- $response = $this->fetch($url,$post);
1092
-
1093
- $entries = Array();
1094
- if (isset($response['feed']['entry']['link']))
1095
- $entries[] = $response['feed']['entry'];
1096
- else
1097
- $entries = $response['feed']['entry'];
1098
- foreach ($entries as $data)
1099
- {
1100
- $my_data = Array();
1101
- $my_data = $data['content']['Email'];
1102
- $d = Array();
1103
- $d['FromID'] = $this->id_from_url($my_data['attr']['id']);
1104
- unset($my_data['attr']);
1105
- foreach ($my_data as $dkey => $dval)
1106
- $d[$dkey] = $dval['value'];
1107
-
1108
- if ($key)
1109
- {
1110
- if ($unique)
1111
- $ret[$d[$key]] = $d;
1112
- else
1113
- $ret[$d[$key]][] = $d;
1114
- }
1115
- else
1116
- $ret[] = $d;
1117
- }
1118
- return $ret;
1119
- }
1120
-
1121
- }
1122
-
1123
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
power-ups/contacts/admin/contacts-admin.php CHANGED
@@ -296,6 +296,24 @@ class WPLeadInContactsAdmin extends WPLeadInAdmin {
296
  echo '<div class="event-time">' . date('g:ia', strtotime($pageview['event_date'])) . '</div>';
297
  echo '<div class="event-content">';
298
  echo '<p class="event-title">Traffic Source: ' . ( $pageview['pageview_source'] ? '<a href="' . $pageview['pageview_source'] . '">' . leadin_strip_params_from_url($pageview['pageview_source']) : 'Direct' ) . '</a></p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  echo '</div>';
300
  echo '</li>';
301
  }
@@ -441,10 +459,10 @@ class WPLeadInContactsAdmin extends WPLeadInAdmin {
441
  $synced_lists = ( isset($tagger->details->tag_synced_lists) ? unserialize($tagger->details->tag_synced_lists) : '' );
442
 
443
  echo '<tr>';
444
- echo '<th scope="row">Sync tagged contacts with these ' . $power_up_name . ' lists</th>';
445
  echo '<td>';
446
  echo '<fieldset>';
447
- echo '<legend class="screen-reader-text"><span>Sync tagged contacts to with these ' . $power_up_name . ' email lists</span></legend>';
448
  //
449
  $esp_name_readable = ucwords(str_replace('_', ' ', $esp_name));
450
  $esp_url = str_replace('_', '', $esp_name) . '.com';
296
  echo '<div class="event-time">' . date('g:ia', strtotime($pageview['event_date'])) . '</div>';
297
  echo '<div class="event-content">';
298
  echo '<p class="event-title">Traffic Source: ' . ( $pageview['pageview_source'] ? '<a href="' . $pageview['pageview_source'] . '">' . leadin_strip_params_from_url($pageview['pageview_source']) : 'Direct' ) . '</a></p>';
299
+ $url_parts = parse_url($pageview['pageview_source']);
300
+ if ( $url_parts['query'] )
301
+ {
302
+ parse_str($url_parts['query'], $url_vars);
303
+ if ( count($url_vars) )
304
+ {
305
+ echo '<ul class="event-detail fields">';
306
+ foreach ( $url_vars as $key => $value )
307
+ {
308
+ echo '<li class="field">';
309
+ echo '<label class="field-label">' . $key . ':</label>';
310
+ echo '<p class="field-value">' . nl2br($value) . '</p>';
311
+ echo '</li>';
312
+ }
313
+ echo '</ul>';
314
+ }
315
+ }
316
+
317
  echo '</div>';
318
  echo '</li>';
319
  }
459
  $synced_lists = ( isset($tagger->details->tag_synced_lists) ? unserialize($tagger->details->tag_synced_lists) : '' );
460
 
461
  echo '<tr>';
462
+ echo '<th scope="row">Push tagged contacts with these ' . $power_up_name . ' lists</th>';
463
  echo '<td>';
464
  echo '<fieldset>';
465
+ echo '<legend class="screen-reader-text"><span>Push tagged contacts to with these ' . $power_up_name . ' email lists</span></legend>';
466
  //
467
  $esp_name_readable = ucwords(str_replace('_', ' ', $esp_name));
468
  $esp_url = str_replace('_', '', $esp_name) . '.com';
power-ups/mailchimp-list-sync/admin/mailchimp-list-sync-admin.php DELETED
@@ -1,202 +0,0 @@
1
- <?php
2
- //=============================================
3
- // WPLeadInAdmin Class
4
- //=============================================
5
- class WPMailChimpListSyncAdmin extends WPLeadInAdmin {
6
-
7
- var $power_up_settings_section = 'leadin_mls_options_section';
8
- var $power_up_icon;
9
- var $options;
10
- var $authed = FALSE;
11
-
12
- /**
13
- * Class constructor
14
- */
15
- function __construct ( $power_up_icon_small )
16
- {
17
- //=============================================
18
- // Hooks & Filters
19
- //=============================================
20
-
21
- if ( is_admin() )
22
- {
23
- $this->power_up_icon = $power_up_icon_small;
24
- add_action('admin_init', array($this, 'leadin_mls_build_settings_page'));
25
- $this->options = get_option('leadin_mls_options');
26
- $this->authed = ( $this->options['li_mls_api_key'] ? TRUE : FALSE );
27
- }
28
- }
29
-
30
- //=============================================
31
- // Settings Page
32
- //=============================================
33
-
34
- /**
35
- * Creates settings options
36
- */
37
- function leadin_mls_build_settings_page ()
38
- {
39
- register_setting('leadin_settings_options', 'leadin_mls_options', array($this, 'sanitize'));
40
- add_settings_section($this->power_up_settings_section, $this->power_up_icon . "MailChimp", '', LEADIN_ADMIN_PATH);
41
- add_settings_field('li_mls_api_key', 'API key', array($this, 'li_mls_api_key_callback'), LEADIN_ADMIN_PATH, $this->power_up_settings_section);
42
-
43
- if ( isset($this->options['li_mls_api_key']) )
44
- add_settings_field('li_print_synced_lists', 'Synced tags', array($this, 'li_print_synced_lists'), LEADIN_ADMIN_PATH, $this->power_up_settings_section);
45
- }
46
-
47
- /**
48
- * Sanitize each setting field as needed
49
- *
50
- * @param array $input Contains all settings fields as array keys
51
- */
52
- public function sanitize ( $input )
53
- {
54
- $new_input = array();
55
-
56
- if( isset( $input['li_mls_api_key'] ) )
57
- $new_input['li_mls_api_key'] = sanitize_text_field( $input['li_mls_api_key'] );
58
-
59
- if( isset( $input['li_mls_subscribers_to_list'] ) )
60
- $new_input['li_mls_subscribers_to_list'] = sanitize_text_field( $input['li_mls_subscribers_to_list'] );
61
-
62
- return $new_input;
63
- }
64
-
65
- /**
66
- * Prints email input for settings page
67
- */
68
- function li_mls_api_key_callback ()
69
- {
70
- $li_mls_api_key = ( $this->options['li_mls_api_key'] ? $this->options['li_mls_api_key'] : '' ); // Get header from options, or show default
71
-
72
- printf(
73
- '<input id="li_mls_api_key" type="text" id="title" name="leadin_mls_options[li_mls_api_key]" value="%s" size="50"/>',
74
- $li_mls_api_key
75
- );
76
-
77
- if ( ! isset($li_mls_api_key) )
78
- echo '<p><a href="http://admin.mailchimp.com/account/api/" target="_blank">Get an API key from MailChimp.com</a></p>';
79
- }
80
-
81
- /**
82
- * Prints email input for settings page
83
- */
84
- function li_print_synced_lists ()
85
- {
86
- $li_mls_api_key = ( $this->options['li_mls_api_key'] ? $this->options['li_mls_api_key'] : '' ); // Get header from options, or show default
87
-
88
- if ( isset($li_mls_api_key ) )
89
- {
90
- $synced_lists = $this->li_get_synced_list_for_esp('mailchimp');
91
- $list_value_pairs = array();
92
- $synced_list_count = 0;
93
-
94
- echo '<table>';
95
- foreach ( $synced_lists as $synced_list )
96
- {
97
- foreach ( stripslashes_deep(unserialize($synced_list->tag_synced_lists)) as $tag_synced_list )
98
- {
99
- if ( $tag_synced_list['esp'] == 'mailchimp' )
100
- {
101
- echo '<tr class="synced-list-row">';
102
- echo '<td class="synced-list-cell"><span class="icon-tag"></span> ' . $synced_list->tag_text . '</td>';
103
- echo '<td class="synced-list-cell"><span class="synced-list-arrow">&#8594;</span></td>';
104
- echo '<td class="synced-list-cell"><span class="icon-envelope"></span> ' . $tag_synced_list['list_name'] . '</td>';
105
- echo '<td class="synced-list-edit"><a href="' . get_bloginfo('wpurl') . '/wp-admin/admin.php?page=leadin_contacts&action=edit_tag&tag=' . $synced_list->tag_id . '">edit</a></td>';
106
- echo '</tr>';
107
-
108
- $synced_list_count++;
109
- }
110
- }
111
- }
112
- echo '</table>';
113
-
114
- if ( ! $synced_list_count )
115
- echo "<p>You don't have any MailChimp lists synced with LeadIn yet...</p>";
116
-
117
- echo '<p><a href="' . get_bloginfo('wpurl') . '/wp-admin/admin.php?page=leadin_contacts&action=manage_tags' . '">Manage tags</a></p>';
118
- }
119
-
120
- if ( $li_mls_api_key )
121
- echo '<p style="padding-top: 10px;"><a href="http://admin.mailchimp.com/lists/new-list/" target="_blank">Create a new list on MailChimp.com</a></p>';
122
- }
123
-
124
- function li_get_synced_list_for_esp ( $esp_name, $output_type = 'OBJECT' )
125
- {
126
- global $wpdb;
127
-
128
- $q = $wpdb->prepare("SELECT * FROM $wpdb->li_tags WHERE tag_synced_lists LIKE '%%%s%%' AND tag_deleted = 0", $esp_name);
129
- $synced_lists = $wpdb->get_results($q, $output_type);
130
-
131
- return $synced_lists;
132
- }
133
-
134
- /**
135
- * Prints email input for settings page
136
- */
137
- function li_mls_subscribers_to_list_callback ()
138
- {
139
- $li_mls_subscribers_to_list = ( isset($this->options['li_mls_subscribers_to_list']) ? $this->options['li_mls_subscribers_to_list'] : '' );
140
-
141
- $lists = $this->li_mls_get_mailchimp_lists($this->options['li_mls_api_key']);
142
-
143
- echo '<select id="li_mls_subscribers_to_list" name="leadin_mls_options[li_mls_subscribers_to_list]" ' . ( ! count($lists['data']) ? 'disabled' : '' ) . '>';
144
-
145
- if ( count($lists['data']) )
146
- {
147
- $list_set = FALSE;
148
-
149
- foreach ( $lists['data'] as $list )
150
- {
151
- if ( $list['id'] == $li_mls_subscribers_to_list && !$list_set )
152
- $list_set = TRUE;
153
-
154
- echo '<option ' . ( $list['id'] == $li_mls_subscribers_to_list ? 'selected' : '' ) . ' value="' . $list['id'] . '">' . $list['name'] . '</option>';
155
- }
156
-
157
- if ( !$list_set )
158
- echo '<option selected value="">No list set...</option>';
159
- }
160
- else
161
- {
162
- echo '<option value="No lists...">No lists...</option>';
163
- }
164
-
165
- echo '</select>';
166
-
167
- echo '<p><a href="http://admin.mailchimp.com/lists/new-list/" target="_blank">Create a new list on MailChimp.com</a></p>';
168
- }
169
-
170
- function li_get_lists ( )
171
- {
172
- $lists = $this->li_mls_get_mailchimp_lists($this->options['li_mls_api_key']);
173
-
174
- $sanitized_lists = array();
175
- foreach ( $lists['data'] as $list )
176
- {
177
- $list_obj = (Object)NULL;
178
- $list_obj->id = $list['id'];
179
- $list_obj->name = $list['name'];
180
-
181
- array_push($sanitized_lists, $list_obj);;
182
- }
183
-
184
- return $sanitized_lists;
185
- }
186
-
187
- function li_mls_get_mailchimp_lists ( $api_key )
188
- {
189
- $MailChimp = new LI_MailChimp($api_key);
190
-
191
- $lists = $MailChimp->call("lists/list", array(
192
- "start" => 0, // optional, control paging of lists, start results at this list #, defaults to 1st page of data (page 0)
193
- "limit" => 25, // optional, control paging of lists, number of lists to return with each call, defaults to 25 (max=100)
194
- "sort_field" => "created", // optional, "created" (the created date, default) or "web" (the display order in the web app). Invalid values will fall back on "created" - case insensitive.
195
- "sort_dir" => "DESC" // optional, "DESC" for descending (default), "ASC" for Ascending. Invalid values will fall back on "created" - case insensitive. Note: to get the exact display order as the web app you'd use "web" and "ASC"
196
- ));
197
-
198
- return $lists;
199
- }
200
- }
201
-
202
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
power-ups/mailchimp-list-sync/inc/MailChimp-API.php DELETED
@@ -1,92 +0,0 @@
1
- <?php
2
-
3
-
4
- /**
5
- * Super-simple, minimum abstraction MailChimp API v2 wrapper
6
- *
7
- * Uses curl if available, falls back to file_get_contents and HTTP stream.
8
- * This probably has more comments than code.
9
- *
10
- * Contributors:
11
- * Michael Minor <me@pixelbacon.com>
12
- * Lorna Jane Mitchell, github.com/lornajane
13
- *
14
- * @author Drew McLellan <drew.mclellan@gmail.com>
15
- * @version 1.1.1
16
- */
17
- class LI_MailChimp
18
- {
19
- private $api_key;
20
- private $api_endpoint = 'https://<dc>.api.mailchimp.com/2.0';
21
- private $verify_ssl = false;
22
-
23
- /**
24
- * Create a new instance
25
- * @param string $api_key Your MailChimp API key
26
- */
27
- function __construct($api_key)
28
- {
29
- $this->api_key = $api_key;
30
- if ( !strstr($this->api_key, '-') )
31
- return FALSE;
32
-
33
- list(, $datacentre) = explode('-', $this->api_key);
34
- $this->api_endpoint = str_replace('<dc>', $datacentre, $this->api_endpoint);
35
- }
36
-
37
- /**
38
- * Call an API method. Every request needs the API key, so that is added automatically -- you don't need to pass it in.
39
- * @param string $method The API method to call, e.g. 'lists/list'
40
- * @param array $args An array of arguments to pass to the method. Will be json-encoded for you.
41
- * @return array Associative array of json decoded API response.
42
- */
43
- public function call($method, $args=array())
44
- {
45
- return $this->makeRequest($method, $args);
46
- }
47
-
48
- /**
49
- * Performs the underlying HTTP request. Not very exciting
50
- * @param string $method The API method to be called
51
- * @param array $args Assoc array of parameters to be passed
52
- * @return array Assoc array of decoded result
53
- */
54
- private function makeRequest($method, $args=array())
55
- {
56
- $args['apikey'] = $this->api_key;
57
-
58
- $url = $this->api_endpoint.'/'.$method.'.json';
59
-
60
- if (function_exists('curl_init') && function_exists('curl_setopt')){
61
- $ch = curl_init();
62
- curl_setopt($ch, CURLOPT_URL, $url);
63
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
64
- curl_setopt($ch, CURLOPT_USERAGENT, 'PHP-MCAPI/2.0');
65
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
66
- curl_setopt($ch, CURLOPT_TIMEOUT, 10);
67
- curl_setopt($ch, CURLOPT_POST, true);
68
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl);
69
- curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($args));
70
- curl_setopt($ch, CURLOPT_HEADER, false);
71
- $result = curl_exec($ch);
72
- curl_close($ch);
73
-
74
-
75
- } else {
76
- $json_data = json_encode($args);
77
- $result = file_get_contents($url, null, stream_context_create(array(
78
- 'http' => array(
79
- 'protocol_version' => 1.1,
80
- 'user_agent' => 'PHP-MCAPI/2.0',
81
- 'method' => 'POST',
82
- 'header' => "Content-type: application/json\r\n".
83
- "Connection: close\r\n" .
84
- "Content-length: " . strlen($json_data) . "\r\n",
85
- 'content' => $json_data,
86
- ),
87
- )));
88
- }
89
-
90
- return $result ? json_decode($result, true) : false;
91
- }
92
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: andygcook, nelsonjoyce
3
  Tags: crm, contacts, lead tracking, click tracking, visitor tracking, analytics, marketing automation, inbound marketing, subscription, marketing, lead generation, mailchimp, constant contact, newsletter, popup, popover, email list, email, contacts database, contact form, forms, form widget, popup form
4
  Requires at least: 3.7
5
- Tested up to: 4.0-RC1
6
- Stable tag: 2.0.1
7
 
8
  Leadin is an easy-to-use marketing automation and lead tracking plugin for WordPress that helps you better understand your web site visitors.
9
 
@@ -17,10 +17,10 @@ When a person submits a form on your WordPress site, you want to know more about
17
 
18
  = How does it work? =
19
 
20
- -1. When you activate the WordPress plugin, Leadin will track each anonymous visitor to your site with a cookie.
21
- -2. Leadin automatically identifies and watches each existing form on your site for submissions.
22
- -3. Once someone fills out any other form on your site, Leadin will identify that person with their email address. and add them to your contact list.
23
- -4. You'll also receive an email with a link to the new contact record with all of their visit history.
24
 
25
  = Multisite Compatible =
26
 
@@ -103,8 +103,15 @@ You betcha! Leadin should work just fine on Multisite right out-of-the-box witho
103
 
104
  == Changelog ==
105
 
106
- - Current version: 2.0.1
107
- - Current version release: 2014-09-01
 
 
 
 
 
 
 
108
 
109
  = 2.0.1 (2014.09.01) =
110
  = Enhancements =
2
  Contributors: andygcook, nelsonjoyce
3
  Tags: crm, contacts, lead tracking, click tracking, visitor tracking, analytics, marketing automation, inbound marketing, subscription, marketing, lead generation, mailchimp, constant contact, newsletter, popup, popover, email list, email, contacts database, contact form, forms, form widget, popup form
4
  Requires at least: 3.7
5
+ Tested up to: 4.0
6
+ Stable tag: 2.0.2
7
 
8
  Leadin is an easy-to-use marketing automation and lead tracking plugin for WordPress that helps you better understand your web site visitors.
9
 
17
 
18
  = How does it work? =
19
 
20
+ 1. When you activate the WordPress plugin, Leadin will track each anonymous visitor to your site with a cookie.
21
+ 2. Leadin automatically identifies and watches each existing form on your site for submissions.
22
+ 3. Once someone fills out any other form on your site, Leadin will identify that person with their email address. and add them to your contact list.
23
+ 4. You'll also receive an email with a link to the new contact record with all of their visit history.
24
 
25
  = Multisite Compatible =
26
 
103
 
104
  == Changelog ==
105
 
106
+ - Current version: 2.0.2
107
+ - Current version release: 2014-09-09
108
+
109
+ = 2.0.2 (2014.09.09) =
110
+
111
+ - Bug fixes
112
+ - Fix inconsistent sources on stats widgets and contact timeline widgets
113
+ - Onboarding tooltip popup for setting up settings now works correctly
114
+ - Parse out get vars for traffic sources in the contact timeline
115
 
116
  = 2.0.1 (2014.09.01) =
117
  = Enhancements =