Creative Mail – Easier WordPress & WooCommerce Email Marketing - Version 1.3.0

Version Description

Download this release

Release Info

Developer constantcontact
Plugin Icon 128x128 Creative Mail – Easier WordPress & WooCommerce Email Marketing
Version 1.3.0
Comparing to
See all releases

Code changes from version 1.2.4 to 1.3.0

Files changed (36) hide show
  1. CHANGELOG.md +3 -0
  2. README.md +2 -1
  3. assets/js/checkout/ConsentCheckoutCapture.js +73 -0
  4. assets/js/checkout/GuestCheckoutCapture.js +69 -0
  5. assets/js/checkout/guest.js +11 -0
  6. assets/js/checkout/index.js +11 -0
  7. assets/js/consent_checkout.js +1 -0
  8. assets/js/dashboard.js +6 -4
  9. assets/js/guest_checkout.js +1 -0
  10. creative-mail-plugin.php +3 -3
  11. readme.txt +2 -1
  12. src/CreativeMail.php +21 -2
  13. src/managers/AdminManager.php +35 -29
  14. src/managers/ApiManager.php +21 -0
  15. src/managers/CheckoutManager.php +681 -0
  16. src/managers/DatabaseManager.php +275 -0
  17. src/managers/EmailManager.php +14 -14
  18. src/modules/DashboardWidgetModule.php +19 -8
  19. src/modules/contacts/Handlers/NinjaFormsPluginHandler.php +53 -28
  20. src/modules/contacts/Handlers/WooCommercePluginHandler.php +64 -26
  21. src/views/admin-dashboard-widget/campaigns.php +2 -2
  22. src/views/admin-dashboard-widget/exception.php +1 -1
  23. src/views/admin-dashboard-widget/most-recent-campaigns.php +4 -4
  24. src/views/admin-dashboard-widget/no-campaign.php +1 -1
  25. src/views/admin-dashboard-widget/no-ce-account.php +1 -1
  26. src/views/admin-dashboard-widget/no-woocommerce.php +1 -1
  27. src/views/admin-feedback-notice/few-contacts.php +1 -1
  28. src/views/admin-feedback-notice/many-contacts.php +1 -1
  29. src/views/dashboard.php +4 -4
  30. src/views/onboarding.php +2 -26
  31. src/views/settings.php +3 -3
  32. vendor/autoload.php +1 -1
  33. vendor/composer/ClassLoader.php +1 -1
  34. vendor/composer/autoload_classmap.php +2 -0
  35. vendor/composer/autoload_real.php +4 -4
  36. vendor/composer/autoload_static.php +6 -4
CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
  Changelog
2
  =========
3
 
 
 
 
4
  #### 1.2.4 - December 16 2020
5
  - Introduces a 'Reset' button on the settings page for accounts that are stuck.
6
 
1
  Changelog
2
  =========
3
 
4
+ #### 1.3.0 - January 12 2021
5
+ - Support for abandoned cart emails
6
+
7
  #### 1.2.4 - December 16 2020
8
  - Introduces a 'Reset' button on the settings page for accounts that are stuck.
9
 
README.md CHANGED
@@ -3,7 +3,7 @@ Contributors: Constant Contact
3
  Tags: email, marketing, newsletter, subscribe, contact form, constant contact, crm, automations, ecommerce, promotion, offers, retargeting
4
  Requires at least: 4.6
5
  Tested up to: 5.6
6
- Stable tag: 1.2.4
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.6
@@ -88,6 +88,7 @@ Creative Mail by Constant Contact [Privacy Notice](https://www.endurance.com/pri
88
  6. Enhance your brand with logomaker
89
 
90
  == Changelog ==
 
91
  * 1.2.4 - Introduces a 'Reset' button on the settings page for accounts that are stuck.
92
  * 1.2.3 - Fixes an issue where the banner would show up again after being dismissed.
93
  * 1.2.2 - Introduction of multi step automations and fixes a couple of small issues in the CreativeMail widgets
3
  Tags: email, marketing, newsletter, subscribe, contact form, constant contact, crm, automations, ecommerce, promotion, offers, retargeting
4
  Requires at least: 4.6
5
  Tested up to: 5.6
6
+ Stable tag: 1.3.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.6
88
  6. Enhance your brand with logomaker
89
 
90
  == Changelog ==
91
+ * 1.3.0 - Support for abandoned cart emails.
92
  * 1.2.4 - Introduces a 'Reset' button on the settings page for accounts that are stuck.
93
  * 1.2.3 - Fixes an issue where the banner would show up again after being dismissed.
94
  * 1.2.2 - Introduction of multi step automations and fixes a couple of small issues in the CreativeMail widgets
assets/js/checkout/ConsentCheckoutCapture.js ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // phpcs:disable
2
+ /**
3
+ * ConsentCheckoutCapture.
4
+ *
5
+ * @package CreativeMail
6
+ */
7
+ export default class ConsentCheckoutCapture {
8
+
9
+ /**
10
+ * @constructor
11
+ *
12
+ * @since 1.3.0
13
+ */
14
+ constructor() {
15
+ this.els = {};
16
+ }
17
+
18
+ /**
19
+ * Init public JS.
20
+ *
21
+ * @since 1.3.0
22
+ */
23
+ init() {
24
+ this.cacheEls();
25
+ this.bindEvents();
26
+ }
27
+
28
+ /**
29
+ * Cache some DOM elements.
30
+ *
31
+ * @since 1.3.0
32
+ */
33
+ cacheEls() {
34
+ this.els.ce4wpConsent = document.getElementById('ce4wp_no_consent');
35
+ this.els.wcCheckoutNonce = document.getElementById('woocommerce-process-checkout-nonce');
36
+ }
37
+
38
+ /**
39
+ * Bind callbacks to events.
40
+ *
41
+ * @since 1.3.0
42
+ */
43
+ bindEvents() {
44
+ var self = this;
45
+ if (this.els.ce4wpConsent && typeof this.els.ce4wpConsent.addEventListener === "function")
46
+ {
47
+ this.els.ce4wpConsent.addEventListener('click', e => {
48
+ e.preventDefault();
49
+ window.setTimeout(function () {
50
+ self.noConsentCaptureGuestCheckout();
51
+ }, 1500);
52
+ });
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Changes the consent of the checkout.
58
+ *
59
+ * @since 1.3.0
60
+ *
61
+ */
62
+ noConsentCaptureGuestCheckout() {
63
+ var self = this;
64
+ wp.ajax.send('ce4wp_abandoned_checkouts_no_consent_checkout', {
65
+ data: {
66
+ nonce: this.els.wcCheckoutNonce.value
67
+ },
68
+ success: function() {
69
+ self.els.ce4wpConsent.parentElement.style.display = 'none';
70
+ }
71
+ });
72
+ }
73
+ }
assets/js/checkout/GuestCheckoutCapture.js ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // phpcs:disable
2
+ /**
3
+ * GuestCheckoutCapture.
4
+ *
5
+ * @package CreativeMail
6
+ */
7
+
8
+ import validateEmail from 'filter-validate-email';
9
+
10
+ export default class GuestCheckoutCapture {
11
+
12
+ /**
13
+ * @constructor
14
+ *
15
+ * @since 1.3.0
16
+ */
17
+ constructor() {
18
+ this.els = {};
19
+ }
20
+
21
+ /**
22
+ * Init public JS.
23
+ *
24
+ * @since 1.3.0
25
+ */
26
+ init() {
27
+ this.cacheEls();
28
+ this.bindEvents();
29
+ }
30
+
31
+ /**
32
+ * Cache some DOM elements.
33
+ *
34
+ * @since 1.3.0
35
+ */
36
+ cacheEls() {
37
+ this.els.billingEmail = document.getElementById( 'billing_email' );
38
+ this.els.wcCheckoutNonce = document.getElementById( 'woocommerce-process-checkout-nonce' );
39
+ }
40
+
41
+ /**
42
+ * Bind callbacks to events.
43
+ *
44
+ * @since 1.3.0
45
+ */
46
+ bindEvents() {
47
+ this.els.billingEmail.addEventListener( 'focusout', e => {
48
+ if ( validateEmail( e.target.value ) ) {
49
+ this.maybeCaptureGuestCheckout(e.target.value);
50
+ }
51
+ } );
52
+ }
53
+
54
+ /**
55
+ * Captures guest checkout if billing email is valid.
56
+ *
57
+ * @since 1.3.0
58
+ *
59
+ * @param {string} emailAddr Billing email address entered by user.
60
+ */
61
+ maybeCaptureGuestCheckout( emailAddr ) {
62
+ wp.ajax.send( 'ce4wp_abandoned_checkouts_capture_guest_checkout', {
63
+ data: {
64
+ nonce: this.els.wcCheckoutNonce.value,
65
+ email: emailAddr
66
+ }
67
+ } );
68
+ }
69
+ }
assets/js/checkout/guest.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Javascript.
3
+ *
4
+ * @package CreativeMail
5
+ */
6
+
7
+ import GuestCheckoutCapture from './GuestCheckoutCapture';
8
+
9
+ // Capture abandoned carts from non-logged-in users.
10
+ const MyGuestCheckoutCapture = new GuestCheckoutCapture();
11
+ MyGuestCheckoutCapture.init();
assets/js/checkout/index.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Javascript.
3
+ *
4
+ * @package CreativeMail
5
+ */
6
+
7
+ import ConsentCheckoutCapture from './ConsentCheckoutCapture';
8
+
9
+ // Capture consent
10
+ const MyConsentCheckoutCapture = new ConsentCheckoutCapture();
11
+ MyConsentCheckoutCapture.init();
assets/js/consent_checkout.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(e){var n={};function t(o){if(n[o])return n[o].exports;var c=n[o]={i:o,l:!1,exports:{}};return e[o].call(c.exports,c,c.exports,t),c.l=!0,c.exports}t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var c in e)t.d(o,c,function(n){return e[n]}.bind(null,c));return o},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){"use strict";function o(e,n){for(var t=0;t<n.length;t++){var o=n[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}t.r(n),(new(function(){function e(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.els={}}var n,t,c;return n=e,(t=[{key:"init",value:function(){this.cacheEls(),this.bindEvents()}},{key:"cacheEls",value:function(){this.els.ce4wpConsent=document.getElementById("ce4wp_no_consent"),this.els.wcCheckoutNonce=document.getElementById("woocommerce-process-checkout-nonce")}},{key:"bindEvents",value:function(){var e=this;this.els.ce4wpConsent&&"function"==typeof this.els.ce4wpConsent.addEventListener&&this.els.ce4wpConsent.addEventListener("click",(function(n){n.preventDefault(),window.setTimeout((function(){e.noConsentCaptureGuestCheckout()}),1500)}))}},{key:"noConsentCaptureGuestCheckout",value:function(){var e=this;wp.ajax.send("ce4wp_abandoned_checkouts_no_consent_checkout",{data:{nonce:this.els.wcCheckoutNonce.value},success:function(){e.els.ce4wpConsent.parentElement.style.display="none"}})}}])&&o(n.prototype,t),c&&o(n,c),e}())).init()}]);
assets/js/dashboard.js CHANGED
@@ -19,10 +19,12 @@ function ce4wpNavigateToDashboard(element, linkReference, linkParameters, startC
19
  link_parameters: linkParameters || undefined,
20
  action: 'ce4wp_request_sso'
21
  },
22
- success: function(data){
23
- ce4wpWindow.location = data;
24
- if (typeof finishCallback === 'function') {
25
- finishCallback(element)
 
 
26
  }
27
  },
28
  error: function(){
19
  link_parameters: linkParameters || undefined,
20
  action: 'ce4wp_request_sso'
21
  },
22
+ success: function(response) {
23
+ if (response.success) {
24
+ ce4wpWindow.location = response.data.url;
25
+ if (typeof finishCallback === 'function') {
26
+ finishCallback(element)
27
+ }
28
  }
29
  },
30
  error: function(){
assets/js/guest_checkout.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(u){var D={};function F(C){if(D[C])return D[C].exports;var A=D[C]={i:C,l:!1,exports:{}};return u[C].call(A.exports,A,A.exports,F),A.l=!0,A.exports}F.m=u,F.c=D,F.d=function(u,D,C){F.o(u,D)||Object.defineProperty(u,D,{enumerable:!0,get:C})},F.r=function(u){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(u,"__esModule",{value:!0})},F.t=function(u,D){if(1&D&&(u=F(u)),8&D)return u;if(4&D&&"object"==typeof u&&u&&u.__esModule)return u;var C=Object.create(null);if(F.r(C),Object.defineProperty(C,"default",{enumerable:!0,value:u}),2&D&&"string"!=typeof u)for(var A in u)F.d(C,A,function(D){return u[D]}.bind(null,A));return C},F.n=function(u){var D=u&&u.__esModule?function(){return u.default}:function(){return u};return F.d(D,"a",D),D},F.o=function(u,D){return Object.prototype.hasOwnProperty.call(u,D)},F.p="",F(F.s=0)}([function(u,D,F){"use strict";F.r(D);var C=/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\.){1,126})+(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))]))$/i,A=/^(?!(?:(?:"?\\[\0-~\u017F\u212A]"?)|(?:"?(?:[\0-!#-\[\]-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])"?)){255,})(?!(?:(?:"?\\[\0-~\u017F\u212A]"?)|(?:"?(?:[\0-!#-\[\]-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])"?)){65,}@)(?:(?:(?:[!#-'\*\+\x2D\/-9=\?A-Z\^-~\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BA\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])+)|(?:"(?:(?:[\x01-\x08\x0B\f\x0E-\x1F!#-\[\]-\x7F\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BA\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])|(?:\\[\0-\x7F\u017F\u212A]))*"))(?:\.(?:(?:(?:[!#-'\*\+\x2D\/-9=\?A-Z\^-~\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BA\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])+)|(?:"(?:(?:[\x01-\x08\x0B\f\x0E-\x1F!#-\[\]-\x7F\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BA\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])|(?:\\[\0-\x7F\u017F\u212A]))*")))*@(?:(?:(?!(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*(?:[\0-\x2D\/-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){64,})(?:(?:(?:xn\x2D\x2D)?[0-9a-z\u017F\u212A]+(?:\x2D+[0-9a-z\u017F\u212A]+)*\.){1,126})+(?:(?:[a-z\u017F\u212A][0-9a-z\u017F\u212A]*)|(?:(?:xn\x2D\x2D)[0-9a-z\u017F\u212A]+))(?:\x2D+[0-9a-z\u017F\u212A]+)*)|(?:\[(?:(?:IPv6:(?:(?:[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){7})|(?:(?!(?:(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*[0-9a-f][:\]]){7,})(?:[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){0,5})?::(?:[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){5}:)|(?:(?!(?:(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*[0-9a-f]:){5,})(?:[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){0,3})?::(?:[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/i;function E(u){return e(C,u)}function B(u){return e(A,u)}var x=function(u){var D=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return(D?B:E)(u)},e=function(u,D){return"string"==typeof D&&D.length<=320&&u.test(D)&&"\n"!==D.slice(-1)&&encodeURIComponent(D).replace(/%../g,"x").length<=320};function t(u,D){for(var F=0;F<D.length;F++){var C=D[F];C.enumerable=C.enumerable||!1,C.configurable=!0,"value"in C&&(C.writable=!0),Object.defineProperty(u,C.key,C)}}(new(function(){function u(){!function(u,D){if(!(u instanceof D))throw new TypeError("Cannot call a class as a function")}(this,u),this.els={}}var D,F,C;return D=u,(F=[{key:"init",value:function(){this.cacheEls(),this.bindEvents()}},{key:"cacheEls",value:function(){this.els.billingEmail=document.getElementById("billing_email"),this.els.wcCheckoutNonce=document.getElementById("woocommerce-process-checkout-nonce")}},{key:"bindEvents",value:function(){var u=this;this.els.billingEmail.addEventListener("focusout",(function(D){x(D.target.value)&&u.maybeCaptureGuestCheckout(D.target.value)}))}},{key:"maybeCaptureGuestCheckout",value:function(u){wp.ajax.send("ce4wp_abandoned_checkouts_capture_guest_checkout",{data:{nonce:this.els.wcCheckoutNonce.value,email:u}})}}])&&t(D.prototype,F),C&&t(D,C),u}())).init()}]);
creative-mail-plugin.php CHANGED
@@ -9,7 +9,7 @@
9
  * Plugin URI: https://wordpress.org/plugins/creative-mail-by-constant-contact/
10
  * Description: Free email marketing designed specifically for WordPress, Jetpack and WooCommerce. Send newsletters, promotions, updates and transactional e-commerce emails. Simple and easy, powered by Constant Contact’s rock solid reliability.
11
  * Author: Constant Contact
12
- * Version: 1.2.4
13
  * Author URI: https://www.constantcontact.com
14
  */
15
  use CreativeMail\CreativeMail;
@@ -24,7 +24,7 @@ function _load_ce4wp_plugin()
24
  define('CE4WP_PLUGIN_DIR', __DIR__ . '/');
25
  define('CE4WP_PLUGIN_URL', plugin_dir_url(__FILE__) . '/');
26
  define('CE4WP_PLUGIN_FILE', __FILE__);
27
- define('CE4WP_PLUGIN_VERSION', '1.2.4');
28
  define('CE4WP_INSTANCE_UUID_KEY', 'ce4wp_instance_uuid');
29
  define('CE4WP_INSTANCE_HANDSHAKE_TOKEN', 'ce4wp_handshake_token');
30
  define('CE4WP_INSTANCE_HANDSHAKE_EXPIRATION', 'ce4wp_handshake_expiration');
@@ -41,7 +41,7 @@ function _load_ce4wp_plugin()
41
  define('CE4WP_APP_GATEWAY_URL', 'https://app-gateway.creativemail.com/');
42
  define('CE4WP_APP_URL', 'https://app.creativemail.com/');
43
  define('CE4WP_ENVIRONMENT', 'PRODUCTION');
44
- define('CE4WP_BUILD_NUMBER', '885');
45
  define('CE4WP_BATCH_SIZE', 500);
46
  define('CE4WP_WC_API_KEY_ID', 'ce4wp_woocommerce_api_key_id');
47
  define('CE4WP_WC_API_CONSUMER_KEY', 'ce4wp_woocommerce_consumer_key');
9
  * Plugin URI: https://wordpress.org/plugins/creative-mail-by-constant-contact/
10
  * Description: Free email marketing designed specifically for WordPress, Jetpack and WooCommerce. Send newsletters, promotions, updates and transactional e-commerce emails. Simple and easy, powered by Constant Contact’s rock solid reliability.
11
  * Author: Constant Contact
12
+ * Version: 1.3.0
13
  * Author URI: https://www.constantcontact.com
14
  */
15
  use CreativeMail\CreativeMail;
24
  define('CE4WP_PLUGIN_DIR', __DIR__ . '/');
25
  define('CE4WP_PLUGIN_URL', plugin_dir_url(__FILE__) . '/');
26
  define('CE4WP_PLUGIN_FILE', __FILE__);
27
+ define('CE4WP_PLUGIN_VERSION', '1.3.0');
28
  define('CE4WP_INSTANCE_UUID_KEY', 'ce4wp_instance_uuid');
29
  define('CE4WP_INSTANCE_HANDSHAKE_TOKEN', 'ce4wp_handshake_token');
30
  define('CE4WP_INSTANCE_HANDSHAKE_EXPIRATION', 'ce4wp_handshake_expiration');
41
  define('CE4WP_APP_GATEWAY_URL', 'https://app-gateway.creativemail.com/');
42
  define('CE4WP_APP_URL', 'https://app.creativemail.com/');
43
  define('CE4WP_ENVIRONMENT', 'PRODUCTION');
44
+ define('CE4WP_BUILD_NUMBER', '961');
45
  define('CE4WP_BATCH_SIZE', 500);
46
  define('CE4WP_WC_API_KEY_ID', 'ce4wp_woocommerce_api_key_id');
47
  define('CE4WP_WC_API_CONSUMER_KEY', 'ce4wp_woocommerce_consumer_key');
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: Constant Contact
3
  Tags: email, marketing, newsletter, subscribe, contact form, constant contact, crm, automations, ecommerce, promotion, offers, retargeting
4
  Requires at least: 4.6
5
  Tested up to: 5.6
6
- Stable tag: 1.2.4
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.6
@@ -93,6 +93,7 @@ Creative Mail by Constant Contact [Privacy Notice](https://www.endurance.com/pri
93
  6. Enhance your brand with logomaker
94
 
95
  == Changelog ==
 
96
  * 1.2.4 - Introduces a 'Reset' button on the settings page for accounts that are stuck.
97
  * 1.2.3 - Fixes an issue where the banner would show up again after being dismissed.
98
  * 1.2.2 - Introduction of multi step automations and fixes a couple of small issues in the CreativeMail widgets
3
  Tags: email, marketing, newsletter, subscribe, contact form, constant contact, crm, automations, ecommerce, promotion, offers, retargeting
4
  Requires at least: 4.6
5
  Tested up to: 5.6
6
+ Stable tag: 1.3.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.6
93
  6. Enhance your brand with logomaker
94
 
95
  == Changelog ==
96
+ * 1.3.0 - Support for abandoned cart emails
97
  * 1.2.4 - Introduces a 'Reset' button on the settings page for accounts that are stuck.
98
  * 1.2.3 - Fixes an issue where the banner would show up again after being dismissed.
99
  * 1.2.2 - Introduction of multi step automations and fixes a couple of small issues in the CreativeMail widgets
src/CreativeMail.php CHANGED
@@ -5,6 +5,8 @@ namespace CreativeMail;
5
 
6
  use CreativeMail\Managers\AdminManager;
7
  use CreativeMail\Managers\ApiManager;
 
 
8
  use CreativeMail\Managers\EmailManager;
9
  use CreativeMail\Managers\InstanceManager;
10
  use CreativeMail\Managers\IntegrationManager;
@@ -18,23 +20,25 @@ class CreativeMail
18
  private $instance_manager;
19
  private $integration_manager;
20
  private $email_manager;
 
 
21
 
22
  public function __construct()
23
  {
24
-
25
  if (current_user_can('administrator')) {
26
  $this->admin_manager = new AdminManager();
27
  }
28
 
 
29
  $this->instance_manager = new InstanceManager();
30
  $this->api_manager = new ApiManager();
31
  $this->integration_manager = new IntegrationManager();
32
  $this->email_manager = new EmailManager();
 
33
  }
34
 
35
  public function add_hooks()
36
  {
37
-
38
  if (!$this->is_active()) {
39
  return;
40
  }
@@ -42,11 +46,26 @@ class CreativeMail
42
  if ($this->admin_manager !== null) {
43
  $this->admin_manager->add_hooks();
44
  }
 
 
 
45
 
46
  $this->api_manager->add_hooks();
47
  $this->integration_manager->add_hooks();
48
  $this->instance_manager->add_hooks();
49
  $this->email_manager->add_hooks();
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
 
52
  public function get_integration_manager()
5
 
6
  use CreativeMail\Managers\AdminManager;
7
  use CreativeMail\Managers\ApiManager;
8
+ use CreativeMail\Managers\CheckoutManager;
9
+ use CreativeMail\Managers\DatabaseManager;
10
  use CreativeMail\Managers\EmailManager;
11
  use CreativeMail\Managers\InstanceManager;
12
  use CreativeMail\Managers\IntegrationManager;
20
  private $instance_manager;
21
  private $integration_manager;
22
  private $email_manager;
23
+ private $database_manager;
24
+ private $checkout_manager;
25
 
26
  public function __construct()
27
  {
 
28
  if (current_user_can('administrator')) {
29
  $this->admin_manager = new AdminManager();
30
  }
31
 
32
+ $this->database_manager = new DatabaseManager();
33
  $this->instance_manager = new InstanceManager();
34
  $this->api_manager = new ApiManager();
35
  $this->integration_manager = new IntegrationManager();
36
  $this->email_manager = new EmailManager();
37
+ $this->checkout_manager = new CheckoutManager();
38
  }
39
 
40
  public function add_hooks()
41
  {
 
42
  if (!$this->is_active()) {
43
  return;
44
  }
46
  if ($this->admin_manager !== null) {
47
  $this->admin_manager->add_hooks();
48
  }
49
+ if ($this->database_manager !== null) {
50
+ $this->database_manager->add_hooks();
51
+ }
52
 
53
  $this->api_manager->add_hooks();
54
  $this->integration_manager->add_hooks();
55
  $this->instance_manager->add_hooks();
56
  $this->email_manager->add_hooks();
57
+
58
+ // check if abandoned cart email is managed by creative mail
59
+ $enabled = $this->email_manager->is_email_managed('cart_abandoned_ce4wp');
60
+ if ($enabled)
61
+ {
62
+ $this->checkout_manager->add_hooks();
63
+ }
64
+ }
65
+
66
+ public function get_database_manager()
67
+ {
68
+ return $this->database_manager;
69
  }
70
 
71
  public function get_integration_manager()
src/managers/AdminManager.php CHANGED
@@ -9,6 +9,7 @@ use CreativeMail\Helpers\SsoHelper;
9
  use CreativeMail\Modules\DashboardWidgetModule;
10
  use CreativeMail\Modules\FeedbackNoticeModule;
11
  use Exception;
 
12
 
13
  /**
14
  * The AdminManager will manage the admin section of the plugin.
@@ -76,10 +77,10 @@ class AdminManager
76
  add_action('wp_ajax_ce4wp_request_sso', [$this, 'request_single_sign_on_url'] );
77
 
78
  // deactivation footer
79
- //add_action(self::ADMIN_ENQUEUE_SCRIPTS_HOOK, [$this, 'deactivation_modal_js'], 20);
80
- //add_action(self::ADMIN_ENQUEUE_SCRIPTS_HOOK, [$this, 'deactivation_modal_css']);
81
- //add_action('admin_footer', [$this, 'show_deactivation_modal']);
82
- //add_action('wp_ajax_ce4wp_deactivate_survey', [$this, 'deactivate_survey_post'] );
83
  }
84
 
85
  private function check_nonce()
@@ -88,7 +89,9 @@ class AdminManager
88
 
89
  if (!wp_verify_nonce($nonce,self::ADMIN_AJAX_NONCE))
90
  {
91
- die (admin_url('admin.php?page=creativemail'));
 
 
92
  }
93
  }
94
 
@@ -107,6 +110,9 @@ class AdminManager
107
 
108
  $sso = $this->get_sso_link($linkReference, $linkParameters);
109
 
 
 
 
110
  if (is_null($sso)) {
111
  $redirectUrl = EnvironmentHelper::get_app_gateway_url('wordpress/v1.0/instances/open?clearSession=true&redirectUrl=');
112
  $onboardingUrl = EnvironmentHelper::get_app_url() . 'marketing/onboarding/signup?wp_site_name=' . $this->instance_name
@@ -126,11 +132,9 @@ class AdminManager
126
  }
127
  $onboardingUrl .= '&utm_source=wordpress&utm_medium=plugin&utm_campaign=' . $utm_campaign;
128
  }
129
- echo $redirectUrl . rawurlencode($onboardingUrl);
130
- die();
131
  }
132
- echo $sso;
133
- die();
134
  }
135
 
136
  function deactivate_survey_post()
@@ -211,7 +215,8 @@ class AdminManager
211
  <span><input type="radio" name="ce4wp_deactivation_option" value="3"> %s</span>
212
  <span><input type="radio" name="ce4wp_deactivation_option" value="4"> %s</span>
213
  <span><input type="radio" name="ce4wp_deactivation_option" value="5"> %s</span>
214
- <span><input type="radio" name="ce4wp_deactivation_option" value="6"> %s: <input type="text" name="other" /></span>
 
215
  <br>
216
  <span><input type="submit" class="button button-primary" value="Submit"></span>
217
  </fieldset>
@@ -221,13 +226,14 @@ class AdminManager
221
  </div>
222
  </div>
223
  </div>',
224
- __('Why are you deactivating Creative Mail?', self::DOMAIN_CE4WP),
225
- __('I no longer send newsletters', self::DOMAIN_CE4WP),
226
- __('I do not like the email designer', self::DOMAIN_CE4WP),
227
- __('I could not get the plugin to work', self::DOMAIN_CE4WP),
228
- __('My version of PHP is not supported', self::DOMAIN_CE4WP),
229
- __('Emails are not sending or arriving', self::DOMAIN_CE4WP),
230
- __('Its a temporary deactivation', self::DOMAIN_CE4WP),
 
231
  __('Other', self::DOMAIN_CE4WP),
232
  __('Thank you', self::DOMAIN_CE4WP),
233
  __('Close this window and deactivate Creative Mail', self::DOMAIN_CE4WP)
@@ -276,7 +282,7 @@ class AdminManager
276
 
277
  update_option('ce4wp_admin_footer_text_rated', 1);
278
 
279
- wp_die();
280
  }
281
 
282
  /**
@@ -374,7 +380,9 @@ class AdminManager
374
 
375
  // Create the root menu item
376
  $icon = file_get_contents(CE4WP_PLUGIN_DIR . 'assets/images/icon.svg');
377
- add_menu_page('Creative Mail', esc_html__('Creative Mail', self::DOMAIN_CE4WP), 'manage_options', 'creativemail', $main_action, 'data:image/svg+xml;base64,' . base64_encode($icon), '99.68491');
 
 
378
 
379
  $sub_actions = array(
380
  array(
@@ -452,15 +460,9 @@ class AdminManager
452
  */
453
  public function show_setup()
454
  {
455
- include CE4WP_PLUGIN_DIR . 'src/views/onboarding.php';
456
- }
457
 
458
- /**
459
- * Renders the consent screen.
460
- */
461
- public function show_consent()
462
- {
463
- include CE4WP_PLUGIN_DIR . 'src/views/consent.php';
464
  }
465
 
466
  /**
@@ -468,13 +470,17 @@ class AdminManager
468
  */
469
  public function show_dashboard()
470
  {
 
 
 
 
 
 
471
  wp_enqueue_script('ce4wp_dashboard', CE4WP_PLUGIN_URL.'assets/js/dashboard.js', null,CE4WP_PLUGIN_VERSION);
472
  wp_localize_script('ce4wp_dashboard', 'ce4wp_data', array(
473
  'url' => admin_url('admin-ajax.php'),
474
  'nonce' => $this->create_nonce()
475
  ));
476
-
477
- include CE4WP_PLUGIN_DIR . 'src/views/dashboard.php';
478
  }
479
 
480
  /**
9
  use CreativeMail\Modules\DashboardWidgetModule;
10
  use CreativeMail\Modules\FeedbackNoticeModule;
11
  use Exception;
12
+ use stdClass;
13
 
14
  /**
15
  * The AdminManager will manage the admin section of the plugin.
77
  add_action('wp_ajax_ce4wp_request_sso', [$this, 'request_single_sign_on_url'] );
78
 
79
  // deactivation footer
80
+ add_action(self::ADMIN_ENQUEUE_SCRIPTS_HOOK, [$this, 'deactivation_modal_js'], 20);
81
+ add_action(self::ADMIN_ENQUEUE_SCRIPTS_HOOK, [$this, 'deactivation_modal_css']);
82
+ add_action('admin_footer', [$this, 'show_deactivation_modal']);
83
+ add_action('wp_ajax_ce4wp_deactivate_survey', [$this, 'deactivate_survey_post'] );
84
  }
85
 
86
  private function check_nonce()
89
 
90
  if (!wp_verify_nonce($nonce,self::ADMIN_AJAX_NONCE))
91
  {
92
+ $response = new stdClass();
93
+ $response->url = admin_url('admin.php?page=creativemail');
94
+ wp_send_json_success($response);
95
  }
96
  }
97
 
110
 
111
  $sso = $this->get_sso_link($linkReference, $linkParameters);
112
 
113
+ $response = new stdClass();
114
+ $response->url = $sso;
115
+
116
  if (is_null($sso)) {
117
  $redirectUrl = EnvironmentHelper::get_app_gateway_url('wordpress/v1.0/instances/open?clearSession=true&redirectUrl=');
118
  $onboardingUrl = EnvironmentHelper::get_app_url() . 'marketing/onboarding/signup?wp_site_name=' . $this->instance_name
132
  }
133
  $onboardingUrl .= '&utm_source=wordpress&utm_medium=plugin&utm_campaign=' . $utm_campaign;
134
  }
135
+ $response->url = $redirectUrl . rawurlencode($onboardingUrl);
 
136
  }
137
+ wp_send_json_success($response);
 
138
  }
139
 
140
  function deactivate_survey_post()
215
  <span><input type="radio" name="ce4wp_deactivation_option" value="3"> %s</span>
216
  <span><input type="radio" name="ce4wp_deactivation_option" value="4"> %s</span>
217
  <span><input type="radio" name="ce4wp_deactivation_option" value="5"> %s</span>
218
+ <span><input type="radio" name="ce4wp_deactivation_option" value="6"> %s</span>
219
+ <span><input type="radio" name="ce4wp_deactivation_option" value="7"> %s: <input type="text" name="other" /></span>
220
  <br>
221
  <span><input type="submit" class="button button-primary" value="Submit"></span>
222
  </fieldset>
226
  </div>
227
  </div>
228
  </div>',
229
+ __('Sadness... why leave so soon?', self::DOMAIN_CE4WP),
230
+ __('I’m not sending email campaigns right now', self::DOMAIN_CE4WP),
231
+ __('It didn’t have the features I want', self::DOMAIN_CE4WP),
232
+ __('I didn’t like the email editor', self::DOMAIN_CE4WP),
233
+ __('It was too confusing', self::DOMAIN_CE4WP),
234
+ __('There were technical issues', self::DOMAIN_CE4WP),
235
+ __('I don’t have enough email contacts', self::DOMAIN_CE4WP),
236
+ __('It’s a temporary deactivation', self::DOMAIN_CE4WP),
237
  __('Other', self::DOMAIN_CE4WP),
238
  __('Thank you', self::DOMAIN_CE4WP),
239
  __('Close this window and deactivate Creative Mail', self::DOMAIN_CE4WP)
282
 
283
  update_option('ce4wp_admin_footer_text_rated', 1);
284
 
285
+ wp_send_json_success();
286
  }
287
 
288
  /**
380
 
381
  // Create the root menu item
382
  $icon = file_get_contents(CE4WP_PLUGIN_DIR . 'assets/images/icon.svg');
383
+ // Filter to change the menu position if there is any conflict.
384
+ $position = apply_filters( 'ce4wp_menu_position', '35.5' );
385
+ add_menu_page('Creative Mail', esc_html__('Creative Mail', self::DOMAIN_CE4WP), 'manage_options', 'creativemail', $main_action, 'data:image/svg+xml;base64,' . base64_encode($icon), $position);
386
 
387
  $sub_actions = array(
388
  array(
460
  */
461
  public function show_setup()
462
  {
463
+ $this->enqueue_dashboard_js();
 
464
 
465
+ include CE4WP_PLUGIN_DIR . 'src/views/onboarding.php';
 
 
 
 
 
466
  }
467
 
468
  /**
470
  */
471
  public function show_dashboard()
472
  {
473
+ $this->enqueue_dashboard_js();
474
+
475
+ include CE4WP_PLUGIN_DIR . 'src/views/dashboard.php';
476
+ }
477
+
478
+ private function enqueue_dashboard_js() {
479
  wp_enqueue_script('ce4wp_dashboard', CE4WP_PLUGIN_URL.'assets/js/dashboard.js', null,CE4WP_PLUGIN_VERSION);
480
  wp_localize_script('ce4wp_dashboard', 'ce4wp_data', array(
481
  'url' => admin_url('admin-ajax.php'),
482
  'nonce' => $this->create_nonce()
483
  ));
 
 
484
  }
485
 
486
  /**
src/managers/ApiManager.php CHANGED
@@ -156,6 +156,13 @@ class ApiManager
156
  return $this->modify_response(new WP_REST_Response($result, 200));
157
  }
158
  ),
 
 
 
 
 
 
 
159
  array (
160
  self::ROUTE_PATH => '/wc_key',
161
  self::ROUTE_METHODS => 'GET',
@@ -336,6 +343,20 @@ class ApiManager
336
  return $response;
337
  }
338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  private function get_wc_keys()
340
  {
341
  $wcKey = CreativeMail::get_instance()->get_api_manager()->get_or_generate_key();
156
  return $this->modify_response(new WP_REST_Response($result, 200));
157
  }
158
  ),
159
+ array (
160
+ self::ROUTE_PATH => '/abandoned_checkout',
161
+ self::ROUTE_METHODS => 'GET',
162
+ self::ROUTE_CALLBACK => function ($request) {
163
+ return $this->modify_response($this->get_ce_checkout($request->get_param('uuid')));
164
+ }
165
+ ),
166
  array (
167
  self::ROUTE_PATH => '/wc_key',
168
  self::ROUTE_METHODS => 'GET',
343
  return $response;
344
  }
345
 
346
+ private function get_ce_checkout($checkout_uuid) {
347
+ if (empty($checkout_uuid)) {
348
+ return new WP_REST_Response("No uuid provided", 400);
349
+ }
350
+
351
+ $checkout = CreativeMail::get_instance()->get_database_manager()->get_checkout_data( 'user_id,user_email,checkout_contents,checkout_updated,checkout_created,checkout_recovered,checkout_uuid',
352
+ 'checkout_uuid = %s', [ $checkout_uuid ] );
353
+ if (empty($checkout)) {
354
+ return new WP_REST_Response($checkout, 404);
355
+ }
356
+
357
+ return new WP_REST_Response($checkout, 200);
358
+ }
359
+
360
  private function get_wc_keys()
361
  {
362
  $wcKey = CreativeMail::get_instance()->get_api_manager()->get_or_generate_key();
src/managers/CheckoutManager.php ADDED
@@ -0,0 +1,681 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace CreativeMail\Managers;
5
+
6
+ use CreativeMail\CreativeMail;
7
+ use CreativeMail\Helpers\EnvironmentHelper;
8
+ use CreativeMail\Helpers\OptionsHelper;
9
+ use stdClass;
10
+ use WC_Coupon;
11
+ use WC_Order;
12
+
13
+ /**
14
+ * Class CheckoutManager
15
+ *
16
+ * @package CreativeMail\Managers
17
+ */
18
+ class CheckoutManager
19
+ {
20
+ /**
21
+ * Current checkout UUID.
22
+ *
23
+ * @var string
24
+ * @since 1.3.0
25
+ */
26
+ protected $checkout_uuid = '';
27
+
28
+ const UPDATE_CHECKOUT_DATA = 'update_checkout_data';
29
+ const META_CHECKOUT_UUID = 'ce4wp_checkout_uuid';
30
+ const CHECKOUT_UUID = 'checkout_uuid';
31
+ const NONCE = 'nonce';
32
+ const EMAIL = 'email';
33
+ const CHECKED = 'checked';
34
+ const DOMAIN = 'ce4wp';
35
+ const BILLING_EMAIL = 'billing_email';
36
+ const BILLING_EMAIL_NOTICE = 'billing_email_notice';
37
+ const BILLING_EMAIL_NO_CONSENT = 'billing_email_no_consent';
38
+ const CHECKOUT_UUID_PARAM = 'checkout_uuid = %s';
39
+ const COUPONS = 'coupons';
40
+ const PRODUCT_ID = 'product_id';
41
+ const VARIATION_ID = 'variation_id';
42
+ const QUANTITY = 'quantity';
43
+ const VARIATION = 'variation';
44
+ const USER_EMAIL = 'user_email';
45
+ const PRODUCTS = 'products';
46
+ const CUSTOMER = 'customer';
47
+
48
+ /**
49
+ * Add hooks
50
+ *
51
+ * @since 1.3.0
52
+ */
53
+ public function add_hooks()
54
+ {
55
+ // check if woocommerce is active
56
+ if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
57
+ add_action('woocommerce_before_checkout_form', array($this, 'enqueue_scripts'));
58
+ // add checkout notice field
59
+ add_filter('woocommerce_form_field_ce4wp_notice', array($this, 'add_email_usage_notice_field'), 10, 4);
60
+ add_filter('woocommerce_checkout_fields', array($this, 'ce4wp_filter_checkout_fields'));
61
+
62
+ add_action('woocommerce_after_template_part', array($this, 'save_or_clear_checkout_data'), 10, 1);
63
+ add_action('woocommerce_add_to_cart', array($this, self::UPDATE_CHECKOUT_DATA));
64
+ add_action('woocommerce_cart_item_removed', array($this, self::UPDATE_CHECKOUT_DATA), 30, 0);
65
+ add_action('woocommerce_cart_item_restored', array($this, self::UPDATE_CHECKOUT_DATA), 30, 0);
66
+ add_action('woocommerce_cart_item_set_quantity', array($this, self::UPDATE_CHECKOUT_DATA), 20, 0);
67
+
68
+ add_action('wp_ajax_ce4wp_abandoned_checkouts_capture_guest_checkout', array($this, 'maybe_capture_guest_checkout'));
69
+ add_action('wp_ajax_nopriv_ce4wp_abandoned_checkouts_capture_guest_checkout', array($this, 'maybe_capture_guest_checkout'));
70
+
71
+ add_action('wp_ajax_ce4wp_abandoned_checkouts_no_consent_checkout', array($this, 'no_consent_checkout'));
72
+ add_action('wp_ajax_nopriv_ce4wp_abandoned_checkouts_no_consent_checkout', array($this, 'no_consent_checkout'));
73
+
74
+ add_action('woocommerce_checkout_create_order', array($this, 'clear_purchased_data'), 10, 1);
75
+ add_action('woocommerce_checkout_order_processed', array($this, 'order_processed'), 10, 1);
76
+ add_action('woocommerce_order_status_completed', array($this, 'order_completed'), 10, 1);
77
+
78
+ // Sanitize checkout UUID.
79
+ $this->checkout_uuid = filter_input(INPUT_GET, 'ce4wp-recover', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
80
+
81
+ if (empty($this->checkout_uuid)) {
82
+ return;
83
+ }
84
+
85
+ add_action('wp_loaded', array($this, 'recover_checkout'));
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Add custom field under billing_email
91
+ *
92
+ * @since 1.3.0
93
+ */
94
+ public function ce4wp_filter_checkout_fields($fields) {
95
+ $fields['billing'][self::BILLING_EMAIL_NOTICE] = array(
96
+ 'type' => 'ce4wp_notice',
97
+ 'required' => false,
98
+ 'class' => array( 'form-row-wide' ),
99
+ 'clear' => true,
100
+ 'priority' => $fields['billing']['billing_email']['priority'] + 0.5
101
+ );
102
+ return $fields;
103
+ }
104
+
105
+ /**
106
+ * Add logic for ce4wp_notice field type
107
+ *
108
+ * @since 1.3.0
109
+ */
110
+ public function add_email_usage_notice_field( $field, $key, $args, $value )
111
+ {
112
+ $field_html = '<label style="font-weight:400;">' . __( 'Your email and cart are saved so we can send you email reminders about this order.', self::DOMAIN ) .' <a href="#" id="ce4wp_no_consent">'. __( 'No thanks', self::DOMAIN ).'</a></label>';
113
+
114
+ $container_class = esc_attr( implode( ' ', $args['class'] ) );
115
+ $container_id = esc_attr( $args['id'] ) . '_field';
116
+
117
+ $after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
118
+
119
+ $field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
120
+
121
+ return sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
122
+ }
123
+
124
+ /**
125
+ * Order has been completed
126
+ *
127
+ * @param int $order_id The order id.
128
+ *
129
+ * @since 1.3.0
130
+ *
131
+ * @return void
132
+ */
133
+ public function order_completed($order_id)
134
+ {
135
+ $this->update_checkout($order_id, '/v1.0/checkout/order_completed');
136
+ }
137
+
138
+ /**
139
+ * Order has been created and is processed
140
+ *
141
+ * @param int $order_id Newly created order id.
142
+ *
143
+ * @since 1.3.0
144
+ *
145
+ * @return void
146
+ */
147
+ public function order_processed( $order_id) {
148
+ $this->update_checkout($order_id, '/v1.0/checkout/order_created');
149
+ }
150
+
151
+ /**
152
+ * Update of checkout data in the external service
153
+ *
154
+ * @param int $order_id Newly created order id.
155
+ * @param string $endpoint Endpoint to call
156
+ *
157
+ * @since 1.3.0
158
+ */
159
+ private function update_checkout($order_id, $endpoint) {
160
+ $order = wc_get_order($order_id);
161
+ if ( empty( $order ) ) {
162
+ return;
163
+ }
164
+ // check if order had checkout uuid
165
+ $uuid = $order->get_meta( self::META_CHECKOUT_UUID);
166
+ // check if order is created with checkout meta
167
+ if (empty($uuid)) {
168
+ return;
169
+ }
170
+ // get the recovery date if recovered
171
+ $recovery_date = $this->get_checkout_recovery_date($uuid);
172
+ // Remote post to ce4wp marking checkout as completed
173
+ $requestItem = new stdClass();
174
+ $requestItem->uuid = $uuid;
175
+ $requestItem->order_id = $order->get_id();
176
+ $requestItem->order_total = $order->get_total();
177
+ $requestItem->order_currency = $order->get_currency();
178
+ $requestItem->recovery_date = $recovery_date;
179
+ $endpoint = EnvironmentHelper::get_app_gateway_url('wordpress') . $endpoint;
180
+ // call remote endpoint to update
181
+ $this->ce4wp_remote_post($requestItem, $endpoint);
182
+ }
183
+
184
+ /**
185
+ * Enqueue abandoned cart javascript files
186
+ *
187
+ * @since 1.3.0
188
+ */
189
+ public function enqueue_scripts() {
190
+ wp_enqueue_script( 'ce4wp-consent-checkout', CE4WP_PLUGIN_URL . 'assets/js/consent_checkout.js', [ 'wp-util' ], CE4WP_PLUGIN_VERSION, false );
191
+
192
+ if ( is_user_logged_in() ) {
193
+ return;
194
+ }
195
+
196
+ wp_enqueue_script( 'ce4wp-guest-checkout', CE4WP_PLUGIN_URL . 'assets/js/guest_checkout.js', [ 'wp-util' ], CE4WP_PLUGIN_VERSION, false );
197
+ }
198
+
199
+ /**
200
+ * AJAX handler for attempting to capture guest checkouts.
201
+ *
202
+ * @since 1.3.0
203
+ */
204
+ public function maybe_capture_guest_checkout() {
205
+ $data = filter_input_array( INPUT_POST, [
206
+ self::NONCE => FILTER_SANITIZE_STRING,
207
+ self::EMAIL => FILTER_SANITIZE_EMAIL
208
+ ] );
209
+
210
+ if ( empty( $data[self::NONCE] ) || ! wp_verify_nonce( $data[self::NONCE], 'woocommerce-process_checkout' ) ) {
211
+ wp_send_json_error( esc_html__( 'Invalid nonce.', self::DOMAIN ) );
212
+ }
213
+
214
+ $email = filter_var( $data[self::EMAIL], FILTER_VALIDATE_EMAIL );
215
+
216
+ if ( ! $email ) {
217
+ wp_send_json_error( esc_html__( 'Invalid email.', self::DOMAIN ) );
218
+ }
219
+
220
+ WC()->session->set( self::BILLING_EMAIL, $email );
221
+ $this->save_checkout_data( $email, true);
222
+
223
+ wp_send_json_success();
224
+ }
225
+
226
+ /**
227
+ * AJAX handler for opt out on abandoned cart.
228
+ *
229
+ * @since 1.3.0
230
+ */
231
+ public function no_consent_checkout()
232
+ {
233
+ $data = filter_input_array(INPUT_POST, [
234
+ self::NONCE => FILTER_SANITIZE_STRING
235
+ ]);
236
+
237
+ if (empty($data[self::NONCE]) || !wp_verify_nonce($data[self::NONCE], 'woocommerce-process_checkout')) {
238
+ wp_send_json_error(esc_html__('Invalid nonce.', self::DOMAIN));
239
+ }
240
+ // save no consent on session
241
+ WC()->session->set( self::BILLING_EMAIL_NO_CONSENT, true);
242
+
243
+ $checkout_id = WC()->session->get( self::CHECKOUT_UUID );
244
+ if (empty($checkout_id)) {
245
+ wp_send_json_success();
246
+ }
247
+
248
+ $endpoint = EnvironmentHelper::get_app_gateway_url('wordpress') . '/v1.0/checkout/'. $checkout_id;
249
+ $this->ce4wp_remote_delete($endpoint);
250
+ CreativeMail::get_instance()->get_database_manager()->change_checkout_consent($checkout_id, false);
251
+
252
+ wp_send_json_success();
253
+ }
254
+
255
+ /**
256
+ * Either call an update of checkout data which will be saved or remove checkout data based on what template we arrive at.
257
+ *
258
+ * @param string $template_name Current template file name.
259
+ *
260
+ * @since 1.3.0
261
+ */
262
+ public function save_or_clear_checkout_data( $template_name) {
263
+
264
+ // If checkout page displayed, save checkout data.
265
+ if ( 'checkout/form-checkout.php' === $template_name ) {
266
+ $this->save_checkout_data();
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Helper function to update current checkout session data in db.
272
+ *
273
+ * Used to strip unneeded params from callbacks.
274
+ *
275
+ * @since 1.3.0
276
+ */
277
+ public function update_checkout_data() {
278
+ $this->save_checkout_data();
279
+ }
280
+
281
+ /**
282
+ * Helper function to retrieve checkout contents based on checkout UUID.
283
+ *
284
+ * @param string $uuid Checkout UUID.
285
+ *
286
+ * @since 1.3.0
287
+ *
288
+ * @return array Checkout contents.
289
+ */
290
+ private function get_checkout_contents( $uuid ) {
291
+ $checkout = CreativeMail::get_instance()->get_database_manager()->get_checkout_data( 'checkout_contents', self::CHECKOUT_UUID_PARAM, [ $uuid ] );
292
+
293
+ if ( empty( $checkout ) ) {
294
+ return [];
295
+ }
296
+
297
+ return maybe_unserialize( array_shift( $checkout )->checkout_contents );
298
+ }
299
+
300
+ /**
301
+ * Helper function to retrieve checkout recovery date based on checkout UUID.
302
+ *
303
+ * @param string $uuid Checkout UUID.
304
+ *
305
+ * @since 1.3.0
306
+ *
307
+ * @return string|null Checkout recovery date if exists, else null.
308
+ */
309
+ private function get_checkout_recovery_date( $uuid ) {
310
+ $checkout = CreativeMail::get_instance()->get_database_manager()->get_checkout_data( 'checkout_recovered', self::CHECKOUT_UUID_PARAM, [ $uuid ] );
311
+
312
+ return ( empty( $checkout ) ? null : array_shift( $checkout )->checkout_recovered );
313
+ }
314
+
315
+ /**
316
+ * Helper function to retrieve checkout UUID for current user.
317
+ *
318
+ * @since 1.3.0
319
+ *
320
+ * @return string Checkout UUID if exists, else empty string.
321
+ */
322
+ private function get_checkout_uuid_by_user() {
323
+ $checkout = CreativeMail::get_instance()->get_database_manager()->get_checkout_data( self::CHECKOUT_UUID, 'user_id = %d', [ get_current_user_id() ] );
324
+
325
+ return ( empty( $checkout ) ? '' : array_shift( $checkout )->checkout_uuid );
326
+ }
327
+
328
+ /**
329
+ * Save current checkout data to db.
330
+ *
331
+ * @param string $billing_email Manually set customer billing email if provided.
332
+ * @param boolean $is_checkout Manually mark current page as checkout if necessary (e.g., coming from ajax callback).
333
+ * @param boolean|null $consent_checkout Manually mark consent value.
334
+ *
335
+ * @since 1.3.0
336
+ *
337
+ * @return void
338
+ */
339
+ protected function save_checkout_data( string $billing_email = '', bool $is_checkout = false) {
340
+ // Get current user email.
341
+ $session_customer = WC()->session->get( self::CUSTOMER );
342
+ $session_billing_email = is_array( $session_customer ) && key_exists( self::EMAIL, $session_customer ) ? $session_customer[self::EMAIL] : '';
343
+
344
+ if (empty($billing_email)) {
345
+ $billing_email = $session_billing_email;
346
+ if (empty($billing_email)) {
347
+ $billing_email = WC()->checkout->get_value( self::BILLING_EMAIL );
348
+ if (empty($billing_email)) {
349
+ $billing_email = WC()->session->get( self::BILLING_EMAIL );
350
+ }
351
+ }
352
+ }
353
+ $is_checkout = $is_checkout ?: is_checkout();
354
+ $uuid = WC()->session->get( self::CHECKOUT_UUID );
355
+
356
+ if ( empty( $billing_email ) ) {
357
+ return;
358
+ }
359
+
360
+ $has_no_consent = WC()->session->get( self::BILLING_EMAIL_NO_CONSENT);
361
+ if($has_no_consent === true)
362
+ {
363
+ return;
364
+ }
365
+
366
+ // Check for existing checkout session.
367
+ if ( ! $uuid ) {
368
+
369
+ // Only create session if cart is not empty.
370
+ // This is to avoid re-creating checkout UUID during checkout process.
371
+ if ( $is_checkout && empty( WC()->cart->get_cart() ) ) {
372
+ return;
373
+ }
374
+
375
+ // Retrieve existing checkout UUID for registered users only.
376
+ if ( is_user_logged_in() ) {
377
+ $existing_uuid = $this->get_checkout_uuid_by_user();
378
+ }
379
+
380
+ // Only create session if currently on checkout page or if current user has an existing session saved.
381
+ if ( ! $is_checkout && empty( $existing_uuid ) ) {
382
+ return;
383
+ }
384
+
385
+ $uuid = isset( $existing_uuid ) && ! empty( $existing_uuid ) ? $existing_uuid : wp_generate_uuid4();
386
+
387
+ WC()->session->set( 'checkout_uuid', $uuid );
388
+ }
389
+
390
+ $current_time = current_time( 'mysql', 1 );
391
+ $user_id = get_current_user_id();
392
+
393
+ $cart_products = WC()->cart->get_cart();
394
+ $cart_coupons = WC()->cart->get_applied_coupons();
395
+
396
+ $checkout_content = [
397
+ self::PRODUCTS => array_values($cart_products),
398
+ self::COUPONS => $cart_coupons,
399
+ ];
400
+
401
+ CreativeMail::get_instance()->get_database_manager()->upsert_checkout($uuid, $user_id, $billing_email, $checkout_content, $current_time);
402
+
403
+ // Remote post to ce4wp create or update cart if email is provided
404
+ $requestItem = new stdClass();
405
+ $requestItem->data = wp_json_encode($this->get_cart_data_for_endpoint($cart_products, $cart_coupons));
406
+ $requestItem->uuid = $uuid;
407
+ $requestItem->user_id = $user_id;
408
+ $requestItem->billing_email = $billing_email;
409
+ $requestItem->timestamp = strtotime($current_time);
410
+ $endpoint = EnvironmentHelper::get_app_gateway_url('wordpress') . '/v1.0/checkout/upsert';
411
+
412
+ $consent = CreativeMail::get_instance()->get_database_manager()->has_checkout_consent($uuid);
413
+ if ($consent) {
414
+ $this->ce4wp_remote_post($requestItem, $endpoint);
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Get cart object with data for each product and coupon
420
+ *
421
+ * @since 1.3.0
422
+ */
423
+ private function get_cart_data_for_endpoint($cart_products, $cart_coupons) {
424
+ $data = new stdClass();
425
+ $data->products = array();
426
+ $data->coupons = array();
427
+ $data->user = new stdClass();
428
+
429
+ try
430
+ {
431
+ // Get user first and last name of available
432
+ $current_user = wp_get_current_user();
433
+ if ($current_user->exists() ) {
434
+ $data->user->id = $current_user->ID;
435
+ $data->user->username = $current_user->user_login;
436
+ $data->user->display_name = $current_user->display_name;
437
+ $data->user->first_name = $current_user->user_firstname;
438
+ $data->user->last_name = $current_user->user_lastname;
439
+ $data->user->email = $current_user->user_email;
440
+ }
441
+
442
+ $dp = 2; // decimal point
443
+
444
+ foreach ($cart_products as $value)
445
+ {
446
+ $product = array_key_exists('data', $value) ? $value['data'] : wc_get_product($value[self::PRODUCT_ID]);
447
+ $product_id = $product->get_id();
448
+ $product_data = array(
449
+ 'images' => array()
450
+ );
451
+ $attachment_ids = $product->get_gallery_image_ids();
452
+ foreach ($attachment_ids as $attachment_id) {
453
+ $product_data['images'][] = wp_get_attachment_url($attachment_id);
454
+ }
455
+
456
+ $product_data["on_sale"] = $product->is_on_sale();
457
+ $product_data["sale_price"] = $product->get_sale_price();
458
+ $product_data["regular_price"] = $product->get_regular_price();
459
+ $src = wc_placeholder_img_src();
460
+ if ($image_id = $product->get_image_id()) {
461
+ list($src) = wp_get_attachment_image_src($image_id, 'full');
462
+ }
463
+
464
+ $line_subtotal = empty($value['line_subtotal']) ? 0: $value['line_subtotal'];
465
+ $line_subtotal_tax =empty($value['line_subtotal_tax']) ? 0: $value['line_subtotal_tax'];
466
+ $line_total = empty($value['line_total']) ? 0: $value['line_total'];
467
+ $line_tax = empty($value['line_tax']) ? 0: $value['line_tax'];
468
+
469
+ $data->products[] = array(
470
+ 'name' => $product->get_name(),
471
+ 'product_id' => $product_id,
472
+ 'product_image' => $src,
473
+ 'product_data' => $product_data,
474
+ 'sku' => is_object($product) ? $product->get_sku() : null,
475
+ 'product_url' => get_the_permalink($product_id),
476
+ 'variation_id' => $value[self::VARIATION_ID],
477
+ 'subtotal' => wc_format_decimal($line_subtotal, $dp),
478
+ 'subtotal_tax' => wc_format_decimal($line_subtotal_tax, $dp),
479
+ 'total' => wc_format_decimal($line_total, $dp),
480
+ 'total_tax' => wc_format_decimal($line_tax, $dp),
481
+ 'price' => wc_format_decimal($line_subtotal, $dp),
482
+ 'quantity' => $value[self::QUANTITY]
483
+ );
484
+ }
485
+
486
+ foreach ($cart_coupons as $coupon_code)
487
+ {
488
+ $coupon_id = wc_get_coupon_id_by_code($coupon_code);
489
+ if ($coupon_id)
490
+ {
491
+ $coupon = new WC_Coupon($coupon_id);
492
+
493
+ $data->coupons[] = array(
494
+ 'code' => $coupon->get_code(),
495
+ 'amount' => $coupon->get_amount(),
496
+ 'discount_type' => $coupon->get_discount_type(),
497
+ 'description' => $coupon->get_description(),
498
+ 'free_shipping' => $coupon->get_free_shipping()
499
+ );
500
+ }
501
+ }
502
+ }
503
+ catch (\Exception $e)
504
+ {
505
+ // silent
506
+ }
507
+
508
+ return $data;
509
+ }
510
+
511
+ /**
512
+ * Remove current checkout session data from db upon successful order submission.
513
+ *
514
+ * @param WC_Order $order Newly created order object.
515
+ *
516
+ * @since 1.3.0
517
+ *
518
+ * @return void
519
+ */
520
+ public function clear_purchased_data( $order) {
521
+ $checkout_id = WC()->session->get( self::CHECKOUT_UUID );
522
+ if (empty($checkout_id)) {
523
+ return;
524
+ }
525
+
526
+ $order->update_meta_data( self::META_CHECKOUT_UUID, $checkout_id );
527
+ CreativeMail::get_instance()->get_database_manager()->remove_checkout_data($checkout_id);
528
+ WC()->session->__unset( self::CHECKOUT_UUID );
529
+ }
530
+
531
+ /**
532
+ * Recovery saved checkout from UUID.
533
+ *
534
+ * @since 1.3.0
535
+ *
536
+ * @return void
537
+ */
538
+ public function recover_checkout() {
539
+
540
+ // Set checkout session UUID.
541
+ WC()->session->set( self::CHECKOUT_UUID, $this->checkout_uuid );
542
+
543
+ // Clear current checkout contents.
544
+ WC()->cart->empty_cart();
545
+
546
+ // Get saved checkout contents.
547
+ $checkout_contents = $this->get_checkout_contents( $this->checkout_uuid );
548
+
549
+ if ( empty($checkout_contents) ) {
550
+ return;
551
+ }
552
+
553
+ // Mark checkout as recovered
554
+ CreativeMail::get_instance()->get_database_manager()->mark_checkout_recovered($this->checkout_uuid);
555
+
556
+ // Recover saved products.
557
+ $this->recover_products( $checkout_contents[self::PRODUCTS] );
558
+
559
+ // Apply coupons.
560
+ foreach ( $checkout_contents[self::COUPONS] as $coupon ) {
561
+ WC()->cart->apply_coupon( $coupon );
562
+ }
563
+
564
+ // Maybe recover checkout email.
565
+ $this->maybe_recover_checkout_email();
566
+
567
+ // Update totals.
568
+ WC()->cart->calculate_totals();
569
+
570
+ // Redirect to checkout page.
571
+ wp_safe_redirect( wc_get_page_permalink( 'cart' ) );
572
+
573
+ exit();
574
+ }
575
+
576
+
577
+ /**
578
+ * Recover checkout email address if guest user and no email is set.
579
+ *
580
+ * @since 1.3.0
581
+ *
582
+ * @return void
583
+ */
584
+ protected function maybe_recover_checkout_email() : void {
585
+ $checkout_email = CreativeMail::get_instance()->get_database_manager()->get_checkout_data( self::USER_EMAIL, self::CHECKOUT_UUID_PARAM, [ $this->checkout_uuid ] );
586
+ $checkout_email = empty( $checkout_email ) ? '' : array_shift( $checkout_email )->user_email;
587
+
588
+ if ( is_user_logged_in() || ! empty( WC()->session->get( self::BILLING_EMAIL ) ) || empty( $checkout_email ) ) {
589
+ return;
590
+ }
591
+
592
+ WC()->session->set( self::BILLING_EMAIL, $checkout_email );
593
+ WC()->customer->set_billing_email( $checkout_email );
594
+ }
595
+
596
+ /**
597
+ * Recover products from saved checkout data.
598
+ *
599
+ * @param array $products Array of product data.
600
+ *
601
+ * @since 1.3.0
602
+ */
603
+ protected function recover_products( $products ) {
604
+ if (empty($products)) {
605
+ return;
606
+ }
607
+ // Programmatically add each product to cart.
608
+ $products_added = [];
609
+ foreach ( $products as $product ) {
610
+ $added = WC()->cart->add_to_cart(
611
+ $product[self::PRODUCT_ID],
612
+ $product[self::QUANTITY],
613
+ empty( $product[self::VARIATION_ID] ) ? 0 : $product[self::VARIATION_ID],
614
+ empty( $product[self::VARIATION] ) ? array() : $product[self::VARIATION]
615
+ );
616
+ if ( false !== $added ) {
617
+ $products_added[ ( empty( $product[self::VARIATION_ID] ) ? $product[self::PRODUCT_ID] : $product[self::VARIATION_ID] ) ] = $product[self::QUANTITY];
618
+ }
619
+ }
620
+
621
+ // Add product notices.
622
+ if ( 0 < count( $products_added ) ) {
623
+ wc_add_to_cart_message( $products_added );
624
+ }
625
+ if ( count( $products ) > count( $products_added ) ) {
626
+ wc_add_notice(
627
+ sprintf(
628
+ /* translators: %d item count */
629
+ _n(
630
+ '%d item from your previous order is currently unavailable and could not be added to your cart.',
631
+ '%d items from your previous order are currently unavailable and could not be added to your cart.',
632
+ ( count( $products ) - count( $products_added ) ),
633
+ self::DOMAIN
634
+ ),
635
+ ( count( $products ) - count( $products_added ) )
636
+ ),
637
+ 'error'
638
+ );
639
+ }
640
+ }
641
+
642
+ private function ce4wp_remote_post($requestItem, $endpoint) {
643
+ try
644
+ {
645
+ // check if abandoned cart email is managed by creative mail
646
+ $enabled = CreativeMail::get_instance()->get_email_manager()->is_email_managed('cart_abandoned_ce4wp');
647
+ if($enabled) {
648
+ wp_remote_post(
649
+ $endpoint, array(
650
+ 'method' => 'POST',
651
+ 'timeout' => 10,
652
+ 'headers' => array(
653
+ 'x-account-id' => OptionsHelper::get_connected_account_id(),
654
+ 'x-api-key' => OptionsHelper::get_instance_api_key(),
655
+ 'content-type' => 'application/json'
656
+ ),
657
+ 'body' => wp_json_encode($requestItem)
658
+ )
659
+ );
660
+ }
661
+ } catch (\Exception $e) {
662
+ // silent
663
+ }
664
+ }
665
+
666
+ private function ce4wp_remote_delete($endpoint) {
667
+ try {
668
+ wp_remote_request($endpoint,
669
+ array(
670
+ 'method' => 'DELETE',
671
+ 'headers' => array(
672
+ 'x-account-id' => OptionsHelper::get_connected_account_id(),
673
+ 'x-api-key' => OptionsHelper::get_instance_api_key()
674
+ )
675
+ )
676
+ );
677
+ } catch (\Exception $e) {
678
+ // silent
679
+ }
680
+ }
681
+ }
src/managers/DatabaseManager.php ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ namespace CreativeMail\Managers;
5
+
6
+ use DateInterval;
7
+ use DateTime;
8
+
9
+ /**
10
+ * Class DatabaseManager
11
+ *
12
+ * @package CreativeMail\Managers
13
+ */
14
+ class DatabaseManager
15
+ {
16
+ /**
17
+ * Current version of abandoned checkouts table.
18
+ *
19
+ * @since 1.3.0
20
+ */
21
+ const DB_VERSION = '1.0';
22
+
23
+ /**
24
+ * Option name for abandoned checkouts db version.
25
+ *
26
+ * @since 1.3.0
27
+ */
28
+ const DB_VERSION_OPTION_NAME = 'ce4wp_abandoned_checkout_db_version';
29
+
30
+ const CHECKOUT_UUID = 'checkout_uuid';
31
+
32
+ /**
33
+ * Abandoned checkouts table name.
34
+ *
35
+ * @since 1.3.0
36
+ */
37
+ const TABLE_NAME = 'ce4wp_abandoned_checkout';
38
+
39
+ public function add_hooks()
40
+ {
41
+ // check if woocommerce is active
42
+ if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
43
+ add_action('admin_init', array($this, 'update_database_check'), 10, 2);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Check if table exists and is up-to-date.
49
+ *
50
+ * @since 1.3.0
51
+ */
52
+ public function update_database_check() {
53
+ if ( ! get_site_option( self::DB_VERSION_OPTION_NAME ) ) {
54
+ // Fresh install: create table.
55
+ $this->create_table();
56
+ } else if(current_user_can('administrator')){
57
+ // Cleanup old expired checkouts
58
+ $this->delete_expired_checkouts();
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Helper function to remove checkout session data from db.
64
+ *
65
+ * @since 1.3.0
66
+ */
67
+ public function remove_checkout_data($checkout_uuid) {
68
+ global $wpdb;
69
+
70
+ // Delete current checkout data.
71
+ $wpdb->delete(
72
+ DatabaseManager::get_table_name(),
73
+ [
74
+ self::CHECKOUT_UUID => $checkout_uuid,
75
+ ],
76
+ [
77
+ '%s',
78
+ ]
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Create abandoned checkouts table.
84
+ *
85
+ * @since 1.3.0
86
+ */
87
+ public function create_table() {
88
+ global $wpdb;
89
+
90
+ $table_name = self::get_table_name();
91
+
92
+ $sql = "CREATE TABLE {$table_name} (
93
+ checkout_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
94
+ user_id bigint(20) unsigned NOT NULL DEFAULT 0,
95
+ user_email varchar(200) NOT NULL DEFAULT '',
96
+ checkout_contents longtext NOT NULL,
97
+ checkout_updated datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
98
+ checkout_updated_ts int(11) unsigned NOT NULL DEFAULT 0,
99
+ checkout_created datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
100
+ checkout_created_ts int(11) unsigned NOT NULL DEFAULT 0,
101
+ checkout_recovered datetime NULL DEFAULT '0000-00-00 00:00:00',
102
+ checkout_recovered_ts int(11) unsigned NULL DEFAULT 0,
103
+ checkout_consent int(11) unsigned NOT NULL DEFAULT 1,
104
+ checkout_uuid varchar(36) NOT NULL DEFAULT '',
105
+ PRIMARY KEY (checkout_id),
106
+ UNIQUE KEY checkout_uuid (checkout_uuid)
107
+ ) {$wpdb->get_charset_collate()}";
108
+
109
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
110
+ dbDelta( $sql );
111
+
112
+ add_option( self::DB_VERSION_OPTION_NAME, self::DB_VERSION );
113
+ }
114
+
115
+ /**
116
+ * Delete expired checkouts.
117
+ *
118
+ * @since 1.3.0
119
+ */
120
+ public function delete_expired_checkouts() {
121
+ global $wpdb;
122
+
123
+ // Delete all checkouts at least 30 days old.
124
+ $table_name = $this->get_table_name();
125
+
126
+ $wpdb->query(
127
+ $wpdb->prepare(
128
+ // phpcs:disable WordPress.DB.PreparedSQL -- Okay use of unprepared variable for table name in SQL.
129
+ "DELETE FROM {$table_name}
130
+ WHERE `checkout_updated_ts` <= %s",
131
+ // phpcs:enable
132
+ ( new DateTime() )->sub( new DateInterval( 'P30D' ) )->format( 'U' )
133
+ )
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Upsert the checkout content
139
+ *
140
+ * @since 1.3.0
141
+ */
142
+ public function upsert_checkout($checkout_uuid, $user_id, $billing_email, $content, $current_time) {
143
+ global $wpdb;
144
+
145
+ $table_name = $this->get_table_name();
146
+
147
+ // phpcs:disable WordPress.DB.PreparedSQL -- Okay use of unprepared variable for table name in SQL.
148
+ $wpdb->query(
149
+ $wpdb->prepare(
150
+ "INSERT INTO {$table_name} (
151
+ `user_id`,
152
+ `user_email`,
153
+ `checkout_contents`,
154
+ `checkout_updated`,
155
+ `checkout_updated_ts`,
156
+ `checkout_created`,
157
+ `checkout_created_ts`,
158
+ `checkout_uuid`
159
+ ) VALUES (
160
+ %d,
161
+ %s,
162
+ %s,
163
+ %s,
164
+ %d,
165
+ %s,
166
+ %d,
167
+ %s
168
+ ) ON DUPLICATE KEY UPDATE `user_id` = VALUES(`user_id`), `user_email` = VALUES(`user_email`), `checkout_updated` = VALUES(`checkout_updated`), `checkout_updated_ts` = VALUES(`checkout_updated_ts`), `checkout_contents` = VALUES(`checkout_contents`)",
169
+ $user_id,
170
+ $billing_email,
171
+ maybe_serialize($content),
172
+ $current_time,
173
+ strtotime( $current_time ),
174
+ $current_time,
175
+ strtotime( $current_time ),
176
+ $checkout_uuid
177
+ )
178
+ );
179
+ // phpcs:enable
180
+ }
181
+
182
+ /**
183
+ * Update the database record with current time for recovery
184
+ *
185
+ * @since 1.3.0
186
+ */
187
+ public function mark_checkout_recovered($checkout_uuid) {
188
+ global $wpdb;
189
+
190
+ $table_name = $this->get_table_name();
191
+
192
+ $current_time = current_time( 'mysql', 1 );
193
+
194
+ $wpdb->update($table_name, array(
195
+ 'checkout_recovered' => $current_time,
196
+ 'checkout_recovered_ts' => strtotime( $current_time )
197
+ ), array(self::CHECKOUT_UUID => $checkout_uuid));
198
+ }
199
+
200
+ /**
201
+ * Update the database record with current consent
202
+ *
203
+ * @since 1.3.0
204
+ */
205
+ public function change_checkout_consent($checkout_uuid, $consent) {
206
+ global $wpdb;
207
+
208
+ $table_name = $this->get_table_name();
209
+
210
+ $int_consent = $consent ? 1 : 0;
211
+
212
+ $wpdb->update($table_name, array(
213
+ 'checkout_consent' => $int_consent
214
+ ), array(self::CHECKOUT_UUID => $checkout_uuid));
215
+ }
216
+
217
+ public function has_checkout_consent($checkout_uuid) {
218
+ global $wpdb;
219
+
220
+ $table_name = $this->get_table_name();
221
+
222
+ $consent_value = $wpdb->get_var($wpdb->prepare("SELECT `checkout_consent` FROM $table_name WHERE `checkout_uuid` = %s", $checkout_uuid));
223
+ return $consent_value === "1";
224
+ }
225
+
226
+ /**
227
+ * Retrieve specific user's checkout data.
228
+ *
229
+ * @param string $select Field to return.
230
+ * @param mixed $where String or array of WHERE clause predicates, using placeholders for values.
231
+ * @param array $where_args Array of WHERE clause arguments.
232
+ * @param string $order_by Order by column.
233
+ * @param string $order Order (ASC/DESC).
234
+ * @param string $limit LIMIT clause.
235
+ * @param array $limit_args Array of LIMIT clause arguments.
236
+ *
237
+ * @since 1.3.0
238
+ *
239
+ * @return mixed Checkout data if exists, else null.
240
+ */
241
+ public function get_checkout_data( string $select, $where, array $where_args, string $order_by = 'checkout_updated_ts', string $order = 'DESC', string $limit = '', array $limit_args = [] ) {
242
+ global $wpdb;
243
+
244
+ $table_name = $this->get_table_name();
245
+ $where = is_array( $where ) ? implode( ' AND ', $where ) : $where;
246
+ $where = empty( $where ) ? 1 : $where;
247
+
248
+ // Construct query to return checkout data.
249
+ // phpcs:disable -- Disabling a number of sniffs that erroneously flag following block of code.
250
+ // $where often includes placeholders for replacement via $wpdb->prepare(). $where_values provides those values.
251
+ return $wpdb->get_results(
252
+ $wpdb->prepare(
253
+ "SELECT {$select}
254
+ FROM {$table_name}
255
+ WHERE {$where}
256
+ ORDER BY {$order_by} {$order}
257
+ {$limit}",
258
+ array_merge( $where_args, $limit_args )
259
+ )
260
+ );
261
+ // phpcs:enable
262
+ }
263
+
264
+ /**
265
+ * A simple utility for grabbing the full table name, including the WPDB table prefix.
266
+ *
267
+ * @since 1.3.0
268
+ *
269
+ * @return string
270
+ */
271
+ public static function get_table_name() : string {
272
+ global $wpdb;
273
+ return $wpdb->prefix . self::TABLE_NAME;
274
+ }
275
+ }
src/managers/EmailManager.php CHANGED
@@ -31,12 +31,16 @@ class EmailManager
31
  'customer_new_account',
32
  'customer_reset_password',
33
  'customer_invoice',
34
- 'customer_note'
 
35
  ];
36
 
 
 
 
37
  public function __construct()
38
  {
39
-
40
  }
41
 
42
  public function add_hooks()
@@ -79,19 +83,19 @@ class EmailManager
79
 
80
  public function ce_checkout_order_meta( $order_id )
81
  {
82
- if ($_POST['ce_checkout_consent_checkbox']) {
83
- $checkbox_value = esc_attr($_POST['ce_checkout_consent_checkbox']);
84
- update_post_meta($order_id, 'ce_checkout_consent', $checkbox_value);
85
  }
86
  }
87
 
88
  public function add_checkout_field( $checkout)
89
  {
90
- $checked = $checkout->get_value('ce_checkout_consent_checkbox') ? $checkout->get_value('ce_checkout_consent_checkbox') : 1;
91
  $checkbox_text = stripslashes(OptionsHelper::get_checkout_checkbox_text());
92
 
93
  woocommerce_form_field(
94
- 'ce_checkout_consent_checkbox', array(
95
  'type' => 'checkbox',
96
  'class' => array('ce-field form-row-wide'),
97
  'label' => $checkbox_text,
@@ -141,12 +145,12 @@ class EmailManager
141
  public function print_ce_manage_button($options)
142
  {
143
  ?><tr valign="top">
144
- <th scope="row" class="titledesc">Customize Emails</th>
145
  <td class="forminp forminp-<?php echo sanitize_title($options['type']); ?>">
146
  <a href="admin.php?page=creativemail">
147
- <button type="button" class="button button-secondary" value="<?php _e('Manage', 'ce4wp'); ?>">Manage</button>
148
  </a>
149
- <p class="description">Manage all your email settings and templates with Creative Mail</p>
150
  </td>
151
  </tr><?php
152
  }
@@ -587,9 +591,6 @@ class EmailManager
587
  */
588
  public function manage_emails()
589
  {
590
-
591
- $this->managed_email_notifications = $this->get_managed_email_notifications();
592
-
593
  if (empty($this->managed_email_notifications) || ! is_array($this->managed_email_notifications) ) {
594
  return;
595
  }
@@ -692,7 +693,6 @@ class EmailManager
692
  */
693
  public function get_managed_notification_param( $email_id, $param )
694
  {
695
-
696
  foreach($this->managed_email_notifications as $managed_email_notification) {
697
  if ($email_id == $managed_email_notification->name && property_exists($managed_email_notification, $param)) {
698
  return $managed_email_notification->$param;
31
  'customer_new_account',
32
  'customer_reset_password',
33
  'customer_invoice',
34
+ 'customer_note',
35
+ 'cart_abandoned_ce4wp'
36
  ];
37
 
38
+ const CHECKOUT_CONSENT_CHECKBOX_ID = 'ce4wp_checkout_consent_checkbox';
39
+ const CHECKOUT_CONSENT_CHECKBOX_VALUE = 'ce4wp_checkout_consent';
40
+
41
  public function __construct()
42
  {
43
+ $this->managed_email_notifications = $this->get_managed_email_notifications();
44
  }
45
 
46
  public function add_hooks()
83
 
84
  public function ce_checkout_order_meta( $order_id )
85
  {
86
+ if ($_POST[self::CHECKOUT_CONSENT_CHECKBOX_ID]) {
87
+ $checkbox_value = esc_attr($_POST[self::CHECKOUT_CONSENT_CHECKBOX_ID]);
88
+ update_post_meta($order_id, self::CHECKOUT_CONSENT_CHECKBOX_VALUE, $checkbox_value);
89
  }
90
  }
91
 
92
  public function add_checkout_field( $checkout)
93
  {
94
+ $checked = $checkout->get_value(self::CHECKOUT_CONSENT_CHECKBOX_ID) ? $checkout->get_value(self::CHECKOUT_CONSENT_CHECKBOX_ID) : 0;
95
  $checkbox_text = stripslashes(OptionsHelper::get_checkout_checkbox_text());
96
 
97
  woocommerce_form_field(
98
+ self::CHECKOUT_CONSENT_CHECKBOX_ID, array(
99
  'type' => 'checkbox',
100
  'class' => array('ce-field form-row-wide'),
101
  'label' => $checkbox_text,
145
  public function print_ce_manage_button($options)
146
  {
147
  ?><tr valign="top">
148
+ <th scope="row" class="titledesc"><?php _e('Customize Emails', 'ce4wp'); ?></th>
149
  <td class="forminp forminp-<?php echo sanitize_title($options['type']); ?>">
150
  <a href="admin.php?page=creativemail">
151
+ <button type="button" class="button button-secondary" value="<?php _e('Manage', 'ce4wp'); ?>"><?php _e('Manage', 'ce4wp'); ?></button>
152
  </a>
153
+ <p class="description"><?php _e('Manage all your email settings and templates with Creative Mail', 'ce4wp'); ?></p>
154
  </td>
155
  </tr><?php
156
  }
591
  */
592
  public function manage_emails()
593
  {
 
 
 
594
  if (empty($this->managed_email_notifications) || ! is_array($this->managed_email_notifications) ) {
595
  return;
596
  }
693
  */
694
  public function get_managed_notification_param( $email_id, $param )
695
  {
 
696
  foreach($this->managed_email_notifications as $managed_email_notification) {
697
  if ($email_id == $managed_email_notification->name && property_exists($managed_email_notification, $param)) {
698
  return $managed_email_notification->$param;
src/modules/DashboardWidgetModule.php CHANGED
@@ -80,15 +80,26 @@ class DashboardWidgetModule
80
 
81
  private function show_woo_commerce()
82
  {
83
- $email_manager = CreativeMail::get_instance()->get_email_manager();
84
- $number_of_active_notifications = count( $email_manager->get_managed_email_notifications() );
85
-
86
- if ( $number_of_active_notifications > 0 ) {
87
- $number_of_possible_notifications = count( $email_manager->get_valid_email_notification_names() );
88
- include CE4WP_PLUGIN_DIR . 'src/views/admin-dashboard-widget/woocommerce.php';
89
- } else {
90
- include CE4WP_PLUGIN_DIR . 'src/views/admin-dashboard-widget/no-woocommerce.php';
 
 
 
 
 
 
 
 
 
 
91
  }
 
92
  }
93
 
94
  private function show_exception()
80
 
81
  private function show_woo_commerce()
82
  {
83
+ $number_of_possible_notifications = 0;
84
+ $number_of_active_notifications = 0;
85
+
86
+ try {
87
+ $email_manager = CreativeMail::get_instance()->get_email_manager();
88
+ $supported_email_notifications = $email_manager->get_managed_email_notifications();
89
+ $active_email_notifications = array_filter($supported_email_notifications, function ($email_notification) {
90
+ return $email_notification->active === true;
91
+ });
92
+
93
+ $number_of_active_notifications = count($active_email_notifications);
94
+
95
+ if ($number_of_active_notifications > 0) {
96
+ $number_of_possible_notifications = count($email_manager->get_valid_email_notification_names());
97
+ include CE4WP_PLUGIN_DIR . 'src/views/admin-dashboard-widget/woocommerce.php';
98
+ } else {
99
+ include CE4WP_PLUGIN_DIR . 'src/views/admin-dashboard-widget/no-woocommerce.php';
100
+ }
101
  }
102
+ catch(\Exception $ex) { }
103
  }
104
 
105
  private function show_exception()
src/modules/contacts/Handlers/NinjaFormsPluginHandler.php CHANGED
@@ -48,9 +48,13 @@ class NinjaFormsPluginHandler extends BaseContactFormPluginHandler
48
 
49
  $contactModel->setEventType(CE4WP_NF_EVENTTYPE);
50
 
51
- $contactModel->setOptIn(true);
52
  $contactModel->setOptOut(false);
53
- $contactModel->setOptActionBy(OptActionBy::Visitor);
 
 
 
 
54
 
55
  $email = $contact->email;
56
  if (!empty($email)) {
@@ -58,7 +62,7 @@ class NinjaFormsPluginHandler extends BaseContactFormPluginHandler
58
  $contactModel->setEmail($email);
59
  }
60
 
61
- $name = $contact->name;
62
  $firstName = null;
63
  $lastName = null;
64
  if (!empty($name)){
@@ -80,6 +84,23 @@ class NinjaFormsPluginHandler extends BaseContactFormPluginHandler
80
  return $contactModel;
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  public function ceHandleNinjaFormSubmission($form_data)
84
  {
85
  try {
@@ -136,39 +157,43 @@ class NinjaFormsPluginHandler extends BaseContactFormPluginHandler
136
  foreach ($fields as $field) {
137
  // Get field settings so we can map the values with it's field type
138
  $field_settings = $field->get_settings();
139
- switch ($field_settings["type"]) {
140
- case 'email':
141
- $email = $field_values[$field_settings["key"]];
142
- if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
 
 
 
 
143
  $contact->email = $email;
144
  }
145
  break;
146
- case 'name' || 'full_name':
147
- $contact->name = $field_values[$field_settings["key"]];
 
148
  break;
149
- case 'firstname' || 'first_name':
150
- $contact->firstName = $field_values[$field_settings["key"]];
 
151
  break;
152
- case 'lastname' || 'last_name':
153
- $contact->lastName = $field_values[$field_settings["key"]];
 
 
 
 
 
 
 
 
 
154
  break;
155
- }
156
- if ($this->isNullOrEmpty($contact->name) && $this->isNullOrEmpty($contact->firstName)){
157
- //Attempt additional checking for name in an attempt to get custom form fields for names
158
- $name = null;
159
-
160
- if (strpos($field_settings["key"], "full_name") !== false) {
161
- $contact->name = $field["value"];
162
- }
163
- if (strpos($field_settings["key"], "first_name") !== false) {
164
- $contact->firstName = $field["value"];
165
- }
166
- if (strpos($field_settings["key"], "last_name") !== false) {
167
- $contact->lastname = $field["value"];
168
- }
169
  }
170
  }
171
- if (!empty($contact->email)) {
 
 
 
172
  //Convert to contactModel and push to the array
173
  $contactModel = $this->convertToContactModel($contact);
174
  array_push($contactsArray, $contactModel);
48
 
49
  $contactModel->setEventType(CE4WP_NF_EVENTTYPE);
50
 
51
+ $contactModel->setOptIn(false);
52
  $contactModel->setOptOut(false);
53
+ $contactModel->setOptActionBy(OptActionBy::Owner);
54
+
55
+ if(isset($contact->optinByOwner)){
56
+ $contactModel->setOptIn(boolval($contact->optinByOwner));
57
+ }
58
 
59
  $email = $contact->email;
60
  if (!empty($email)) {
62
  $contactModel->setEmail($email);
63
  }
64
 
65
+ $name = !empty($contact->name) ? $contact->name : null;
66
  $firstName = null;
67
  $lastName = null;
68
  if (!empty($name)){
84
  return $contactModel;
85
  }
86
 
87
+ public function attemptAdditionalNameExtraction($contact, $field_key, $field_values){
88
+ //Attempt additional checking for name in an attempt to get custom form fields for names
89
+ $name = null;
90
+ if (strpos($field_key, "full_name") !== false || isset($field_values["name"])) {
91
+ $contact->name = $field_values[$field_key];
92
+ return;
93
+ }
94
+ if (strpos($field_key, "first_name") !== false || isset($field_values["firstname"])) {
95
+ $contact->firstName = $field_values[$field_key];
96
+ return;
97
+ }
98
+ if (strpos($field_key, "last_name") !== false || isset($field_values["lastname"])) {
99
+ $contact->lastname = $field_values[$field_key];
100
+ return;
101
+ }
102
+ }
103
+
104
  public function ceHandleNinjaFormSubmission($form_data)
105
  {
106
  try {
157
  foreach ($fields as $field) {
158
  // Get field settings so we can map the values with it's field type
159
  $field_settings = $field->get_settings();
160
+ $field_key = $field_settings["key"];
161
+ $field_type = $field_settings["type"];
162
+
163
+ switch($field_type)
164
+ {
165
+ case 'email';
166
+ $email = isset($field_values[$field_key]) ? $field_values[$field_key] : null;
167
+ if (filter_var($email, FILTER_VALIDATE_EMAIL)){
168
  $contact->email = $email;
169
  }
170
  break;
171
+ case 'name';
172
+ case 'full_name';
173
+ $contact->name = $field_values[$field_key];
174
  break;
175
+ case 'firstname';
176
+ case 'first_name';
177
+ $contact->firstName = $field_values[$field_key];
178
  break;
179
+ case 'lastname';
180
+ case 'last_name';
181
+ $contact->lastname = $field_values[$field_key];
182
+ break;
183
+ case 'textbox';
184
+ case 'text';
185
+ if (empty($contact->name) && (empty($contact->firstName) || empty($contact->lastName))){
186
+ $this->attemptAdditionalNameExtraction($contact, $field_key, $field_values);
187
+ }
188
+ break;
189
+ default;
190
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
  }
193
+
194
+ if (!empty($contact->email) && $contact->email != null) {
195
+ //set optin by owner on db sync
196
+ $contact->optinByOwner = true;
197
  //Convert to contactModel and push to the array
198
  $contactModel = $this->convertToContactModel($contact);
199
  array_push($contactsArray, $contactModel);
src/modules/contacts/Handlers/WooCommercePluginHandler.php CHANGED
@@ -10,10 +10,15 @@ namespace CreativeMail\Modules\Contacts\Handlers;
10
 
11
  define('CE4WP_WC_EVENTTYPE', 'WordPress - WooCommerce');
12
 
 
13
  use CreativeMail\Modules\Contacts\Models\ContactModel;
14
 
15
  class WooCommercePluginHandler extends BaseContactFormPluginHandler
16
  {
 
 
 
 
17
  public function convertToContactModel($orderId)
18
  {
19
  $contactModel = new ContactModel();
@@ -31,6 +36,12 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
31
  $contactModel->setEmail($products_detail["_billing_email"][0]);
32
  }
33
 
 
 
 
 
 
 
34
  if (!empty($contactModel->getEmail())) {
35
  $contactModel->setEventType(CE4WP_WC_EVENTTYPE);
36
  $contactModel->setOptActionBy(2);
@@ -40,15 +51,16 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
40
 
41
  $checkbox_value = null;
42
 
43
- if (array_key_exists('ce_checkout_consent_checkbox', $_POST)) {
44
- $checkbox_value = esc_attr($_POST['ce_checkout_consent_checkbox']);
45
- } else if (!empty($products_detail["ce_checkout_consent_checkbox"])) {
46
- $checkbox_value = $products_detail["ce_checkout_consent_checkbox"];
47
- } else if (array_key_exists('ce_checkout_consent', $_POST)) {
48
- // In the database the value is saved as ce_checkout_consent instead of ce_checkout_consent_checkbox
49
- $checkbox_value = esc_attr($_POST['ce_checkout_consent']);
50
- } else if (!empty($products_detail["ce_checkout_consent"])) {
51
- $checkbox_value = $products_detail["ce_checkout_consent"];
 
52
  }
53
 
54
  if (!is_null($checkbox_value)) {
@@ -60,32 +72,58 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
60
  return $contactModel;
61
  }
62
 
63
- // public function ceHandlerWooCommerceNewCustomer($customer_id, $new_customer_data) {
64
- // try {
65
- // $this->upsertContact($this->convertToContactModel($new_customer_data));
66
- // }
67
- // catch (\Exception $exception) {
68
- // // silent exception
69
- // }
70
- // }
71
 
72
- function ceHandlerWooCommerceNewOrder($order_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  {
74
  try {
75
  $order = wc_get_order($order_id);
76
  $this->upsertContact($this->convertToContactModel($order->ID));
77
- }
78
- catch (\Exception $exception) {
79
  // silent exception
80
  }
81
  }
82
 
83
  public function registerHooks()
84
  {
85
- add_action('woocommerce_new_order', array($this, 'ceHandlerWooCommerceNewOrder'));
86
  // hook function to synchronize
87
  add_action(CE4WP_SYNCHRONIZE_ACTION, array($this, 'syncAction'));
88
- //add_action('woocommerce_created_customer', array($this,'ceHandlerWooCommerceNewCustomer'));
89
  }
90
 
91
  public function unregisterHooks()
@@ -98,7 +136,7 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
98
 
99
  public function syncAction($limit = null)
100
  {
101
- if(!is_int($limit) || $limit <= 0) {
102
  $limit = null;
103
  }
104
 
@@ -107,7 +145,7 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
107
  $args = array(
108
  'posts_per_page' => -1,
109
  'post_type' => 'shop_order',
110
- 'post_status'=> array_keys(wc_get_order_statuses())
111
  );
112
 
113
  if ($limit != null) {
@@ -116,7 +154,7 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
116
 
117
  $products_orders = get_posts($args);
118
 
119
- foreach ( $products_orders as $products_order ) {
120
 
121
  $contactModel = $this->convertToContactModel($products_order->ID);
122
 
@@ -129,7 +167,7 @@ class WooCommercePluginHandler extends BaseContactFormPluginHandler
129
  if (!empty($backfillArray)) {
130
 
131
  $batches = array_chunk($backfillArray, CE4WP_BATCH_SIZE);
132
- foreach($batches as $batch){
133
  $this->batchUpsertContacts($batch);
134
  }
135
  }
10
 
11
  define('CE4WP_WC_EVENTTYPE', 'WordPress - WooCommerce');
12
 
13
+ use CreativeMail\Modules\Contacts\Models\ContactAddressModel;
14
  use CreativeMail\Modules\Contacts\Models\ContactModel;
15
 
16
  class WooCommercePluginHandler extends BaseContactFormPluginHandler
17
  {
18
+ const CHECKOUT_CONSENT_CHECKBOX_ID = 'ce4wp_checkout_consent_checkbox';
19
+ const CHECKOUT_CONSENT_CHECKBOX_VALUE = 'ce4wp_checkout_consent';
20
+ const CHECKOUT_CONSENT_CHECKBOX_VALUE_OLD = 'ce_checkout_consent';
21
+
22
  public function convertToContactModel($orderId)
23
  {
24
  $contactModel = new ContactModel();
36
  $contactModel->setEmail($products_detail["_billing_email"][0]);
37
  }
38
 
39
+ $contactAddress = $this->getContactAddressFromOrder($products_detail);
40
+
41
+ if (!empty($contactAddress)) {
42
+ $contactModel->setContactAddress($contactAddress);
43
+ }
44
+
45
  if (!empty($contactModel->getEmail())) {
46
  $contactModel->setEventType(CE4WP_WC_EVENTTYPE);
47
  $contactModel->setOptActionBy(2);
51
 
52
  $checkbox_value = null;
53
 
54
+ if (!empty($_POST[self::CHECKOUT_CONSENT_CHECKBOX_ID])) {
55
+ $checkbox_value = esc_attr($_POST[self::CHECKOUT_CONSENT_CHECKBOX_ID]);
56
+ } else if (!empty($products_detail[self::CHECKOUT_CONSENT_CHECKBOX_ID])) {
57
+ $checkbox_value = $products_detail[self::CHECKOUT_CONSENT_CHECKBOX_ID];
58
+ } else if (!empty($_POST[self::CHECKOUT_CONSENT_CHECKBOX_VALUE])) {
59
+ $checkbox_value = esc_attr($_POST[self::CHECKOUT_CONSENT_CHECKBOX_VALUE]);
60
+ } else if (!empty($products_detail[self::CHECKOUT_CONSENT_CHECKBOX_VALUE])) {
61
+ $checkbox_value = $products_detail[self::CHECKOUT_CONSENT_CHECKBOX_VALUE];
62
+ } else if (!empty($products_detail[self::CHECKOUT_CONSENT_CHECKBOX_VALUE_OLD])) {
63
+ $checkbox_value = $products_detail[self::CHECKOUT_CONSENT_CHECKBOX_VALUE_OLD];
64
  }
65
 
66
  if (!is_null($checkbox_value)) {
72
  return $contactModel;
73
  }
74
 
75
+ function getContactAddressFromOrder($products_detail)
76
+ {
77
+ $contactAddress = new ContactAddressModel();
 
 
 
 
 
78
 
79
+ if (isset($products_detail)) {
80
+ if (!empty($products_detail["_billing_address_1"])) {
81
+ $contactAddress->setAddress($products_detail["_billing_address_1"][0]);
82
+ }
83
+ if (!empty($products_detail["_billing_address_2"])) {
84
+ $contactAddress->setAddress2($products_detail["_billing_address_2"][0]);
85
+ }
86
+ if (!empty($products_detail["_billing_city"])) {
87
+ $contactAddress->setCity($products_detail["_billing_city"][0]);
88
+ }
89
+ if (!empty($products_detail["_billing_country"])) {
90
+ $contactAddress->setCountryCode($products_detail["_billing_country"][0]);
91
+ }
92
+ if (!empty($products_detail["_billing_postcode"])) {
93
+ $contactAddress->setPostalCode($products_detail["_billing_postcode"][0]);
94
+ }
95
+ if (!empty($products_detail["_billing_state"])) {
96
+ $contactAddress->setStateCode($products_detail["_billing_state"][0]);
97
+ }
98
+ }
99
+ return $contactAddress;
100
+ }
101
+
102
+ // public function ceHandlerWooCommerceNewCustomer($customer_id, $new_customer_data, $password)
103
+ // {
104
+ // try {
105
+ // $this->upsertContact($this->convertToContactModel($new_customer_data));
106
+ // } catch (\Exception $exception) {
107
+ // // silent exception
108
+ // }
109
+ // }
110
+
111
+ public function ceHandlerWooCommerceNewOrder($order_id)
112
  {
113
  try {
114
  $order = wc_get_order($order_id);
115
  $this->upsertContact($this->convertToContactModel($order->ID));
116
+ } catch (\Exception $exception) {
 
117
  // silent exception
118
  }
119
  }
120
 
121
  public function registerHooks()
122
  {
123
+ add_action('woocommerce_new_order', array($this, 'ceHandlerWooCommerceNewOrder'), 10, 1);
124
  // hook function to synchronize
125
  add_action(CE4WP_SYNCHRONIZE_ACTION, array($this, 'syncAction'));
126
+ // add_action('woocommerce_created_customer', array($this, 'ceHandlerWooCommerceNewCustomer'), 10, 3);
127
  }
128
 
129
  public function unregisterHooks()
136
 
137
  public function syncAction($limit = null)
138
  {
139
+ if (!is_int($limit) || $limit <= 0) {
140
  $limit = null;
141
  }
142
 
145
  $args = array(
146
  'posts_per_page' => -1,
147
  'post_type' => 'shop_order',
148
+ 'post_status' => array_keys(wc_get_order_statuses())
149
  );
150
 
151
  if ($limit != null) {
154
 
155
  $products_orders = get_posts($args);
156
 
157
+ foreach ($products_orders as $products_order) {
158
 
159
  $contactModel = $this->convertToContactModel($products_order->ID);
160
 
167
  if (!empty($backfillArray)) {
168
 
169
  $batches = array_chunk($backfillArray, CE4WP_BATCH_SIZE);
170
+ foreach ($batches as $batch) {
171
  $this->batchUpsertContacts($batch);
172
  }
173
  }
src/views/admin-dashboard-widget/campaigns.php CHANGED
@@ -40,6 +40,6 @@
40
  </div>
41
  </section>
42
  <section class="ce4wp-campaign-actions">
43
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '93b1417d-2efb-406d-a9a6-aa8af8f813a3', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Create a new campaign', 'ce4wp' ); ?></button>
44
- <button class="button" onclick="ce4wpNavigateToDashboard(this, '5166faec-1dbb-4434-bad0-bb2f75898f92', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'View all campaigns', 'ce4wp' ); ?></button>
45
  </section>
40
  </div>
41
  </section>
42
  <section class="ce4wp-campaign-actions">
43
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '93b1417d-2efb-406d-a9a6-aa8af8f813a3', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Create a new campaign', 'ce4wp' ); ?></button>
44
+ <button class="button" onclick="ce4wpNavigateToDashboard(this, '5166faec-1dbb-4434-bad0-bb2f75898f92', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'View all campaigns', 'ce4wp' ); ?></button>
45
  </section>
src/views/admin-dashboard-widget/exception.php CHANGED
@@ -1,6 +1,6 @@
1
  <div style="display: flex;">
2
  <section style="flex: 1;">
3
- <p style="margin-top: 0;"><?= __( 'Well... this is embarassing!', 'ce4wp' ); ?></p>
4
  <p><?= __( 'Creative Mail ran into an error.', 'ce4wp' ); ?></p>
5
  <p><?= __( 'Please try again at a later time.', 'ce4wp') ?></p>
6
  </section>
1
  <div style="display: flex;">
2
  <section style="flex: 1;">
3
+ <p style="margin-top: 0;"><?= __( 'Well... this is embarrassing!', 'ce4wp' ); ?></p>
4
  <p><?= __( 'Creative Mail ran into an error.', 'ce4wp' ); ?></p>
5
  <p><?= __( 'Please try again at a later time.', 'ce4wp') ?></p>
6
  </section>
src/views/admin-dashboard-widget/most-recent-campaigns.php CHANGED
@@ -71,11 +71,11 @@ p.ce4wp-campaigns__item__subtitle {
71
  </section>
72
  <section class="ce4wp-campaigns__item__section ce4wp-campaigns__item__section--grow">
73
  <?php if ( $campaign->is_draft ) { ?>
74
- <a class="ce4wp-campaigns__item__title" onclick="ce4wpNavigateToDashboard(this, 'c182bb37-9cef-4962-a706-7fa14ffef01e', { campaignId: '<?= esc_attr( $campaign->id ); ?>' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
75
  <strong><?= esc_html( $campaign->name ); ?></strong>
76
  </a>
77
  <?php } else { ?>
78
- <a class="ce4wp-campaigns__item__title" onclick="ce4wpNavigateToDashboard(this, 'bd38068c-329b-4c9f-9b2d-fb03a9278bbb', { campaignId: '<?= esc_attr( $campaign->id ); ?>' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
79
  <strong><?= esc_html( $campaign->name ); ?></strong>
80
  </a>
81
  <?php } ?>
@@ -92,10 +92,10 @@ p.ce4wp-campaigns__item__subtitle {
92
  <?php } ?>
93
  </section>
94
  <section class="ce4wp-campaign-actions">
95
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '93b1417d-2efb-406d-a9a6-aa8af8f813a3', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
96
  <?= __( 'Create a new campaign', 'ce4wp' ); ?>
97
  </button>
98
- <button class="button" onclick="ce4wpNavigateToDashboard(this, '5166faec-1dbb-4434-bad0-bb2f75898f92', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
99
  <?= __( 'View all campaigns', 'ce4wp' ); ?>
100
  </button>
101
  </section>
71
  </section>
72
  <section class="ce4wp-campaigns__item__section ce4wp-campaigns__item__section--grow">
73
  <?php if ( $campaign->is_draft ) { ?>
74
+ <a class="ce4wp-campaigns__item__title" onclick="ce4wpNavigateToDashboard(this, 'c182bb37-9cef-4962-a706-7fa14ffef01e', { campaignId: '<?= esc_attr( $campaign->id ); ?>', source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
75
  <strong><?= esc_html( $campaign->name ); ?></strong>
76
  </a>
77
  <?php } else { ?>
78
+ <a class="ce4wp-campaigns__item__title" onclick="ce4wpNavigateToDashboard(this, 'bd38068c-329b-4c9f-9b2d-fb03a9278bbb', { campaignId: '<?= esc_attr( $campaign->id ); ?>', source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
79
  <strong><?= esc_html( $campaign->name ); ?></strong>
80
  </a>
81
  <?php } ?>
92
  <?php } ?>
93
  </section>
94
  <section class="ce4wp-campaign-actions">
95
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '93b1417d-2efb-406d-a9a6-aa8af8f813a3', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
96
  <?= __( 'Create a new campaign', 'ce4wp' ); ?>
97
  </button>
98
+ <button class="button" onclick="ce4wpNavigateToDashboard(this, '5166faec-1dbb-4434-bad0-bb2f75898f92', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
99
  <?= __( 'View all campaigns', 'ce4wp' ); ?>
100
  </button>
101
  </section>
src/views/admin-dashboard-widget/no-campaign.php CHANGED
@@ -3,7 +3,7 @@
3
  <p style="margin-top: 0;">
4
  <?= __( 'Thanks for signing up with Creative Mail. Let’s create your first campaign!', 'ce4wp' ); ?>
5
  </p>
6
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '93b1417d-2efb-406d-a9a6-aa8af8f813a3', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Create a campaign', 'ce4wp' ); ?></button>
7
  </section>
8
  <img
9
  src="<?= CE4WP_PLUGIN_URL . 'assets/images/admin-dashboard-widget/airplane.svg'; ?>"
3
  <p style="margin-top: 0;">
4
  <?= __( 'Thanks for signing up with Creative Mail. Let’s create your first campaign!', 'ce4wp' ); ?>
5
  </p>
6
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '93b1417d-2efb-406d-a9a6-aa8af8f813a3', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Create a campaign', 'ce4wp' ); ?></button>
7
  </section>
8
  <img
9
  src="<?= CE4WP_PLUGIN_URL . 'assets/images/admin-dashboard-widget/airplane.svg'; ?>"
src/views/admin-dashboard-widget/no-ce-account.php CHANGED
@@ -3,7 +3,7 @@
3
  <p style="margin-top: 0;">
4
  <?= __('Our intelligent email editor makes it easy to create professional emails to engage your audience.', 'ce4wp'); ?>
5
  </p>
6
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, undefined, undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
7
  <?= __("Let's go!", 'ce4wp'); ?>
8
  </button>
9
  </section>
3
  <p style="margin-top: 0;">
4
  <?= __('Our intelligent email editor makes it easy to create professional emails to engage your audience.', 'ce4wp'); ?>
5
  </p>
6
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, 'd25f690a-217a-4d68-9c58-8693965d4673', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
7
  <?= __("Let's go!", 'ce4wp'); ?>
8
  </button>
9
  </section>
src/views/admin-dashboard-widget/no-woocommerce.php CHANGED
@@ -3,7 +3,7 @@
3
  <p style="margin-top: 0;">
4
  <?= __( 'Easily manage and brand all of your important transactional WooCommerce store emails.', 'ce4wp' ); ?>
5
  </p>
6
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '1fabdbe2-95ed-4e1e-a2f3-ba0278f5096f', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
7
  <?= __( "Let's go!", 'ce4wp' ); ?>
8
  </button>
9
  </section>
3
  <p style="margin-top: 0;">
4
  <?= __( 'Easily manage and brand all of your important transactional WooCommerce store emails.', 'ce4wp' ); ?>
5
  </p>
6
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, '1fabdbe2-95ed-4e1e-a2f3-ba0278f5096f', { source: 'dashboard_widget' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
7
  <?= __( "Let's go!", 'ce4wp' ); ?>
8
  </button>
9
  </section>
src/views/admin-feedback-notice/few-contacts.php CHANGED
@@ -6,6 +6,6 @@
6
  </p>
7
  <p><?= __( 'These contacts are already in Creative Mail, send a quick campaign...', 'ce4wp' ); ?></p>
8
  </section>
9
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, 'd25f690a-217a-4d68-9c58-8693965d4673', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Get started', 'ce4wp' ); ?></button>
10
  <span id="close" onclick="hideAdminFeedbackNotice('feedback_notice_few_contacts')"></span>
11
  </div>
6
  </p>
7
  <p><?= __( 'These contacts are already in Creative Mail, send a quick campaign...', 'ce4wp' ); ?></p>
8
  </section>
9
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, 'd25f690a-217a-4d68-9c58-8693965d4673', { source: 'feedback_notice' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Get started', 'ce4wp' ); ?></button>
10
  <span id="close" onclick="hideAdminFeedbackNotice('feedback_notice_few_contacts')"></span>
11
  </div>
src/views/admin-feedback-notice/many-contacts.php CHANGED
@@ -10,6 +10,6 @@
10
  <?= __( 'contacts are ready for a Creative Mail email campaign. Send one now!', 'ce4wp' ); ?>
11
  </p>
12
  </section>
13
- <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, 'd25f690a-217a-4d68-9c58-8693965d4673', undefined, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Get started', 'ce4wp' ); ?></button>
14
  <span id="close" onclick="hideAdminFeedbackNotice('feedback_notice_many_contacts')"></span>
15
  </div>
10
  <?= __( 'contacts are ready for a Creative Mail email campaign. Send one now!', 'ce4wp' ); ?>
11
  </p>
12
  </section>
13
+ <button class="button button-primary" onclick="ce4wpNavigateToDashboard(this, 'd25f690a-217a-4d68-9c58-8693965d4673', { source: 'feedback_notice' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)"><?= __( 'Get started', 'ce4wp' ); ?></button>
14
  <span id="close" onclick="hideAdminFeedbackNotice('feedback_notice_many_contacts')"></span>
15
  </div>
src/views/dashboard.php CHANGED
@@ -21,7 +21,7 @@
21
  <?= __( 'You’re all set! Creative Mail and WordPress have been linked.', 'ce4wp'); ?>
22
  </p>
23
  <div id="ce4wploaded">
24
- <a id='ce4wp-go-button' onclick="ce4wpNavigateToDashboard(this, undefined, undefined, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)" class="ce4wp-button-base-root ce4wp-button-root ce4wp-button-contained ce4wp-button-contained-primary ce4wp-mt-2" tabindex="0" type="button" data-element-type="button">
25
  <span class="ce4wp-button-label" style="width: 100%;"><?= __( 'Open your Creative Mail dashboard', 'ce4wp'); ?><span class="ce4wp-button-endIcon">
26
  <svg class="ce4wp-Svgicon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
27
  <path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path>
@@ -33,7 +33,7 @@
33
  <?= __( 'Or jump straight into:', 'ce4wp'); ?>
34
  </h6>
35
  <div id='ce4wp-sub-apps-container' class="ce4wp-grid ce4wp-mt-3">
36
- <div class="ce4wp-grid-item" onclick="ce4wpNavigateToDashboard(this, '1fabdbe2-95ed-4e1e-a2f3-ba0278f5096f', undefined, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)">
37
  <div class="ce4wp-grid-item-card ce4wp-mb-4">
38
  <div class="ce4wp-grid-item-card-media" title="WooCommerce emails" style="background-image: url(<?php echo CE4WP_PLUGIN_URL . 'assets/images/tile-img-woocommerce.svg'; ?>);"></div>
39
  <div class="ce4wp-grid-item-card-content-root">
@@ -42,7 +42,7 @@
42
  </div>
43
  </div>
44
  </div>
45
- <div class="ce4wp-grid-item" onclick="ce4wpNavigateToDashboard(this, 'd5baea05-c603-4cca-852e-f8e82414f6b0', undefined, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)">
46
  <div class="ce4wp-grid-item-card ce4wp-mb-4">
47
  <div class="ce4wp-grid-item-card-media" title="Email Automations" style="background-image: url(<?php echo CE4WP_PLUGIN_URL . 'assets/images/tile-img-automations.svg'; ?>);"></div>
48
  <div class="ce4wp-grid-item-card-content-root">
@@ -51,7 +51,7 @@
51
  </div>
52
  </div>
53
  </div>
54
- <div class="ce4wp-grid-item" onclick="ce4wpNavigateToDashboard(this, '836b20fc-9ff1-41b2-912b-a8646caf05a4', undefined, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)">
55
  <div class="ce4wp-grid-item-card ce4wp-mb-4">
56
  <div class="ce4wp-grid-item-card-media" title="Contact Management" style="background-image: url(<?php echo CE4WP_PLUGIN_URL . 'assets/images/tile-img-contactmanagement.svg'; ?>);"></div>
57
  <div class="ce4wp-grid-item-card-content-root">
21
  <?= __( 'You’re all set! Creative Mail and WordPress have been linked.', 'ce4wp'); ?>
22
  </p>
23
  <div id="ce4wploaded">
24
+ <a id='ce4wp-go-button' onclick="ce4wpNavigateToDashboard(this, 'd25f690a-217a-4d68-9c58-8693965d4673', { source: 'ce4wp_dashboard' }, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)" class="ce4wp-button-base-root ce4wp-button-root ce4wp-button-contained ce4wp-button-contained-primary ce4wp-mt-2" tabindex="0" type="button" data-element-type="button">
25
  <span class="ce4wp-button-label" style="width: 100%;"><?= __( 'Open your Creative Mail dashboard', 'ce4wp'); ?><span class="ce4wp-button-endIcon">
26
  <svg class="ce4wp-Svgicon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
27
  <path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path>
33
  <?= __( 'Or jump straight into:', 'ce4wp'); ?>
34
  </h6>
35
  <div id='ce4wp-sub-apps-container' class="ce4wp-grid ce4wp-mt-3">
36
+ <div class="ce4wp-grid-item" onclick="ce4wpNavigateToDashboard(this, '1fabdbe2-95ed-4e1e-a2f3-ba0278f5096f', { source: 'ce4wp_dashboard' }, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)">
37
  <div class="ce4wp-grid-item-card ce4wp-mb-4">
38
  <div class="ce4wp-grid-item-card-media" title="WooCommerce emails" style="background-image: url(<?php echo CE4WP_PLUGIN_URL . 'assets/images/tile-img-woocommerce.svg'; ?>);"></div>
39
  <div class="ce4wp-grid-item-card-content-root">
42
  </div>
43
  </div>
44
  </div>
45
+ <div class="ce4wp-grid-item" onclick="ce4wpNavigateToDashboard(this, 'd5baea05-c603-4cca-852e-f8e82414f6b0', { source: 'ce4wp_dashboard' }, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)">
46
  <div class="ce4wp-grid-item-card ce4wp-mb-4">
47
  <div class="ce4wp-grid-item-card-media" title="Email Automations" style="background-image: url(<?php echo CE4WP_PLUGIN_URL . 'assets/images/tile-img-automations.svg'; ?>);"></div>
48
  <div class="ce4wp-grid-item-card-content-root">
51
  </div>
52
  </div>
53
  </div>
54
+ <div class="ce4wp-grid-item" onclick="ce4wpNavigateToDashboard(this, '836b20fc-9ff1-41b2-912b-a8646caf05a4', { source: 'ce4wp_dashboard' }, ce4wpDashboardStartCallback, ce4wpDashboardFinishCallback)">
55
  <div class="ce4wp-grid-item-card ce4wp-mb-4">
56
  <div class="ce4wp-grid-item-card-media" title="Contact Management" style="background-image: url(<?php echo CE4WP_PLUGIN_URL . 'assets/images/tile-img-contactmanagement.svg'; ?>);"></div>
57
  <div class="ce4wp-grid-item-card-content-root">
src/views/onboarding.php CHANGED
@@ -1,27 +1,3 @@
1
- <?php
2
- use CreativeMail\Helpers\EnvironmentHelper;
3
- use CreativeMail\Helpers\OptionsHelper;
4
-
5
- $redirectUrl = EnvironmentHelper::get_app_gateway_url('wordpress/v1.0/instances/open?clearSession=true&redirectUrl=');
6
- $onboardingUrl = EnvironmentHelper::get_app_url() . 'marketing/onboarding/signup?wp_site_name=' . $this->instance_name
7
- . '&wp_site_uuid=' . $this->instance_uuid
8
- . '&wp_handshake=' . $this->instance_handshake_token
9
- . '&wp_callback_url=' . $this->instance_callback_url
10
- . '&wp_instance_url=' . $this->instance_url
11
- . '&wp_version=' . get_bloginfo('version')
12
- . '&plugin_version=' . CE4WP_PLUGIN_VERSION;
13
- $referred_by = OptionsHelper::get_referred_by();
14
- if (isset($referred_by)) {
15
- $utm_campaign = '';
16
- if (is_array($referred_by) && array_key_exists('plugin', $referred_by) && array_key_exists('source', $referred_by)) {
17
- $utm_campaign = $referred_by['plugin'] . $referred_by['source'];
18
- } else if (is_string($referred_by)) {
19
- $utm_campaign = str_replace(';', '|', $referred_by);
20
- }
21
- $onboardingUrl .= '&utm_source=wordpress&utm_medium=plugin&utm_campaign=' . $utm_campaign;
22
- }
23
- ?>
24
-
25
  <div class="ce4wp-admin-wrapper">
26
  <header class="ce4wp-swoosh-header"></header>
27
 
@@ -74,12 +50,12 @@ if (isset($referred_by)) {
74
  </li>
75
  </ul>
76
  <a id='ce4wp-go-button'
77
- href="<?php echo esc_url($redirectUrl . rawurlencode($onboardingUrl)) ?>"
78
  target="_blank"
79
  class="ce4wp-button-base-root ce4wp-button-root ce4wp-button-contained ce4wp-button-contained-primary ce4wp-mb-4 ce4wp-mt-2"
80
  tabindex="0"
81
  type="button"
82
- data-element-type="button">
 
83
  <span class="ce4wp-button-label" style="width: 100%;">
84
  <?= __('I Agree and let\'s get started!', 'ce4wp') ?><span class="ce4wp-button-endIcon">
85
  <svg class="ce4wp-Svgicon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="ce4wp-admin-wrapper">
2
  <header class="ce4wp-swoosh-header"></header>
3
 
50
  </li>
51
  </ul>
52
  <a id='ce4wp-go-button'
 
53
  target="_blank"
54
  class="ce4wp-button-base-root ce4wp-button-root ce4wp-button-contained ce4wp-button-contained-primary ce4wp-mb-4 ce4wp-mt-2"
55
  tabindex="0"
56
  type="button"
57
+ data-element-type="button"
58
+ onclick="ce4wpNavigateToDashboard(this, undefined, { source: 'onboarding' }, ce4wpWidgetStartCallback, ce4wpWidgetFinishCallback)">
59
  <span class="ce4wp-button-label" style="width: 100%;">
60
  <?= __('I Agree and let\'s get started!', 'ce4wp') ?><span class="ce4wp-button-endIcon">
61
  <svg class="ce4wp-Svgicon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
src/views/settings.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
 
3
- use CreativeMail\CreativeMail;
4
- use CreativeMail\Helpers\EnvironmentHelper;
5
- use CreativeMail\Helpers\OptionsHelper;
6
 
7
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
8
 
1
  <?php
2
 
3
+ use CreativeMail\CreativeMail;
4
+ use CreativeMail\Helpers\EnvironmentHelper;
5
+ use CreativeMail\Helpers\OptionsHelper;
6
 
7
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
8
 
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit1bf2baaec5a947c9725005d396762edd::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit5218f9aec364198b823da642da7b30b2::getLoader();
vendor/composer/ClassLoader.php CHANGED
@@ -60,7 +60,7 @@ class ClassLoader
60
  public function getPrefixes()
61
  {
62
  if (!empty($this->prefixesPsr0)) {
63
- return call_user_func_array('array_merge', $this->prefixesPsr0);
64
  }
65
 
66
  return array();
60
  public function getPrefixes()
61
  {
62
  if (!empty($this->prefixesPsr0)) {
63
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
64
  }
65
 
66
  return array();
vendor/composer/autoload_classmap.php CHANGED
@@ -18,6 +18,8 @@ return array(
18
  'CreativeMail\\Integrations\\Integration' => $baseDir . '/src/integrations/Integration.php',
19
  'CreativeMail\\Managers\\AdminManager' => $baseDir . '/src/managers/AdminManager.php',
20
  'CreativeMail\\Managers\\ApiManager' => $baseDir . '/src/managers/ApiManager.php',
 
 
21
  'CreativeMail\\Managers\\EmailManager' => $baseDir . '/src/managers/EmailManager.php',
22
  'CreativeMail\\Managers\\InstanceManager' => $baseDir . '/src/managers/InstanceManager.php',
23
  'CreativeMail\\Managers\\IntegrationManager' => $baseDir . '/src/managers/IntegrationManager.php',
18
  'CreativeMail\\Integrations\\Integration' => $baseDir . '/src/integrations/Integration.php',
19
  'CreativeMail\\Managers\\AdminManager' => $baseDir . '/src/managers/AdminManager.php',
20
  'CreativeMail\\Managers\\ApiManager' => $baseDir . '/src/managers/ApiManager.php',
21
+ 'CreativeMail\\Managers\\CheckoutManager' => $baseDir . '/src/managers/CheckoutManager.php',
22
+ 'CreativeMail\\Managers\\DatabaseManager' => $baseDir . '/src/managers/DatabaseManager.php',
23
  'CreativeMail\\Managers\\EmailManager' => $baseDir . '/src/managers/EmailManager.php',
24
  'CreativeMail\\Managers\\InstanceManager' => $baseDir . '/src/managers/InstanceManager.php',
25
  'CreativeMail\\Managers\\IntegrationManager' => $baseDir . '/src/managers/IntegrationManager.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit1bf2baaec5a947c9725005d396762edd
6
  {
7
  private static $loader;
8
 
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit1bf2baaec5a947c9725005d396762edd
22
  return self::$loader;
23
  }
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInit1bf2baaec5a947c9725005d396762edd', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
- spl_autoload_unregister(array('ComposerAutoloaderInit1bf2baaec5a947c9725005d396762edd', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
- call_user_func(\Composer\Autoload\ComposerStaticInit1bf2baaec5a947c9725005d396762edd::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit5218f9aec364198b823da642da7b30b2
6
  {
7
  private static $loader;
8
 
22
  return self::$loader;
23
  }
24
 
25
+ spl_autoload_register(array('ComposerAutoloaderInit5218f9aec364198b823da642da7b30b2', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
+ spl_autoload_unregister(array('ComposerAutoloaderInit5218f9aec364198b823da642da7b30b2', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
+ call_user_func(\Composer\Autoload\ComposerStaticInit5218f9aec364198b823da642da7b30b2::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit1bf2baaec5a947c9725005d396762edd
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'F' =>
@@ -74,6 +74,8 @@ class ComposerStaticInit1bf2baaec5a947c9725005d396762edd
74
  'CreativeMail\\Integrations\\Integration' => __DIR__ . '/../..' . '/src/integrations/Integration.php',
75
  'CreativeMail\\Managers\\AdminManager' => __DIR__ . '/../..' . '/src/managers/AdminManager.php',
76
  'CreativeMail\\Managers\\ApiManager' => __DIR__ . '/../..' . '/src/managers/ApiManager.php',
 
 
77
  'CreativeMail\\Managers\\EmailManager' => __DIR__ . '/../..' . '/src/managers/EmailManager.php',
78
  'CreativeMail\\Managers\\InstanceManager' => __DIR__ . '/../..' . '/src/managers/InstanceManager.php',
79
  'CreativeMail\\Managers\\IntegrationManager' => __DIR__ . '/../..' . '/src/managers/IntegrationManager.php',
@@ -128,9 +130,9 @@ class ComposerStaticInit1bf2baaec5a947c9725005d396762edd
128
  public static function getInitializer(ClassLoader $loader)
129
  {
130
  return \Closure::bind(function () use ($loader) {
131
- $loader->prefixLengthsPsr4 = ComposerStaticInit1bf2baaec5a947c9725005d396762edd::$prefixLengthsPsr4;
132
- $loader->prefixDirsPsr4 = ComposerStaticInit1bf2baaec5a947c9725005d396762edd::$prefixDirsPsr4;
133
- $loader->classMap = ComposerStaticInit1bf2baaec5a947c9725005d396762edd::$classMap;
134
 
135
  }, null, ClassLoader::class);
136
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit5218f9aec364198b823da642da7b30b2
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'F' =>
74
  'CreativeMail\\Integrations\\Integration' => __DIR__ . '/../..' . '/src/integrations/Integration.php',
75
  'CreativeMail\\Managers\\AdminManager' => __DIR__ . '/../..' . '/src/managers/AdminManager.php',
76
  'CreativeMail\\Managers\\ApiManager' => __DIR__ . '/../..' . '/src/managers/ApiManager.php',
77
+ 'CreativeMail\\Managers\\CheckoutManager' => __DIR__ . '/../..' . '/src/managers/CheckoutManager.php',
78
+ 'CreativeMail\\Managers\\DatabaseManager' => __DIR__ . '/../..' . '/src/managers/DatabaseManager.php',
79
  'CreativeMail\\Managers\\EmailManager' => __DIR__ . '/../..' . '/src/managers/EmailManager.php',
80
  'CreativeMail\\Managers\\InstanceManager' => __DIR__ . '/../..' . '/src/managers/InstanceManager.php',
81
  'CreativeMail\\Managers\\IntegrationManager' => __DIR__ . '/../..' . '/src/managers/IntegrationManager.php',
130
  public static function getInitializer(ClassLoader $loader)
131
  {
132
  return \Closure::bind(function () use ($loader) {
133
+ $loader->prefixLengthsPsr4 = ComposerStaticInit5218f9aec364198b823da642da7b30b2::$prefixLengthsPsr4;
134
+ $loader->prefixDirsPsr4 = ComposerStaticInit5218f9aec364198b823da642da7b30b2::$prefixDirsPsr4;
135
+ $loader->classMap = ComposerStaticInit5218f9aec364198b823da642da7b30b2::$classMap;
136
 
137
  }, null, ClassLoader::class);
138
  }