WooCommerce Cart Abandonment Recovery - Version 1.1.3

Version Description

Download this release

Release Info

Developer sandesh055
Plugin Icon 128x128 WooCommerce Cart Abandonment Recovery
Version 1.1.3
Comparing to
See all releases

Code changes from version 1.1.2 to 1.1.3

admin/assets/css/admin-cart-abandonment-rtl.css CHANGED
@@ -1,398 +1,398 @@
1
-
2
- .wcf-ca-ibox {
3
- clear: both;
4
- margin-bottom: 25px;
5
- margin-top: 0;
6
- padding: 0;
7
- }
8
-
9
- .wcf-ca-ibox-title {
10
- background-color: white;
11
- border-image: none;
12
- border-width: 3px 0px 0;
13
- color: inherit;
14
- margin-bottom: 0;
15
- padding: 14px 15px 7px;
16
- min-height: 48px;
17
- }
18
-
19
- .wcf-ca-ibox-content {
20
- background-color: white;
21
- color: inherit;
22
- padding: 15px 20px 20px 20px;
23
- border-color: #d7dadc;
24
- border-image: none;
25
- border-style: solid solid none;
26
- border-width: 1px 0px;
27
- }
28
-
29
- .wcf-ca-raw {
30
- margin-right: -15px;
31
- margin-left: -15px;
32
- }
33
-
34
- .wcf-ca-grid-container {
35
- display: grid;
36
- grid-template-columns: 1fr 1fr 1fr;
37
- grid-gap: 20px;
38
- }
39
-
40
- .grid-container > div {
41
- background-color: rgba(255, 255, 255, 0.8);
42
- text-align: center;
43
- padding: 20px 0;
44
- font-size: 30px;
45
- }
46
-
47
-
48
- .wcf-ca-center-msg {
49
- margin: auto;
50
- width: 50%;
51
- padding: 10px;
52
- margin-top: 20px;
53
- text-align: center;
54
- }
55
-
56
-
57
- .wcf-ca-switch {
58
- cursor: pointer;
59
- text-indent: -999em;
60
- display: block;
61
- width: 38px;
62
- height: 22px;
63
- border-radius: 30px;
64
- border: none;
65
- position: relative;
66
- box-sizing: border-box;
67
- -webkit-transition: all .3s ease;
68
- transition: all .3s ease;
69
- box-shadow: inset 0 0 0 0 transparent;
70
- }
71
- .wcf-ca-switch:focus {
72
- outline: none;
73
- }
74
- .wcf-ca-switch:before {
75
- border-radius: 50%;
76
- background: #ffffff;
77
- content: '';
78
- position: absolute;
79
- display: block;
80
- width: 18px;
81
- height: 18px;
82
- top: 2px;
83
- right: 2px;
84
- -webkit-transition: all .15s ease;
85
- transition: all .15s ease;
86
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
87
- }
88
- .wcf-ca-switch[wcf-ca-template-switch="on"] {
89
- box-shadow: inset 0 0 0 11px #008000;
90
- }
91
- .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
92
- -webkit-transform: translateX(-16px);
93
- transform: translateX(-16px);
94
- }
95
- .wcf-ca-switch[wcf-ca-template-switch="off"] {
96
- background: #ccc;
97
- }
98
- .wcf-ca-switch.wcap-loading {
99
- cursor: default;
100
- opacity: 0.5;
101
- }
102
-
103
- .wcf-ca-trigger-input{
104
- height: 28px;
105
- width: 40%;
106
- margin-left: 10px;
107
- }
108
-
109
- .wcf-ca-report-btn {
110
- padding: 15px 0px 15px 0px;
111
- display: table;
112
- width: 100%;
113
- }
114
-
115
- .wcf-ca-email-inputs {
116
- width: 25%;
117
- }
118
-
119
- .wcf-ca-coupon-inputs {
120
- width: 10%;
121
- vertical-align: middle;
122
- }
123
-
124
- .wcf-ca-filter-input{
125
- height: 28px;
126
- width: 7em;
127
- margin: 0;
128
- text-align: center;
129
- }
130
-
131
- .wcf-ca-left-report-field-group {
132
- display: table-cell; text-align: right;
133
- }
134
- .wcf-ca-right-report-field-group {
135
- display: table-cell; text-align: left;
136
- }
137
- .wcf-ca-report-table-row {
138
- color: #636363;
139
- border: 1px solid #e5e5e5;
140
- }
141
-
142
- /* Newly Added for the modification of the User Order detail window UI */
143
-
144
- /* Column Classes */
145
-
146
- .wcf-ca-column-one{
147
- width: 100%;
148
- }
149
-
150
- .wcf-ca-column-two,
151
- .wcf-ca-user-address{
152
- width: 50%;
153
- }
154
-
155
- .wcf-pull-left{
156
- float: right;
157
- }
158
- .wcf-ca-email-data,
159
- .wcf-ca-user-detail{
160
- border-radius: 3px;
161
- padding: 20px 25px;
162
- min-height: 330px;
163
- max-height: 420px;
164
- width: 100%;
165
- overflow: auto;
166
- }
167
-
168
- .wcf-ca-user-detail{
169
- max-height: 100%;
170
- }
171
-
172
- .wcf-ca-user-order{
173
- border-radius: 3px;
174
- padding: 25px 25px 30px 25px;
175
- overflow: hidden;
176
- height: auto;
177
- width: 100%;
178
- }
179
-
180
- /* Column Classes */
181
-
182
- /* Section classes */
183
-
184
- .wcf-ca-margin-right{
185
- margin-left: 13px;
186
- }
187
- .wcf-ca-margin-left{
188
- margin-right: 13px;
189
- }
190
-
191
- .wcf-ca-column{
192
- background-color: #fff;
193
- border-radius: 3px;
194
- display: flex;
195
- }
196
-
197
- /* Section Classes */
198
-
199
-
200
- .wcf-ca-right-report-field-group .back-button{
201
- height: auto;
202
- padding: 3px 5px 3px 10px;
203
- }
204
-
205
- .wcf-ca-left-report-field-group .back-button .dashicons{
206
- vertical-align: middle;
207
- }
208
-
209
- .wcf-ca-panel{
210
- cursor: default;
211
- /*background-color: #fff;*/
212
- border-radius: 5px;
213
- display: flex;
214
- padding: 0px;
215
- margin: 10px 0 25px;
216
- }
217
-
218
- .wcf-table{
219
- border: none;
220
- text-align: right;
221
- width: 100%;
222
- }
223
- .wcf-table tr,
224
- .wcf-table tr th,
225
- .wcf-table tr td{
226
- border: none;
227
- }
228
-
229
- .wcf-table tr th a,
230
- .wcf-table tr td a{
231
- text-decoration: none;
232
- cursor: pointer;
233
- }
234
-
235
- .wcf-table tr th{
236
- vertical-align: bottom;
237
- border-bottom: 2px solid #ddd;
238
- }
239
-
240
- .wcf-table tr td{
241
- border-bottom: 1px solid #ddd;
242
- line-height: 1.42857143;
243
- vertical-align: top;
244
- position: relative;
245
- }
246
-
247
- .wcf-ca-panel h2{
248
- margin: 0;
249
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
250
- font-size: 21px;
251
- font-weight: 400;
252
- line-height: 1.2;
253
- text-shadow: -1px 1px 1px #fff;
254
- padding: 10px 0 15px;
255
- margin: 0;
256
- }
257
-
258
- .wcf-ca-user-order table{
259
- width: 100%;
260
- }
261
-
262
- .wcf-ca-user-order table thead th{
263
- text-align: center;
264
- padding: 1em 3em;
265
- font-weight: 400;
266
- color: #999;
267
- /*background: #f8f8f8;*/
268
- -webkit-touch-callout: none;
269
- -webkit-user-select: none;
270
- -moz-user-select: none;
271
- -ms-user-select: none;
272
- user-select: none;
273
- }
274
-
275
- .wcf-ca-user-order table thead th:first-of-type{
276
- padding-right: 3.6em;
277
- text-align: right;
278
- }
279
-
280
- .wcf-ca-user-order table tbody tr td {
281
- text-align: center;
282
- padding: 1em 3em;
283
- vertical-align: middle;
284
- }
285
-
286
- .wcf-ca-user-order table tbody tr td:first-of-type{
287
- text-align: right;
288
- /*width: 38px;*/
289
- padding-right: 3em;
290
- }
291
-
292
-
293
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
294
- .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
295
- .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
296
- .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
297
- text-align: left;
298
- font-weight: 600;
299
- width: 82%;
300
- }
301
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
302
- border-top: 1px solid #ccc;
303
- }
304
-
305
- .wcf-ca-tooltip-text.display_tool_tip{
306
- display: block;
307
- }
308
-
309
- .wcf-ca-tooltip-text::before {
310
- border-right: 5px solid transparent;
311
- border-left: 5px solid transparent;
312
- border-top: 5px solid transparent;
313
- border-bottom: 5px solid #444;
314
- bottom: auto;
315
- content: " ";
316
- font-size: 0;
317
- right: 25px;
318
- line-height: 0;
319
- margin-right: -5px;
320
- position: absolute;
321
- top: -10px;
322
- width: 0;
323
- }
324
-
325
- .wcf-ca-tooltip-text {
326
- background: #444;
327
- border-radius: 3px;
328
- color: #fff;
329
- height: auto;
330
- right: 0;
331
- margin-top: 10px;
332
- max-width: 150px;
333
- position: absolute;
334
- padding: 6px 10px;
335
- width: 100%;
336
- display: none;
337
- z-index: 10000;
338
- }
339
- /* Newly Added for the modification of the User Order detail window UI */
340
-
341
-
342
-
343
- .wcf-ca-tags {
344
- list-style: none;
345
- margin: 0;
346
- overflow: hidden;
347
- padding: 0;
348
- }
349
-
350
- .wcf-ca-tags li {
351
- float: right;
352
- }
353
-
354
- .wcf-ca-tag {
355
- background-color: #f16334;
356
- border-radius: 0 3px 3px 0;
357
- color: #fff;
358
- display: inline-block;
359
- height: 26px;
360
- line-height: 26px;
361
- padding: 0 23px 0 20px;
362
- position: relative;
363
- margin: 0 0 0px 5px;
364
- text-decoration: none;
365
- -webkit-transition: color 0.2s;
366
- }
367
-
368
- .wcf-ca-tag::before {
369
- background: #fff;
370
- border-radius: 10px;
371
- box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
372
- content: '';
373
- height: 6px;
374
- right: 10px;
375
- position: absolute;
376
- width: 6px;
377
- top: 10px;
378
- }
379
-
380
- .wcf-ca-tag::after {
381
- background: #fff;
382
- border-bottom: 13px solid transparent;
383
- border-right: 10px solid #f16334;;
384
- border-top: 13px solid transparent;
385
- content: '';
386
- position: absolute;
387
- left: 0;
388
- top: 0;
389
- }
390
-
391
- .wcf-ca-tag:hover {
392
- background-color: #f16334;
393
- color: white;
394
- }
395
-
396
- .wcf-ca-tag:hover::after {
397
- border-right-color: #f16334;
398
  }
1
+
2
+ .wcf-ca-ibox {
3
+ clear: both;
4
+ margin-bottom: 25px;
5
+ margin-top: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ .wcf-ca-ibox-title {
10
+ background-color: white;
11
+ border-image: none;
12
+ border-width: 3px 0px 0;
13
+ color: inherit;
14
+ margin-bottom: 0;
15
+ padding: 14px 15px 7px;
16
+ min-height: 48px;
17
+ }
18
+
19
+ .wcf-ca-ibox-content {
20
+ background-color: white;
21
+ color: inherit;
22
+ padding: 15px 20px 20px 20px;
23
+ border-color: #d7dadc;
24
+ border-image: none;
25
+ border-style: solid solid none;
26
+ border-width: 1px 0px;
27
+ }
28
+
29
+ .wcf-ca-raw {
30
+ margin-right: -15px;
31
+ margin-left: -15px;
32
+ }
33
+
34
+ .wcf-ca-grid-container {
35
+ display: grid;
36
+ grid-template-columns: 1fr 1fr 1fr;
37
+ grid-gap: 20px;
38
+ }
39
+
40
+ .grid-container > div {
41
+ background-color: rgba(255, 255, 255, 0.8);
42
+ text-align: center;
43
+ padding: 20px 0;
44
+ font-size: 30px;
45
+ }
46
+
47
+
48
+ .wcf-ca-center-msg {
49
+ margin: auto;
50
+ width: 50%;
51
+ padding: 10px;
52
+ margin-top: 20px;
53
+ text-align: center;
54
+ }
55
+
56
+
57
+ .wcf-ca-switch {
58
+ cursor: pointer;
59
+ text-indent: -999em;
60
+ display: block;
61
+ width: 38px;
62
+ height: 22px;
63
+ border-radius: 30px;
64
+ border: none;
65
+ position: relative;
66
+ box-sizing: border-box;
67
+ -webkit-transition: all .3s ease;
68
+ transition: all .3s ease;
69
+ box-shadow: inset 0 0 0 0 transparent;
70
+ }
71
+ .wcf-ca-switch:focus {
72
+ outline: none;
73
+ }
74
+ .wcf-ca-switch:before {
75
+ border-radius: 50%;
76
+ background: #ffffff;
77
+ content: '';
78
+ position: absolute;
79
+ display: block;
80
+ width: 18px;
81
+ height: 18px;
82
+ top: 2px;
83
+ right: 2px;
84
+ -webkit-transition: all .15s ease;
85
+ transition: all .15s ease;
86
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
87
+ }
88
+ .wcf-ca-switch[wcf-ca-template-switch="on"] {
89
+ box-shadow: inset 0 0 0 11px #008000;
90
+ }
91
+ .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
92
+ -webkit-transform: translateX(-16px);
93
+ transform: translateX(-16px);
94
+ }
95
+ .wcf-ca-switch[wcf-ca-template-switch="off"] {
96
+ background: #ccc;
97
+ }
98
+ .wcf-ca-switch.wcap-loading {
99
+ cursor: default;
100
+ opacity: 0.5;
101
+ }
102
+
103
+ .wcf-ca-trigger-input{
104
+ height: 28px;
105
+ width: 40%;
106
+ margin-left: 10px;
107
+ }
108
+
109
+ .wcf-ca-report-btn {
110
+ padding: 15px 0px 15px 0px;
111
+ display: table;
112
+ width: 100%;
113
+ }
114
+
115
+ .wcf-ca-email-inputs {
116
+ width: 25%;
117
+ }
118
+
119
+ .wcf-ca-coupon-inputs {
120
+ width: 10%;
121
+ vertical-align: middle;
122
+ }
123
+
124
+ .wcf-ca-filter-input{
125
+ height: 28px;
126
+ width: 7em;
127
+ margin: 0;
128
+ text-align: center;
129
+ }
130
+
131
+ .wcf-ca-left-report-field-group {
132
+ display: table-cell; text-align: right;
133
+ }
134
+ .wcf-ca-right-report-field-group {
135
+ display: table-cell; text-align: left;
136
+ }
137
+ .wcf-ca-report-table-row {
138
+ color: #636363;
139
+ border: 1px solid #e5e5e5;
140
+ }
141
+
142
+ /* Newly Added for the modification of the User Order detail window UI */
143
+
144
+ /* Column Classes */
145
+
146
+ .wcf-ca-column-one{
147
+ width: 100%;
148
+ }
149
+
150
+ .wcf-ca-column-two,
151
+ .wcf-ca-user-address{
152
+ width: 50%;
153
+ }
154
+
155
+ .wcf-pull-left{
156
+ float: right;
157
+ }
158
+ .wcf-ca-email-data,
159
+ .wcf-ca-user-detail{
160
+ border-radius: 3px;
161
+ padding: 20px 25px;
162
+ min-height: 330px;
163
+ max-height: 420px;
164
+ width: 100%;
165
+ overflow: auto;
166
+ }
167
+
168
+ .wcf-ca-user-detail{
169
+ max-height: 100%;
170
+ }
171
+
172
+ .wcf-ca-user-order{
173
+ border-radius: 3px;
174
+ padding: 25px 25px 30px 25px;
175
+ overflow: hidden;
176
+ height: auto;
177
+ width: 100%;
178
+ }
179
+
180
+ /* Column Classes */
181
+
182
+ /* Section classes */
183
+
184
+ .wcf-ca-margin-right{
185
+ margin-left: 13px;
186
+ }
187
+ .wcf-ca-margin-left{
188
+ margin-right: 13px;
189
+ }
190
+
191
+ .wcf-ca-column{
192
+ background-color: #fff;
193
+ border-radius: 3px;
194
+ display: flex;
195
+ }
196
+
197
+ /* Section Classes */
198
+
199
+
200
+ .wcf-ca-right-report-field-group .back-button{
201
+ height: auto;
202
+ padding: 3px 5px 3px 10px;
203
+ }
204
+
205
+ .wcf-ca-left-report-field-group .back-button .dashicons{
206
+ vertical-align: middle;
207
+ }
208
+
209
+ .wcf-ca-panel{
210
+ cursor: default;
211
+ /*background-color: #fff;*/
212
+ border-radius: 5px;
213
+ display: flex;
214
+ padding: 0px;
215
+ margin: 10px 0 25px;
216
+ }
217
+
218
+ .wcf-table{
219
+ border: none;
220
+ text-align: right;
221
+ width: 100%;
222
+ }
223
+ .wcf-table tr,
224
+ .wcf-table tr th,
225
+ .wcf-table tr td{
226
+ border: none;
227
+ }
228
+
229
+ .wcf-table tr th a,
230
+ .wcf-table tr td a{
231
+ text-decoration: none;
232
+ cursor: pointer;
233
+ }
234
+
235
+ .wcf-table tr th{
236
+ vertical-align: bottom;
237
+ border-bottom: 2px solid #ddd;
238
+ }
239
+
240
+ .wcf-table tr td{
241
+ border-bottom: 1px solid #ddd;
242
+ line-height: 1.42857143;
243
+ vertical-align: top;
244
+ position: relative;
245
+ }
246
+
247
+ .wcf-ca-panel h2{
248
+ margin: 0;
249
+ font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
250
+ font-size: 21px;
251
+ font-weight: 400;
252
+ line-height: 1.2;
253
+ text-shadow: -1px 1px 1px #fff;
254
+ padding: 10px 0 15px;
255
+ margin: 0;
256
+ }
257
+
258
+ .wcf-ca-user-order table{
259
+ width: 100%;
260
+ }
261
+
262
+ .wcf-ca-user-order table thead th{
263
+ text-align: center;
264
+ padding: 1em 3em;
265
+ font-weight: 400;
266
+ color: #999;
267
+ /*background: #f8f8f8;*/
268
+ -webkit-touch-callout: none;
269
+ -webkit-user-select: none;
270
+ -moz-user-select: none;
271
+ -ms-user-select: none;
272
+ user-select: none;
273
+ }
274
+
275
+ .wcf-ca-user-order table thead th:first-of-type{
276
+ padding-right: 3.6em;
277
+ text-align: right;
278
+ }
279
+
280
+ .wcf-ca-user-order table tbody tr td {
281
+ text-align: center;
282
+ padding: 1em 3em;
283
+ vertical-align: middle;
284
+ }
285
+
286
+ .wcf-ca-user-order table tbody tr td:first-of-type{
287
+ text-align: right;
288
+ /*width: 38px;*/
289
+ padding-right: 3em;
290
+ }
291
+
292
+
293
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
294
+ .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
295
+ .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
296
+ .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
297
+ text-align: left;
298
+ font-weight: 600;
299
+ width: 82%;
300
+ }
301
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
302
+ border-top: 1px solid #ccc;
303
+ }
304
+
305
+ .wcf-ca-tooltip-text.display_tool_tip{
306
+ display: block;
307
+ }
308
+
309
+ .wcf-ca-tooltip-text::before {
310
+ border-right: 5px solid transparent;
311
+ border-left: 5px solid transparent;
312
+ border-top: 5px solid transparent;
313
+ border-bottom: 5px solid #444;
314
+ bottom: auto;
315
+ content: " ";
316
+ font-size: 0;
317
+ right: 25px;
318
+ line-height: 0;
319
+ margin-right: -5px;
320
+ position: absolute;
321
+ top: -10px;
322
+ width: 0;
323
+ }
324
+
325
+ .wcf-ca-tooltip-text {
326
+ background: #444;
327
+ border-radius: 3px;
328
+ color: #fff;
329
+ height: auto;
330
+ right: 0;
331
+ margin-top: 10px;
332
+ max-width: 150px;
333
+ position: absolute;
334
+ padding: 6px 10px;
335
+ width: 100%;
336
+ display: none;
337
+ z-index: 10000;
338
+ }
339
+ /* Newly Added for the modification of the User Order detail window UI */
340
+
341
+
342
+
343
+ .wcf-ca-tags {
344
+ list-style: none;
345
+ margin: 0;
346
+ overflow: hidden;
347
+ padding: 0;
348
+ }
349
+
350
+ .wcf-ca-tags li {
351
+ float: right;
352
+ }
353
+
354
+ .wcf-ca-tag {
355
+ background-color: #f16334;
356
+ border-radius: 0 3px 3px 0;
357
+ color: #fff;
358
+ display: inline-block;
359
+ height: 26px;
360
+ line-height: 26px;
361
+ padding: 0 23px 0 20px;
362
+ position: relative;
363
+ margin: 0 0 0px 5px;
364
+ text-decoration: none;
365
+ -webkit-transition: color 0.2s;
366
+ }
367
+
368
+ .wcf-ca-tag::before {
369
+ background: #fff;
370
+ border-radius: 10px;
371
+ box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
372
+ content: '';
373
+ height: 6px;
374
+ right: 10px;
375
+ position: absolute;
376
+ width: 6px;
377
+ top: 10px;
378
+ }
379
+
380
+ .wcf-ca-tag::after {
381
+ background: #fff;
382
+ border-bottom: 13px solid transparent;
383
+ border-right: 10px solid #f16334;;
384
+ border-top: 13px solid transparent;
385
+ content: '';
386
+ position: absolute;
387
+ left: 0;
388
+ top: 0;
389
+ }
390
+
391
+ .wcf-ca-tag:hover {
392
+ background-color: #f16334;
393
+ color: white;
394
+ }
395
+
396
+ .wcf-ca-tag:hover::after {
397
+ border-right-color: #f16334;
398
  }
admin/assets/css/admin-cart-abandonment.css CHANGED
@@ -1,398 +1,398 @@
1
-
2
- .wcf-ca-ibox {
3
- clear: both;
4
- margin-bottom: 25px;
5
- margin-top: 0;
6
- padding: 0;
7
- }
8
-
9
- .wcf-ca-ibox-title {
10
- background-color: white;
11
- border-image: none;
12
- border-width: 3px 0px 0;
13
- color: inherit;
14
- margin-bottom: 0;
15
- padding: 14px 15px 7px;
16
- min-height: 48px;
17
- }
18
-
19
- .wcf-ca-ibox-content {
20
- background-color: white;
21
- color: inherit;
22
- padding: 15px 20px 20px 20px;
23
- border-color: #d7dadc;
24
- border-image: none;
25
- border-style: solid solid none;
26
- border-width: 1px 0px;
27
- }
28
-
29
- .wcf-ca-raw {
30
- margin-left: -15px;
31
- margin-right: -15px;
32
- }
33
-
34
- .wcf-ca-grid-container {
35
- display: grid;
36
- grid-template-columns: 1fr 1fr 1fr;
37
- grid-gap: 20px;
38
- }
39
-
40
- .grid-container > div {
41
- background-color: rgba(255, 255, 255, 0.8);
42
- text-align: center;
43
- padding: 20px 0;
44
- font-size: 30px;
45
- }
46
-
47
-
48
- .wcf-ca-center-msg {
49
- margin: auto;
50
- width: 50%;
51
- padding: 10px;
52
- margin-top: 20px;
53
- text-align: center;
54
- }
55
-
56
-
57
- .wcf-ca-switch {
58
- cursor: pointer;
59
- text-indent: -999em;
60
- display: block;
61
- width: 38px;
62
- height: 22px;
63
- border-radius: 30px;
64
- border: none;
65
- position: relative;
66
- box-sizing: border-box;
67
- -webkit-transition: all .3s ease;
68
- transition: all .3s ease;
69
- box-shadow: inset 0 0 0 0 transparent;
70
- }
71
- .wcf-ca-switch:focus {
72
- outline: none;
73
- }
74
- .wcf-ca-switch:before {
75
- border-radius: 50%;
76
- background: #ffffff;
77
- content: '';
78
- position: absolute;
79
- display: block;
80
- width: 18px;
81
- height: 18px;
82
- top: 2px;
83
- left: 2px;
84
- -webkit-transition: all .15s ease;
85
- transition: all .15s ease;
86
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
87
- }
88
- .wcf-ca-switch[wcf-ca-template-switch="on"] {
89
- box-shadow: inset 0 0 0 11px #008000;
90
- }
91
- .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
92
- -webkit-transform: translateX(16px);
93
- transform: translateX(16px);
94
- }
95
- .wcf-ca-switch[wcf-ca-template-switch="off"] {
96
- background: #ccc;
97
- }
98
- .wcf-ca-switch.wcap-loading {
99
- cursor: default;
100
- opacity: 0.5;
101
- }
102
-
103
- .wcf-ca-trigger-input{
104
- height: 28px;
105
- width: 40%;
106
- margin-right: 10px;
107
- }
108
-
109
- .wcf-ca-report-btn {
110
- padding: 15px 0px 15px 0px;
111
- display: table;
112
- width: 100%;
113
- }
114
-
115
- .wcf-ca-email-inputs {
116
- width: 25%;
117
- }
118
-
119
- .wcf-ca-coupon-inputs {
120
- width: 10%;
121
- vertical-align: middle;
122
- }
123
-
124
- .wcf-ca-filter-input{
125
- height: 28px;
126
- width: 7em;
127
- margin: 0;
128
- text-align: center;
129
- }
130
-
131
- .wcf-ca-left-report-field-group {
132
- display: table-cell; text-align: left;
133
- }
134
- .wcf-ca-right-report-field-group {
135
- display: table-cell; text-align: right;
136
- }
137
- .wcf-ca-report-table-row {
138
- color: #636363;
139
- border: 1px solid #e5e5e5;
140
- }
141
-
142
- /* Newly Added for the modification of the User Order detail window UI */
143
-
144
- /* Column Classes */
145
-
146
- .wcf-ca-column-one{
147
- width: 100%;
148
- }
149
-
150
- .wcf-ca-column-two,
151
- .wcf-ca-user-address{
152
- width: 50%;
153
- }
154
-
155
- .wcf-pull-left{
156
- float: left;
157
- }
158
- .wcf-ca-email-data,
159
- .wcf-ca-user-detail{
160
- border-radius: 3px;
161
- padding: 20px 25px;
162
- min-height: 330px;
163
- max-height: 420px;
164
- width: 100%;
165
- overflow: auto;
166
- }
167
-
168
- .wcf-ca-user-detail{
169
- max-height: 100%;
170
- }
171
-
172
- .wcf-ca-user-order{
173
- border-radius: 3px;
174
- padding: 25px 25px 30px 25px;
175
- overflow: hidden;
176
- height: auto;
177
- width: 100%;
178
- }
179
-
180
- /* Column Classes */
181
-
182
- /* Section classes */
183
-
184
- .wcf-ca-margin-right{
185
- margin-right: 13px;
186
- }
187
- .wcf-ca-margin-left{
188
- margin-left: 13px;
189
- }
190
-
191
- .wcf-ca-column{
192
- background-color: #fff;
193
- border-radius: 3px;
194
- display: flex;
195
- }
196
-
197
- /* Section Classes */
198
-
199
-
200
- .wcf-ca-right-report-field-group .back-button{
201
- height: auto;
202
- padding: 3px 10px 3px 5px;
203
- }
204
-
205
- .wcf-ca-left-report-field-group .back-button .dashicons{
206
- vertical-align: middle;
207
- }
208
-
209
- .wcf-ca-panel{
210
- cursor: default;
211
- /*background-color: #fff;*/
212
- border-radius: 5px;
213
- display: flex;
214
- padding: 0px;
215
- margin: 10px 0 25px;
216
- }
217
-
218
- .wcf-table{
219
- border: none;
220
- text-align: left;
221
- width: 100%;
222
- }
223
- .wcf-table tr,
224
- .wcf-table tr th,
225
- .wcf-table tr td{
226
- border: none;
227
- }
228
-
229
- .wcf-table tr th a,
230
- .wcf-table tr td a{
231
- text-decoration: none;
232
- cursor: pointer;
233
- }
234
-
235
- .wcf-table tr th{
236
- vertical-align: bottom;
237
- border-bottom: 2px solid #ddd;
238
- }
239
-
240
- .wcf-table tr td{
241
- border-bottom: 1px solid #ddd;
242
- line-height: 1.42857143;
243
- vertical-align: top;
244
- position: relative;
245
- }
246
-
247
- .wcf-ca-panel h2{
248
- margin: 0;
249
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
250
- font-size: 21px;
251
- font-weight: 400;
252
- line-height: 1.2;
253
- text-shadow: 1px 1px 1px #fff;
254
- padding: 10px 0 15px;
255
- margin: 0;
256
- }
257
-
258
- .wcf-ca-user-order table{
259
- width: 100%;
260
- }
261
-
262
- .wcf-ca-user-order table thead th{
263
- text-align: center;
264
- padding: 1em 3em;
265
- font-weight: 400;
266
- color: #999;
267
- /*background: #f8f8f8;*/
268
- -webkit-touch-callout: none;
269
- -webkit-user-select: none;
270
- -moz-user-select: none;
271
- -ms-user-select: none;
272
- user-select: none;
273
- }
274
-
275
- .wcf-ca-user-order table thead th:first-of-type{
276
- padding-left: 3.6em;
277
- text-align: left;
278
- }
279
-
280
- .wcf-ca-user-order table tbody tr td {
281
- text-align: center;
282
- padding: 1em 3em;
283
- vertical-align: middle;
284
- }
285
-
286
- .wcf-ca-user-order table tbody tr td:first-of-type{
287
- text-align: left;
288
- /*width: 38px;*/
289
- padding-left: 3em;
290
- }
291
-
292
-
293
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
294
- .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
295
- .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
296
- .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
297
- text-align: right;
298
- font-weight: 600;
299
- width: 82%;
300
- }
301
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
302
- border-top: 1px solid #ccc;
303
- }
304
-
305
- .wcf-ca-tooltip-text.display_tool_tip{
306
- display: block;
307
- }
308
-
309
- .wcf-ca-tooltip-text::before {
310
- border-left: 5px solid transparent;
311
- border-right: 5px solid transparent;
312
- border-top: 5px solid transparent;
313
- border-bottom: 5px solid #444;
314
- bottom: auto;
315
- content: " ";
316
- font-size: 0;
317
- left: 25px;
318
- line-height: 0;
319
- margin-left: -5px;
320
- position: absolute;
321
- top: -10px;
322
- width: 0;
323
- }
324
-
325
- .wcf-ca-tooltip-text {
326
- background: #444;
327
- border-radius: 3px;
328
- color: #fff;
329
- height: auto;
330
- left: 0;
331
- margin-top: 10px;
332
- max-width: 150px;
333
- position: absolute;
334
- padding: 6px 10px;
335
- width: 100%;
336
- display: none;
337
- z-index: 10000;
338
- }
339
- /* Newly Added for the modification of the User Order detail window UI */
340
-
341
-
342
-
343
- .wcf-ca-tags {
344
- list-style: none;
345
- margin: 0;
346
- overflow: hidden;
347
- padding: 0;
348
- }
349
-
350
- .wcf-ca-tags li {
351
- float: left;
352
- }
353
-
354
- .wcf-ca-tag {
355
- background-color: #f16334;
356
- border-radius: 3px 0 0 3px;
357
- color: #fff;
358
- display: inline-block;
359
- height: 26px;
360
- line-height: 26px;
361
- padding: 0 20px 0 23px;
362
- position: relative;
363
- margin: 0 5px 0px 0;
364
- text-decoration: none;
365
- -webkit-transition: color 0.2s;
366
- }
367
-
368
- .wcf-ca-tag::before {
369
- background: #fff;
370
- border-radius: 10px;
371
- box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
372
- content: '';
373
- height: 6px;
374
- left: 10px;
375
- position: absolute;
376
- width: 6px;
377
- top: 10px;
378
- }
379
-
380
- .wcf-ca-tag::after {
381
- background: #fff;
382
- border-bottom: 13px solid transparent;
383
- border-left: 10px solid #f16334;;
384
- border-top: 13px solid transparent;
385
- content: '';
386
- position: absolute;
387
- right: 0;
388
- top: 0;
389
- }
390
-
391
- .wcf-ca-tag:hover {
392
- background-color: #f16334;
393
- color: white;
394
- }
395
-
396
- .wcf-ca-tag:hover::after {
397
- border-left-color: #f16334;
398
  }
1
+
2
+ .wcf-ca-ibox {
3
+ clear: both;
4
+ margin-bottom: 25px;
5
+ margin-top: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ .wcf-ca-ibox-title {
10
+ background-color: white;
11
+ border-image: none;
12
+ border-width: 3px 0px 0;
13
+ color: inherit;
14
+ margin-bottom: 0;
15
+ padding: 14px 15px 7px;
16
+ min-height: 48px;
17
+ }
18
+
19
+ .wcf-ca-ibox-content {
20
+ background-color: white;
21
+ color: inherit;
22
+ padding: 15px 20px 20px 20px;
23
+ border-color: #d7dadc;
24
+ border-image: none;
25
+ border-style: solid solid none;
26
+ border-width: 1px 0px;
27
+ }
28
+
29
+ .wcf-ca-raw {
30
+ margin-left: -15px;
31
+ margin-right: -15px;
32
+ }
33
+
34
+ .wcf-ca-grid-container {
35
+ display: grid;
36
+ grid-template-columns: 1fr 1fr 1fr;
37
+ grid-gap: 20px;
38
+ }
39
+
40
+ .grid-container > div {
41
+ background-color: rgba(255, 255, 255, 0.8);
42
+ text-align: center;
43
+ padding: 20px 0;
44
+ font-size: 30px;
45
+ }
46
+
47
+
48
+ .wcf-ca-center-msg {
49
+ margin: auto;
50
+ width: 50%;
51
+ padding: 10px;
52
+ margin-top: 20px;
53
+ text-align: center;
54
+ }
55
+
56
+
57
+ .wcf-ca-switch {
58
+ cursor: pointer;
59
+ text-indent: -999em;
60
+ display: block;
61
+ width: 38px;
62
+ height: 22px;
63
+ border-radius: 30px;
64
+ border: none;
65
+ position: relative;
66
+ box-sizing: border-box;
67
+ -webkit-transition: all .3s ease;
68
+ transition: all .3s ease;
69
+ box-shadow: inset 0 0 0 0 transparent;
70
+ }
71
+ .wcf-ca-switch:focus {
72
+ outline: none;
73
+ }
74
+ .wcf-ca-switch:before {
75
+ border-radius: 50%;
76
+ background: #ffffff;
77
+ content: '';
78
+ position: absolute;
79
+ display: block;
80
+ width: 18px;
81
+ height: 18px;
82
+ top: 2px;
83
+ left: 2px;
84
+ -webkit-transition: all .15s ease;
85
+ transition: all .15s ease;
86
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
87
+ }
88
+ .wcf-ca-switch[wcf-ca-template-switch="on"] {
89
+ box-shadow: inset 0 0 0 11px #008000;
90
+ }
91
+ .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
92
+ -webkit-transform: translateX(16px);
93
+ transform: translateX(16px);
94
+ }
95
+ .wcf-ca-switch[wcf-ca-template-switch="off"] {
96
+ background: #ccc;
97
+ }
98
+ .wcf-ca-switch.wcap-loading {
99
+ cursor: default;
100
+ opacity: 0.5;
101
+ }
102
+
103
+ .wcf-ca-trigger-input{
104
+ height: 28px;
105
+ width: 40%;
106
+ margin-right: 10px;
107
+ }
108
+
109
+ .wcf-ca-report-btn {
110
+ padding: 15px 0px 15px 0px;
111
+ display: table;
112
+ width: 100%;
113
+ }
114
+
115
+ .wcf-ca-email-inputs {
116
+ width: 25%;
117
+ }
118
+
119
+ .wcf-ca-coupon-inputs {
120
+ width: 10%;
121
+ vertical-align: middle;
122
+ }
123
+
124
+ .wcf-ca-filter-input{
125
+ height: 28px;
126
+ width: 7em;
127
+ margin: 0;
128
+ text-align: center;
129
+ }
130
+
131
+ .wcf-ca-left-report-field-group {
132
+ display: table-cell; text-align: left;
133
+ }
134
+ .wcf-ca-right-report-field-group {
135
+ display: table-cell; text-align: right;
136
+ }
137
+ .wcf-ca-report-table-row {
138
+ color: #636363;
139
+ border: 1px solid #e5e5e5;
140
+ }
141
+
142
+ /* Newly Added for the modification of the User Order detail window UI */
143
+
144
+ /* Column Classes */
145
+
146
+ .wcf-ca-column-one{
147
+ width: 100%;
148
+ }
149
+
150
+ .wcf-ca-column-two,
151
+ .wcf-ca-user-address{
152
+ width: 50%;
153
+ }
154
+
155
+ .wcf-pull-left{
156
+ float: left;
157
+ }
158
+ .wcf-ca-email-data,
159
+ .wcf-ca-user-detail{
160
+ border-radius: 3px;
161
+ padding: 20px 25px;
162
+ min-height: 330px;
163
+ max-height: 420px;
164
+ width: 100%;
165
+ overflow: auto;
166
+ }
167
+
168
+ .wcf-ca-user-detail{
169
+ max-height: 100%;
170
+ }
171
+
172
+ .wcf-ca-user-order{
173
+ border-radius: 3px;
174
+ padding: 25px 25px 30px 25px;
175
+ overflow: hidden;
176
+ height: auto;
177
+ width: 100%;
178
+ }
179
+
180
+ /* Column Classes */
181
+
182
+ /* Section classes */
183
+
184
+ .wcf-ca-margin-right{
185
+ margin-right: 13px;
186
+ }
187
+ .wcf-ca-margin-left{
188
+ margin-left: 13px;
189
+ }
190
+
191
+ .wcf-ca-column{
192
+ background-color: #fff;
193
+ border-radius: 3px;
194
+ display: flex;
195
+ }
196
+
197
+ /* Section Classes */
198
+
199
+
200
+ .wcf-ca-right-report-field-group .back-button{
201
+ height: auto;
202
+ padding: 3px 10px 3px 5px;
203
+ }
204
+
205
+ .wcf-ca-left-report-field-group .back-button .dashicons{
206
+ vertical-align: middle;
207
+ }
208
+
209
+ .wcf-ca-panel{
210
+ cursor: default;
211
+ /*background-color: #fff;*/
212
+ border-radius: 5px;
213
+ display: flex;
214
+ padding: 0px;
215
+ margin: 10px 0 25px;
216
+ }
217
+
218
+ .wcf-table{
219
+ border: none;
220
+ text-align: left;
221
+ width: 100%;
222
+ }
223
+ .wcf-table tr,
224
+ .wcf-table tr th,
225
+ .wcf-table tr td{
226
+ border: none;
227
+ }
228
+
229
+ .wcf-table tr th a,
230
+ .wcf-table tr td a{
231
+ text-decoration: none;
232
+ cursor: pointer;
233
+ }
234
+
235
+ .wcf-table tr th{
236
+ vertical-align: bottom;
237
+ border-bottom: 2px solid #ddd;
238
+ }
239
+
240
+ .wcf-table tr td{
241
+ border-bottom: 1px solid #ddd;
242
+ line-height: 1.42857143;
243
+ vertical-align: top;
244
+ position: relative;
245
+ }
246
+
247
+ .wcf-ca-panel h2{
248
+ margin: 0;
249
+ font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
250
+ font-size: 21px;
251
+ font-weight: 400;
252
+ line-height: 1.2;
253
+ text-shadow: 1px 1px 1px #fff;
254
+ padding: 10px 0 15px;
255
+ margin: 0;
256
+ }
257
+
258
+ .wcf-ca-user-order table{
259
+ width: 100%;
260
+ }
261
+
262
+ .wcf-ca-user-order table thead th{
263
+ text-align: center;
264
+ padding: 1em 3em;
265
+ font-weight: 400;
266
+ color: #999;
267
+ /*background: #f8f8f8;*/
268
+ -webkit-touch-callout: none;
269
+ -webkit-user-select: none;
270
+ -moz-user-select: none;
271
+ -ms-user-select: none;
272
+ user-select: none;
273
+ }
274
+
275
+ .wcf-ca-user-order table thead th:first-of-type{
276
+ padding-left: 3.6em;
277
+ text-align: left;
278
+ }
279
+
280
+ .wcf-ca-user-order table tbody tr td {
281
+ text-align: center;
282
+ padding: 1em 3em;
283
+ vertical-align: middle;
284
+ }
285
+
286
+ .wcf-ca-user-order table tbody tr td:first-of-type{
287
+ text-align: left;
288
+ /*width: 38px;*/
289
+ padding-left: 3em;
290
+ }
291
+
292
+
293
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
294
+ .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
295
+ .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
296
+ .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
297
+ text-align: right;
298
+ font-weight: 600;
299
+ width: 82%;
300
+ }
301
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
302
+ border-top: 1px solid #ccc;
303
+ }
304
+
305
+ .wcf-ca-tooltip-text.display_tool_tip{
306
+ display: block;
307
+ }
308
+
309
+ .wcf-ca-tooltip-text::before {
310
+ border-left: 5px solid transparent;
311
+ border-right: 5px solid transparent;
312
+ border-top: 5px solid transparent;
313
+ border-bottom: 5px solid #444;
314
+ bottom: auto;
315
+ content: " ";
316
+ font-size: 0;
317
+ left: 25px;
318
+ line-height: 0;
319
+ margin-left: -5px;
320
+ position: absolute;
321
+ top: -10px;
322
+ width: 0;
323
+ }
324
+
325
+ .wcf-ca-tooltip-text {
326
+ background: #444;
327
+ border-radius: 3px;
328
+ color: #fff;
329
+ height: auto;
330
+ left: 0;
331
+ margin-top: 10px;
332
+ max-width: 150px;
333
+ position: absolute;
334
+ padding: 6px 10px;
335
+ width: 100%;
336
+ display: none;
337
+ z-index: 10000;
338
+ }
339
+ /* Newly Added for the modification of the User Order detail window UI */
340
+
341
+
342
+
343
+ .wcf-ca-tags {
344
+ list-style: none;
345
+ margin: 0;
346
+ overflow: hidden;
347
+ padding: 0;
348
+ }
349
+
350
+ .wcf-ca-tags li {
351
+ float: left;
352
+ }
353
+
354
+ .wcf-ca-tag {
355
+ background-color: #f16334;
356
+ border-radius: 3px 0 0 3px;
357
+ color: #fff;
358
+ display: inline-block;
359
+ height: 26px;
360
+ line-height: 26px;
361
+ padding: 0 20px 0 23px;
362
+ position: relative;
363
+ margin: 0 5px 0px 0;
364
+ text-decoration: none;
365
+ -webkit-transition: color 0.2s;
366
+ }
367
+
368
+ .wcf-ca-tag::before {
369
+ background: #fff;
370
+ border-radius: 10px;
371
+ box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
372
+ content: '';
373
+ height: 6px;
374
+ left: 10px;
375
+ position: absolute;
376
+ width: 6px;
377
+ top: 10px;
378
+ }
379
+
380
+ .wcf-ca-tag::after {
381
+ background: #fff;
382
+ border-bottom: 13px solid transparent;
383
+ border-left: 10px solid #f16334;;
384
+ border-top: 13px solid transparent;
385
+ content: '';
386
+ position: absolute;
387
+ right: 0;
388
+ top: 0;
389
+ }
390
+
391
+ .wcf-ca-tag:hover {
392
+ background-color: #f16334;
393
+ color: white;
394
+ }
395
+
396
+ .wcf-ca-tag:hover::after {
397
+ border-left-color: #f16334;
398
  }
admin/assets/js/admin-email-templates.js CHANGED
@@ -1,257 +1,257 @@
1
- (function ($) {
2
-
3
- CartAbandonmentSettings = {
4
-
5
- init: function () {
6
-
7
- $("#wcf_ca_custom_filter_from").datepicker({
8
- dateFormat: 'yy-mm-dd',
9
- maxDate: '0',
10
- onClose: function( selectedDate ) {
11
- jQuery( "#wcf_ca_custom_filter_to" ).datepicker( "option", "minDate", selectedDate );
12
- }
13
- }).attr('readonly','readonly').css('background', 'white');
14
-
15
- $("#wcf_ca_custom_filter_to").datepicker({
16
- dateFormat: 'yy-mm-dd',
17
- maxDate: '0',
18
- onClose: function( selectedDate ) {
19
- jQuery( "#wcf_ca_custom_filter_from" ).datepicker( "option", "maxDate", selectedDate );
20
- }
21
- }).attr('readonly','readonly').css('background', 'white');
22
-
23
- $("#wcf_ca_custom_filter").click(function () {
24
- var from = $("#wcf_ca_custom_filter_from").val().trim();
25
- var to = $("#wcf_ca_custom_filter_to").val().trim();
26
- var url = window.location.search;
27
- url = url + "&from_date=" + from + "&to_date=" + to + "&filter=custom";
28
- window.location.href = url;
29
-
30
- });
31
-
32
- // Hide initially.
33
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry, #wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status, #wcf_ca_gdpr_message").closest('tr').hide();
34
-
35
-
36
- if( $("#wcf_ca_gdpr_status:checked").length ) {
37
- $("#wcf_ca_gdpr_message").closest('tr').show();
38
- }
39
-
40
- if ($("#wcf_ca_zapier_tracking_status:checked").length) {
41
- $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').show();
42
- }
43
-
44
- if ( $("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length ) {
45
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').show();
46
- }
47
-
48
- $("#wcf_ca_coupon_code_status").click(
49
- function () {
50
- if (!$("#wcf_ca_coupon_code_status:checked").length) {
51
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
52
- } else {
53
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
54
- }
55
- }
56
- );
57
-
58
- $("#wcf_ca_gdpr_status").click(
59
- function () {
60
- if (!$("#wcf_ca_gdpr_status:checked").length) {
61
- $("#wcf_ca_gdpr_message").closest('tr').fadeOut();
62
- } else {
63
- $("#wcf_ca_gdpr_message").closest('tr').fadeIn();
64
- }
65
- }
66
- );
67
-
68
- $("#wcf_ca_zapier_tracking_status").click(
69
- function () {
70
- if (!$("#wcf_ca_zapier_tracking_status:checked").length) {
71
- $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeOut();
72
- } else {
73
- $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeIn();
74
- }
75
-
76
- if ($("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length) {
77
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
78
- } else {
79
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
80
- }
81
- }
82
- );
83
-
84
- }
85
- }
86
-
87
- EmailTemplatesAdmin = {
88
-
89
- init: function () {
90
-
91
- $(document).on('click', '#wcf_preview_email', EmailTemplatesAdmin.send_test_email);
92
- $(document).on('click', '.wcf-ca-switch.wcf-toggle-template-status', EmailTemplatesAdmin.toggle_activate_template);
93
-
94
- $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').hide();
95
- if ( $("#wcf_override_global_coupon").is(":checked")) {
96
- $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').show();
97
- }
98
-
99
- $(document).on('click', '#wcf_override_global_coupon', EmailTemplatesAdmin.toggle_coupon_fileds);
100
-
101
- },
102
-
103
- toggle_coupon_fileds: function() {
104
-
105
- if ( $("#wcf_override_global_coupon").is(":checked")) {
106
- $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').fadeIn();
107
- } else {
108
- $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').fadeOut();
109
- }
110
-
111
- },
112
-
113
- send_test_email: function () {
114
-
115
- var email_body = '';
116
- if (jQuery("#wp-wcf_email_body-wrap").hasClass("tmce-active")) {
117
- email_body = tinyMCE.get('wcf_email_body').getContent();
118
- } else {
119
- email_body = jQuery('#wcf_email_body').val();
120
- }
121
-
122
- var email_subject = $('#wcf_email_subject').val();
123
- var email_send_to = $('#wcf_send_test_email').val();
124
- var wp_nonce = $("#_wpnonce").val();
125
-
126
- $(this).next('div.error').remove();
127
-
128
- if (!$.trim(email_body)) {
129
- $(this).after('<div class="error-message wcf-ca-error-msg"> Email body is required! </div>');
130
- } else if (!$.trim(email_subject)) {
131
- $(this).after('<div class="error-message wcf-ca-error-msg"> Email subject is required! </div>');
132
- } else if (!$.trim(email_send_to)) {
133
- $(this).after('<div class="error-message wcf-ca-error-msg"> You must add your email id! </div>');
134
- }
135
- else {
136
-
137
- var data = {
138
- email_subject: email_subject,
139
- email_body: email_body,
140
- email_send_to: email_send_to,
141
- action: 'wcf_ca_preview_email_send',
142
- security: wp_nonce
143
- };
144
- $("#wcf_preview_email").css('cursor', 'wait').attr("disabled", true);
145
-
146
- // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
147
- $.post(
148
- ajaxurl, data, function (response) {
149
- $("#mail_response_msg").empty().fadeIn();;
150
-
151
- if (response.success) {
152
- var htmlString = "<strong> Email has been sent successfully! </strong>";
153
- $("#mail_response_msg").css('color','green').html(htmlString).delay(3000).fadeOut();
154
-
155
- } else {
156
- var htmlString = "<strong> Email sending failed! Please check your <a href='"+ CAEmailTemplate.settings_url +"'> email settings! </a></strong>"
157
- $("#mail_response_msg").css('color','red').html(htmlString).delay(3000).fadeOut();;
158
- }
159
- $("#wcf_preview_email").css('cursor', '').attr("disabled", false);
160
-
161
- }
162
- );
163
- }
164
-
165
- $(".wcf-ca-error-msg").delay(2000).fadeOut();
166
- },
167
-
168
- toggle_activate_template: function () {
169
-
170
- var $switch, state, new_state;
171
- $switch = $(this);
172
- state = $switch.attr('wcf-ca-template-switch');
173
- new_state = state === 'on' ? 'off' : 'on';
174
-
175
- $("#wcf_activate_email_template").val(new_state == 'on' ? 1 : 0);
176
- $switch.attr('wcf-ca-template-switch', new_state);
177
- }
178
-
179
- }
180
-
181
- ZapierSettings = {
182
- init: function () {
183
-
184
- $(document).delegate("#wcf_ca_trigger_web_hook_abandoned_btn", "click",
185
- { 'order_status': 'abandoned' },
186
- ZapierSettings.zapier_trigger_sample);
187
- },
188
- zapier_trigger_sample: function( event ) {
189
-
190
- var zapier_webhook_url = $("#wcf_ca_zapier_cart_"+ event.data.order_status +"_webhook").val().trim();
191
-
192
- if ( ! zapier_webhook_url.length ) {
193
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Webhook URL is required.").fadeIn().css('color', '#dc3232').delay(2000).fadeOut();
194
- return;
195
- }
196
-
197
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Triggering...").fadeIn();
198
-
199
- var now = new Date();
200
- var datetime = now.getFullYear()+'/'+(now.getMonth()+1)+'/'+now.getDate();
201
- datetime += ' '+now.getHours()+':'+now.getMinutes()+':'+now.getSeconds();
202
- if ($.trim(zapier_webhook_url) !== "") {
203
- var sample_data = {
204
- "first_name": CartFlowsCADetails.name,
205
- "last_name": CartFlowsCADetails.surname,
206
- "email": CartFlowsCADetails.email,
207
- "order_status": event.data.order_status,
208
- "checkout_url": window.location.origin + "/checkout/?wcf_ac_token=something",
209
- "coupon_code": "abcgefgh",
210
- "product_names": "Product1, Product2 & Product3",
211
- "cart_total": CartFlowsCADetails.woo_currency_symbol + "20"
212
- };
213
- $.ajax({
214
- url: zapier_webhook_url,
215
- type: 'POST',
216
- data: sample_data,
217
- success: function(data) {
218
- if (data.status == "success") {
219
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Success!").css('color', '#46b450');
220
- } else {
221
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
222
- }
223
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").fadeIn().delay(2000).fadeOut();
224
- },
225
- error: function() {
226
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
227
- }
228
- });
229
- } else {
230
- $("wcf_ca"+ event.data.order_status +"_btn_message").text("Please verify webhook URL.").fadeIn().delay(2000).fadeOut();;
231
- }
232
- },
233
- }
234
-
235
- ToolTipHover = {
236
- init: function () {
237
-
238
- $(".wcf-ca-report-table-row .wcf-ca-icon-row").hover(function(){
239
- $(this).find('.wcf-ca-tooltip-text').toggleClass("display_tool_tip");
240
- });
241
- },
242
-
243
-
244
- }
245
-
246
- $(document).ready(
247
- function () {
248
- EmailTemplatesAdmin.init();
249
- CartAbandonmentSettings.init();
250
- ZapierSettings.init();
251
-
252
- ToolTipHover.init();
253
- }
254
- );
255
-
256
-
257
  })(jQuery);
1
+ (function ($) {
2
+
3
+ CartAbandonmentSettings = {
4
+
5
+ init: function () {
6
+
7
+ $("#wcf_ca_custom_filter_from").datepicker({
8
+ dateFormat: 'yy-mm-dd',
9
+ maxDate: '0',
10
+ onClose: function( selectedDate ) {
11
+ jQuery( "#wcf_ca_custom_filter_to" ).datepicker( "option", "minDate", selectedDate );
12
+ }
13
+ }).attr('readonly','readonly').css('background', 'white');
14
+
15
+ $("#wcf_ca_custom_filter_to").datepicker({
16
+ dateFormat: 'yy-mm-dd',
17
+ maxDate: '0',
18
+ onClose: function( selectedDate ) {
19
+ jQuery( "#wcf_ca_custom_filter_from" ).datepicker( "option", "maxDate", selectedDate );
20
+ }
21
+ }).attr('readonly','readonly').css('background', 'white');
22
+
23
+ $("#wcf_ca_custom_filter").click(function () {
24
+ var from = $("#wcf_ca_custom_filter_from").val().trim();
25
+ var to = $("#wcf_ca_custom_filter_to").val().trim();
26
+ var url = window.location.search;
27
+ url = url + "&from_date=" + from + "&to_date=" + to + "&filter=custom";
28
+ window.location.href = url;
29
+
30
+ });
31
+
32
+ // Hide initially.
33
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry, #wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status, #wcf_ca_gdpr_message").closest('tr').hide();
34
+
35
+
36
+ if( $("#wcf_ca_gdpr_status:checked").length ) {
37
+ $("#wcf_ca_gdpr_message").closest('tr').show();
38
+ }
39
+
40
+ if ($("#wcf_ca_zapier_tracking_status:checked").length) {
41
+ $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').show();
42
+ }
43
+
44
+ if ( $("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length ) {
45
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').show();
46
+ }
47
+
48
+ $("#wcf_ca_coupon_code_status").click(
49
+ function () {
50
+ if (!$("#wcf_ca_coupon_code_status:checked").length) {
51
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
52
+ } else {
53
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
54
+ }
55
+ }
56
+ );
57
+
58
+ $("#wcf_ca_gdpr_status").click(
59
+ function () {
60
+ if (!$("#wcf_ca_gdpr_status:checked").length) {
61
+ $("#wcf_ca_gdpr_message").closest('tr').fadeOut();
62
+ } else {
63
+ $("#wcf_ca_gdpr_message").closest('tr').fadeIn();
64
+ }
65
+ }
66
+ );
67
+
68
+ $("#wcf_ca_zapier_tracking_status").click(
69
+ function () {
70
+ if (!$("#wcf_ca_zapier_tracking_status:checked").length) {
71
+ $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeOut();
72
+ } else {
73
+ $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeIn();
74
+ }
75
+
76
+ if ($("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length) {
77
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
78
+ } else {
79
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
80
+ }
81
+ }
82
+ );
83
+
84
+ }
85
+ }
86
+
87
+ EmailTemplatesAdmin = {
88
+
89
+ init: function () {
90
+
91
+ $(document).on('click', '#wcf_preview_email', EmailTemplatesAdmin.send_test_email);
92
+ $(document).on('click', '.wcf-ca-switch.wcf-toggle-template-status', EmailTemplatesAdmin.toggle_activate_template);
93
+
94
+ $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').hide();
95
+ if ( $("#wcf_override_global_coupon").is(":checked")) {
96
+ $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').show();
97
+ }
98
+
99
+ $(document).on('click', '#wcf_override_global_coupon', EmailTemplatesAdmin.toggle_coupon_fileds);
100
+
101
+ },
102
+
103
+ toggle_coupon_fileds: function() {
104
+
105
+ if ( $("#wcf_override_global_coupon").is(":checked")) {
106
+ $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').fadeIn();
107
+ } else {
108
+ $("#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date").closest('tr').fadeOut();
109
+ }
110
+
111
+ },
112
+
113
+ send_test_email: function () {
114
+
115
+ var email_body = '';
116
+ if (jQuery("#wp-wcf_email_body-wrap").hasClass("tmce-active")) {
117
+ email_body = tinyMCE.get('wcf_email_body').getContent();
118
+ } else {
119
+ email_body = jQuery('#wcf_email_body').val();
120
+ }
121
+
122
+ var email_subject = $('#wcf_email_subject').val();
123
+ var email_send_to = $('#wcf_send_test_email').val();
124
+ var wp_nonce = $("#_wpnonce").val();
125
+
126
+ $(this).next('div.error').remove();
127
+
128
+ if (!$.trim(email_body)) {
129
+ $(this).after('<div class="error-message wcf-ca-error-msg"> Email body is required! </div>');
130
+ } else if (!$.trim(email_subject)) {
131
+ $(this).after('<div class="error-message wcf-ca-error-msg"> Email subject is required! </div>');
132
+ } else if (!$.trim(email_send_to)) {
133
+ $(this).after('<div class="error-message wcf-ca-error-msg"> You must add your email id! </div>');
134
+ }
135
+ else {
136
+
137
+ var data = {
138
+ email_subject: email_subject,
139
+ email_body: email_body,
140
+ email_send_to: email_send_to,
141
+ action: 'wcf_ca_preview_email_send',
142
+ security: wp_nonce
143
+ };
144
+ $("#wcf_preview_email").css('cursor', 'wait').attr("disabled", true);
145
+
146
+ // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
147
+ $.post(
148
+ ajaxurl, data, function (response) {
149
+ $("#mail_response_msg").empty().fadeIn();;
150
+
151
+ if (response.success) {
152
+ var htmlString = "<strong> Email has been sent successfully! </strong>";
153
+ $("#mail_response_msg").css('color','green').html(htmlString).delay(3000).fadeOut();
154
+
155
+ } else {
156
+ var htmlString = "<strong> Email sending failed! Please check your <a href='"+ CAEmailTemplate.settings_url +"'> email settings! </a></strong>"
157
+ $("#mail_response_msg").css('color','red').html(htmlString).delay(3000).fadeOut();;
158
+ }
159
+ $("#wcf_preview_email").css('cursor', '').attr("disabled", false);
160
+
161
+ }
162
+ );
163
+ }
164
+
165
+ $(".wcf-ca-error-msg").delay(2000).fadeOut();
166
+ },
167
+
168
+ toggle_activate_template: function () {
169
+
170
+ var $switch, state, new_state;
171
+ $switch = $(this);
172
+ state = $switch.attr('wcf-ca-template-switch');
173
+ new_state = state === 'on' ? 'off' : 'on';
174
+
175
+ $("#wcf_activate_email_template").val(new_state == 'on' ? 1 : 0);
176
+ $switch.attr('wcf-ca-template-switch', new_state);
177
+ }
178
+
179
+ }
180
+
181
+ ZapierSettings = {
182
+ init: function () {
183
+
184
+ $(document).delegate("#wcf_ca_trigger_web_hook_abandoned_btn", "click",
185
+ { 'order_status': 'abandoned' },
186
+ ZapierSettings.zapier_trigger_sample);
187
+ },
188
+ zapier_trigger_sample: function( event ) {
189
+
190
+ var zapier_webhook_url = $("#wcf_ca_zapier_cart_"+ event.data.order_status +"_webhook").val().trim();
191
+
192
+ if ( ! zapier_webhook_url.length ) {
193
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Webhook URL is required.").fadeIn().css('color', '#dc3232').delay(2000).fadeOut();
194
+ return;
195
+ }
196
+
197
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Triggering...").fadeIn();
198
+
199
+ var now = new Date();
200
+ var datetime = now.getFullYear()+'/'+(now.getMonth()+1)+'/'+now.getDate();
201
+ datetime += ' '+now.getHours()+':'+now.getMinutes()+':'+now.getSeconds();
202
+ if ($.trim(zapier_webhook_url) !== "") {
203
+ var sample_data = {
204
+ "first_name": CartFlowsCADetails.name,
205
+ "last_name": CartFlowsCADetails.surname,
206
+ "email": CartFlowsCADetails.email,
207
+ "order_status": event.data.order_status,
208
+ "checkout_url": window.location.origin + "/checkout/?wcf_ac_token=something",
209
+ "coupon_code": "abcgefgh",
210
+ "product_names": "Product1, Product2 & Product3",
211
+ "cart_total": CartFlowsCADetails.woo_currency_symbol + "20"
212
+ };
213
+ $.ajax({
214
+ url: zapier_webhook_url,
215
+ type: 'POST',
216
+ data: sample_data,
217
+ success: function(data) {
218
+ if (data.status == "success") {
219
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Success!").css('color', '#46b450');
220
+ } else {
221
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
222
+ }
223
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").fadeIn().delay(2000).fadeOut();
224
+ },
225
+ error: function() {
226
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
227
+ }
228
+ });
229
+ } else {
230
+ $("wcf_ca"+ event.data.order_status +"_btn_message").text("Please verify webhook URL.").fadeIn().delay(2000).fadeOut();;
231
+ }
232
+ },
233
+ }
234
+
235
+ ToolTipHover = {
236
+ init: function () {
237
+
238
+ $(".wcf-ca-report-table-row .wcf-ca-icon-row").hover(function(){
239
+ $(this).find('.wcf-ca-tooltip-text').toggleClass("display_tool_tip");
240
+ });
241
+ },
242
+
243
+
244
+ }
245
+
246
+ $(document).ready(
247
+ function () {
248
+ EmailTemplatesAdmin.init();
249
+ CartAbandonmentSettings.init();
250
+ ZapierSettings.init();
251
+
252
+ ToolTipHover.init();
253
+ }
254
+ );
255
+
256
+
257
  })(jQuery);
admin/assets/js/admin-mce.js CHANGED
@@ -1,109 +1,109 @@
1
- (function ($) {
2
-
3
- $(document).ready(
4
- function () {
5
- tinymce.PluginManager.add(
6
- 'cartflows_ac', function (editor, url) {
7
-
8
- editor.addButton(
9
- 'cartflows_ac', {
10
- type: 'menubutton',
11
- text: 'CartFlows Field',
12
- icon: false,
13
- menu: [
14
- {
15
- text: 'Admin Firstname',
16
- value: '{{admin.firstname}}',
17
- onclick: function () {
18
- editor.insertContent(this.value());
19
- }
20
- },
21
- {
22
- text: 'Admin Company',
23
- value: '{{admin.company}}',
24
- onclick: function () {
25
- editor.insertContent(this.value());
26
- }
27
- },
28
- {
29
- text: 'Abandoned Product Details Table',
30
- value: '{{cart.product.table}}',
31
- onclick: function () {
32
- editor.insertContent(this.value());
33
- }
34
- },
35
- {
36
- text: 'Abandoned Product Names',
37
- value: '{{cart.product.names}}',
38
- onclick: function () {
39
- editor.insertContent(this.value());
40
- }
41
- },
42
- {
43
- text: 'Cart Checkout URL',
44
- value: '{{cart.checkout_url}}',
45
- onclick: function () {
46
- editor.insertContent(this.value());
47
- }
48
- },
49
- {
50
- text: 'Coupon Code',
51
- value: '{{cart.coupon_code}}',
52
- onclick: function () {
53
- editor.insertContent(this.value());
54
- }
55
- },
56
- {
57
- text: 'Customer First Name',
58
- value: '{{customer.firstname}}',
59
- onclick: function () {
60
- editor.insertContent(this.value());
61
- }
62
- },
63
- {
64
- text: 'Customer Last Name',
65
- value: '{{customer.lastname}}',
66
- onclick: function () {
67
- editor.insertContent(this.value());
68
- }
69
- },
70
- {
71
- text: 'Customer Full Name',
72
- value: '{{customer.fullname}}',
73
- onclick: function () {
74
- editor.insertContent(this.value());
75
- }
76
- },
77
- {
78
- text: 'Cart Abandonment Date',
79
- value: '{{cart.abandoned_date}}',
80
- onclick: function () {
81
- editor.insertContent(this.value());
82
- }
83
- },
84
- {
85
- text: 'Site URL',
86
- value: '{{site.url}}',
87
- onclick: function () {
88
- editor.insertContent(this.value());
89
- }
90
- },
91
- {
92
- text: 'Unsubscribe Link',
93
- value: '{{cart.unsubscribe}}',
94
- onclick: function () {
95
- editor.insertContent(this.value());
96
- }
97
- },
98
- ].sort(function(a,b){
99
- return a.text.localeCompare(b.text);
100
- })
101
- }
102
- );
103
- }
104
- );
105
- }
106
- );
107
-
108
- })(jQuery);
109
-
1
+ (function ($) {
2
+
3
+ $(document).ready(
4
+ function () {
5
+ tinymce.PluginManager.add(
6
+ 'cartflows_ac', function (editor, url) {
7
+
8
+ editor.addButton(
9
+ 'cartflows_ac', {
10
+ type: 'menubutton',
11
+ text: 'CartFlows Field',
12
+ icon: false,
13
+ menu: [
14
+ {
15
+ text: 'Admin Firstname',
16
+ value: '{{admin.firstname}}',
17
+ onclick: function () {
18
+ editor.insertContent(this.value());
19
+ }
20
+ },
21
+ {
22
+ text: 'Admin Company',
23
+ value: '{{admin.company}}',
24
+ onclick: function () {
25
+ editor.insertContent(this.value());
26
+ }
27
+ },
28
+ {
29
+ text: 'Abandoned Product Details Table',
30
+ value: '{{cart.product.table}}',
31
+ onclick: function () {
32
+ editor.insertContent(this.value());
33
+ }
34
+ },
35
+ {
36
+ text: 'Abandoned Product Names',
37
+ value: '{{cart.product.names}}',
38
+ onclick: function () {
39
+ editor.insertContent(this.value());
40
+ }
41
+ },
42
+ {
43
+ text: 'Cart Checkout URL',
44
+ value: '{{cart.checkout_url}}',
45
+ onclick: function () {
46
+ editor.insertContent(this.value());
47
+ }
48
+ },
49
+ {
50
+ text: 'Coupon Code',
51
+ value: '{{cart.coupon_code}}',
52
+ onclick: function () {
53
+ editor.insertContent(this.value());
54
+ }
55
+ },
56
+ {
57
+ text: 'Customer First Name',
58
+ value: '{{customer.firstname}}',
59
+ onclick: function () {
60
+ editor.insertContent(this.value());
61
+ }
62
+ },
63
+ {
64
+ text: 'Customer Last Name',
65
+ value: '{{customer.lastname}}',
66
+ onclick: function () {
67
+ editor.insertContent(this.value());
68
+ }
69
+ },
70
+ {
71
+ text: 'Customer Full Name',
72
+ value: '{{customer.fullname}}',
73
+ onclick: function () {
74
+ editor.insertContent(this.value());
75
+ }
76
+ },
77
+ {
78
+ text: 'Cart Abandonment Date',
79
+ value: '{{cart.abandoned_date}}',
80
+ onclick: function () {
81
+ editor.insertContent(this.value());
82
+ }
83
+ },
84
+ {
85
+ text: 'Site URL',
86
+ value: '{{site.url}}',
87
+ onclick: function () {
88
+ editor.insertContent(this.value());
89
+ }
90
+ },
91
+ {
92
+ text: 'Unsubscribe Link',
93
+ value: '{{cart.unsubscribe}}',
94
+ onclick: function () {
95
+ editor.insertContent(this.value());
96
+ }
97
+ },
98
+ ].sort(function(a,b){
99
+ return a.text.localeCompare(b.text);
100
+ })
101
+ }
102
+ );
103
+ }
104
+ );
105
+ }
106
+ );
107
+
108
+ })(jQuery);
109
+
assets/images/cartflows-icon.svg CHANGED
@@ -1,18 +1,18 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
- <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
- width="95px" height="95px" viewBox="0 0 95 95" enable-background="new 0 0 95 95" xml:space="preserve">
6
- <g>
7
- <path fill="#81878c" d="M58.942,5.609c-3.444,3.354-5.587,8.036-5.587,13.22v30.718c0,4.521-3.668,8.188-8.188,8.188H24.574
8
- c-4.52,0-8.188-3.668-8.188-8.188c0-4.52,3.668-8.188,8.188-8.188h22.583V24.974H24.574c-1.399,0-2.763,0.115-4.099,0.34
9
- C8.86,27.26,0,37.377,0,49.547c0,10.7,6.843,19.803,16.386,23.176c1.318,0.466,2.681,0.825,4.09,1.058
10
- c1.336,0.225,2.699,0.341,4.099,0.341h20.592c1.399,0,2.763-0.116,4.099-0.341c1.409-0.232,2.771-0.592,4.09-1.058
11
- C62.897,69.35,69.74,60.247,69.74,49.547v-8.188c9.05,0,16.386-7.337,16.386-16.386H69.74v-6.145c0-1.13,0.915-2.044,2.045-2.044
12
- h4.098c4.996,0,9.525-1.982,12.843-5.212c2.987-2.905,4.996-6.807,5.471-11.174H71.786C66.799,0.399,62.261,2.381,58.942,5.609"/>
13
- <path fill="#81878c" d="M24.575,78.218c-4.523,0-8.191,3.667-8.191,8.191c0,4.523,3.667,8.191,8.191,8.191s8.191-3.668,8.191-8.191
14
- C32.766,81.885,29.098,78.218,24.575,78.218"/>
15
- <path fill="#81878c" d="M49.149,78.218c-4.524,0-8.192,3.667-8.192,8.191c0,4.523,3.667,8.191,8.192,8.191
16
- c4.523,0,8.191-3.668,8.191-8.191C57.34,81.885,53.672,78.218,49.149,78.218"/>
17
- </g>
18
- </svg>
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ width="95px" height="95px" viewBox="0 0 95 95" enable-background="new 0 0 95 95" xml:space="preserve">
6
+ <g>
7
+ <path fill="#81878c" d="M58.942,5.609c-3.444,3.354-5.587,8.036-5.587,13.22v30.718c0,4.521-3.668,8.188-8.188,8.188H24.574
8
+ c-4.52,0-8.188-3.668-8.188-8.188c0-4.52,3.668-8.188,8.188-8.188h22.583V24.974H24.574c-1.399,0-2.763,0.115-4.099,0.34
9
+ C8.86,27.26,0,37.377,0,49.547c0,10.7,6.843,19.803,16.386,23.176c1.318,0.466,2.681,0.825,4.09,1.058
10
+ c1.336,0.225,2.699,0.341,4.099,0.341h20.592c1.399,0,2.763-0.116,4.099-0.341c1.409-0.232,2.771-0.592,4.09-1.058
11
+ C62.897,69.35,69.74,60.247,69.74,49.547v-8.188c9.05,0,16.386-7.337,16.386-16.386H69.74v-6.145c0-1.13,0.915-2.044,2.045-2.044
12
+ h4.098c4.996,0,9.525-1.982,12.843-5.212c2.987-2.905,4.996-6.807,5.471-11.174H71.786C66.799,0.399,62.261,2.381,58.942,5.609"/>
13
+ <path fill="#81878c" d="M24.575,78.218c-4.523,0-8.191,3.667-8.191,8.191c0,4.523,3.667,8.191,8.191,8.191s8.191-3.668,8.191-8.191
14
+ C32.766,81.885,29.098,78.218,24.575,78.218"/>
15
+ <path fill="#81878c" d="M49.149,78.218c-4.524,0-8.192,3.667-8.192,8.191c0,4.523,3.667,8.191,8.192,8.191
16
+ c4.523,0,8.191-3.668,8.191-8.191C57.34,81.885,53.672,78.218,49.149,78.218"/>
17
+ </g>
18
+ </svg>
assets/images/cartflows-logo.svg CHANGED
@@ -1,50 +1,50 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
- <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
- width="500px" height="95px" viewBox="0 0 500 95" enable-background="new 0 0 500 95" xml:space="preserve">
6
- <g>
7
- <path fill="#F06335" d="M135.779,68.374c-5.939,0-10.946-1.951-14.934-5.939c-3.989-3.988-5.939-8.995-5.939-15.019
8
- c0-6.025,1.951-11.031,5.939-15.02c3.988-3.988,8.995-6.024,14.934-6.024c6.535,0,11.964,2.376,16.208,7.212l7.211-6.194
9
- c-6.194-7.043-14-10.606-23.42-10.606c-8.74,0-16.207,2.885-22.317,8.74c-6.023,5.854-9.079,13.152-9.079,21.893
10
- c0,8.739,3.056,16.037,9.079,21.892c6.11,5.77,13.577,8.655,22.317,8.655c9.25,0,17.735-3.988,23.505-10.776l-7.127-6.194
11
- C148,65.914,142.483,68.374,135.779,68.374"/>
12
- <path fill="#F06335" d="M199.086,40.372c-1.443-4.157-6.619-7.127-13.661-7.127c-6.025,0-11.117,2.121-15.274,6.448
13
- c-4.073,4.243-6.11,9.504-6.11,15.868s2.037,11.625,6.11,15.952c4.157,4.243,9.249,6.364,15.274,6.364
14
- c7.042,0,12.218-2.97,13.661-7.128v6.194h10.182V34.178h-10.182V40.372z M196.03,64.896c-2.46,2.461-5.6,3.733-9.249,3.733
15
- c-3.648,0-6.619-1.272-9.08-3.733c-2.375-2.461-3.563-5.601-3.563-9.334c0-3.734,1.188-6.873,3.563-9.334
16
- c2.461-2.461,5.432-3.734,9.08-3.734c3.649,0,6.788,1.273,9.249,3.734c2.547,2.461,3.819,5.6,3.819,9.334
17
- C199.85,59.295,198.577,62.435,196.03,64.896"/>
18
- <path fill="#F06335" d="M229.891,40.542v-6.363h-10.098v42.767h10.098V54.458c0-7.043,4.498-11.455,11.541-11.455
19
- c1.527,0,2.971,0.17,4.243,0.424v-9.843c-0.848-0.169-1.867-0.254-3.055-0.254C236.595,33.33,231.928,36.045,229.891,40.542"/>
20
- <polygon fill="#F06335" points="267.654,17.802 257.472,17.802 257.472,34.178 251.955,34.178 251.955,43.427 257.472,43.427
21
- 257.472,76.944 267.654,76.944 267.654,43.427 276.902,43.427 276.902,34.178 267.654,34.178 "/>
22
- <polygon fill="#F06335" points="286.834,76.944 297.439,76.944 297.439,51.827 320.436,51.827 320.436,42.239 297.439,42.239
23
- 297.439,27.39 322.641,27.39 322.641,17.802 286.834,17.802 "/>
24
- <rect x="332.487" y="17.802" fill="#F06335" width="10.183" height="59.143"/>
25
- <path fill="#F06335" d="M374.832,32.905c-6.534,0-12.049,2.206-16.547,6.533c-4.498,4.328-6.789,9.759-6.789,16.123
26
- s2.291,11.795,6.789,16.122s10.013,6.534,16.547,6.534c6.533,0,12.049-2.207,16.547-6.534c4.496-4.327,6.787-9.758,6.787-16.122
27
- s-2.291-11.795-6.787-16.123C386.881,35.111,381.365,32.905,374.832,32.905 M384.25,65.149c-2.545,2.546-5.685,3.819-9.418,3.819
28
- c-3.819,0-6.959-1.273-9.505-3.819c-2.46-2.63-3.733-5.77-3.733-9.588s1.273-6.958,3.733-9.504
29
- c2.546-2.631,5.686-3.903,9.505-3.903c3.733,0,6.873,1.272,9.418,3.903c2.547,2.546,3.818,5.686,3.818,9.504
30
- S386.797,62.52,384.25,65.149"/>
31
- <polygon fill="#F06335" points="443.992,60.822 435.337,34.178 427.615,34.178 418.959,60.822 410.051,34.178 400.461,34.178
32
- 414.717,76.944 422.693,76.944 431.518,49.876 440.344,76.944 448.234,76.944 462.575,34.178 452.902,34.178 "/>
33
- <path fill="#F06335" d="M488.545,51.743c-1.697-0.595-4.074-1.442-5.346-1.782c-1.104-0.424-2.801-1.104-3.479-1.527
34
- c-1.188-0.764-1.952-1.527-1.952-2.97c0-2.291,2.037-3.818,5.176-3.818c3.649,0,6.449,1.188,8.316,3.563l5.686-6.024
35
- c-3.225-4.158-7.807-6.279-13.832-6.279c-4.242,0-7.807,1.188-10.776,3.479c-2.886,2.291-4.327,5.346-4.327,9.333
36
- c0,6.109,3.648,9.589,10.521,12.05c1.443,0.594,3.988,1.357,5.262,1.782c1.271,0.424,3.055,1.018,3.988,1.611
37
- c1.442,0.765,2.459,1.952,2.459,3.395c0,2.631-2.291,4.667-7.636,4.667c-5.176,0-9.333-2.291-11.286-5.346l-6.533,5.516
38
- c2.715,5.346,9.08,8.655,17.65,8.655c11.624,0,17.564-5.685,17.564-13.577C500,58.361,496.436,54.543,488.545,51.743"/>
39
- <path fill="#F06335" d="M58.942,5.609c-3.444,3.354-5.587,8.036-5.587,13.22v30.718c0,4.521-3.668,8.188-8.188,8.188H24.574
40
- c-4.52,0-8.188-3.668-8.188-8.188c0-4.52,3.668-8.188,8.188-8.188h22.583V24.974H24.574c-1.399,0-2.763,0.115-4.099,0.34
41
- C8.86,27.26,0,37.377,0,49.547c0,10.7,6.843,19.803,16.386,23.176c1.318,0.466,2.681,0.825,4.09,1.058
42
- c1.336,0.225,2.699,0.341,4.099,0.341h20.592c1.399,0,2.763-0.116,4.099-0.341c1.409-0.232,2.771-0.592,4.09-1.058
43
- C62.897,69.35,69.74,60.247,69.74,49.547v-8.188c9.05,0,16.386-7.337,16.386-16.386H69.74v-6.145c0-1.13,0.915-2.044,2.045-2.044
44
- h4.098c4.996,0,9.525-1.982,12.843-5.212c2.987-2.905,4.996-6.807,5.471-11.174H71.786C66.799,0.399,62.261,2.381,58.942,5.609"/>
45
- <path fill="#F06335" d="M24.575,78.218c-4.523,0-8.191,3.667-8.191,8.191c0,4.523,3.667,8.191,8.191,8.191s8.191-3.668,8.191-8.191
46
- C32.766,81.885,29.098,78.218,24.575,78.218"/>
47
- <path fill="#F06335" d="M49.149,78.218c-4.524,0-8.192,3.667-8.192,8.191c0,4.523,3.667,8.191,8.192,8.191
48
- c4.523,0,8.191-3.668,8.191-8.191C57.34,81.885,53.672,78.218,49.149,78.218"/>
49
- </g>
50
- </svg>
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ width="500px" height="95px" viewBox="0 0 500 95" enable-background="new 0 0 500 95" xml:space="preserve">
6
+ <g>
7
+ <path fill="#F06335" d="M135.779,68.374c-5.939,0-10.946-1.951-14.934-5.939c-3.989-3.988-5.939-8.995-5.939-15.019
8
+ c0-6.025,1.951-11.031,5.939-15.02c3.988-3.988,8.995-6.024,14.934-6.024c6.535,0,11.964,2.376,16.208,7.212l7.211-6.194
9
+ c-6.194-7.043-14-10.606-23.42-10.606c-8.74,0-16.207,2.885-22.317,8.74c-6.023,5.854-9.079,13.152-9.079,21.893
10
+ c0,8.739,3.056,16.037,9.079,21.892c6.11,5.77,13.577,8.655,22.317,8.655c9.25,0,17.735-3.988,23.505-10.776l-7.127-6.194
11
+ C148,65.914,142.483,68.374,135.779,68.374"/>
12
+ <path fill="#F06335" d="M199.086,40.372c-1.443-4.157-6.619-7.127-13.661-7.127c-6.025,0-11.117,2.121-15.274,6.448
13
+ c-4.073,4.243-6.11,9.504-6.11,15.868s2.037,11.625,6.11,15.952c4.157,4.243,9.249,6.364,15.274,6.364
14
+ c7.042,0,12.218-2.97,13.661-7.128v6.194h10.182V34.178h-10.182V40.372z M196.03,64.896c-2.46,2.461-5.6,3.733-9.249,3.733
15
+ c-3.648,0-6.619-1.272-9.08-3.733c-2.375-2.461-3.563-5.601-3.563-9.334c0-3.734,1.188-6.873,3.563-9.334
16
+ c2.461-2.461,5.432-3.734,9.08-3.734c3.649,0,6.788,1.273,9.249,3.734c2.547,2.461,3.819,5.6,3.819,9.334
17
+ C199.85,59.295,198.577,62.435,196.03,64.896"/>
18
+ <path fill="#F06335" d="M229.891,40.542v-6.363h-10.098v42.767h10.098V54.458c0-7.043,4.498-11.455,11.541-11.455
19
+ c1.527,0,2.971,0.17,4.243,0.424v-9.843c-0.848-0.169-1.867-0.254-3.055-0.254C236.595,33.33,231.928,36.045,229.891,40.542"/>
20
+ <polygon fill="#F06335" points="267.654,17.802 257.472,17.802 257.472,34.178 251.955,34.178 251.955,43.427 257.472,43.427
21
+ 257.472,76.944 267.654,76.944 267.654,43.427 276.902,43.427 276.902,34.178 267.654,34.178 "/>
22
+ <polygon fill="#F06335" points="286.834,76.944 297.439,76.944 297.439,51.827 320.436,51.827 320.436,42.239 297.439,42.239
23
+ 297.439,27.39 322.641,27.39 322.641,17.802 286.834,17.802 "/>
24
+ <rect x="332.487" y="17.802" fill="#F06335" width="10.183" height="59.143"/>
25
+ <path fill="#F06335" d="M374.832,32.905c-6.534,0-12.049,2.206-16.547,6.533c-4.498,4.328-6.789,9.759-6.789,16.123
26
+ s2.291,11.795,6.789,16.122s10.013,6.534,16.547,6.534c6.533,0,12.049-2.207,16.547-6.534c4.496-4.327,6.787-9.758,6.787-16.122
27
+ s-2.291-11.795-6.787-16.123C386.881,35.111,381.365,32.905,374.832,32.905 M384.25,65.149c-2.545,2.546-5.685,3.819-9.418,3.819
28
+ c-3.819,0-6.959-1.273-9.505-3.819c-2.46-2.63-3.733-5.77-3.733-9.588s1.273-6.958,3.733-9.504
29
+ c2.546-2.631,5.686-3.903,9.505-3.903c3.733,0,6.873,1.272,9.418,3.903c2.547,2.546,3.818,5.686,3.818,9.504
30
+ S386.797,62.52,384.25,65.149"/>
31
+ <polygon fill="#F06335" points="443.992,60.822 435.337,34.178 427.615,34.178 418.959,60.822 410.051,34.178 400.461,34.178
32
+ 414.717,76.944 422.693,76.944 431.518,49.876 440.344,76.944 448.234,76.944 462.575,34.178 452.902,34.178 "/>
33
+ <path fill="#F06335" d="M488.545,51.743c-1.697-0.595-4.074-1.442-5.346-1.782c-1.104-0.424-2.801-1.104-3.479-1.527
34
+ c-1.188-0.764-1.952-1.527-1.952-2.97c0-2.291,2.037-3.818,5.176-3.818c3.649,0,6.449,1.188,8.316,3.563l5.686-6.024
35
+ c-3.225-4.158-7.807-6.279-13.832-6.279c-4.242,0-7.807,1.188-10.776,3.479c-2.886,2.291-4.327,5.346-4.327,9.333
36
+ c0,6.109,3.648,9.589,10.521,12.05c1.443,0.594,3.988,1.357,5.262,1.782c1.271,0.424,3.055,1.018,3.988,1.611
37
+ c1.442,0.765,2.459,1.952,2.459,3.395c0,2.631-2.291,4.667-7.636,4.667c-5.176,0-9.333-2.291-11.286-5.346l-6.533,5.516
38
+ c2.715,5.346,9.08,8.655,17.65,8.655c11.624,0,17.564-5.685,17.564-13.577C500,58.361,496.436,54.543,488.545,51.743"/>
39
+ <path fill="#F06335" d="M58.942,5.609c-3.444,3.354-5.587,8.036-5.587,13.22v30.718c0,4.521-3.668,8.188-8.188,8.188H24.574
40
+ c-4.52,0-8.188-3.668-8.188-8.188c0-4.52,3.668-8.188,8.188-8.188h22.583V24.974H24.574c-1.399,0-2.763,0.115-4.099,0.34
41
+ C8.86,27.26,0,37.377,0,49.547c0,10.7,6.843,19.803,16.386,23.176c1.318,0.466,2.681,0.825,4.09,1.058
42
+ c1.336,0.225,2.699,0.341,4.099,0.341h20.592c1.399,0,2.763-0.116,4.099-0.341c1.409-0.232,2.771-0.592,4.09-1.058
43
+ C62.897,69.35,69.74,60.247,69.74,49.547v-8.188c9.05,0,16.386-7.337,16.386-16.386H69.74v-6.145c0-1.13,0.915-2.044,2.045-2.044
44
+ h4.098c4.996,0,9.525-1.982,12.843-5.212c2.987-2.905,4.996-6.807,5.471-11.174H71.786C66.799,0.399,62.261,2.381,58.942,5.609"/>
45
+ <path fill="#F06335" d="M24.575,78.218c-4.523,0-8.191,3.667-8.191,8.191c0,4.523,3.667,8.191,8.191,8.191s8.191-3.668,8.191-8.191
46
+ C32.766,81.885,29.098,78.218,24.575,78.218"/>
47
+ <path fill="#F06335" d="M49.149,78.218c-4.524,0-8.192,3.667-8.192,8.191c0,4.523,3.667,8.191,8.192,8.191
48
+ c4.523,0,8.191-3.668,8.191-8.191C57.34,81.885,53.672,78.218,49.149,78.218"/>
49
+ </g>
50
+ </svg>
changelog.txt CHANGED
@@ -1,16 +1,22 @@
1
- Version 1.1.2 - Wednesday, 12th June 2019
2
- - Fix: Issue of timezone while sending mail through cron.
3
- - Fix: Delete single cart abandonment order.
4
- - Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
5
-
6
- Version 1.1.1 - Thursday, 06th June 2019
7
- - New: Added feature to reschedule emails for Admin.
8
- - Fix: Coupon expiry time issue.
9
- - Fix: Email issue for a user who has an already purchased order.
10
- - Fix: Translatable strings updated.
11
-
12
- Version 1.1.0 - Thursday, 30th May 2019
13
- - Added a view for admin to check email status specific to the particular abandoned user.
14
-
15
- Version 1.0.0 - Monday, 27th May 2019
 
 
 
 
 
 
16
  - Initial Release
1
+ Version 1.1.3 - Thursday, 27th June 2019
2
+ - Improvement: Added checkout link for abandoned cart inside the admin section.
3
+ - Fix: Added pagination for reports.
4
+ - Fix: Recover report calculations before campaign triggers.
5
+ - Fix: Empty cart notice when CartFlows checkout is set global.
6
+
7
+ Version 1.1.2 - Wednesday, 12th June 2019
8
+ - Fix: Issue of timezone while sending mail through cron.
9
+ - Fix: Delete single cart abandonment order.
10
+ - Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
11
+
12
+ Version 1.1.1 - Thursday, 06th June 2019
13
+ - New: Added feature to reschedule emails for Admin.
14
+ - Fix: Coupon expiry time issue.
15
+ - Fix: Email issue for a user who has an already purchased order.
16
+ - Fix: Translatable strings updated.
17
+
18
+ Version 1.1.0 - Thursday, 30th May 2019
19
+ - Added a view for admin to check email status specific to the particular abandoned user.
20
+
21
+ Version 1.0.0 - Monday, 27th May 2019
22
  - Initial Release
classes/class-cartflows-ca-loader.php CHANGED
@@ -1,352 +1,352 @@
1
- <?php
2
- /**
3
- * CartFlows Loader.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'CARTFLOWS_CA_Loader' ) ) {
9
-
10
- /**
11
- * Class CARTFLOWS_CA_Loader.
12
- */
13
- final class CARTFLOWS_CA_Loader {
14
-
15
-
16
- /**
17
- * Member Variable
18
- *
19
- * @var instance
20
- */
21
- private static $instance = null;
22
-
23
- /**
24
- * Member Variable
25
- *
26
- * @var utils
27
- */
28
- public $utils = null;
29
-
30
-
31
- /**
32
- * Initiator
33
- */
34
- public static function get_instance() {
35
-
36
- if ( is_null( self::$instance ) ) {
37
-
38
- self::$instance = new self;
39
-
40
- /**
41
- * CartFlows CA loaded.
42
- *
43
- * Fires when Cartflows CA was fully loaded and instantiated.
44
- *
45
- * @since 1.0.0
46
- */
47
- do_action( 'cartflows_ca_loaded' );
48
- }
49
-
50
- return self::$instance;
51
- }
52
-
53
- /**
54
- * Constructor
55
- */
56
- public function __construct() {
57
-
58
- $this->define_constants();
59
-
60
- // Activation hook.
61
- register_activation_hook( CARTFLOWS_CA_FILE, array( $this, 'activation_reset' ) );
62
-
63
- // deActivation hook.
64
- register_deactivation_hook( CARTFLOWS_CA_FILE, array( $this, 'deactivation_reset' ) );
65
-
66
- add_action( 'plugins_loaded', array( $this, 'load_plugin' ), 99 );
67
-
68
- add_action( 'plugins_loaded', array( $this, 'load_cf_textdomain' ) );
69
- }
70
-
71
- /**
72
- * Defines all constants
73
- *
74
- * @since 1.0.0
75
- */
76
- public function define_constants() {
77
- define( 'CARTFLOWS_CA_BASE', plugin_basename( CARTFLOWS_CA_FILE ) );
78
- define( 'CARTFLOWS_CA_DIR', plugin_dir_path( CARTFLOWS_CA_FILE ) );
79
- define( 'CARTFLOWS_CA_URL', plugins_url( '/', CARTFLOWS_CA_FILE ) );
80
- define( 'CARTFLOWS_CA_VER', '1.1.2' );
81
- define( 'CARTFLOWS_CA_SLUG', 'cartflows_ca' );
82
-
83
- define( 'CARTFLOWS_CA_CART_ABANDONMENT_TABLE', 'cartflows_ca_cart_abandonment' );
84
- define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE', 'cartflows_ca_email_templates' );
85
- define( 'CARTFLOWS_CA_EMAIL_HISTORY_TABLE', 'cartflows_ca_email_history' );
86
- define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE', 'cartflows_ca_email_templates_meta' );
87
- }
88
-
89
- /**
90
- * Loads plugin files.
91
- *
92
- * @since 1.0.0
93
- *
94
- * @return void
95
- */
96
- function load_plugin() {
97
-
98
- if ( ! function_exists( 'WC' ) ) {
99
- add_action( 'admin_notices', array( $this, 'fails_to_load' ) );
100
- return;
101
- }
102
-
103
- $this->load_helper_files_components();
104
- $this->load_core_files();
105
- $this->load_core_components();
106
-
107
- /**
108
- * CartFlows Init.
109
- *
110
- * Fires when Cartflows is instantiated.
111
- *
112
- * @since 1.0.0
113
- */
114
- do_action( 'cartflows_ca_init' );
115
- }
116
-
117
- /**
118
- * Fires admin notice when Elementor is not installed and activated.
119
- *
120
- * @since 1.0.0
121
- *
122
- * @return void
123
- */
124
- public function fails_to_load() {
125
-
126
- $screen = get_current_screen();
127
-
128
- if ( isset( $screen->parent_file ) && 'plugins.php' === $screen->parent_file && 'update' === $screen->id ) {
129
- return;
130
- }
131
-
132
- $class = 'notice notice-error';
133
- /* translators: %s: html tags */
134
- $message = sprintf( __( 'The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires %1$sWooCommerce%2$s plugin installed & activated.', 'cartflows-ca' ), '<strong>', '</strong>' );
135
-
136
- $plugin = 'woocommerce/woocommerce.php';
137
-
138
- if ( $this->is_woo_installed() ) {
139
- if ( ! current_user_can( 'activate_plugins' ) ) {
140
- return;
141
- }
142
-
143
- $action_url = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $plugin );
144
- $button_label = __( 'Activate WooCommerce', 'cartflows-ca' );
145
-
146
- } else {
147
- if ( ! current_user_can( 'install_plugins' ) ) {
148
- return;
149
- }
150
-
151
- $action_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=woocommerce' ), 'install-plugin_woocommerce' );
152
- $button_label = __( 'Install WooCommerce', 'cartflows-ca' );
153
- }
154
-
155
- $button = '<p><a href="' . $action_url . '" class="button-primary">' . $button_label . '</a></p><p></p>';
156
-
157
- printf( '<div class="%1$s"><p>%2$s</p>%3$s</div>', esc_attr( $class ), $message, $button );
158
- }
159
-
160
-
161
- /**
162
- * Is woocommerce plugin installed.
163
- *
164
- * @since 1.0.0
165
- *
166
- * @access public
167
- */
168
- function is_woo_installed() {
169
-
170
- $path = 'woocommerce/woocommerce.php';
171
- $plugins = get_plugins();
172
-
173
- return isset( $plugins[ $path ] );
174
- }
175
-
176
- /**
177
- * Create new database tables for plugin updates.
178
- *
179
- * @since 1.0.0
180
- *
181
- * @return void
182
- */
183
- function initialize_cart_abandonment_tables() {
184
-
185
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
186
- $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
187
- $db->create_tables();
188
- $db->template_table_seeder();
189
- }
190
-
191
-
192
- /**
193
- * Load Helper Files and Components.
194
- *
195
- * @since 1.0.0
196
- *
197
- * @return void
198
- */
199
- function load_helper_files_components() {
200
-
201
- include_once CARTFLOWS_CA_DIR . 'classes/class-cartflows-ca-utils.php';
202
- $this->utils = Cartflows_Ca_Utils::get_instance();
203
- }
204
-
205
- /**
206
- * Load core files.
207
- */
208
- function load_core_files() {
209
- /* Update compatibility. */
210
- require_once CARTFLOWS_CA_DIR . 'classes/class-cartflows-ca-update.php';
211
-
212
- include_once CARTFLOWS_CA_DIR . 'classes/class-cartflows-ca-settings.php';
213
- }
214
-
215
- /**
216
- * Load CartFlows Ca Text Domain.
217
- * This will load the translation textdomain depending on the file priorities.
218
- * 1. Global Languages /wp-content/languages/%plugin-folder-name%/ folder
219
- * 2. Local dorectory /wp-content/plugins/%plugin-folder-name%/languages/ folder
220
- *
221
- * @since 1.0.3
222
- * @return void
223
- */
224
- public function load_cf_textdomain() {
225
-
226
- // Default languages directory for CartFlows Ca.
227
- $lang_dir = CARTFLOWS_CA_DIR . 'languages/';
228
-
229
- /**
230
- * Filters the languages directory path to use for CartFlows Ca.
231
- *
232
- * @param string $lang_dir The languages directory path.
233
- */
234
- $lang_dir = apply_filters( 'carflows_ca_languages_directory', $lang_dir );
235
-
236
- // Traditional WordPress plugin locale filter.
237
- global $wp_version;
238
-
239
- $get_locale = get_locale();
240
-
241
- if ( $wp_version >= 4.7 ) {
242
- $get_locale = get_user_locale();
243
- }
244
-
245
- /**
246
- * Language Locale for CartFlows Ca
247
- *
248
- * @var $get_locale The locale to use.
249
- * Uses get_user_locale()` in WordPress 4.7 or greater,
250
- * otherwise uses `get_locale()`.
251
- */
252
- $locale = apply_filters( 'plugin_locale', $get_locale, 'cartflows-ca' );
253
- $mofile = sprintf( '%1$s-%2$s.mo', 'cartflows-ca', $locale );
254
-
255
- // Setup paths to current locale file.
256
- $mofile_local = $lang_dir . $mofile;
257
- $mofile_global = WP_LANG_DIR . '/plugins/' . $mofile;
258
-
259
- if ( file_exists( $mofile_global ) ) {
260
- // Look in global /wp-content/languages/%plugin-folder-name%/ folder.
261
- load_textdomain( 'cartflows-ca', $mofile_global );
262
- } elseif ( file_exists( $mofile_local ) ) {
263
- // Look in local /wp-content/plugins/%plugin-folder-name%/languages/ folder.
264
- load_textdomain( 'cartflows-ca', $mofile_local );
265
- } else {
266
- // Load the default language files.
267
- load_plugin_textdomain( 'cartflows-ca', false, $lang_dir );
268
- }
269
- }
270
- /**
271
- * Load Core Components.
272
- *
273
- * @since 1.0.0
274
- *
275
- * @return void
276
- */
277
- function load_core_components() {
278
-
279
- /* Cart abandonment templates class */
280
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-module-loader.php';
281
-
282
- }
283
-
284
-
285
- /**
286
- * Activation Reset
287
- */
288
- function activation_reset() {
289
- $this->update_default_settings();
290
- $this->initialize_cart_abandonment_tables();
291
- }
292
-
293
-
294
- /**
295
- * Set the default cart abandonment settings.
296
- */
297
- function update_default_settings() {
298
-
299
- $current_user = wp_get_current_user();
300
- $email_from = ( isset( $current_user->user_firstname ) && ! empty( $current_user->user_firstname ) ) ? $current_user->user_firstname . ' ' . $current_user->user_lastname : 'Admin';
301
- $default_settings = array(
302
- 'wcf_ca_status' => 'on',
303
- 'wcf_ca_gdpr_status' => 'off',
304
- 'wcf_ca_coupon_code_status' => 'off',
305
- 'wcf_ca_zapier_tracking_status' => 'off',
306
- 'wcf_ca_cut_off_time' => 15,
307
- 'wcf_ca_from_name' => $email_from,
308
- 'wcf_ca_from_email' => $current_user->user_email,
309
- 'wcf_ca_reply_email' => $current_user->user_email,
310
- 'wcf_ca_discount_type' => 'percent',
311
- 'wcf_ca_coupon_amount' => 10,
312
- 'wcf_ca_zapier_cart_abandoned_webhook' => '',
313
- 'wcf_ca_gdpr_message' => 'Your email & cart are saved so we can send email reminders about this order.',
314
- 'wcf_ca_coupon_expiry' => 0,
315
- 'wcf_ca_coupon_expiry_unit' => 'hours',
316
- );
317
-
318
- foreach ( $default_settings as $option_key => $option_value ) {
319
- if ( ! get_option( $option_key ) ) {
320
- update_option( $option_key, $option_value );
321
- }
322
- }
323
- }
324
-
325
- /**
326
- * Deactivation Reset
327
- */
328
- function deactivation_reset() {
329
- wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
330
- }
331
-
332
- }
333
-
334
- /**
335
- * Prepare if class 'CARTFLOWS_CA_Loader' exist.
336
- * Kicking this off by calling 'get_instance()' method
337
- */
338
- CARTFLOWS_CA_Loader::get_instance();
339
- }
340
-
341
-
342
- if ( ! function_exists( 'wcf_ca' ) ) {
343
- /**
344
- * Get global class.
345
- *
346
- * @return object
347
- */
348
- function wcf_ca() {
349
- return CARTFLOWS_CA_Loader::get_instance();
350
- }
351
- }
352
-
1
+ <?php
2
+ /**
3
+ * CartFlows Loader.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'CARTFLOWS_CA_Loader' ) ) {
9
+
10
+ /**
11
+ * Class CARTFLOWS_CA_Loader.
12
+ */
13
+ final class CARTFLOWS_CA_Loader {
14
+
15
+
16
+ /**
17
+ * Member Variable
18
+ *
19
+ * @var instance
20
+ */
21
+ private static $instance = null;
22
+
23
+ /**
24
+ * Member Variable
25
+ *
26
+ * @var utils
27
+ */
28
+ public $utils = null;
29
+
30
+
31
+ /**
32
+ * Initiator
33
+ */
34
+ public static function get_instance() {
35
+
36
+ if ( is_null( self::$instance ) ) {
37
+
38
+ self::$instance = new self;
39
+
40
+ /**
41
+ * CartFlows CA loaded.
42
+ *
43
+ * Fires when Cartflows CA was fully loaded and instantiated.
44
+ *
45
+ * @since 1.0.0
46
+ */
47
+ do_action( 'cartflows_ca_loaded' );
48
+ }
49
+
50
+ return self::$instance;
51
+ }
52
+
53
+ /**
54
+ * Constructor
55
+ */
56
+ public function __construct() {
57
+
58
+ $this->define_constants();
59
+
60
+ // Activation hook.
61
+ register_activation_hook( CARTFLOWS_CA_FILE, array( $this, 'activation_reset' ) );
62
+
63
+ // deActivation hook.
64
+ register_deactivation_hook( CARTFLOWS_CA_FILE, array( $this, 'deactivation_reset' ) );
65
+
66
+ add_action( 'plugins_loaded', array( $this, 'load_plugin' ), 99 );
67
+
68
+ add_action( 'plugins_loaded', array( $this, 'load_cf_textdomain' ) );
69
+ }
70
+
71
+ /**
72
+ * Defines all constants
73
+ *
74
+ * @since 1.0.0
75
+ */
76
+ public function define_constants() {
77
+ define( 'CARTFLOWS_CA_BASE', plugin_basename( CARTFLOWS_CA_FILE ) );
78
+ define( 'CARTFLOWS_CA_DIR', plugin_dir_path( CARTFLOWS_CA_FILE ) );
79
+ define( 'CARTFLOWS_CA_URL', plugins_url( '/', CARTFLOWS_CA_FILE ) );
80
+ define( 'CARTFLOWS_CA_VER', '1.1.3' );
81
+ define( 'CARTFLOWS_CA_SLUG', 'cartflows_ca' );
82
+
83
+ define( 'CARTFLOWS_CA_CART_ABANDONMENT_TABLE', 'cartflows_ca_cart_abandonment' );
84
+ define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE', 'cartflows_ca_email_templates' );
85
+ define( 'CARTFLOWS_CA_EMAIL_HISTORY_TABLE', 'cartflows_ca_email_history' );
86
+ define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE', 'cartflows_ca_email_templates_meta' );
87
+ }
88
+
89
+ /**
90
+ * Loads plugin files.
91
+ *
92
+ * @since 1.0.0
93
+ *
94
+ * @return void
95
+ */
96
+ function load_plugin() {
97
+
98
+ if ( ! function_exists( 'WC' ) ) {
99
+ add_action( 'admin_notices', array( $this, 'fails_to_load' ) );
100
+ return;
101
+ }
102
+
103
+ $this->load_helper_files_components();
104
+ $this->load_core_files();
105
+ $this->load_core_components();
106
+
107
+ /**
108
+ * CartFlows Init.
109
+ *
110
+ * Fires when Cartflows is instantiated.
111
+ *
112
+ * @since 1.0.0
113
+ */
114
+ do_action( 'cartflows_ca_init' );
115
+ }
116
+
117
+ /**
118
+ * Fires admin notice when Elementor is not installed and activated.
119
+ *
120
+ * @since 1.0.0
121
+ *
122
+ * @return void
123
+ */
124
+ public function fails_to_load() {
125
+
126
+ $screen = get_current_screen();
127
+
128
+ if ( isset( $screen->parent_file ) && 'plugins.php' === $screen->parent_file && 'update' === $screen->id ) {
129
+ return;
130
+ }
131
+
132
+ $class = 'notice notice-error';
133
+ /* translators: %s: html tags */
134
+ $message = sprintf( __( 'The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires %1$sWooCommerce%2$s plugin installed & activated.', 'cartflows-ca' ), '<strong>', '</strong>' );
135
+
136
+ $plugin = 'woocommerce/woocommerce.php';
137
+
138
+ if ( $this->is_woo_installed() ) {
139
+ if ( ! current_user_can( 'activate_plugins' ) ) {
140
+ return;
141
+ }
142
+
143
+ $action_url = wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $plugin );
144
+ $button_label = __( 'Activate WooCommerce', 'cartflows-ca' );
145
+
146
+ } else {
147
+ if ( ! current_user_can( 'install_plugins' ) ) {
148
+ return;
149
+ }
150
+
151
+ $action_url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=woocommerce' ), 'install-plugin_woocommerce' );
152
+ $button_label = __( 'Install WooCommerce', 'cartflows-ca' );
153
+ }
154
+
155
+ $button = '<p><a href="' . $action_url . '" class="button-primary">' . $button_label . '</a></p><p></p>';
156
+
157
+ printf( '<div class="%1$s"><p>%2$s</p>%3$s</div>', esc_attr( $class ), $message, $button );
158
+ }
159
+
160
+
161
+ /**
162
+ * Is woocommerce plugin installed.
163
+ *
164
+ * @since 1.0.0
165
+ *
166
+ * @access public
167
+ */
168
+ function is_woo_installed() {
169
+
170
+ $path = 'woocommerce/woocommerce.php';
171
+ $plugins = get_plugins();
172
+
173
+ return isset( $plugins[ $path ] );
174
+ }
175
+
176
+ /**
177
+ * Create new database tables for plugin updates.
178
+ *
179
+ * @since 1.0.0
180
+ *
181
+ * @return void
182
+ */
183
+ function initialize_cart_abandonment_tables() {
184
+
185
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
186
+ $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
187
+ $db->create_tables();
188
+ $db->template_table_seeder();
189
+ }
190
+
191
+
192
+ /**
193
+ * Load Helper Files and Components.
194
+ *
195
+ * @since 1.0.0
196
+ *
197
+ * @return void
198
+ */
199
+ function load_helper_files_components() {
200
+
201
+ include_once CARTFLOWS_CA_DIR . 'classes/class-cartflows-ca-utils.php';
202
+ $this->utils = Cartflows_Ca_Utils::get_instance();
203
+ }
204
+
205
+ /**
206
+ * Load core files.
207
+ */
208
+ function load_core_files() {
209
+ /* Update compatibility. */
210
+ require_once CARTFLOWS_CA_DIR . 'classes/class-cartflows-ca-update.php';
211
+
212
+ include_once CARTFLOWS_CA_DIR . 'classes/class-cartflows-ca-settings.php';
213
+ }
214
+
215
+ /**
216
+ * Load CartFlows Ca Text Domain.
217
+ * This will load the translation textdomain depending on the file priorities.
218
+ * 1. Global Languages /wp-content/languages/%plugin-folder-name%/ folder
219
+ * 2. Local dorectory /wp-content/plugins/%plugin-folder-name%/languages/ folder
220
+ *
221
+ * @since 1.0.3
222
+ * @return void
223
+ */
224
+ public function load_cf_textdomain() {
225
+
226
+ // Default languages directory for CartFlows Ca.
227
+ $lang_dir = CARTFLOWS_CA_DIR . 'languages/';
228
+
229
+ /**
230
+ * Filters the languages directory path to use for CartFlows Ca.
231
+ *
232
+ * @param string $lang_dir The languages directory path.
233
+ */
234
+ $lang_dir = apply_filters( 'carflows_ca_languages_directory', $lang_dir );
235
+
236
+ // Traditional WordPress plugin locale filter.
237
+ global $wp_version;
238
+
239
+ $get_locale = get_locale();
240
+
241
+ if ( $wp_version >= 4.7 ) {
242
+ $get_locale = get_user_locale();
243
+ }
244
+
245
+ /**
246
+ * Language Locale for CartFlows Ca
247
+ *
248
+ * @var $get_locale The locale to use.
249
+ * Uses get_user_locale()` in WordPress 4.7 or greater,
250
+ * otherwise uses `get_locale()`.
251
+ */
252
+ $locale = apply_filters( 'plugin_locale', $get_locale, 'cartflows-ca' );
253
+ $mofile = sprintf( '%1$s-%2$s.mo', 'cartflows-ca', $locale );
254
+
255
+ // Setup paths to current locale file.
256
+ $mofile_local = $lang_dir . $mofile;
257
+ $mofile_global = WP_LANG_DIR . '/plugins/' . $mofile;
258
+
259
+ if ( file_exists( $mofile_global ) ) {
260
+ // Look in global /wp-content/languages/%plugin-folder-name%/ folder.
261
+ load_textdomain( 'cartflows-ca', $mofile_global );
262
+ } elseif ( file_exists( $mofile_local ) ) {
263
+ // Look in local /wp-content/plugins/%plugin-folder-name%/languages/ folder.
264
+ load_textdomain( 'cartflows-ca', $mofile_local );
265
+ } else {
266
+ // Load the default language files.
267
+ load_plugin_textdomain( 'cartflows-ca', false, $lang_dir );
268
+ }
269
+ }
270
+ /**
271
+ * Load Core Components.
272
+ *
273
+ * @since 1.0.0
274
+ *
275
+ * @return void
276
+ */
277
+ function load_core_components() {
278
+
279
+ /* Cart abandonment templates class */
280
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-module-loader.php';
281
+
282
+ }
283
+
284
+
285
+ /**
286
+ * Activation Reset
287
+ */
288
+ function activation_reset() {
289
+ $this->update_default_settings();
290
+ $this->initialize_cart_abandonment_tables();
291
+ }
292
+
293
+
294
+ /**
295
+ * Set the default cart abandonment settings.
296
+ */
297
+ function update_default_settings() {
298
+
299
+ $current_user = wp_get_current_user();
300
+ $email_from = ( isset( $current_user->user_firstname ) && ! empty( $current_user->user_firstname ) ) ? $current_user->user_firstname . ' ' . $current_user->user_lastname : 'Admin';
301
+ $default_settings = array(
302
+ 'wcf_ca_status' => 'on',
303
+ 'wcf_ca_gdpr_status' => 'off',
304
+ 'wcf_ca_coupon_code_status' => 'off',
305
+ 'wcf_ca_zapier_tracking_status' => 'off',
306
+ 'wcf_ca_cut_off_time' => 15,
307
+ 'wcf_ca_from_name' => $email_from,
308
+ 'wcf_ca_from_email' => $current_user->user_email,
309
+ 'wcf_ca_reply_email' => $current_user->user_email,
310
+ 'wcf_ca_discount_type' => 'percent',
311
+ 'wcf_ca_coupon_amount' => 10,
312
+ 'wcf_ca_zapier_cart_abandoned_webhook' => '',
313
+ 'wcf_ca_gdpr_message' => 'Your email & cart are saved so we can send email reminders about this order.',
314
+ 'wcf_ca_coupon_expiry' => 0,
315
+ 'wcf_ca_coupon_expiry_unit' => 'hours',
316
+ );
317
+
318
+ foreach ( $default_settings as $option_key => $option_value ) {
319
+ if ( ! get_option( $option_key ) ) {
320
+ update_option( $option_key, $option_value );
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Deactivation Reset
327
+ */
328
+ function deactivation_reset() {
329
+ wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
330
+ }
331
+
332
+ }
333
+
334
+ /**
335
+ * Prepare if class 'CARTFLOWS_CA_Loader' exist.
336
+ * Kicking this off by calling 'get_instance()' method
337
+ */
338
+ CARTFLOWS_CA_Loader::get_instance();
339
+ }
340
+
341
+
342
+ if ( ! function_exists( 'wcf_ca' ) ) {
343
+ /**
344
+ * Get global class.
345
+ *
346
+ * @return object
347
+ */
348
+ function wcf_ca() {
349
+ return CARTFLOWS_CA_Loader::get_instance();
350
+ }
351
+ }
352
+
classes/class-cartflows-ca-settings.php CHANGED
@@ -1,569 +1,569 @@
1
- <?php
2
- /**
3
- * Settings.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- /**
9
- * Class Cartflows_Ca_Utils.
10
- */
11
- class Cartflows_Ca_Settings {
12
-
13
-
14
- /**
15
- * Member Variable
16
- *
17
- * @var instance
18
- */
19
- private static $instance;
20
-
21
-
22
- /**
23
- * Cartflows_Ca_Settings constructor.
24
- */
25
- public function __construct() {
26
- add_action( 'admin_init', array( $this, 'wcf_initialize_settings' ) );
27
- add_filter( 'plugin_action_links_' . CARTFLOWS_CA_BASE, array( $this, 'add_action_links' ), 999 );
28
- }
29
-
30
- /**
31
- * Adding action links for plugin list page.
32
- *
33
- * @param array $links links.
34
- * @return array
35
- */
36
- public function add_action_links( $links ) {
37
- $mylinks = array(
38
- '<a href="' . admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME ) . '">Settings</a>',
39
- );
40
-
41
- return array_merge( $mylinks, $links );
42
- }
43
- /**
44
- * Add new settings for cart abandonment settings.
45
- *
46
- * @since 1.1.5
47
- */
48
- function wcf_initialize_settings() {
49
-
50
- // Start: Settings for cart abandonment.
51
- add_settings_section(
52
- WCF_CA_GENERAL_SETTINGS_SECTION,
53
- __( 'Cart Abandonment Settings', 'cartflows-ca' ),
54
- array( $this, 'wcf_cart_abandonment_options_callback' ),
55
- WCF_CA_PAGE_NAME
56
- );
57
-
58
- add_settings_field(
59
- 'wcf_ca_status',
60
- __( 'Enable Cart Abandonment Tracking', 'cartflows-ca' ),
61
- array( $this, 'wcf_ca_status_callback' ),
62
- WCF_CA_PAGE_NAME,
63
- WCF_CA_GENERAL_SETTINGS_SECTION,
64
- array( __( 'Start capturing abandoned carts. <br/><br/> <span class="description"><strong>Note:</strong> Cart will be considered abandoned if order is not completed in <strong>15 minutes</strong>.</span>', 'cartflows-ca' ) )
65
- );
66
-
67
- register_setting(
68
- WCF_CA_SETTINGS_OPTION_GROUP,
69
- 'wcf_ca_status'
70
- );
71
-
72
- // End: Settings for cart abandonment.
73
- // Start: Settings for email templates.
74
- add_settings_section(
75
- WCF_CA_EMAIL_SETTINGS_SECTION,
76
- __( 'Email settings', 'cartflows-ca' ),
77
- array( $this, 'wcf_cart_abandonment_options_callback' ),
78
- WCF_CA_PAGE_NAME
79
- );
80
-
81
- add_settings_field(
82
- 'wcf_ca_from_name',
83
- __( '"From" Name', 'cartflows-ca' ),
84
- array( $this, 'wcf_ca_from_name_callback' ),
85
- WCF_CA_PAGE_NAME,
86
- WCF_CA_EMAIL_SETTINGS_SECTION,
87
- array( 'Name will appear in email sent.', 'cartflows-ca' )
88
- );
89
-
90
- add_settings_field(
91
- 'wcf_ca_from_email',
92
- __( '"From" Address', 'cartflows-ca' ),
93
- array( $this, 'wcf_ca_from_email_callback' ),
94
- WCF_CA_PAGE_NAME,
95
- WCF_CA_EMAIL_SETTINGS_SECTION,
96
- array( 'Email which send from.', 'cartflows-ca' )
97
- );
98
-
99
- add_settings_field(
100
- 'wcf_ca_reply_email',
101
- __( 'Send Reply Emails to', 'cartflows-ca' ),
102
- array( $this, 'wcf_ca_reply_email_callback' ),
103
- WCF_CA_PAGE_NAME,
104
- WCF_CA_EMAIL_SETTINGS_SECTION,
105
- array( 'When a user clicks reply, which email address should that reply be sent to?', 'cartflows-ca' )
106
- );
107
-
108
- register_setting(
109
- WCF_CA_SETTINGS_OPTION_GROUP,
110
- 'wcf_ca_from_name'
111
- );
112
-
113
- register_setting(
114
- WCF_CA_SETTINGS_OPTION_GROUP,
115
- 'wcf_ca_from_email',
116
- array( $this, 'wcf_ca_from_email_validation' )
117
- );
118
-
119
- register_setting(
120
- WCF_CA_SETTINGS_OPTION_GROUP,
121
- 'wcf_ca_reply_email',
122
- array( $this, 'wcf_ca_reply_email_validation' )
123
- );
124
- // End: Settings for email templates.
125
- // Start: Settings for coupon code.
126
- add_settings_field(
127
- 'wcf_ca_zapier_tracking_status',
128
- __( 'Enable Webhook', 'cartflows-ca' ),
129
- array( $this, 'wcf_ca_zapier_tracking_status_callback' ),
130
- WCF_CA_PAGE_NAME,
131
- WCF_CA_ZAPIER_SETTINGS_SECTION,
132
- array( __( 'Allows you to trigger webhooks automatically upon cart abandonment and recovery.', 'cartflows-ca' ) )
133
- );
134
-
135
- add_settings_field(
136
- 'wcf_ca_zapier_cart_abandoned_webhook',
137
- __( 'Webhook URL', 'cartflows-ca' ),
138
- array( $this, 'wcf_ca_zapier_cart_abandoned_webhook_callback' ),
139
- WCF_CA_PAGE_NAME,
140
- WCF_CA_ZAPIER_SETTINGS_SECTION,
141
- array( '', 'cartflows-ca' )
142
- );
143
-
144
- register_setting(
145
- WCF_CA_SETTINGS_OPTION_GROUP,
146
- 'wcf_ca_zapier_tracking_status'
147
- );
148
-
149
- register_setting(
150
- WCF_CA_SETTINGS_OPTION_GROUP,
151
- 'wcf_ca_zapier_cart_abandoned_webhook'
152
- );
153
-
154
- add_settings_section(
155
- WCF_CA_ZAPIER_SETTINGS_SECTION,
156
- __( 'Coupon Code Settings', 'cartflows-ca' ),
157
- array( $this, 'wcf_cart_abandonment_options_callback' ),
158
- WCF_CA_PAGE_NAME
159
- );
160
-
161
- add_settings_field(
162
- 'wcf_ca_coupon_code_status',
163
- __( 'Create Coupon Code', 'cartflows-ca' ),
164
- array( $this, 'wcf_ca_coupon_code_status_callback' ),
165
- WCF_CA_PAGE_NAME,
166
- WCF_CA_ZAPIER_SETTINGS_SECTION,
167
- array( __( 'Auto-create the special coupon for the abandoned cart to send over the emails.', 'cartflows-ca' ) )
168
- );
169
-
170
- add_settings_field(
171
- 'wcf_ca_discount_type',
172
- __( 'Discount Type', 'cartflows-ca' ),
173
- array( $this, 'wcf_ca_discount_type_callback' ),
174
- WCF_CA_PAGE_NAME,
175
- WCF_CA_ZAPIER_SETTINGS_SECTION,
176
- array( '', 'cartflows-ca' )
177
- );
178
-
179
- add_settings_field(
180
- 'wcf_ca_coupon_amount',
181
- __( 'Coupon Amount', 'cartflows-ca' ),
182
- array( $this, 'wcf_ca_coupon_amount_callback' ),
183
- WCF_CA_PAGE_NAME,
184
- WCF_CA_ZAPIER_SETTINGS_SECTION,
185
- array( '', 'cartflows-ca' )
186
- );
187
-
188
- add_settings_field(
189
- 'wcf_ca_coupon_expiry',
190
- __( 'Coupon Expires After', 'cartflows-ca' ),
191
- array( $this, 'wcf_ca_coupon_expiry_callback' ),
192
- WCF_CA_PAGE_NAME,
193
- WCF_CA_ZAPIER_SETTINGS_SECTION,
194
- array( '<br/><br/> <span class="description"><strong>Note: </strong> Enter zero (0) to restrict coupon from expiring.</span>', 'cartflows-ca' )
195
- );
196
-
197
- register_setting(
198
- WCF_CA_SETTINGS_OPTION_GROUP,
199
- 'wcf_ca_coupon_expiry'
200
- );
201
- register_setting(
202
- WCF_CA_SETTINGS_OPTION_GROUP,
203
- 'wcf_ca_coupon_expiry_unit'
204
- );
205
-
206
- register_setting(
207
- WCF_CA_SETTINGS_OPTION_GROUP,
208
- 'wcf_ca_coupon_code_status'
209
- );
210
-
211
- register_setting(
212
- WCF_CA_SETTINGS_OPTION_GROUP,
213
- 'wcf_ca_discount_type'
214
- );
215
-
216
- register_setting(
217
- WCF_CA_SETTINGS_OPTION_GROUP,
218
- 'wcf_ca_coupon_amount',
219
- array( $this, 'wcf_ca_coupon_amount_validation' )
220
- );
221
- // End: Settings for coupon code.
222
- // Start: Settings for Zapier.
223
- add_settings_section(
224
- WCF_CA_ZAPIER_SETTINGS_SECTION,
225
- __( 'Webhook Settings', 'cartflows-ca' ),
226
- array( $this, 'wcf_cart_abandonment_options_callback' ),
227
- WCF_CA_PAGE_NAME
228
- );
229
-
230
- // End: Settings for webhook.
231
- // Start: GDPR Settings.
232
- add_settings_section(
233
- WCF_CA_GDPR_SETTINGS_SECTION,
234
- __( 'GDPR Settings', 'cartflows-ca' ),
235
- array( $this, 'wcf_cart_abandonment_options_callback' ),
236
- WCF_CA_PAGE_NAME
237
- );
238
-
239
- add_settings_field(
240
- 'wcf_ca_gdpr_status',
241
- __( 'Enable GDPR integration', 'cartflows-ca' ),
242
- array( $this, 'wcf_ca_gdpr_status_callback' ),
243
- WCF_CA_PAGE_NAME,
244
- WCF_CA_GDPR_SETTINGS_SECTION,
245
- array( __( 'Ask confirmation from the user before tracking data. <br/><br/> <span class="description"><strong>Note:</strong> By checking this, it will show up confirmation text below the email id on checkout page.</span>', 'cartflows-ca' ) )
246
- );
247
-
248
- add_settings_field(
249
- 'wcf_ca_gdpr_message',
250
- __( 'GDPR Message', 'cartflows-ca' ),
251
- array( $this, 'wcf_ca_gdpr_message_callback' ),
252
- WCF_CA_PAGE_NAME,
253
- WCF_CA_GDPR_SETTINGS_SECTION,
254
- array( '', 'cartflows-ca' )
255
- );
256
-
257
- register_setting(
258
- WCF_CA_SETTINGS_OPTION_GROUP,
259
- 'wcf_ca_gdpr_status'
260
- );
261
- register_setting(
262
- WCF_CA_SETTINGS_OPTION_GROUP,
263
- 'wcf_ca_gdpr_message'
264
- );
265
-
266
- }
267
-
268
- /**
269
- * Callback for cart abandonment status.
270
- *
271
- * @param array $args args.
272
- * @since 1.1.5
273
- */
274
- function wcf_ca_coupon_code_status_callback( $args ) {
275
- $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
276
- $html = '';
277
- printf(
278
- '<input type="checkbox" id="wcf_ca_coupon_code_status" name="wcf_ca_coupon_code_status" value="on"
279
- ' . checked( 'on', $wcf_ca_coupon_code_status, false ) . ' />'
280
- );
281
- $html .= '<label for="wcf_ca_coupon_code_status"> ' . $args[0] . '</label>';
282
- echo $html;
283
- }
284
-
285
-
286
- /**
287
- * Callback for cart abandonment cut off time.
288
- *
289
- * @param array $args args.
290
- * @since 1.1.5
291
- */
292
- function wcf_ca_zapier_cart_abandoned_webhook_callback( $args ) {
293
- $wcf_ca_zapier_cart_abandoned_webhook = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
294
- echo '<input type="text" class="wcf-ca-trigger-input" id="wcf_ca_zapier_cart_abandoned_webhook" name="wcf_ca_zapier_cart_abandoned_webhook" value="' . sanitize_text_field( $wcf_ca_zapier_cart_abandoned_webhook ) . '" />';
295
- echo '<button id="wcf_ca_trigger_web_hook_abandoned_btn" type="button" class="button"> Trigger Sample </button>';
296
- echo '<span style="margin-left: 10px;" id="wcf_ca_abandoned_btn_message"></span>';
297
- $html = '<label for="wcf_ca_zapier_cart_abandoned_webhook"> ' . $args[0] . '</label>';
298
- echo $html;
299
- }
300
-
301
-
302
- /**
303
- * Callback for cart abandonment status.
304
- *
305
- * @param array $args args.
306
- * @since 1.1.5
307
- */
308
- function wcf_ca_zapier_tracking_status_callback( $args ) {
309
- $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
310
-
311
- $html = '';
312
- printf(
313
- '<input type="checkbox" id="wcf_ca_zapier_tracking_status" name="wcf_ca_zapier_tracking_status" value="on"
314
- ' . checked( 'on', $wcf_ca_zapier_tracking_status, false ) . ' />'
315
- );
316
- $html .= '<label for="wcf_ca_zapier_tracking_status"> ' . $args[0] . '</label>';
317
- echo $html;
318
- }
319
-
320
-
321
- /**
322
- * Callback for cart abandonment cut off time.
323
- *
324
- * @param array $args args.
325
- * @since 1.1.5
326
- */
327
- function wcf_ca_coupon_amount_callback( $args ) {
328
- $wcf_ca_coupon_amount = get_option( 'wcf_ca_coupon_amount' );
329
- printf(
330
- '<input type="number" class="wcf-ca-trigger-input wcf-ca-email-inputs" id="wcf_ca_coupon_amount" name="wcf_ca_coupon_amount" value="%s" />',
331
- isset( $wcf_ca_coupon_amount ) ? esc_attr( $wcf_ca_coupon_amount ) : ''
332
- );
333
- $html = '<label for="wcf_ca_coupon_amount"> ' . $args[0] . '</label>';
334
- echo $html;
335
- }
336
-
337
- /**
338
- * Callback for cart abandonment cut off time.
339
- *
340
- * @param array $args args.
341
- * @since 1.1.5
342
- */
343
- function wcf_ca_coupon_expiry_callback( $args ) {
344
- $wcf_ca_coupon_expiry = intval( get_option( 'wcf_ca_coupon_expiry' ) );
345
- printf(
346
- '<input type="number" class="wcf-ca-trigger-input wcf-ca-coupon-inputs" id="wcf_ca_coupon_expiry" name="wcf_ca_coupon_expiry" value="%s" autocomplete="off" />',
347
- isset( $wcf_ca_coupon_expiry ) ? esc_attr( $wcf_ca_coupon_expiry ) : ''
348
- );
349
-
350
- $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
351
- $items = array(
352
- 'hours' => 'Hour(s)',
353
- 'days' => 'Day(s)',
354
- );
355
- echo "<select id='wcf_ca_coupon_expiry_unit' name='wcf_ca_coupon_expiry_unit'>";
356
- foreach ( $items as $key => $item ) {
357
- $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
358
- echo "<option value='$key' $selected>$item</option>";
359
- }
360
- echo '</select>';
361
-
362
- $html = '<label for="wcf_ca_coupon_expiry_unit"> ' . $args[0] . '</label>';
363
- echo $html;
364
- }
365
-
366
-
367
-
368
- /**
369
- * Callback for cart abandonment cut off time.
370
- *
371
- * @param array $args args.
372
- * @since 1.1.5
373
- */
374
- function wcf_ca_gdpr_message_callback( $args ) {
375
- $wcf_ca_gdpr_message = get_option( 'wcf_ca_gdpr_message' );
376
-
377
- printf(
378
- '<textarea rows="2" cols="60" id="wcf_ca_gdpr_message" name="wcf_ca_gdpr_message" spellcheck="false">%s</textarea>',
379
- isset( $wcf_ca_gdpr_message ) ? esc_attr( $wcf_ca_gdpr_message ) : ''
380
- );
381
- $html = '<label for="wcf_ca_gdpr_message"> ' . $args[0] . '</label>';
382
- echo $html;
383
- }
384
-
385
- /**
386
- * Callback for cart abandonment cut off time.
387
- *
388
- * @param array $args args.
389
- * @since 1.1.5
390
- */
391
- function wcf_ca_discount_type_callback( $args ) {
392
-
393
- $discount_type = get_option( 'wcf_ca_discount_type' );
394
- $items = array(
395
- 'percent' => 'Percentage discount',
396
- 'fixed_cart' => 'Fixed cart discount',
397
- );
398
- echo "<select id='wcf_ca_discount_type' name='wcf_ca_discount_type'>";
399
- foreach ( $items as $key => $item ) {
400
- $selected = ( $discount_type === $key ) ? 'selected="selected"' : '';
401
- echo "<option value='$key' $selected>$item</option>";
402
- }
403
- echo '</select>';
404
- }
405
-
406
- /**
407
- * Validation for cart abandonment `cut-off` settings.
408
- *
409
- * @param array $input input.
410
- * @since 1.1.5
411
- */
412
- function wcf_ca_coupon_amount_validation( $input ) {
413
-
414
- $output = '';
415
- if ( ( is_numeric( $input ) && $input >= 1 ) ) {
416
- $output = stripslashes( $input );
417
- } else {
418
- add_settings_error(
419
- 'wcf_ca_coupon_amount',
420
- 'error found',
421
- __( 'Coupon code should be numeric and has to be greater than or equals to 1.', 'cartflows-ca' )
422
- );
423
- }
424
- return $output;
425
- }
426
-
427
- /**
428
- * Callback for cart abandonment options.
429
- *
430
- * @since 1.1.5
431
- */
432
- function wcf_cart_abandonment_options_callback() {
433
- echo '<hr/>';
434
- }
435
-
436
-
437
- /**
438
- * Callback for cart abandonment status.
439
- *
440
- * @param array $args args.
441
- * @since 1.1.5
442
- */
443
- function wcf_ca_status_callback( $args ) {
444
- $wcf_ca_status = get_option( 'wcf_ca_status' );
445
- $html = '';
446
- printf(
447
- '<input type="checkbox" id="wcf_ca_status" name="wcf_ca_status" value="on"
448
- ' . checked( 'on', $wcf_ca_status, false ) . ' />'
449
- );
450
- $html .= '<label for="wcf_ca_status"> ' . $args[0] . '</label>';
451
- echo $html;
452
- }
453
-
454
- /**
455
- * Callback for cart abandonment status.
456
- *
457
- * @param array $args args.
458
- * @since 1.1.5
459
- */
460
- function wcf_ca_gdpr_status_callback( $args ) {
461
- $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
462
- $html = '';
463
- printf(
464
- '<input type="checkbox" id="wcf_ca_gdpr_status" name="wcf_ca_gdpr_status" value="on"
465
- ' . checked( 'on', $wcf_ca_gdpr_status, false ) . ' />'
466
- );
467
- $html .= '<label for="wcf_ca_gdpr_status"> ' . $args[0] . '</label>';
468
- echo $html;
469
- }
470
-
471
- /**
472
- * Callback for email from name.
473
- *
474
- * @param array $args Arguments.
475
- */
476
- public static function wcf_ca_from_name_callback( $args ) {
477
- $wcf_ca_from_name = get_option( 'wcf_ca_from_name' );
478
- printf(
479
- '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_name" name="wcf_ca_from_name" value="%s" />',
480
- isset( $wcf_ca_from_name ) ? esc_attr( $wcf_ca_from_name ) : ''
481
- );
482
- $html = '<label for="wcf_ca_from_name"> ' . $args[0] . '</label>';
483
- echo $html;
484
- }
485
-
486
- /**
487
- * Callback for email from.
488
- *
489
- * @param array $args Arguments.
490
- */
491
- public static function wcf_ca_from_email_callback( $args ) {
492
- $wcf_ca_from_email = get_option( 'wcf_ca_from_email' );
493
- printf(
494
- '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_email" name="wcf_ca_from_email" value="%s" />',
495
- isset( $wcf_ca_from_email ) ? esc_attr( $wcf_ca_from_email ) : ''
496
- );
497
- $html = '<label for="wcf_ca_from_email"> ' . $args[0] . '</label>';
498
- echo $html;
499
- }
500
-
501
- /**
502
- * Callback for email reply.
503
- *
504
- * @param array $args Arguments.
505
- * @since 3.5
506
- */
507
- public static function wcf_ca_reply_email_callback( $args ) {
508
- $wcf_ca_reply_email = get_option( 'wcf_ca_reply_email' );
509
- printf(
510
- '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_reply_email" name="wcf_ca_reply_email" value="%s" />',
511
- isset( $wcf_ca_reply_email ) ? esc_attr( $wcf_ca_reply_email ) : ''
512
- );
513
-
514
- $html = '<label for="wcf_ca_reply_email"> ' . $args[0] . '</label>';
515
- echo $html;
516
- }
517
-
518
-
519
- /**
520
- * Validation for email.
521
- *
522
- * @param array $input input.
523
- * @since 1.1.5
524
- */
525
- function wcf_ca_from_email_validation( $input ) {
526
-
527
- if ( $input && ! is_email( $input ) ) {
528
- add_settings_error(
529
- 'wcf_ca_from_email',
530
- 'error found',
531
- __( 'Invalid email "From" address field', 'cartflows-ca' )
532
- );
533
- }
534
- return sanitize_email( $input );
535
- }
536
-
537
- /**
538
- * Validation for reply email.
539
- *
540
- * @param array $input input.
541
- * @since 1.1.5
542
- */
543
- function wcf_ca_reply_email_validation( $input ) {
544
-
545
- if ( $input && ! is_email( $input ) ) {
546
- add_settings_error(
547
- 'wcf_ca_reply_email',
548
- 'error found',
549
- __( 'Invalid email "Reply" address field', 'cartflows-ca' )
550
- );
551
- }
552
- return sanitize_email( $input );
553
- }
554
-
555
- /**
556
- * Initiator
557
- */
558
- public static function get_instance() {
559
- if ( ! isset( self::$instance ) ) {
560
- self::$instance = new self;
561
- }
562
- return self::$instance;
563
- }
564
-
565
-
566
-
567
-
568
- }
569
- Cartflows_Ca_Settings::get_instance();
1
+ <?php
2
+ /**
3
+ * Settings.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ /**
9
+ * Class Cartflows_Ca_Utils.
10
+ */
11
+ class Cartflows_Ca_Settings {
12
+
13
+
14
+ /**
15
+ * Member Variable
16
+ *
17
+ * @var instance
18
+ */
19
+ private static $instance;
20
+
21
+
22
+ /**
23
+ * Cartflows_Ca_Settings constructor.
24
+ */
25
+ public function __construct() {
26
+ add_action( 'admin_init', array( $this, 'wcf_initialize_settings' ) );
27
+ add_filter( 'plugin_action_links_' . CARTFLOWS_CA_BASE, array( $this, 'add_action_links' ), 999 );
28
+ }
29
+
30
+ /**
31
+ * Adding action links for plugin list page.
32
+ *
33
+ * @param array $links links.
34
+ * @return array
35
+ */
36
+ public function add_action_links( $links ) {
37
+ $mylinks = array(
38
+ '<a href="' . admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME ) . '">Settings</a>',
39
+ );
40
+
41
+ return array_merge( $mylinks, $links );
42
+ }
43
+ /**
44
+ * Add new settings for cart abandonment settings.
45
+ *
46
+ * @since 1.1.5
47
+ */
48
+ function wcf_initialize_settings() {
49
+
50
+ // Start: Settings for cart abandonment.
51
+ add_settings_section(
52
+ WCF_CA_GENERAL_SETTINGS_SECTION,
53
+ __( 'Cart Abandonment Settings', 'cartflows-ca' ),
54
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
55
+ WCF_CA_PAGE_NAME
56
+ );
57
+
58
+ add_settings_field(
59
+ 'wcf_ca_status',
60
+ __( 'Enable Cart Abandonment Tracking', 'cartflows-ca' ),
61
+ array( $this, 'wcf_ca_status_callback' ),
62
+ WCF_CA_PAGE_NAME,
63
+ WCF_CA_GENERAL_SETTINGS_SECTION,
64
+ array( __( 'Start capturing abandoned carts. <br/><br/> <span class="description"><strong>Note:</strong> Cart will be considered abandoned if order is not completed in <strong>15 minutes</strong>.</span>', 'cartflows-ca' ) )
65
+ );
66
+
67
+ register_setting(
68
+ WCF_CA_SETTINGS_OPTION_GROUP,
69
+ 'wcf_ca_status'
70
+ );
71
+
72
+ // End: Settings for cart abandonment.
73
+ // Start: Settings for email templates.
74
+ add_settings_section(
75
+ WCF_CA_EMAIL_SETTINGS_SECTION,
76
+ __( 'Email settings', 'cartflows-ca' ),
77
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
78
+ WCF_CA_PAGE_NAME
79
+ );
80
+
81
+ add_settings_field(
82
+ 'wcf_ca_from_name',
83
+ __( '"From" Name', 'cartflows-ca' ),
84
+ array( $this, 'wcf_ca_from_name_callback' ),
85
+ WCF_CA_PAGE_NAME,
86
+ WCF_CA_EMAIL_SETTINGS_SECTION,
87
+ array( 'Name will appear in email sent.', 'cartflows-ca' )
88
+ );
89
+
90
+ add_settings_field(
91
+ 'wcf_ca_from_email',
92
+ __( '"From" Address', 'cartflows-ca' ),
93
+ array( $this, 'wcf_ca_from_email_callback' ),
94
+ WCF_CA_PAGE_NAME,
95
+ WCF_CA_EMAIL_SETTINGS_SECTION,
96
+ array( 'Email which send from.', 'cartflows-ca' )
97
+ );
98
+
99
+ add_settings_field(
100
+ 'wcf_ca_reply_email',
101
+ __( 'Send Reply Emails to', 'cartflows-ca' ),
102
+ array( $this, 'wcf_ca_reply_email_callback' ),
103
+ WCF_CA_PAGE_NAME,
104
+ WCF_CA_EMAIL_SETTINGS_SECTION,
105
+ array( 'When a user clicks reply, which email address should that reply be sent to?', 'cartflows-ca' )
106
+ );
107
+
108
+ register_setting(
109
+ WCF_CA_SETTINGS_OPTION_GROUP,
110
+ 'wcf_ca_from_name'
111
+ );
112
+
113
+ register_setting(
114
+ WCF_CA_SETTINGS_OPTION_GROUP,
115
+ 'wcf_ca_from_email',
116
+ array( $this, 'wcf_ca_from_email_validation' )
117
+ );
118
+
119
+ register_setting(
120
+ WCF_CA_SETTINGS_OPTION_GROUP,
121
+ 'wcf_ca_reply_email',
122
+ array( $this, 'wcf_ca_reply_email_validation' )
123
+ );
124
+ // End: Settings for email templates.
125
+ // Start: Settings for coupon code.
126
+ add_settings_field(
127
+ 'wcf_ca_zapier_tracking_status',
128
+ __( 'Enable Webhook', 'cartflows-ca' ),
129
+ array( $this, 'wcf_ca_zapier_tracking_status_callback' ),
130
+ WCF_CA_PAGE_NAME,
131
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
132
+ array( __( 'Allows you to trigger webhooks automatically upon cart abandonment and recovery.', 'cartflows-ca' ) )
133
+ );
134
+
135
+ add_settings_field(
136
+ 'wcf_ca_zapier_cart_abandoned_webhook',
137
+ __( 'Webhook URL', 'cartflows-ca' ),
138
+ array( $this, 'wcf_ca_zapier_cart_abandoned_webhook_callback' ),
139
+ WCF_CA_PAGE_NAME,
140
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
141
+ array( '', 'cartflows-ca' )
142
+ );
143
+
144
+ register_setting(
145
+ WCF_CA_SETTINGS_OPTION_GROUP,
146
+ 'wcf_ca_zapier_tracking_status'
147
+ );
148
+
149
+ register_setting(
150
+ WCF_CA_SETTINGS_OPTION_GROUP,
151
+ 'wcf_ca_zapier_cart_abandoned_webhook'
152
+ );
153
+
154
+ add_settings_section(
155
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
156
+ __( 'Coupon Code Settings', 'cartflows-ca' ),
157
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
158
+ WCF_CA_PAGE_NAME
159
+ );
160
+
161
+ add_settings_field(
162
+ 'wcf_ca_coupon_code_status',
163
+ __( 'Create Coupon Code', 'cartflows-ca' ),
164
+ array( $this, 'wcf_ca_coupon_code_status_callback' ),
165
+ WCF_CA_PAGE_NAME,
166
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
167
+ array( __( 'Auto-create the special coupon for the abandoned cart to send over the emails.', 'cartflows-ca' ) )
168
+ );
169
+
170
+ add_settings_field(
171
+ 'wcf_ca_discount_type',
172
+ __( 'Discount Type', 'cartflows-ca' ),
173
+ array( $this, 'wcf_ca_discount_type_callback' ),
174
+ WCF_CA_PAGE_NAME,
175
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
176
+ array( '', 'cartflows-ca' )
177
+ );
178
+
179
+ add_settings_field(
180
+ 'wcf_ca_coupon_amount',
181
+ __( 'Coupon Amount', 'cartflows-ca' ),
182
+ array( $this, 'wcf_ca_coupon_amount_callback' ),
183
+ WCF_CA_PAGE_NAME,
184
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
185
+ array( '', 'cartflows-ca' )
186
+ );
187
+
188
+ add_settings_field(
189
+ 'wcf_ca_coupon_expiry',
190
+ __( 'Coupon Expires After', 'cartflows-ca' ),
191
+ array( $this, 'wcf_ca_coupon_expiry_callback' ),
192
+ WCF_CA_PAGE_NAME,
193
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
194
+ array( '<br/><br/> <span class="description"><strong>Note: </strong> Enter zero (0) to restrict coupon from expiring.</span>', 'cartflows-ca' )
195
+ );
196
+
197
+ register_setting(
198
+ WCF_CA_SETTINGS_OPTION_GROUP,
199
+ 'wcf_ca_coupon_expiry'
200
+ );
201
+ register_setting(
202
+ WCF_CA_SETTINGS_OPTION_GROUP,
203
+ 'wcf_ca_coupon_expiry_unit'
204
+ );
205
+
206
+ register_setting(
207
+ WCF_CA_SETTINGS_OPTION_GROUP,
208
+ 'wcf_ca_coupon_code_status'
209
+ );
210
+
211
+ register_setting(
212
+ WCF_CA_SETTINGS_OPTION_GROUP,
213
+ 'wcf_ca_discount_type'
214
+ );
215
+
216
+ register_setting(
217
+ WCF_CA_SETTINGS_OPTION_GROUP,
218
+ 'wcf_ca_coupon_amount',
219
+ array( $this, 'wcf_ca_coupon_amount_validation' )
220
+ );
221
+ // End: Settings for coupon code.
222
+ // Start: Settings for Zapier.
223
+ add_settings_section(
224
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
225
+ __( 'Webhook Settings', 'cartflows-ca' ),
226
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
227
+ WCF_CA_PAGE_NAME
228
+ );
229
+
230
+ // End: Settings for webhook.
231
+ // Start: GDPR Settings.
232
+ add_settings_section(
233
+ WCF_CA_GDPR_SETTINGS_SECTION,
234
+ __( 'GDPR Settings', 'cartflows-ca' ),
235
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
236
+ WCF_CA_PAGE_NAME
237
+ );
238
+
239
+ add_settings_field(
240
+ 'wcf_ca_gdpr_status',
241
+ __( 'Enable GDPR integration', 'cartflows-ca' ),
242
+ array( $this, 'wcf_ca_gdpr_status_callback' ),
243
+ WCF_CA_PAGE_NAME,
244
+ WCF_CA_GDPR_SETTINGS_SECTION,
245
+ array( __( 'Ask confirmation from the user before tracking data. <br/><br/> <span class="description"><strong>Note:</strong> By checking this, it will show up confirmation text below the email id on checkout page.</span>', 'cartflows-ca' ) )
246
+ );
247
+
248
+ add_settings_field(
249
+ 'wcf_ca_gdpr_message',
250
+ __( 'GDPR Message', 'cartflows-ca' ),
251
+ array( $this, 'wcf_ca_gdpr_message_callback' ),
252
+ WCF_CA_PAGE_NAME,
253
+ WCF_CA_GDPR_SETTINGS_SECTION,
254
+ array( '', 'cartflows-ca' )
255
+ );
256
+
257
+ register_setting(
258
+ WCF_CA_SETTINGS_OPTION_GROUP,
259
+ 'wcf_ca_gdpr_status'
260
+ );
261
+ register_setting(
262
+ WCF_CA_SETTINGS_OPTION_GROUP,
263
+ 'wcf_ca_gdpr_message'
264
+ );
265
+
266
+ }
267
+
268
+ /**
269
+ * Callback for cart abandonment status.
270
+ *
271
+ * @param array $args args.
272
+ * @since 1.1.5
273
+ */
274
+ function wcf_ca_coupon_code_status_callback( $args ) {
275
+ $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
276
+ $html = '';
277
+ printf(
278
+ '<input type="checkbox" id="wcf_ca_coupon_code_status" name="wcf_ca_coupon_code_status" value="on"
279
+ ' . checked( 'on', $wcf_ca_coupon_code_status, false ) . ' />'
280
+ );
281
+ $html .= '<label for="wcf_ca_coupon_code_status"> ' . $args[0] . '</label>';
282
+ echo $html;
283
+ }
284
+
285
+
286
+ /**
287
+ * Callback for cart abandonment cut off time.
288
+ *
289
+ * @param array $args args.
290
+ * @since 1.1.5
291
+ */
292
+ function wcf_ca_zapier_cart_abandoned_webhook_callback( $args ) {
293
+ $wcf_ca_zapier_cart_abandoned_webhook = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
294
+ echo '<input type="text" class="wcf-ca-trigger-input" id="wcf_ca_zapier_cart_abandoned_webhook" name="wcf_ca_zapier_cart_abandoned_webhook" value="' . sanitize_text_field( $wcf_ca_zapier_cart_abandoned_webhook ) . '" />';
295
+ echo '<button id="wcf_ca_trigger_web_hook_abandoned_btn" type="button" class="button"> Trigger Sample </button>';
296
+ echo '<span style="margin-left: 10px;" id="wcf_ca_abandoned_btn_message"></span>';
297
+ $html = '<label for="wcf_ca_zapier_cart_abandoned_webhook"> ' . $args[0] . '</label>';
298
+ echo $html;
299
+ }
300
+
301
+
302
+ /**
303
+ * Callback for cart abandonment status.
304
+ *
305
+ * @param array $args args.
306
+ * @since 1.1.5
307
+ */
308
+ function wcf_ca_zapier_tracking_status_callback( $args ) {
309
+ $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
310
+
311
+ $html = '';
312
+ printf(
313
+ '<input type="checkbox" id="wcf_ca_zapier_tracking_status" name="wcf_ca_zapier_tracking_status" value="on"
314
+ ' . checked( 'on', $wcf_ca_zapier_tracking_status, false ) . ' />'
315
+ );
316
+ $html .= '<label for="wcf_ca_zapier_tracking_status"> ' . $args[0] . '</label>';
317
+ echo $html;
318
+ }
319
+
320
+
321
+ /**
322
+ * Callback for cart abandonment cut off time.
323
+ *
324
+ * @param array $args args.
325
+ * @since 1.1.5
326
+ */
327
+ function wcf_ca_coupon_amount_callback( $args ) {
328
+ $wcf_ca_coupon_amount = get_option( 'wcf_ca_coupon_amount' );
329
+ printf(
330
+ '<input type="number" class="wcf-ca-trigger-input wcf-ca-email-inputs" id="wcf_ca_coupon_amount" name="wcf_ca_coupon_amount" value="%s" />',
331
+ isset( $wcf_ca_coupon_amount ) ? esc_attr( $wcf_ca_coupon_amount ) : ''
332
+ );
333
+ $html = '<label for="wcf_ca_coupon_amount"> ' . $args[0] . '</label>';
334
+ echo $html;
335
+ }
336
+
337
+ /**
338
+ * Callback for cart abandonment cut off time.
339
+ *
340
+ * @param array $args args.
341
+ * @since 1.1.5
342
+ */
343
+ function wcf_ca_coupon_expiry_callback( $args ) {
344
+ $wcf_ca_coupon_expiry = intval( get_option( 'wcf_ca_coupon_expiry' ) );
345
+ printf(
346
+ '<input type="number" class="wcf-ca-trigger-input wcf-ca-coupon-inputs" id="wcf_ca_coupon_expiry" name="wcf_ca_coupon_expiry" value="%s" autocomplete="off" />',
347
+ isset( $wcf_ca_coupon_expiry ) ? esc_attr( $wcf_ca_coupon_expiry ) : ''
348
+ );
349
+
350
+ $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
351
+ $items = array(
352
+ 'hours' => 'Hour(s)',
353
+ 'days' => 'Day(s)',
354
+ );
355
+ echo "<select id='wcf_ca_coupon_expiry_unit' name='wcf_ca_coupon_expiry_unit'>";
356
+ foreach ( $items as $key => $item ) {
357
+ $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
358
+ echo "<option value='$key' $selected>$item</option>";
359
+ }
360
+ echo '</select>';
361
+
362
+ $html = '<label for="wcf_ca_coupon_expiry_unit"> ' . $args[0] . '</label>';
363
+ echo $html;
364
+ }
365
+
366
+
367
+
368
+ /**
369
+ * Callback for cart abandonment cut off time.
370
+ *
371
+ * @param array $args args.
372
+ * @since 1.1.5
373
+ */
374
+ function wcf_ca_gdpr_message_callback( $args ) {
375
+ $wcf_ca_gdpr_message = get_option( 'wcf_ca_gdpr_message' );
376
+
377
+ printf(
378
+ '<textarea rows="2" cols="60" id="wcf_ca_gdpr_message" name="wcf_ca_gdpr_message" spellcheck="false">%s</textarea>',
379
+ isset( $wcf_ca_gdpr_message ) ? esc_attr( $wcf_ca_gdpr_message ) : ''
380
+ );
381
+ $html = '<label for="wcf_ca_gdpr_message"> ' . $args[0] . '</label>';
382
+ echo $html;
383
+ }
384
+
385
+ /**
386
+ * Callback for cart abandonment cut off time.
387
+ *
388
+ * @param array $args args.
389
+ * @since 1.1.5
390
+ */
391
+ function wcf_ca_discount_type_callback( $args ) {
392
+
393
+ $discount_type = get_option( 'wcf_ca_discount_type' );
394
+ $items = array(
395
+ 'percent' => 'Percentage discount',
396
+ 'fixed_cart' => 'Fixed cart discount',
397
+ );
398
+ echo "<select id='wcf_ca_discount_type' name='wcf_ca_discount_type'>";
399
+ foreach ( $items as $key => $item ) {
400
+ $selected = ( $discount_type === $key ) ? 'selected="selected"' : '';
401
+ echo "<option value='$key' $selected>$item</option>";
402
+ }
403
+ echo '</select>';
404
+ }
405
+
406
+ /**
407
+ * Validation for cart abandonment `cut-off` settings.
408
+ *
409
+ * @param array $input input.
410
+ * @since 1.1.5
411
+ */
412
+ function wcf_ca_coupon_amount_validation( $input ) {
413
+
414
+ $output = '';
415
+ if ( ( is_numeric( $input ) && $input >= 1 ) ) {
416
+ $output = stripslashes( $input );
417
+ } else {
418
+ add_settings_error(
419
+ 'wcf_ca_coupon_amount',
420
+ 'error found',
421
+ __( 'Coupon code should be numeric and has to be greater than or equals to 1.', 'cartflows-ca' )
422
+ );
423
+ }
424
+ return $output;
425
+ }
426
+
427
+ /**
428
+ * Callback for cart abandonment options.
429
+ *
430
+ * @since 1.1.5
431
+ */
432
+ function wcf_cart_abandonment_options_callback() {
433
+ echo '<hr/>';
434
+ }
435
+
436
+
437
+ /**
438
+ * Callback for cart abandonment status.
439
+ *
440
+ * @param array $args args.
441
+ * @since 1.1.5
442
+ */
443
+ function wcf_ca_status_callback( $args ) {
444
+ $wcf_ca_status = get_option( 'wcf_ca_status' );
445
+ $html = '';
446
+ printf(
447
+ '<input type="checkbox" id="wcf_ca_status" name="wcf_ca_status" value="on"
448
+ ' . checked( 'on', $wcf_ca_status, false ) . ' />'
449
+ );
450
+ $html .= '<label for="wcf_ca_status"> ' . $args[0] . '</label>';
451
+ echo $html;
452
+ }
453
+
454
+ /**
455
+ * Callback for cart abandonment status.
456
+ *
457
+ * @param array $args args.
458
+ * @since 1.1.5
459
+ */
460
+ function wcf_ca_gdpr_status_callback( $args ) {
461
+ $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
462
+ $html = '';
463
+ printf(
464
+ '<input type="checkbox" id="wcf_ca_gdpr_status" name="wcf_ca_gdpr_status" value="on"
465
+ ' . checked( 'on', $wcf_ca_gdpr_status, false ) . ' />'
466
+ );
467
+ $html .= '<label for="wcf_ca_gdpr_status"> ' . $args[0] . '</label>';
468
+ echo $html;
469
+ }
470
+
471
+ /**
472
+ * Callback for email from name.
473
+ *
474
+ * @param array $args Arguments.
475
+ */
476
+ public static function wcf_ca_from_name_callback( $args ) {
477
+ $wcf_ca_from_name = get_option( 'wcf_ca_from_name' );
478
+ printf(
479
+ '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_name" name="wcf_ca_from_name" value="%s" />',
480
+ isset( $wcf_ca_from_name ) ? esc_attr( $wcf_ca_from_name ) : ''
481
+ );
482
+ $html = '<label for="wcf_ca_from_name"> ' . $args[0] . '</label>';
483
+ echo $html;
484
+ }
485
+
486
+ /**
487
+ * Callback for email from.
488
+ *
489
+ * @param array $args Arguments.
490
+ */
491
+ public static function wcf_ca_from_email_callback( $args ) {
492
+ $wcf_ca_from_email = get_option( 'wcf_ca_from_email' );
493
+ printf(
494
+ '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_email" name="wcf_ca_from_email" value="%s" />',
495
+ isset( $wcf_ca_from_email ) ? esc_attr( $wcf_ca_from_email ) : ''
496
+ );
497
+ $html = '<label for="wcf_ca_from_email"> ' . $args[0] . '</label>';
498
+ echo $html;
499
+ }
500
+
501
+ /**
502
+ * Callback for email reply.
503
+ *
504
+ * @param array $args Arguments.
505
+ * @since 3.5
506
+ */
507
+ public static function wcf_ca_reply_email_callback( $args ) {
508
+ $wcf_ca_reply_email = get_option( 'wcf_ca_reply_email' );
509
+ printf(
510
+ '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_reply_email" name="wcf_ca_reply_email" value="%s" />',
511
+ isset( $wcf_ca_reply_email ) ? esc_attr( $wcf_ca_reply_email ) : ''
512
+ );
513
+
514
+ $html = '<label for="wcf_ca_reply_email"> ' . $args[0] . '</label>';
515
+ echo $html;
516
+ }
517
+
518
+
519
+ /**
520
+ * Validation for email.
521
+ *
522
+ * @param array $input input.
523
+ * @since 1.1.5
524
+ */
525
+ function wcf_ca_from_email_validation( $input ) {
526
+
527
+ if ( $input && ! is_email( $input ) ) {
528
+ add_settings_error(
529
+ 'wcf_ca_from_email',
530
+ 'error found',
531
+ __( 'Invalid email "From" address field', 'cartflows-ca' )
532
+ );
533
+ }
534
+ return sanitize_email( $input );
535
+ }
536
+
537
+ /**
538
+ * Validation for reply email.
539
+ *
540
+ * @param array $input input.
541
+ * @since 1.1.5
542
+ */
543
+ function wcf_ca_reply_email_validation( $input ) {
544
+
545
+ if ( $input && ! is_email( $input ) ) {
546
+ add_settings_error(
547
+ 'wcf_ca_reply_email',
548
+ 'error found',
549
+ __( 'Invalid email "Reply" address field', 'cartflows-ca' )
550
+ );
551
+ }
552
+ return sanitize_email( $input );
553
+ }
554
+
555
+ /**
556
+ * Initiator
557
+ */
558
+ public static function get_instance() {
559
+ if ( ! isset( self::$instance ) ) {
560
+ self::$instance = new self;
561
+ }
562
+ return self::$instance;
563
+ }
564
+
565
+
566
+
567
+
568
+ }
569
+ Cartflows_Ca_Settings::get_instance();
classes/class-cartflows-ca-update.php CHANGED
@@ -1,78 +1,78 @@
1
- <?php
2
- /**
3
- * Update Compatibility
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'Cartflows_Ca_Update' ) ) :
9
-
10
- /**
11
- * CartFlows CA Update initial setup
12
- *
13
- * @since 1.0.0
14
- */
15
- class Cartflows_Ca_Update {
16
-
17
- /**
18
- * Class instance.
19
- *
20
- * @access private
21
- * @var $instance Class instance.
22
- */
23
- private static $instance;
24
-
25
- /**
26
- * Initiator
27
- */
28
- public static function get_instance() {
29
- if ( ! isset( self::$instance ) ) {
30
- self::$instance = new self();
31
- }
32
- return self::$instance;
33
- }
34
-
35
- /**
36
- * Constructor
37
- */
38
- public function __construct() {
39
- add_action( 'admin_init', __CLASS__ . '::init' );
40
- }
41
-
42
- /**
43
- * Init
44
- *
45
- * @since 1.0.0
46
- * @return void
47
- */
48
- static public function init() {
49
-
50
- do_action( 'cartflows_ca_update_before' );
51
-
52
- // Get auto saved version number.
53
- $saved_version = get_option( 'wcf_ca_version', false );
54
-
55
- // Update auto saved version number.
56
- if ( ! $saved_version ) {
57
- update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
58
- return;
59
- }
60
-
61
- // If equals then return.
62
- if ( version_compare( $saved_version, CARTFLOWS_CA_VER, '=' ) ) {
63
- return;
64
- }
65
-
66
- // Update auto saved version number.
67
- update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
68
-
69
- do_action( 'cartflows_ca_update_after' );
70
- }
71
- }
72
-
73
- /**
74
- * Kicking this off by calling 'get_instance()' method
75
- */
76
- Cartflows_Ca_Update::get_instance();
77
-
78
- endif;
1
+ <?php
2
+ /**
3
+ * Update Compatibility
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'Cartflows_Ca_Update' ) ) :
9
+
10
+ /**
11
+ * CartFlows CA Update initial setup
12
+ *
13
+ * @since 1.0.0
14
+ */
15
+ class Cartflows_Ca_Update {
16
+
17
+ /**
18
+ * Class instance.
19
+ *
20
+ * @access private
21
+ * @var $instance Class instance.
22
+ */
23
+ private static $instance;
24
+
25
+ /**
26
+ * Initiator
27
+ */
28
+ public static function get_instance() {
29
+ if ( ! isset( self::$instance ) ) {
30
+ self::$instance = new self();
31
+ }
32
+ return self::$instance;
33
+ }
34
+
35
+ /**
36
+ * Constructor
37
+ */
38
+ public function __construct() {
39
+ add_action( 'admin_init', __CLASS__ . '::init' );
40
+ }
41
+
42
+ /**
43
+ * Init
44
+ *
45
+ * @since 1.0.0
46
+ * @return void
47
+ */
48
+ static public function init() {
49
+
50
+ do_action( 'cartflows_ca_update_before' );
51
+
52
+ // Get auto saved version number.
53
+ $saved_version = get_option( 'wcf_ca_version', false );
54
+
55
+ // Update auto saved version number.
56
+ if ( ! $saved_version ) {
57
+ update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
58
+ return;
59
+ }
60
+
61
+ // If equals then return.
62
+ if ( version_compare( $saved_version, CARTFLOWS_CA_VER, '=' ) ) {
63
+ return;
64
+ }
65
+
66
+ // Update auto saved version number.
67
+ update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
68
+
69
+ do_action( 'cartflows_ca_update_after' );
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Kicking this off by calling 'get_instance()' method
75
+ */
76
+ Cartflows_Ca_Update::get_instance();
77
+
78
+ endif;
classes/class-cartflows-ca-utils.php CHANGED
@@ -1,115 +1,115 @@
1
- <?php
2
- /**
3
- * Utils.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly.
10
- }
11
-
12
- /**
13
- * Class Cartflows_Ca_Utils.
14
- */
15
- class Cartflows_Ca_Utils {
16
-
17
-
18
- /**
19
- * Member Variable
20
- *
21
- * @var instance
22
- */
23
- private static $instance;
24
-
25
- /**
26
- * Common zapier data
27
- *
28
- * @var zapier
29
- */
30
- private static $zapier = null;
31
-
32
- /**
33
- * Common zapier data
34
- *
35
- * @var zapier
36
- */
37
- private static $cart_abandonment_settings = null;
38
-
39
-
40
- /**
41
- * Initiator
42
- */
43
- public static function get_instance() {
44
- if ( ! isset( self::$instance ) ) {
45
- self::$instance = new self;
46
- }
47
- return self::$instance;
48
- }
49
-
50
- /**
51
- * Check if cart abandonment tracking is enabled.
52
- *
53
- * @return bool
54
- */
55
- function is_cart_abandonment_tracking_enabled() {
56
-
57
- $wcf_ca_status = get_option( 'wcf_ca_status' );
58
-
59
- // Check if abandonment cart tracking is disabled or zapier webhook is empty.
60
- if ( isset( $wcf_ca_status ) && 'on' === $wcf_ca_status ) {
61
- return true;
62
- }
63
-
64
- return false;
65
- }
66
-
67
- /**
68
- * Check if cart abandonment tracking is enabled.
69
- *
70
- * @return bool
71
- */
72
- function is_zapier_trigger_enabled() {
73
-
74
- $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
75
-
76
- // Check if zapier tracking is disabled or zapier webhook is empty.
77
- if ( isset( $wcf_ca_zapier_tracking_status ) && 'on' === $wcf_ca_zapier_tracking_status ) {
78
- return true;
79
- }
80
-
81
- return false;
82
- }
83
-
84
- /**
85
- * Get cart abandonment tracking cutoff time.
86
- *
87
- * @param boolean $in_seconds get cutoff time in seconds if true.
88
- * @return bool
89
- */
90
- function get_cart_abandonment_tracking_cut_off_time( $in_seconds = false ) {
91
-
92
- $cart_abandoned_time = apply_filters( 'cartflows_ca_cart_abandonment_cut_off_time', WCF_DEFAULT_CUT_OFF_TIME );
93
- return $in_seconds ? $cart_abandoned_time * MINUTE_IN_SECONDS : $cart_abandoned_time;
94
-
95
- }
96
-
97
- /**
98
- * Check if GDPR is enabled.
99
- *
100
- * @return bool
101
- */
102
- function is_gdpr_enabled() {
103
-
104
- $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
105
-
106
- // Check if abandonment cart tracking is disabled or zapier webhook is empty.
107
- if ( isset( $wcf_ca_gdpr_status ) && 'on' === $wcf_ca_gdpr_status ) {
108
- return true;
109
- }
110
-
111
- return false;
112
- }
113
-
114
-
115
- }
1
+ <?php
2
+ /**
3
+ * Utils.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly.
10
+ }
11
+
12
+ /**
13
+ * Class Cartflows_Ca_Utils.
14
+ */
15
+ class Cartflows_Ca_Utils {
16
+
17
+
18
+ /**
19
+ * Member Variable
20
+ *
21
+ * @var instance
22
+ */
23
+ private static $instance;
24
+
25
+ /**
26
+ * Common zapier data
27
+ *
28
+ * @var zapier
29
+ */
30
+ private static $zapier = null;
31
+
32
+ /**
33
+ * Common zapier data
34
+ *
35
+ * @var zapier
36
+ */
37
+ private static $cart_abandonment_settings = null;
38
+
39
+
40
+ /**
41
+ * Initiator
42
+ */
43
+ public static function get_instance() {
44
+ if ( ! isset( self::$instance ) ) {
45
+ self::$instance = new self;
46
+ }
47
+ return self::$instance;
48
+ }
49
+
50
+ /**
51
+ * Check if cart abandonment tracking is enabled.
52
+ *
53
+ * @return bool
54
+ */
55
+ function is_cart_abandonment_tracking_enabled() {
56
+
57
+ $wcf_ca_status = get_option( 'wcf_ca_status' );
58
+
59
+ // Check if abandonment cart tracking is disabled or zapier webhook is empty.
60
+ if ( isset( $wcf_ca_status ) && 'on' === $wcf_ca_status ) {
61
+ return true;
62
+ }
63
+
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Check if cart abandonment tracking is enabled.
69
+ *
70
+ * @return bool
71
+ */
72
+ function is_zapier_trigger_enabled() {
73
+
74
+ $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
75
+
76
+ // Check if zapier tracking is disabled or zapier webhook is empty.
77
+ if ( isset( $wcf_ca_zapier_tracking_status ) && 'on' === $wcf_ca_zapier_tracking_status ) {
78
+ return true;
79
+ }
80
+
81
+ return false;
82
+ }
83
+
84
+ /**
85
+ * Get cart abandonment tracking cutoff time.
86
+ *
87
+ * @param boolean $in_seconds get cutoff time in seconds if true.
88
+ * @return bool
89
+ */
90
+ function get_cart_abandonment_tracking_cut_off_time( $in_seconds = false ) {
91
+
92
+ $cart_abandoned_time = apply_filters( 'cartflows_ca_cart_abandonment_cut_off_time', WCF_DEFAULT_CUT_OFF_TIME );
93
+ return $in_seconds ? $cart_abandoned_time * MINUTE_IN_SECONDS : $cart_abandoned_time;
94
+
95
+ }
96
+
97
+ /**
98
+ * Check if GDPR is enabled.
99
+ *
100
+ * @return bool
101
+ */
102
+ function is_gdpr_enabled() {
103
+
104
+ $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
105
+
106
+ // Check if abandonment cart tracking is disabled or zapier webhook is empty.
107
+ if ( isset( $wcf_ca_gdpr_status ) && 'on' === $wcf_ca_gdpr_status ) {
108
+ return true;
109
+ }
110
+
111
+ return false;
112
+ }
113
+
114
+
115
+ }
languages/cartflows-ca.pot CHANGED
@@ -1,521 +1,525 @@
1
- # Copyright (C) 2019 CartFlows Inc
2
- # This file is distributed under the same license as the WooCommerce Cart Abandonment Recovery package.
3
- msgid ""
4
- msgstr ""
5
- "Project-Id-Version: WooCommerce Cart Abandonment Recovery 1.1.2\n"
6
- "Report-Msgid-Bugs-To: "
7
- "https://wordpress.org/support/plugin/woo-cart-abandonment-recovery\n"
8
- "POT-Creation-Date: 2019-06-12 10:03:46+00:00\n"
9
- "MIME-Version: 1.0\n"
10
- "Content-Type: text/plain; charset=utf-8\n"
11
- "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "Language: en\n"
16
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
- "X-Poedit-Country: United States\n"
18
- "X-Poedit-SourceCharset: UTF-8\n"
19
- "X-Poedit-KeywordsList: "
20
- "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21
- "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22
- "X-Poedit-Basepath: ../\n"
23
- "X-Poedit-SearchPath-0: .\n"
24
- "X-Poedit-Bookmarks: \n"
25
- "X-Textdomain-Support: yes\n"
26
- "X-Generator: grunt-wp-i18n 1.0.3\n"
27
-
28
- #: classes/class-cartflows-ca-loader.php:134
29
- #. translators: %s: html tags
30
- msgid ""
31
- "The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires "
32
- "%1$sWooCommerce%2$s plugin installed & activated."
33
- msgstr ""
34
-
35
- #: classes/class-cartflows-ca-loader.php:144
36
- msgid "Activate WooCommerce"
37
- msgstr ""
38
-
39
- #: classes/class-cartflows-ca-loader.php:152
40
- msgid "Install WooCommerce"
41
- msgstr ""
42
-
43
- #: classes/class-cartflows-ca-settings.php:53
44
- msgid "Cart Abandonment Settings"
45
- msgstr ""
46
-
47
- #: classes/class-cartflows-ca-settings.php:60
48
- msgid "Enable Cart Abandonment Tracking"
49
- msgstr ""
50
-
51
- #: classes/class-cartflows-ca-settings.php:64
52
- msgid ""
53
- "Start capturing abandoned carts. <br/><br/> <span "
54
- "class=\"description\"><strong>Note:</strong> Cart will be considered "
55
- "abandoned if order is not completed in <strong>15 minutes</strong>.</span>"
56
- msgstr ""
57
-
58
- #: classes/class-cartflows-ca-settings.php:76
59
- msgid "Email settings"
60
- msgstr ""
61
-
62
- #: classes/class-cartflows-ca-settings.php:83
63
- msgid "\"From\" Name"
64
- msgstr ""
65
-
66
- #: classes/class-cartflows-ca-settings.php:92
67
- msgid "\"From\" Address"
68
- msgstr ""
69
-
70
- #: classes/class-cartflows-ca-settings.php:101
71
- msgid "Send Reply Emails to"
72
- msgstr ""
73
-
74
- #: classes/class-cartflows-ca-settings.php:128
75
- msgid "Enable Webhook"
76
- msgstr ""
77
-
78
- #: classes/class-cartflows-ca-settings.php:132
79
- msgid ""
80
- "Allows you to trigger webhooks automatically upon cart abandonment and "
81
- "recovery."
82
- msgstr ""
83
-
84
- #: classes/class-cartflows-ca-settings.php:137
85
- msgid "Webhook URL"
86
- msgstr ""
87
-
88
- #: classes/class-cartflows-ca-settings.php:156
89
- msgid "Coupon Code Settings"
90
- msgstr ""
91
-
92
- #: classes/class-cartflows-ca-settings.php:163
93
- msgid "Create Coupon Code"
94
- msgstr ""
95
-
96
- #: classes/class-cartflows-ca-settings.php:167
97
- msgid ""
98
- "Auto-create the special coupon for the abandoned cart to send over the "
99
- "emails."
100
- msgstr ""
101
-
102
- #: classes/class-cartflows-ca-settings.php:172
103
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:491
104
- msgid "Discount Type"
105
- msgstr ""
106
-
107
- #: classes/class-cartflows-ca-settings.php:181
108
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:523
109
- msgid "Coupon Amount"
110
- msgstr ""
111
-
112
- #: classes/class-cartflows-ca-settings.php:190
113
- msgid "Coupon Expires After"
114
- msgstr ""
115
-
116
- #: classes/class-cartflows-ca-settings.php:225
117
- msgid "Webhook Settings"
118
- msgstr ""
119
-
120
- #: classes/class-cartflows-ca-settings.php:234
121
- msgid "GDPR Settings"
122
- msgstr ""
123
-
124
- #: classes/class-cartflows-ca-settings.php:241
125
- msgid "Enable GDPR integration"
126
- msgstr ""
127
-
128
- #: classes/class-cartflows-ca-settings.php:245
129
- msgid ""
130
- "Ask confirmation from the user before tracking data. <br/><br/> <span "
131
- "class=\"description\"><strong>Note:</strong> By checking this, it will show "
132
- "up confirmation text below the email id on checkout page.</span>"
133
- msgstr ""
134
-
135
- #: classes/class-cartflows-ca-settings.php:250
136
- msgid "GDPR Message"
137
- msgstr ""
138
-
139
- #: classes/class-cartflows-ca-settings.php:421
140
- msgid "Coupon code should be numeric and has to be greater than or equals to 1."
141
- msgstr ""
142
-
143
- #: classes/class-cartflows-ca-settings.php:531
144
- msgid "Invalid email \"From\" address field"
145
- msgstr ""
146
-
147
- #: classes/class-cartflows-ca-settings.php:549
148
- msgid "Invalid email \"Reply\" address field"
149
- msgstr ""
150
-
151
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:65
152
- msgid "View"
153
- msgstr ""
154
-
155
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:66
156
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:122
157
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:85
158
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:119
159
- msgid "Delete"
160
- msgstr ""
161
-
162
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:70
163
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1410
164
- msgid "Unsubscribe"
165
- msgstr ""
166
-
167
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:188
168
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1507
169
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1551
170
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:156
171
- msgid "Name"
172
- msgstr ""
173
-
174
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:189
175
- msgid "Email"
176
- msgstr ""
177
-
178
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:190
179
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1573
180
- msgid "Cart Total"
181
- msgstr ""
182
-
183
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:191
184
- msgid "Order Status"
185
- msgstr ""
186
-
187
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:192
188
- msgid "Time"
189
- msgstr ""
190
-
191
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:97
192
- msgid "Mail has been sent successfully!"
193
- msgstr ""
194
-
195
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:99
196
- msgid "Mail sending failed!"
197
- msgstr ""
198
-
199
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:132
200
- msgid "Every Fifteen Minutes"
201
- msgstr ""
202
-
203
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:197
204
- msgid "You have successfully unsubscribed from our email list."
205
- msgstr ""
206
-
207
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:197
208
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:147
209
- msgid "Unsubscribed"
210
- msgstr ""
211
-
212
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:347
213
- msgid "No Thanks"
214
- msgstr ""
215
-
216
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:348
217
- msgid "You won't receive further emails from us, thank you!"
218
- msgstr ""
219
-
220
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:742
221
- msgid "CartFlows says: This order was abandoned & subsequently recovered."
222
- msgstr ""
223
-
224
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:853
225
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:854
226
- msgid "Cart Abandonment"
227
- msgstr ""
228
-
229
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:887
230
- msgid "Items deleted: %d"
231
- msgstr ""
232
-
233
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:904
234
- msgid "User unsubscribed successfully!"
235
- msgstr ""
236
-
237
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1099
238
- msgid "Report"
239
- msgstr ""
240
-
241
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1115
242
- msgid "Emails"
243
- msgstr ""
244
-
245
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1131
246
- msgid "Settings"
247
- msgstr ""
248
-
249
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1380
250
- msgid "there"
251
- msgstr ""
252
-
253
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1506
254
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1550
255
- msgid "Item"
256
- msgstr ""
257
-
258
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1508
259
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1552
260
- msgid "Quantity"
261
- msgstr ""
262
-
263
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1509
264
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1553
265
- msgid "Price"
266
- msgstr ""
267
-
268
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1510
269
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1554
270
- msgid "Line Subtotal"
271
- msgstr ""
272
-
273
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1560
274
- msgid "Discount"
275
- msgstr ""
276
-
277
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1564
278
- msgid "Other"
279
- msgstr ""
280
-
281
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1569
282
- msgid "Shipping"
283
- msgstr ""
284
-
285
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:73
286
- msgid "Edit"
287
- msgstr ""
288
-
289
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:97
290
- msgid "Clone"
291
- msgstr ""
292
-
293
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:183
294
- msgid "Template Name"
295
- msgstr ""
296
-
297
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:184
298
- msgid "Email Subject"
299
- msgstr ""
300
-
301
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:185
302
- msgid "Trigger After"
303
- msgstr ""
304
-
305
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:186
306
- msgid "Is Activated?"
307
- msgstr ""
308
-
309
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:187
310
- msgid "The Email Template has been successfully added."
311
- msgstr ""
312
-
313
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:197
314
- msgid "The Email Template has been cloned successfully."
315
- msgstr ""
316
-
317
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:207
318
- msgid "The Email Template has been successfully deleted."
319
- msgstr ""
320
-
321
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:216
322
- msgid "The Email Template has been successfully updated."
323
- msgstr ""
324
-
325
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:226
326
- msgid "Default Email Templates has been restored successfully."
327
- msgstr ""
328
-
329
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:392
330
- msgid "Activate Template now?"
331
- msgstr ""
332
-
333
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:412
334
- msgid "Template Name:"
335
- msgstr ""
336
-
337
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:427
338
- msgid "Email Subject:"
339
- msgstr ""
340
-
341
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:442
342
- msgid "Email Body:"
343
- msgstr ""
344
-
345
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:471
346
- msgid "Create Coupon"
347
- msgstr ""
348
-
349
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:541
350
- msgid "Coupon expiry date"
351
- msgstr ""
352
-
353
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:578
354
- msgid "Send This Email"
355
- msgstr ""
356
-
357
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:611
358
- msgid "after cart is abandoned."
359
- msgstr ""
360
-
361
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:621
362
- msgid "Send Test Email To:"
363
- msgstr ""
364
-
365
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:935
366
- msgid "Create New Template"
367
- msgstr ""
368
-
369
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:938
370
- msgid " Restore Default Templates"
371
- msgstr ""
372
-
373
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:38
374
- msgid "Email Details:"
375
- msgstr ""
376
-
377
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:70
378
- msgid " No Email Scheduled."
379
- msgstr ""
380
-
381
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:106
382
- msgid "The email has unsubscribed and won't be sent further."
383
- msgstr ""
384
-
385
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:109
386
- msgid "The email has been sent."
387
- msgstr ""
388
-
389
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:112
390
- msgid "Email is in the queue and will be sent at the scheduled time."
391
- msgstr ""
392
-
393
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:143
394
- msgid "User Address Details:"
395
- msgstr ""
396
-
397
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:155
398
- msgid "Billing Address"
399
- msgstr ""
400
-
401
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:159
402
- msgid "Email address"
403
- msgstr ""
404
-
405
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:164
406
- msgid "Phone"
407
- msgstr ""
408
-
409
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:169
410
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:189
411
- msgid "Address 1:"
412
- msgstr ""
413
-
414
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:172
415
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:192
416
- msgid "Address 2:"
417
- msgstr ""
418
-
419
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:175
420
- msgid "Country, City:"
421
- msgstr ""
422
-
423
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:178
424
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:198
425
- msgid "State:"
426
- msgstr ""
427
-
428
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:182
429
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:204
430
- msgid "Postcode:"
431
- msgstr ""
432
-
433
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:187
434
- msgid "Shipping Address"
435
- msgstr ""
436
-
437
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:195
438
- msgid "City:"
439
- msgstr ""
440
-
441
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:201
442
- msgid "Country:"
443
- msgstr ""
444
-
445
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:217
446
- msgid "User Order Details:"
447
- msgstr ""
448
-
449
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:46
450
- msgid "Recoverable Orders"
451
- msgstr ""
452
-
453
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:50
454
- msgid "Total Recoverable Orders."
455
- msgstr ""
456
-
457
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:55
458
- msgid "Recovered Orders"
459
- msgstr ""
460
-
461
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:57
462
- msgid "Total Recovered Orders."
463
- msgstr ""
464
-
465
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:62
466
- msgid "Lost Orders"
467
- msgstr ""
468
-
469
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:65
470
- msgid "Total Lost Orders."
471
- msgstr ""
472
-
473
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:74
474
- msgid "Recoverable Revenue"
475
- msgstr ""
476
-
477
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:79
478
- msgid "Total Recoverable Revenue."
479
- msgstr ""
480
-
481
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:84
482
- msgid "Recovered Revenue"
483
- msgstr ""
484
-
485
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:90
486
- msgid "Total Recovered Revenue."
487
- msgstr ""
488
-
489
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:95
490
- msgid "Recovery Rate"
491
- msgstr ""
492
-
493
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:97
494
- msgid "Total Percentage Of Recovered Orders After Abandonment."
495
- msgstr ""
496
-
497
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:135
498
- msgid "No Orders Found."
499
- msgstr ""
500
-
501
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php:10
502
- msgid "Woocommerce Cart Abandonment Recovery "
503
- msgstr ""
504
-
505
- #. Plugin Name of the plugin/theme
506
- msgid "WooCommerce Cart Abandonment Recovery"
507
- msgstr ""
508
-
509
- #. Author URI of the plugin/theme
510
- msgid "https://cartflows.com/"
511
- msgstr ""
512
-
513
- #. Description of the plugin/theme
514
- msgid ""
515
- "Recover your lost revenue. Capture email address of users on the checkout "
516
- "page and send follow up emails if they don't complete the purchase."
517
- msgstr ""
518
-
519
- #. Author of the plugin/theme
520
- msgid "CartFlows Inc"
 
 
 
 
521
  msgstr ""
1
+ # Copyright (C) 2019 CartFlows Inc
2
+ # This file is distributed under the same license as the WooCommerce Cart Abandonment Recovery package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: WooCommerce Cart Abandonment Recovery 1.1.3\n"
6
+ "Report-Msgid-Bugs-To: "
7
+ "https://wordpress.org/support/plugin/woo-cart-abandonment-recovery\n"
8
+ "POT-Creation-Date: 2019-06-27 10:59:22+00:00\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=utf-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: en\n"
16
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
+ "X-Poedit-Country: United States\n"
18
+ "X-Poedit-SourceCharset: UTF-8\n"
19
+ "X-Poedit-KeywordsList: "
20
+ "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21
+ "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22
+ "X-Poedit-Basepath: ../\n"
23
+ "X-Poedit-SearchPath-0: .\n"
24
+ "X-Poedit-Bookmarks: \n"
25
+ "X-Textdomain-Support: yes\n"
26
+ "X-Generator: grunt-wp-i18n 1.0.3\n"
27
+
28
+ #: classes/class-cartflows-ca-loader.php:134
29
+ #. translators: %s: html tags
30
+ msgid ""
31
+ "The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires "
32
+ "%1$sWooCommerce%2$s plugin installed & activated."
33
+ msgstr ""
34
+
35
+ #: classes/class-cartflows-ca-loader.php:144
36
+ msgid "Activate WooCommerce"
37
+ msgstr ""
38
+
39
+ #: classes/class-cartflows-ca-loader.php:152
40
+ msgid "Install WooCommerce"
41
+ msgstr ""
42
+
43
+ #: classes/class-cartflows-ca-settings.php:53
44
+ msgid "Cart Abandonment Settings"
45
+ msgstr ""
46
+
47
+ #: classes/class-cartflows-ca-settings.php:60
48
+ msgid "Enable Cart Abandonment Tracking"
49
+ msgstr ""
50
+
51
+ #: classes/class-cartflows-ca-settings.php:64
52
+ msgid ""
53
+ "Start capturing abandoned carts. <br/><br/> <span "
54
+ "class=\"description\"><strong>Note:</strong> Cart will be considered "
55
+ "abandoned if order is not completed in <strong>15 minutes</strong>.</span>"
56
+ msgstr ""
57
+
58
+ #: classes/class-cartflows-ca-settings.php:76
59
+ msgid "Email settings"
60
+ msgstr ""
61
+
62
+ #: classes/class-cartflows-ca-settings.php:83
63
+ msgid "\"From\" Name"
64
+ msgstr ""
65
+
66
+ #: classes/class-cartflows-ca-settings.php:92
67
+ msgid "\"From\" Address"
68
+ msgstr ""
69
+
70
+ #: classes/class-cartflows-ca-settings.php:101
71
+ msgid "Send Reply Emails to"
72
+ msgstr ""
73
+
74
+ #: classes/class-cartflows-ca-settings.php:128
75
+ msgid "Enable Webhook"
76
+ msgstr ""
77
+
78
+ #: classes/class-cartflows-ca-settings.php:132
79
+ msgid ""
80
+ "Allows you to trigger webhooks automatically upon cart abandonment and "
81
+ "recovery."
82
+ msgstr ""
83
+
84
+ #: classes/class-cartflows-ca-settings.php:137
85
+ msgid "Webhook URL"
86
+ msgstr ""
87
+
88
+ #: classes/class-cartflows-ca-settings.php:156
89
+ msgid "Coupon Code Settings"
90
+ msgstr ""
91
+
92
+ #: classes/class-cartflows-ca-settings.php:163
93
+ msgid "Create Coupon Code"
94
+ msgstr ""
95
+
96
+ #: classes/class-cartflows-ca-settings.php:167
97
+ msgid ""
98
+ "Auto-create the special coupon for the abandoned cart to send over the "
99
+ "emails."
100
+ msgstr ""
101
+
102
+ #: classes/class-cartflows-ca-settings.php:172
103
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:491
104
+ msgid "Discount Type"
105
+ msgstr ""
106
+
107
+ #: classes/class-cartflows-ca-settings.php:181
108
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:523
109
+ msgid "Coupon Amount"
110
+ msgstr ""
111
+
112
+ #: classes/class-cartflows-ca-settings.php:190
113
+ msgid "Coupon Expires After"
114
+ msgstr ""
115
+
116
+ #: classes/class-cartflows-ca-settings.php:225
117
+ msgid "Webhook Settings"
118
+ msgstr ""
119
+
120
+ #: classes/class-cartflows-ca-settings.php:234
121
+ msgid "GDPR Settings"
122
+ msgstr ""
123
+
124
+ #: classes/class-cartflows-ca-settings.php:241
125
+ msgid "Enable GDPR integration"
126
+ msgstr ""
127
+
128
+ #: classes/class-cartflows-ca-settings.php:245
129
+ msgid ""
130
+ "Ask confirmation from the user before tracking data. <br/><br/> <span "
131
+ "class=\"description\"><strong>Note:</strong> By checking this, it will show "
132
+ "up confirmation text below the email id on checkout page.</span>"
133
+ msgstr ""
134
+
135
+ #: classes/class-cartflows-ca-settings.php:250
136
+ msgid "GDPR Message"
137
+ msgstr ""
138
+
139
+ #: classes/class-cartflows-ca-settings.php:421
140
+ msgid "Coupon code should be numeric and has to be greater than or equals to 1."
141
+ msgstr ""
142
+
143
+ #: classes/class-cartflows-ca-settings.php:531
144
+ msgid "Invalid email \"From\" address field"
145
+ msgstr ""
146
+
147
+ #: classes/class-cartflows-ca-settings.php:549
148
+ msgid "Invalid email \"Reply\" address field"
149
+ msgstr ""
150
+
151
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:65
152
+ msgid "View"
153
+ msgstr ""
154
+
155
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:66
156
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:122
157
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:85
158
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:119
159
+ msgid "Delete"
160
+ msgstr ""
161
+
162
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:70
163
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1417
164
+ msgid "Unsubscribe"
165
+ msgstr ""
166
+
167
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:188
168
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1514
169
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1558
170
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:156
171
+ msgid "Name"
172
+ msgstr ""
173
+
174
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:189
175
+ msgid "Email"
176
+ msgstr ""
177
+
178
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:190
179
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1580
180
+ msgid "Cart Total"
181
+ msgstr ""
182
+
183
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:191
184
+ msgid "Order Status"
185
+ msgstr ""
186
+
187
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:192
188
+ msgid "Time"
189
+ msgstr ""
190
+
191
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:97
192
+ msgid "Mail has been sent successfully!"
193
+ msgstr ""
194
+
195
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:99
196
+ msgid "Mail sending failed!"
197
+ msgstr ""
198
+
199
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:132
200
+ msgid "Every Fifteen Minutes"
201
+ msgstr ""
202
+
203
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:197
204
+ msgid "You have successfully unsubscribed from our email list."
205
+ msgstr ""
206
+
207
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:197
208
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:147
209
+ msgid "Unsubscribed"
210
+ msgstr ""
211
+
212
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:348
213
+ msgid "No Thanks"
214
+ msgstr ""
215
+
216
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:349
217
+ msgid "You won't receive further emails from us, thank you!"
218
+ msgstr ""
219
+
220
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:748
221
+ msgid "CartFlows says: This order was abandoned & subsequently recovered."
222
+ msgstr ""
223
+
224
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:860
225
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:861
226
+ msgid "Cart Abandonment"
227
+ msgstr ""
228
+
229
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:894
230
+ msgid "Items deleted: %d"
231
+ msgstr ""
232
+
233
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:911
234
+ msgid "User unsubscribed successfully!"
235
+ msgstr ""
236
+
237
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1106
238
+ msgid "Report"
239
+ msgstr ""
240
+
241
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1122
242
+ msgid "Emails"
243
+ msgstr ""
244
+
245
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1138
246
+ msgid "Settings"
247
+ msgstr ""
248
+
249
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1387
250
+ msgid "there"
251
+ msgstr ""
252
+
253
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1513
254
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1557
255
+ msgid "Item"
256
+ msgstr ""
257
+
258
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1515
259
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1559
260
+ msgid "Quantity"
261
+ msgstr ""
262
+
263
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1516
264
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1560
265
+ msgid "Price"
266
+ msgstr ""
267
+
268
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1517
269
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1561
270
+ msgid "Line Subtotal"
271
+ msgstr ""
272
+
273
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1567
274
+ msgid "Discount"
275
+ msgstr ""
276
+
277
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1571
278
+ msgid "Other"
279
+ msgstr ""
280
+
281
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1576
282
+ msgid "Shipping"
283
+ msgstr ""
284
+
285
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:73
286
+ msgid "Edit"
287
+ msgstr ""
288
+
289
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:97
290
+ msgid "Clone"
291
+ msgstr ""
292
+
293
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:183
294
+ msgid "Template Name"
295
+ msgstr ""
296
+
297
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:184
298
+ msgid "Email Subject"
299
+ msgstr ""
300
+
301
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:185
302
+ msgid "Trigger After"
303
+ msgstr ""
304
+
305
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:186
306
+ msgid "Is Activated?"
307
+ msgstr ""
308
+
309
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:187
310
+ msgid "The Email Template has been successfully added."
311
+ msgstr ""
312
+
313
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:197
314
+ msgid "The Email Template has been cloned successfully."
315
+ msgstr ""
316
+
317
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:207
318
+ msgid "The Email Template has been successfully deleted."
319
+ msgstr ""
320
+
321
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:216
322
+ msgid "The Email Template has been successfully updated."
323
+ msgstr ""
324
+
325
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:226
326
+ msgid "Default Email Templates has been restored successfully."
327
+ msgstr ""
328
+
329
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:392
330
+ msgid "Activate Template now?"
331
+ msgstr ""
332
+
333
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:412
334
+ msgid "Template Name:"
335
+ msgstr ""
336
+
337
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:427
338
+ msgid "Email Subject:"
339
+ msgstr ""
340
+
341
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:442
342
+ msgid "Email Body:"
343
+ msgstr ""
344
+
345
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:471
346
+ msgid "Create Coupon"
347
+ msgstr ""
348
+
349
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:541
350
+ msgid "Coupon expiry date"
351
+ msgstr ""
352
+
353
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:578
354
+ msgid "Send This Email"
355
+ msgstr ""
356
+
357
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:611
358
+ msgid "after cart is abandoned."
359
+ msgstr ""
360
+
361
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:621
362
+ msgid "Send Test Email To:"
363
+ msgstr ""
364
+
365
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:935
366
+ msgid "Create New Template"
367
+ msgstr ""
368
+
369
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:938
370
+ msgid " Restore Default Templates"
371
+ msgstr ""
372
+
373
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:38
374
+ msgid "Email Details:"
375
+ msgstr ""
376
+
377
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:70
378
+ msgid " No Email Scheduled."
379
+ msgstr ""
380
+
381
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:106
382
+ msgid "The email has unsubscribed and won't be sent further."
383
+ msgstr ""
384
+
385
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:109
386
+ msgid "The email has been sent."
387
+ msgstr ""
388
+
389
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:112
390
+ msgid "Email is in the queue and will be sent at the scheduled time."
391
+ msgstr ""
392
+
393
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:143
394
+ msgid "User Address Details:"
395
+ msgstr ""
396
+
397
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:155
398
+ msgid "Billing Address"
399
+ msgstr ""
400
+
401
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:159
402
+ msgid "Email address"
403
+ msgstr ""
404
+
405
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:164
406
+ msgid "Phone"
407
+ msgstr ""
408
+
409
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:169
410
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:189
411
+ msgid "Address 1:"
412
+ msgstr ""
413
+
414
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:172
415
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:192
416
+ msgid "Address 2:"
417
+ msgstr ""
418
+
419
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:175
420
+ msgid "Country, City:"
421
+ msgstr ""
422
+
423
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:178
424
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:198
425
+ msgid "State:"
426
+ msgstr ""
427
+
428
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:182
429
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:204
430
+ msgid "Postcode:"
431
+ msgstr ""
432
+
433
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:187
434
+ msgid "Shipping Address"
435
+ msgstr ""
436
+
437
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:195
438
+ msgid "City:"
439
+ msgstr ""
440
+
441
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:201
442
+ msgid "Country:"
443
+ msgstr ""
444
+
445
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:209
446
+ msgid "Checkout Link"
447
+ msgstr ""
448
+
449
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:224
450
+ msgid "User Order Details:"
451
+ msgstr ""
452
+
453
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:46
454
+ msgid "Recoverable Orders"
455
+ msgstr ""
456
+
457
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:50
458
+ msgid "Total Recoverable Orders."
459
+ msgstr ""
460
+
461
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:55
462
+ msgid "Recovered Orders"
463
+ msgstr ""
464
+
465
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:57
466
+ msgid "Total Recovered Orders."
467
+ msgstr ""
468
+
469
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:62
470
+ msgid "Lost Orders"
471
+ msgstr ""
472
+
473
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:65
474
+ msgid "Total Lost Orders."
475
+ msgstr ""
476
+
477
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:74
478
+ msgid "Recoverable Revenue"
479
+ msgstr ""
480
+
481
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:79
482
+ msgid "Total Recoverable Revenue."
483
+ msgstr ""
484
+
485
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:84
486
+ msgid "Recovered Revenue"
487
+ msgstr ""
488
+
489
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:90
490
+ msgid "Total Recovered Revenue."
491
+ msgstr ""
492
+
493
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:95
494
+ msgid "Recovery Rate"
495
+ msgstr ""
496
+
497
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:97
498
+ msgid "Total Percentage Of Recovered Orders After Abandonment."
499
+ msgstr ""
500
+
501
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:135
502
+ msgid "No Orders Found."
503
+ msgstr ""
504
+
505
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php:10
506
+ msgid "Woocommerce Cart Abandonment Recovery "
507
+ msgstr ""
508
+
509
+ #. Plugin Name of the plugin/theme
510
+ msgid "WooCommerce Cart Abandonment Recovery"
511
+ msgstr ""
512
+
513
+ #. Author URI of the plugin/theme
514
+ msgid "https://cartflows.com/"
515
+ msgstr ""
516
+
517
+ #. Description of the plugin/theme
518
+ msgid ""
519
+ "Recover your lost revenue. Capture email address of users on the checkout "
520
+ "page and send follow up emails if they don't complete the purchase."
521
+ msgstr ""
522
+
523
+ #. Author of the plugin/theme
524
+ msgid "CartFlows Inc"
525
  msgstr ""
modules/cart-abandonment/assets/js/cart-abandonment-tracking.js CHANGED
@@ -1,161 +1,161 @@
1
- (function ($) {
2
-
3
- var timer;
4
- var wcf_cart_abandonment = {
5
-
6
- init: function () {
7
-
8
- if ( CartFlowsProCAVars._show_gdpr_message && ! $("#wcf_cf_gdpr_message_block").length ) {
9
- $("#billing_email").after("<span id='wcf_cf_gdpr_message_block'> <span style='font-size: xx-small'> "+ CartFlowsProCAVars._gdpr_message +" <a style='cursor: pointer' id='wcf_ca_gdpr_no_thanks'> "+ CartFlowsProCAVars._gdpr_nothanks_msg +" </a></span></span>");
10
- }
11
-
12
- $(document).on(
13
- 'keyup keypress change',
14
- '#billing_email, #billing_phone, input.input-text, textarea.input-text, select',
15
- this._getCheckoutData
16
- );
17
-
18
- $("#wcf_ca_gdpr_no_thanks").click( function () {
19
- wcf_cart_abandonment._set_cookie();
20
- } );
21
-
22
- $( document.body ).on( 'updated_checkout', function(){
23
- wcf_cart_abandonment._getCheckoutData();
24
- });
25
-
26
- $(document).on('ready', function(e) {
27
- setTimeout(function() {
28
- wcf_cart_abandonment._getCheckoutData();
29
- }, 800);
30
- });
31
- },
32
-
33
- _set_cookie: function() {
34
-
35
-
36
- var data = {
37
- 'wcf_ca_skip_track_data': true,
38
- 'action': 'cartflows_skip_cart_tracking_gdpr',
39
- 'security': CartFlowsProCAVars._gdpr_nonce,
40
- };
41
-
42
- jQuery.post(
43
- CartFlowsProCAVars.ajaxurl,data,
44
- function (response) {
45
-
46
- if(response.success) {
47
- $("#wcf_cf_gdpr_message_block").empty().append("<span style='font-size: xx-small'>" + CartFlowsProCAVars._gdpr_after_no_thanks_msg + "</span>").delay(5000).fadeOut();
48
- }
49
-
50
- }
51
- );
52
-
53
- },
54
-
55
- _validate_email: function (value) {
56
- var valid = true;
57
- if (value.indexOf('@') == -1) {
58
- valid = false;
59
- } else {
60
- var parts = value.split('@');
61
- var domain = parts[1];
62
- if (domain.indexOf('.') == -1) {
63
- valid = false;
64
- } else {
65
- var domainParts = domain.split('.');
66
- var ext = domainParts[1];
67
- if (ext.length > 14 || ext.length < 2) {
68
- valid = false;
69
- }
70
- }
71
- }
72
- return valid;
73
- },
74
-
75
- _getCheckoutData: function () {
76
-
77
- var wcf_phone = jQuery("#billing_phone").val();
78
- var wcf_email = jQuery("#billing_email").val();
79
- var atposition = wcf_email.indexOf("@");
80
- var dotposition = wcf_email.lastIndexOf(".");
81
-
82
- if (typeof wcf_phone === 'undefined' || wcf_phone === null) { //If phone number field does not exist on the Checkout form
83
- wcf_phone = '';
84
- }
85
-
86
- clearTimeout(timer);
87
-
88
- if (!(atposition < 1 || dotposition < atposition + 2 || dotposition + 2 >= wcf_email.length) || wcf_phone.length >= 1) { //Checking if the email field is valid or phone number is longer than 1 digit
89
- //If Email or Phone valid
90
- var wcf_name = jQuery("#billing_first_name").val();
91
- var wcf_surname = jQuery("#billing_last_name").val();
92
- var wcf_phone = jQuery("#billing_phone").val();
93
- var wcf_country = jQuery("#billing_country").val();
94
- var wcf_city = jQuery("#billing_city").val();
95
-
96
- //Other fields used for "Remember user input" function
97
- var wcf_billing_company = jQuery("#billing_company").val();
98
- var wcf_billing_address_1 = jQuery("#billing_address_1").val();
99
- var wcf_billing_address_2 = jQuery("#billing_address_2").val();
100
- var wcf_billing_state = jQuery("#billing_state").val();
101
- var wcf_billing_postcode = jQuery("#billing_postcode").val();
102
- var wcf_shipping_first_name = jQuery("#shipping_first_name").val();
103
- var wcf_shipping_last_name = jQuery("#shipping_last_name").val();
104
- var wcf_shipping_company = jQuery("#shipping_company").val();
105
- var wcf_shipping_country = jQuery("#shipping_country").val();
106
- var wcf_shipping_address_1 = jQuery("#shipping_address_1").val();
107
- var wcf_shipping_address_2 = jQuery("#shipping_address_2").val();
108
- var wcf_shipping_city = jQuery("#shipping_city").val();
109
- var wcf_shipping_state = jQuery("#shipping_state").val();
110
- var wcf_shipping_postcode = jQuery("#shipping_postcode").val();
111
- var wcf_order_comments = jQuery("#order_comments").val();
112
-
113
- var data = {
114
- action: "cartflows_save_cart_abandonment_data",
115
- wcf_email: wcf_email,
116
- wcf_name: wcf_name,
117
- wcf_surname: wcf_surname,
118
- wcf_phone: wcf_phone,
119
- wcf_country: wcf_country,
120
- wcf_city: wcf_city,
121
- wcf_billing_company: wcf_billing_company,
122
- wcf_billing_address_1: wcf_billing_address_1,
123
- wcf_billing_address_2: wcf_billing_address_2,
124
- wcf_billing_state: wcf_billing_state,
125
- wcf_billing_postcode: wcf_billing_postcode,
126
- wcf_shipping_first_name: wcf_shipping_first_name,
127
- wcf_shipping_last_name: wcf_shipping_last_name,
128
- wcf_shipping_company: wcf_shipping_company,
129
- wcf_shipping_country: wcf_shipping_country,
130
- wcf_shipping_address_1: wcf_shipping_address_1,
131
- wcf_shipping_address_2: wcf_shipping_address_2,
132
- wcf_shipping_city: wcf_shipping_city,
133
- wcf_shipping_state: wcf_shipping_state,
134
- wcf_shipping_postcode: wcf_shipping_postcode,
135
- wcf_order_comments: wcf_order_comments,
136
- security: CartFlowsProCAVars._nonce,
137
- wcf_post_id: CartFlowsProCAVars._post_id,
138
- }
139
-
140
- timer = setTimeout(
141
- function () {
142
- if (wcf_cart_abandonment._validate_email(data.wcf_email)) {
143
- jQuery.post(
144
- CartFlowsProCAVars.ajaxurl, data, //Ajaxurl coming from localized script and contains the link to wp-admin/admin-ajax.php file that handles AJAX requests on Wordpress
145
- function (response) {
146
- // success response
147
- }
148
- );
149
- }
150
- }, 500
151
- );
152
- } else {
153
- //console.log("Not a valid e-mail or phone address");
154
- }
155
- }
156
-
157
- }
158
-
159
- wcf_cart_abandonment.init();
160
-
161
  })(jQuery);
1
+ (function ($) {
2
+
3
+ var timer;
4
+ var wcf_cart_abandonment = {
5
+
6
+ init: function () {
7
+
8
+ if ( CartFlowsProCAVars._show_gdpr_message && ! $("#wcf_cf_gdpr_message_block").length ) {
9
+ $("#billing_email").after("<span id='wcf_cf_gdpr_message_block'> <span style='font-size: xx-small'> "+ CartFlowsProCAVars._gdpr_message +" <a style='cursor: pointer' id='wcf_ca_gdpr_no_thanks'> "+ CartFlowsProCAVars._gdpr_nothanks_msg +" </a></span></span>");
10
+ }
11
+
12
+ $(document).on(
13
+ 'keyup keypress change',
14
+ '#billing_email, #billing_phone, input.input-text, textarea.input-text, select',
15
+ this._getCheckoutData
16
+ );
17
+
18
+ $("#wcf_ca_gdpr_no_thanks").click( function () {
19
+ wcf_cart_abandonment._set_cookie();
20
+ } );
21
+
22
+ $( document.body ).on( 'updated_checkout', function(){
23
+ wcf_cart_abandonment._getCheckoutData();
24
+ });
25
+
26
+ $(document).on('ready', function(e) {
27
+ setTimeout(function() {
28
+ wcf_cart_abandonment._getCheckoutData();
29
+ }, 800);
30
+ });
31
+ },
32
+
33
+ _set_cookie: function() {
34
+
35
+
36
+ var data = {
37
+ 'wcf_ca_skip_track_data': true,
38
+ 'action': 'cartflows_skip_cart_tracking_gdpr',
39
+ 'security': CartFlowsProCAVars._gdpr_nonce,
40
+ };
41
+
42
+ jQuery.post(
43
+ CartFlowsProCAVars.ajaxurl,data,
44
+ function (response) {
45
+
46
+ if(response.success) {
47
+ $("#wcf_cf_gdpr_message_block").empty().append("<span style='font-size: xx-small'>" + CartFlowsProCAVars._gdpr_after_no_thanks_msg + "</span>").delay(5000).fadeOut();
48
+ }
49
+
50
+ }
51
+ );
52
+
53
+ },
54
+
55
+ _validate_email: function (value) {
56
+ var valid = true;
57
+ if (value.indexOf('@') == -1) {
58
+ valid = false;
59
+ } else {
60
+ var parts = value.split('@');
61
+ var domain = parts[1];
62
+ if (domain.indexOf('.') == -1) {
63
+ valid = false;
64
+ } else {
65
+ var domainParts = domain.split('.');
66
+ var ext = domainParts[1];
67
+ if (ext.length > 14 || ext.length < 2) {
68
+ valid = false;
69
+ }
70
+ }
71
+ }
72
+ return valid;
73
+ },
74
+
75
+ _getCheckoutData: function () {
76
+
77
+ var wcf_phone = jQuery("#billing_phone").val();
78
+ var wcf_email = jQuery("#billing_email").val();
79
+ var atposition = wcf_email.indexOf("@");
80
+ var dotposition = wcf_email.lastIndexOf(".");
81
+
82
+ if (typeof wcf_phone === 'undefined' || wcf_phone === null) { //If phone number field does not exist on the Checkout form
83
+ wcf_phone = '';
84
+ }
85
+
86
+ clearTimeout(timer);
87
+
88
+ if (!(atposition < 1 || dotposition < atposition + 2 || dotposition + 2 >= wcf_email.length) || wcf_phone.length >= 1) { //Checking if the email field is valid or phone number is longer than 1 digit
89
+ //If Email or Phone valid
90
+ var wcf_name = jQuery("#billing_first_name").val();
91
+ var wcf_surname = jQuery("#billing_last_name").val();
92
+ var wcf_phone = jQuery("#billing_phone").val();
93
+ var wcf_country = jQuery("#billing_country").val();
94
+ var wcf_city = jQuery("#billing_city").val();
95
+
96
+ //Other fields used for "Remember user input" function
97
+ var wcf_billing_company = jQuery("#billing_company").val();
98
+ var wcf_billing_address_1 = jQuery("#billing_address_1").val();
99
+ var wcf_billing_address_2 = jQuery("#billing_address_2").val();
100
+ var wcf_billing_state = jQuery("#billing_state").val();
101
+ var wcf_billing_postcode = jQuery("#billing_postcode").val();
102
+ var wcf_shipping_first_name = jQuery("#shipping_first_name").val();
103
+ var wcf_shipping_last_name = jQuery("#shipping_last_name").val();
104
+ var wcf_shipping_company = jQuery("#shipping_company").val();
105
+ var wcf_shipping_country = jQuery("#shipping_country").val();
106
+ var wcf_shipping_address_1 = jQuery("#shipping_address_1").val();
107
+ var wcf_shipping_address_2 = jQuery("#shipping_address_2").val();
108
+ var wcf_shipping_city = jQuery("#shipping_city").val();
109
+ var wcf_shipping_state = jQuery("#shipping_state").val();
110
+ var wcf_shipping_postcode = jQuery("#shipping_postcode").val();
111
+ var wcf_order_comments = jQuery("#order_comments").val();
112
+
113
+ var data = {
114
+ action: "cartflows_save_cart_abandonment_data",
115
+ wcf_email: wcf_email,
116
+ wcf_name: wcf_name,
117
+ wcf_surname: wcf_surname,
118
+ wcf_phone: wcf_phone,
119
+ wcf_country: wcf_country,
120
+ wcf_city: wcf_city,
121
+ wcf_billing_company: wcf_billing_company,
122
+ wcf_billing_address_1: wcf_billing_address_1,
123
+ wcf_billing_address_2: wcf_billing_address_2,
124
+ wcf_billing_state: wcf_billing_state,
125
+ wcf_billing_postcode: wcf_billing_postcode,
126
+ wcf_shipping_first_name: wcf_shipping_first_name,
127
+ wcf_shipping_last_name: wcf_shipping_last_name,
128
+ wcf_shipping_company: wcf_shipping_company,
129
+ wcf_shipping_country: wcf_shipping_country,
130
+ wcf_shipping_address_1: wcf_shipping_address_1,
131
+ wcf_shipping_address_2: wcf_shipping_address_2,
132
+ wcf_shipping_city: wcf_shipping_city,
133
+ wcf_shipping_state: wcf_shipping_state,
134
+ wcf_shipping_postcode: wcf_shipping_postcode,
135
+ wcf_order_comments: wcf_order_comments,
136
+ security: CartFlowsProCAVars._nonce,
137
+ wcf_post_id: CartFlowsProCAVars._post_id,
138
+ }
139
+
140
+ timer = setTimeout(
141
+ function () {
142
+ if (wcf_cart_abandonment._validate_email(data.wcf_email)) {
143
+ jQuery.post(
144
+ CartFlowsProCAVars.ajaxurl, data, //Ajaxurl coming from localized script and contains the link to wp-admin/admin-ajax.php file that handles AJAX requests on Wordpress
145
+ function (response) {
146
+ // success response
147
+ }
148
+ );
149
+ }
150
+ }, 500
151
+ );
152
+ } else {
153
+ //console.log("Not a valid e-mail or phone address");
154
+ }
155
+ }
156
+
157
+ }
158
+
159
+ wcf_cart_abandonment.init();
160
+
161
  })(jQuery);
modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php CHANGED
@@ -1,241 +1,241 @@
1
- <?php
2
- /**
3
- * Cart Abandonment DB
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- /**
9
- * Cart Abandonment DB class.
10
- */
11
- class Cartflows_Ca_Cart_Abandonment_Db {
12
-
13
-
14
-
15
- /**
16
- * Member Variable
17
- *
18
- * @var object instance
19
- */
20
- private static $instance;
21
-
22
- /**
23
- * Initiator
24
- */
25
- public static function get_instance() {
26
- if ( ! isset( self::$instance ) ) {
27
- self::$instance = new self;
28
- }
29
- return self::$instance;
30
- }
31
-
32
- /**
33
- * Create tables
34
- */
35
- public function create_tables() {
36
- $this->create_cart_abandonment_table();
37
- $this->create_cart_abandonment_template_table();
38
- $this->create_email_templates_meta_table();
39
- $this->create_email_history_table();
40
- }
41
-
42
- /**
43
- * Create Email templates meta table.
44
- */
45
- public function create_email_templates_meta_table() {
46
- global $wpdb;
47
-
48
- $email_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
49
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
50
- $charset_collate = $wpdb->get_charset_collate();
51
-
52
- // Email templates meta table db sql command.
53
- $sql = "CREATE TABLE IF NOT EXISTS $email_template_meta_db (
54
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
55
- `email_template_id` BIGINT(20) NOT NULL,
56
- `meta_key` varchar(255) NOT NULL,
57
- `meta_value` longtext NOT NULL,
58
- PRIMARY KEY (`id`),
59
- FOREIGN KEY ( `email_template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE
60
- ) $charset_collate;\n";
61
-
62
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
63
- dbDelta( $sql );
64
-
65
- }
66
-
67
- /**
68
- * Create tables for analytics.
69
- */
70
- public function create_cart_abandonment_table() {
71
-
72
- global $wpdb;
73
-
74
- $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
75
- $charset_collate = $wpdb->get_charset_collate();
76
-
77
- // Cart abandonment tracking db sql command.
78
- $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_db (
79
- id BIGINT(20) NOT NULL AUTO_INCREMENT,
80
- checkout_id int(11) NOT NULL,
81
- email VARCHAR(100),
82
- cart_contents LONGTEXT,
83
- cart_total DECIMAL(10,2),
84
- session_id VARCHAR(60) NOT NULL,
85
- other_fields LONGTEXT,
86
- order_status ENUM( 'normal','abandoned','completed','lost') NOT NULL DEFAULT 'normal',
87
- unsubscribed boolean DEFAULT 0,
88
- coupon_code VARCHAR(50),
89
- time DATETIME DEFAULT NULL,
90
- PRIMARY KEY (`id`, `session_id`),
91
- UNIQUE KEY `session_id_UNIQUE` (`session_id`)
92
- ) $charset_collate;\n";
93
-
94
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
95
- dbDelta( $sql );
96
-
97
- }
98
-
99
- /**
100
- * Create tables for analytics.
101
- */
102
- public function create_cart_abandonment_template_table() {
103
-
104
- global $wpdb;
105
-
106
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
107
-
108
- $charset_collate = $wpdb->get_charset_collate();
109
-
110
- // Cart abandonment tracking db sql command.
111
- $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_template_db (
112
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
113
- `template_name` text NOT NULL,
114
- `email_subject` text NOT NULL,
115
- `email_body` mediumtext NOT NULL,
116
- `is_activated` tinyint(1) NOT NULL DEFAULT '0',
117
- `frequency` int(11) NOT NULL,
118
- `frequency_unit` ENUM( 'MINUTE','HOUR','DAY') NOT NULL DEFAULT 'MINUTE',
119
- PRIMARY KEY (`id`)
120
- ) $charset_collate;\n";
121
-
122
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
123
- dbDelta( $sql );
124
-
125
- }
126
-
127
- /**
128
- * Create tables for analytics.
129
- */
130
- public function create_email_history_table() {
131
-
132
- global $wpdb;
133
-
134
- $cart_abandonment_history_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
135
- $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
136
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
137
-
138
- $charset_collate = $wpdb->get_charset_collate();
139
-
140
- $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_history_db (
141
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
142
- `template_id` BIGINT(20) NOT NULL,
143
- `ca_session_id` VARCHAR(60),
144
- `coupon_code` VARCHAR(50),
145
- `scheduled_time` DATETIME,
146
- `email_sent` boolean DEFAULT 0,
147
- PRIMARY KEY (`id`),
148
- FOREIGN KEY ( `template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE,
149
- FOREIGN KEY ( `ca_session_id` ) REFERENCES $cart_abandonment_db(`session_id`) ON DELETE CASCADE
150
- ) $charset_collate;\n";
151
-
152
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
153
- dbDelta( $sql );
154
-
155
- }
156
-
157
- /**
158
- * Insert initial sample email templates.
159
- *
160
- * @param boolean $force_restore restore forcefully.
161
- */
162
- public function template_table_seeder( $force_restore = false ) {
163
- global $wpdb;
164
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
165
- $cart_abandonment_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
166
-
167
- $email_template_count = $wpdb->get_var( "SELECT COUNT(*) FROM $cart_abandonment_template_db" ); // phpcs:ignore
168
-
169
- if ( ( ! $email_template_count ) || $force_restore ) {
170
-
171
- $email_templates = array(
172
- array(
173
- 'template_name' => 'Sample Email Template 1',
174
- 'subject' => 'Purchase issue?',
175
- 'body' => "<p>Hi {{customer.firstname}}!</p><p>We\'re having trouble processing your recent purchase. Would you mind completing it?</p><p>Here\'s a link to continue where you left off:</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Continue Your Purchase Now </a></p><p>Kindly,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
176
- 'frequency' => 30,
177
- 'frequency_unit' => 'MINUTE',
178
- ),
179
- array(
180
- 'template_name' => 'Sample Email Template 2',
181
- 'subject' => 'Need help?',
182
- 'body' => "<p>Hi {{customer.firstname}}!</p><p>I'm {{admin.firstname}}, and I help handle customer issues at {{admin.company}}.</p><p>I just noticed that you tried to make a purchase, but unfortunately, there was some trouble. Is there anything I can do to help?</p><p>You should be able to complete your checkout in less than a minute:<br /><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Click here to continue your purchase </a><p><p>Thanks!<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
183
- 'frequency' => 1,
184
- 'frequency_unit' => 'DAY',
185
- ),
186
- array(
187
- 'template_name' => 'Sample Email Template 3',
188
- 'subject' => 'Exclusive discount for you. Let\'s get things started!',
189
- 'body' => "<p>Few days back you left {{cart.product.names}} in your cart.</p><p>To help make up your mind, we have added an exclusive 10% discount coupon {{cart.coupon_code}} to your cart.</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'>Complete Your Purchase Now &gt;&gt;</a></p><p>Hurry! This is a onetime offer and will expire in 24 Hours.</p><p>In case you couldn\'t finish your order due to technical difficulties or because you need some help, just reply to this email we will be happy to help.</p><p>Kind Regards,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
190
- 'frequency' => 3,
191
- 'frequency_unit' => 'DAY',
192
- ),
193
- );
194
-
195
- // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
196
- $template_index = 1;
197
- $template_meta_index = 1;
198
- foreach ( $email_templates as $email_template ) {
199
- $wpdb->query(
200
- $wpdb->prepare(
201
- "INSERT INTO $cart_abandonment_template_db (`id`, `template_name`, `email_subject`, `email_body`, `frequency`, `frequency_unit`)
202
- VALUES ( %d, %s, %s, %s, %d, %s )",
203
- $force_restore ? null : $template_index++,
204
- $email_template['template_name'],
205
- $email_template['subject'],
206
- $email_template['body'],
207
- $email_template['frequency'],
208
- $email_template['frequency_unit']
209
- )
210
- );
211
-
212
- $meta_data = array(
213
- 'override_global_coupon' => false,
214
- 'discount_type' => 'percent',
215
- 'coupon_amount' => 10,
216
- 'coupon_expiry_date' => '',
217
- 'coupon_expiry_unit' => 'hours',
218
- );
219
-
220
- $email_tmpl_id = $wpdb->insert_id;
221
-
222
- foreach ( $meta_data as $meta_key => $meta_value ) {
223
- $wpdb->query(
224
- $wpdb->prepare(
225
- "INSERT INTO $cart_abandonment_template_meta_db ( `id`, `email_template_id`, `meta_key`, `meta_value` )
226
- VALUES ( %d, %d, %s, %s )",
227
- $force_restore ? null : $template_meta_index++,
228
- $email_tmpl_id,
229
- $meta_key,
230
- $meta_value
231
- )
232
- );
233
- }
234
- }
235
- // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
236
- }
237
-
238
- }
239
- }
240
-
241
- Cartflows_Ca_Cart_Abandonment_Db::get_instance();
1
+ <?php
2
+ /**
3
+ * Cart Abandonment DB
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ /**
9
+ * Cart Abandonment DB class.
10
+ */
11
+ class Cartflows_Ca_Cart_Abandonment_Db {
12
+
13
+
14
+
15
+ /**
16
+ * Member Variable
17
+ *
18
+ * @var object instance
19
+ */
20
+ private static $instance;
21
+
22
+ /**
23
+ * Initiator
24
+ */
25
+ public static function get_instance() {
26
+ if ( ! isset( self::$instance ) ) {
27
+ self::$instance = new self;
28
+ }
29
+ return self::$instance;
30
+ }
31
+
32
+ /**
33
+ * Create tables
34
+ */
35
+ public function create_tables() {
36
+ $this->create_cart_abandonment_table();
37
+ $this->create_cart_abandonment_template_table();
38
+ $this->create_email_templates_meta_table();
39
+ $this->create_email_history_table();
40
+ }
41
+
42
+ /**
43
+ * Create Email templates meta table.
44
+ */
45
+ public function create_email_templates_meta_table() {
46
+ global $wpdb;
47
+
48
+ $email_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
49
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
50
+ $charset_collate = $wpdb->get_charset_collate();
51
+
52
+ // Email templates meta table db sql command.
53
+ $sql = "CREATE TABLE IF NOT EXISTS $email_template_meta_db (
54
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
55
+ `email_template_id` BIGINT(20) NOT NULL,
56
+ `meta_key` varchar(255) NOT NULL,
57
+ `meta_value` longtext NOT NULL,
58
+ PRIMARY KEY (`id`),
59
+ FOREIGN KEY ( `email_template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE
60
+ ) $charset_collate;\n";
61
+
62
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
63
+ dbDelta( $sql );
64
+
65
+ }
66
+
67
+ /**
68
+ * Create tables for analytics.
69
+ */
70
+ public function create_cart_abandonment_table() {
71
+
72
+ global $wpdb;
73
+
74
+ $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
75
+ $charset_collate = $wpdb->get_charset_collate();
76
+
77
+ // Cart abandonment tracking db sql command.
78
+ $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_db (
79
+ id BIGINT(20) NOT NULL AUTO_INCREMENT,
80
+ checkout_id int(11) NOT NULL,
81
+ email VARCHAR(100),
82
+ cart_contents LONGTEXT,
83
+ cart_total DECIMAL(10,2),
84
+ session_id VARCHAR(60) NOT NULL,
85
+ other_fields LONGTEXT,
86
+ order_status ENUM( 'normal','abandoned','completed','lost') NOT NULL DEFAULT 'normal',
87
+ unsubscribed boolean DEFAULT 0,
88
+ coupon_code VARCHAR(50),
89
+ time DATETIME DEFAULT NULL,
90
+ PRIMARY KEY (`id`, `session_id`),
91
+ UNIQUE KEY `session_id_UNIQUE` (`session_id`)
92
+ ) $charset_collate;\n";
93
+
94
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
95
+ dbDelta( $sql );
96
+
97
+ }
98
+
99
+ /**
100
+ * Create tables for analytics.
101
+ */
102
+ public function create_cart_abandonment_template_table() {
103
+
104
+ global $wpdb;
105
+
106
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
107
+
108
+ $charset_collate = $wpdb->get_charset_collate();
109
+
110
+ // Cart abandonment tracking db sql command.
111
+ $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_template_db (
112
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
113
+ `template_name` text NOT NULL,
114
+ `email_subject` text NOT NULL,
115
+ `email_body` mediumtext NOT NULL,
116
+ `is_activated` tinyint(1) NOT NULL DEFAULT '0',
117
+ `frequency` int(11) NOT NULL,
118
+ `frequency_unit` ENUM( 'MINUTE','HOUR','DAY') NOT NULL DEFAULT 'MINUTE',
119
+ PRIMARY KEY (`id`)
120
+ ) $charset_collate;\n";
121
+
122
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
123
+ dbDelta( $sql );
124
+
125
+ }
126
+
127
+ /**
128
+ * Create tables for analytics.
129
+ */
130
+ public function create_email_history_table() {
131
+
132
+ global $wpdb;
133
+
134
+ $cart_abandonment_history_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
135
+ $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
136
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
137
+
138
+ $charset_collate = $wpdb->get_charset_collate();
139
+
140
+ $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_history_db (
141
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
142
+ `template_id` BIGINT(20) NOT NULL,
143
+ `ca_session_id` VARCHAR(60),
144
+ `coupon_code` VARCHAR(50),
145
+ `scheduled_time` DATETIME,
146
+ `email_sent` boolean DEFAULT 0,
147
+ PRIMARY KEY (`id`),
148
+ FOREIGN KEY ( `template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE,
149
+ FOREIGN KEY ( `ca_session_id` ) REFERENCES $cart_abandonment_db(`session_id`) ON DELETE CASCADE
150
+ ) $charset_collate;\n";
151
+
152
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
153
+ dbDelta( $sql );
154
+
155
+ }
156
+
157
+ /**
158
+ * Insert initial sample email templates.
159
+ *
160
+ * @param boolean $force_restore restore forcefully.
161
+ */
162
+ public function template_table_seeder( $force_restore = false ) {
163
+ global $wpdb;
164
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
165
+ $cart_abandonment_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
166
+
167
+ $email_template_count = $wpdb->get_var( "SELECT COUNT(*) FROM $cart_abandonment_template_db" ); // phpcs:ignore
168
+
169
+ if ( ( ! $email_template_count ) || $force_restore ) {
170
+
171
+ $email_templates = array(
172
+ array(
173
+ 'template_name' => 'Sample Email Template 1',
174
+ 'subject' => 'Purchase issue?',
175
+ 'body' => "<p>Hi {{customer.firstname}}!</p><p>We\'re having trouble processing your recent purchase. Would you mind completing it?</p><p>Here\'s a link to continue where you left off:</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Continue Your Purchase Now </a></p><p>Kindly,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
176
+ 'frequency' => 30,
177
+ 'frequency_unit' => 'MINUTE',
178
+ ),
179
+ array(
180
+ 'template_name' => 'Sample Email Template 2',
181
+ 'subject' => 'Need help?',
182
+ 'body' => "<p>Hi {{customer.firstname}}!</p><p>I'm {{admin.firstname}}, and I help handle customer issues at {{admin.company}}.</p><p>I just noticed that you tried to make a purchase, but unfortunately, there was some trouble. Is there anything I can do to help?</p><p>You should be able to complete your checkout in less than a minute:<br /><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Click here to continue your purchase </a><p><p>Thanks!<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
183
+ 'frequency' => 1,
184
+ 'frequency_unit' => 'DAY',
185
+ ),
186
+ array(
187
+ 'template_name' => 'Sample Email Template 3',
188
+ 'subject' => 'Exclusive discount for you. Let\'s get things started!',
189
+ 'body' => "<p>Few days back you left {{cart.product.names}} in your cart.</p><p>To help make up your mind, we have added an exclusive 10% discount coupon {{cart.coupon_code}} to your cart.</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'>Complete Your Purchase Now &gt;&gt;</a></p><p>Hurry! This is a onetime offer and will expire in 24 Hours.</p><p>In case you couldn\'t finish your order due to technical difficulties or because you need some help, just reply to this email we will be happy to help.</p><p>Kind Regards,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
190
+ 'frequency' => 3,
191
+ 'frequency_unit' => 'DAY',
192
+ ),
193
+ );
194
+
195
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
196
+ $template_index = 1;
197
+ $template_meta_index = 1;
198
+ foreach ( $email_templates as $email_template ) {
199
+ $wpdb->query(
200
+ $wpdb->prepare(
201
+ "INSERT INTO $cart_abandonment_template_db (`id`, `template_name`, `email_subject`, `email_body`, `frequency`, `frequency_unit`)
202
+ VALUES ( %d, %s, %s, %s, %d, %s )",
203
+ $force_restore ? null : $template_index++,
204
+ $email_template['template_name'],
205
+ $email_template['subject'],
206
+ $email_template['body'],
207
+ $email_template['frequency'],
208
+ $email_template['frequency_unit']
209
+ )
210
+ );
211
+
212
+ $meta_data = array(
213
+ 'override_global_coupon' => false,
214
+ 'discount_type' => 'percent',
215
+ 'coupon_amount' => 10,
216
+ 'coupon_expiry_date' => '',
217
+ 'coupon_expiry_unit' => 'hours',
218
+ );
219
+
220
+ $email_tmpl_id = $wpdb->insert_id;
221
+
222
+ foreach ( $meta_data as $meta_key => $meta_value ) {
223
+ $wpdb->query(
224
+ $wpdb->prepare(
225
+ "INSERT INTO $cart_abandonment_template_meta_db ( `id`, `email_template_id`, `meta_key`, `meta_value` )
226
+ VALUES ( %d, %d, %s, %s )",
227
+ $force_restore ? null : $template_meta_index++,
228
+ $email_tmpl_id,
229
+ $meta_key,
230
+ $meta_value
231
+ )
232
+ );
233
+ }
234
+ }
235
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
236
+ }
237
+
238
+ }
239
+ }
240
+
241
+ Cartflows_Ca_Cart_Abandonment_Db::get_instance();
modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php CHANGED
@@ -1,235 +1,235 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'WP_List_Table' ) ) {
9
- include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
- }
11
- /**
12
- * Cart abandonment tracking table class.
13
- */
14
- class Cartflows_Ca_Cart_Abandonment_Table extends WP_List_Table {
15
-
16
-
17
-
18
- /**
19
- * Constructor function.
20
- */
21
- function __construct() {
22
- global $status, $page;
23
-
24
- parent::__construct(
25
- array(
26
- 'singular' => 'id',
27
- 'plural' => 'ids',
28
- )
29
- );
30
- }
31
-
32
- /**
33
- * Default columns.
34
- *
35
- * @param object $item item.
36
- * @param string $column_name column name.
37
- */
38
- function column_default( $item, $column_name ) {
39
- return $item[ $column_name ];
40
- }
41
-
42
- /**
43
- * Column name surname.
44
- *
45
- * @param object $item item.
46
- * @return string
47
- */
48
- function column_nameSurname( $item ) {
49
-
50
- $item_details = unserialize( $item['other_fields'] );
51
-
52
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
53
-
54
- $view_url = add_query_arg(
55
- array(
56
- 'page' => WCF_CA_PAGE_NAME,
57
- 'action' => WCF_ACTION_REPORTS,
58
- 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
59
- 'session_id' => sanitize_text_field( $item['session_id'] ),
60
- ),
61
- admin_url( '/admin.php' )
62
- );
63
-
64
- $actions = array(
65
- 'view' => sprintf( '<a href="%s">%s</a>', esc_url( $view_url ), __( 'View', 'cartflows-ca' ) ),
66
- 'delete' => sprintf( '<a onclick="return confirm(\'Are you sure to delete this order?\');" href="?page=%s&action=delete&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Delete', 'cartflows-ca' ) ),
67
- );
68
-
69
- if ( WCF_CART_ABANDONED_ORDER === $item['order_status'] && ! $item['unsubscribed'] ) {
70
- $actions['unsubscribe'] = sprintf( '<a onclick="return confirm(\'Are you sure to unsubscribe this user? \');" href="?page=%s&action=unsubscribe&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Unsubscribe', 'cartflows-ca' ) );
71
-
72
- }
73
-
74
- return sprintf(
75
- '<a href="%s"><span class="dashicons dashicons-admin-users"></span> %s %s %s </a>',
76
- esc_url( $view_url ),
77
- esc_html( $item_details['wcf_first_name'] ),
78
- esc_html( $item_details['wcf_last_name'] ),
79
- $this->row_actions( $actions )
80
- );
81
- }
82
-
83
- /**
84
- * Render date column
85
- *
86
- * @param object $item - row (key, value array).
87
- * @return HTML
88
- */
89
- function column_time( $item ) {
90
- $database_time = $item['time'];
91
- $date_time = new DateTime( $database_time );
92
- $date = $date_time->format( 'd.m.Y' );
93
- $time = $date_time->format( 'H:i:s' );
94
-
95
- return sprintf(
96
- '<span class="dashicons dashicons-clock"></span> %s %s',
97
- esc_html( $time ),
98
- esc_html( $date )
99
- );
100
- }
101
-
102
- /**
103
- * This is how checkbox column renders.
104
- *
105
- * @param object $item item.
106
- * @return HTML
107
- */
108
- function column_cb( $item ) {
109
- return sprintf(
110
- '<input type="checkbox" name="id[]" value="%s" />',
111
- esc_html( $item['id'] )
112
- );
113
- }
114
-
115
- /**
116
- * [OPTIONAL] Return array of bult actions if has any
117
- *
118
- * @return array
119
- */
120
- function get_bulk_actions() {
121
- $actions = array(
122
- 'delete' => __( 'Delete', 'cartflows-ca' ),
123
- );
124
- return $actions;
125
- }
126
-
127
- /**
128
- * Whether the table has items to display or not
129
- *
130
- * @return bool
131
- */
132
- public function has_items() {
133
- return ! empty( $this->items );
134
- }
135
-
136
- /**
137
- * Fetch data from the database to render on view.
138
- *
139
- * @param string $cart_type abandoned|completed.
140
- * @param string $from_date from date.
141
- * @param string $to_date to date.
142
- */
143
- function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER, $from_date = '', $to_date = '' ) {
144
- global $wpdb;
145
- $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
146
-
147
- $per_page = 10;
148
-
149
- $columns = $this->get_columns();
150
- $hidden = array();
151
- $sortable = $this->get_sortable_columns();
152
-
153
- $this->_column_headers = array( $columns, $hidden, $sortable );
154
-
155
- $this->process_bulk_action();
156
-
157
- $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
158
- $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
159
- $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
160
-
161
- $paged = $paged ? max( 0, $paged - 1 ) : 0;
162
- $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
163
- $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
164
-
165
- $this->items = $wpdb->get_results(
166
- $wpdb->prepare("SELECT * FROM $cart_abandonment_table_name WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s ORDER BY $orderby $order LIMIT %d OFFSET %d", $cart_type, $from_date, $to_date, $per_page, $paged * $per_page), ARRAY_A); // phpcs:ignore
167
-
168
- $total_items = count( $this->items );
169
-
170
- // [REQUIRED] configure pagination
171
- $this->set_pagination_args(
172
- array(
173
- 'total_items' => $total_items,
174
- 'per_page' => $per_page,
175
- 'total_pages' => ceil( $total_items / $per_page ),
176
- )
177
- );
178
- }
179
-
180
- /**
181
- * Table columns.
182
- *
183
- * @return array
184
- */
185
- function get_columns() {
186
- $columns = array(
187
- 'cb' => '<input type="checkbox" />',
188
- 'nameSurname' => __( 'Name', 'cartflows-ca' ),
189
- 'email' => __( 'Email', 'cartflows-ca' ),
190
- 'cart_total' => __( 'Cart Total', 'cartflows-ca' ),
191
- 'order_status' => __( 'Order Status', 'cartflows-ca' ),
192
- 'time' => __( 'Time', 'cartflows-ca' ),
193
- );
194
- return $columns;
195
- }
196
-
197
- /**
198
- * Table sortable columns.
199
- *
200
- * @return array
201
- */
202
- public function get_sortable_columns() {
203
- $sortable = array(
204
- 'nameSurname' => array( 'name', true ),
205
- 'cart_total' => array( 'cart_total', true ),
206
- 'cart_total' => array( 'Cart Total', true ),
207
- 'order_status' => array( 'Order Status', true ),
208
- 'time' => array( 'time', true ),
209
- );
210
- return $sortable;
211
- }
212
-
213
- /**
214
- * Processes bulk actions
215
- */
216
- function process_bulk_action() {
217
- global $wpdb;
218
- $table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
219
-
220
- if ( 'delete' === $this->current_action() ) {
221
-
222
- $ids = array();
223
- if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) {
224
- $ids = array_map( 'intval', $_REQUEST['id'] );
225
- } elseif ( isset( $_REQUEST['id'] ) ) {
226
- $ids = array( intval( $_REQUEST['id'] ) );
227
- }
228
- $ids = implode( ',', $ids );
229
-
230
- if ( ! empty( $ids ) ) {
231
- $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
232
- }
233
- }
234
- }
235
- }
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'WP_List_Table' ) ) {
9
+ include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
+ }
11
+ /**
12
+ * Cart abandonment tracking table class.
13
+ */
14
+ class Cartflows_Ca_Cart_Abandonment_Table extends WP_List_Table {
15
+
16
+
17
+
18
+ /**
19
+ * Constructor function.
20
+ */
21
+ function __construct() {
22
+ global $status, $page;
23
+
24
+ parent::__construct(
25
+ array(
26
+ 'singular' => 'id',
27
+ 'plural' => 'ids',
28
+ )
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Default columns.
34
+ *
35
+ * @param object $item item.
36
+ * @param string $column_name column name.
37
+ */
38
+ function column_default( $item, $column_name ) {
39
+ return $item[ $column_name ];
40
+ }
41
+
42
+ /**
43
+ * Column name surname.
44
+ *
45
+ * @param object $item item.
46
+ * @return string
47
+ */
48
+ function column_nameSurname( $item ) {
49
+
50
+ $item_details = unserialize( $item['other_fields'] );
51
+
52
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
53
+
54
+ $view_url = add_query_arg(
55
+ array(
56
+ 'page' => WCF_CA_PAGE_NAME,
57
+ 'action' => WCF_ACTION_REPORTS,
58
+ 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
59
+ 'session_id' => sanitize_text_field( $item['session_id'] ),
60
+ ),
61
+ admin_url( '/admin.php' )
62
+ );
63
+
64
+ $actions = array(
65
+ 'view' => sprintf( '<a href="%s">%s</a>', esc_url( $view_url ), __( 'View', 'cartflows-ca' ) ),
66
+ 'delete' => sprintf( '<a onclick="return confirm(\'Are you sure to delete this order?\');" href="?page=%s&action=delete&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Delete', 'cartflows-ca' ) ),
67
+ );
68
+
69
+ if ( WCF_CART_ABANDONED_ORDER === $item['order_status'] && ! $item['unsubscribed'] ) {
70
+ $actions['unsubscribe'] = sprintf( '<a onclick="return confirm(\'Are you sure to unsubscribe this user? \');" href="?page=%s&action=unsubscribe&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Unsubscribe', 'cartflows-ca' ) );
71
+
72
+ }
73
+
74
+ return sprintf(
75
+ '<a href="%s"><span class="dashicons dashicons-admin-users"></span> %s %s %s </a>',
76
+ esc_url( $view_url ),
77
+ esc_html( $item_details['wcf_first_name'] ),
78
+ esc_html( $item_details['wcf_last_name'] ),
79
+ $this->row_actions( $actions )
80
+ );
81
+ }
82
+
83
+ /**
84
+ * Render date column
85
+ *
86
+ * @param object $item - row (key, value array).
87
+ * @return HTML
88
+ */
89
+ function column_time( $item ) {
90
+ $database_time = $item['time'];
91
+ $date_time = new DateTime( $database_time );
92
+ $date = $date_time->format( 'd.m.Y' );
93
+ $time = $date_time->format( 'H:i:s' );
94
+
95
+ return sprintf(
96
+ '<span class="dashicons dashicons-clock"></span> %s %s',
97
+ esc_html( $time ),
98
+ esc_html( $date )
99
+ );
100
+ }
101
+
102
+ /**
103
+ * This is how checkbox column renders.
104
+ *
105
+ * @param object $item item.
106
+ * @return HTML
107
+ */
108
+ function column_cb( $item ) {
109
+ return sprintf(
110
+ '<input type="checkbox" name="id[]" value="%s" />',
111
+ esc_html( $item['id'] )
112
+ );
113
+ }
114
+
115
+ /**
116
+ * [OPTIONAL] Return array of bult actions if has any
117
+ *
118
+ * @return array
119
+ */
120
+ function get_bulk_actions() {
121
+ $actions = array(
122
+ 'delete' => __( 'Delete', 'cartflows-ca' ),
123
+ );
124
+ return $actions;
125
+ }
126
+
127
+ /**
128
+ * Whether the table has items to display or not
129
+ *
130
+ * @return bool
131
+ */
132
+ public function has_items() {
133
+ return ! empty( $this->items );
134
+ }
135
+
136
+ /**
137
+ * Fetch data from the database to render on view.
138
+ *
139
+ * @param string $cart_type abandoned|completed.
140
+ * @param string $from_date from date.
141
+ * @param string $to_date to date.
142
+ */
143
+ function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER, $from_date = '', $to_date = '' ) {
144
+ global $wpdb;
145
+ $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
146
+
147
+ $per_page = 10;
148
+
149
+ $columns = $this->get_columns();
150
+ $hidden = array();
151
+ $sortable = $this->get_sortable_columns();
152
+
153
+ $this->_column_headers = array( $columns, $hidden, $sortable );
154
+
155
+ $this->process_bulk_action();
156
+
157
+ $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
158
+ $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
159
+ $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
160
+
161
+ $paged = $paged ? max( 0, $paged - 1 ) : 0;
162
+ $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
163
+ $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
164
+
165
+ $this->items = $wpdb->get_results(
166
+ $wpdb->prepare("SELECT * FROM $cart_abandonment_table_name WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s ORDER BY $orderby $order LIMIT %d OFFSET %d", $cart_type, $from_date, $to_date, $per_page, $paged * $per_page), ARRAY_A); // phpcs:ignore
167
+
168
+ $total_items = $wpdb->get_var($wpdb->prepare("SELECT count(*) FROM $cart_abandonment_table_name WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s", $cart_type, $from_date, $to_date)); // phpcs:ignore
169
+
170
+ // [REQUIRED] configure pagination
171
+ $this->set_pagination_args(
172
+ array(
173
+ 'total_items' => $total_items,
174
+ 'per_page' => $per_page,
175
+ 'total_pages' => ceil( $total_items / $per_page ),
176
+ )
177
+ );
178
+ }
179
+
180
+ /**
181
+ * Table columns.
182
+ *
183
+ * @return array
184
+ */
185
+ function get_columns() {
186
+ $columns = array(
187
+ 'cb' => '<input type="checkbox" />',
188
+ 'nameSurname' => __( 'Name', 'cartflows-ca' ),
189
+ 'email' => __( 'Email', 'cartflows-ca' ),
190
+ 'cart_total' => __( 'Cart Total', 'cartflows-ca' ),
191
+ 'order_status' => __( 'Order Status', 'cartflows-ca' ),
192
+ 'time' => __( 'Time', 'cartflows-ca' ),
193
+ );
194
+ return $columns;
195
+ }
196
+
197
+ /**
198
+ * Table sortable columns.
199
+ *
200
+ * @return array
201
+ */
202
+ public function get_sortable_columns() {
203
+ $sortable = array(
204
+ 'nameSurname' => array( 'name', true ),
205
+ 'cart_total' => array( 'cart_total', true ),
206
+ 'cart_total' => array( 'Cart Total', true ),
207
+ 'order_status' => array( 'Order Status', true ),
208
+ 'time' => array( 'time', true ),
209
+ );
210
+ return $sortable;
211
+ }
212
+
213
+ /**
214
+ * Processes bulk actions
215
+ */
216
+ function process_bulk_action() {
217
+ global $wpdb;
218
+ $table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
219
+
220
+ if ( 'delete' === $this->current_action() ) {
221
+
222
+ $ids = array();
223
+ if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) {
224
+ $ids = array_map( 'intval', $_REQUEST['id'] );
225
+ } elseif ( isset( $_REQUEST['id'] ) ) {
226
+ $ids = array( intval( $_REQUEST['id'] ) );
227
+ }
228
+ $ids = implode( ',', $ids );
229
+
230
+ if ( ! empty( $ids ) ) {
231
+ $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
232
+ }
233
+ }
234
+ }
235
+ }
modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php CHANGED
@@ -1,1722 +1,1734 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- /**
9
- * Cart abandonment tracking class.
10
- */
11
- class Cartflows_Ca_Cart_Abandonment {
12
-
13
-
14
-
15
- /**
16
- * Member Variable
17
- *
18
- * @var object instance
19
- */
20
- private static $instance;
21
-
22
- /**
23
- * Initiator
24
- */
25
- public static function get_instance() {
26
- if ( ! isset( self::$instance ) ) {
27
- self::$instance = new self;
28
- }
29
- return self::$instance;
30
- }
31
-
32
- /**
33
- * Constructor function that initializes required actions and hooks.
34
- */
35
- public function __construct() {
36
-
37
- $this->define_cart_abandonment_constants();
38
-
39
- // Adding menu to view cart abandonment report.
40
- add_action( 'admin_menu', array( $this, 'abandoned_cart_tracking_menu' ), 999 );
41
-
42
- // Adding the styles and scripts for the cart abandonment.
43
- add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_cart_abandonment_script' ), 20 );
44
-
45
- if ( wcf_ca()->utils->is_cart_abandonment_tracking_enabled() && ! isset( $_COOKIE['wcf_ca_skip_track_data'] ) ) {
46
-
47
- add_action( 'woocommerce_update_cart_action_cart_updated', 'on_action_cart_updated', 20, 1 );
48
-
49
- // Add script to track the cart abandonment.
50
- add_action( 'woocommerce_after_checkout_form', array( $this, 'cart_abandonment_tracking_script' ) );
51
-
52
- // Store user details from the current checkout page.
53
- add_action( 'wp_ajax_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
54
- add_action( 'wp_ajax_nopriv_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
55
-
56
- // GDPR actions.
57
- add_action( 'wp_ajax_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
58
- add_action( 'wp_ajax_nopriv_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
59
-
60
- // Delete the stored cart abandonment data once order gets created.
61
- add_action( 'woocommerce_new_order', array( $this, 'delete_cart_abandonment_data' ) );
62
- add_action( 'woocommerce_thankyou', array( $this, 'delete_cart_abandonment_data' ) );
63
-
64
- // Adding filter to restore the data if recreating abandonment order.
65
- add_filter( 'wp', array( $this, 'restore_cart_abandonment_data' ), 10 );
66
- add_filter( 'wp', array( $this, 'unsubscribe_cart_abandonment_emails' ), 10 );
67
-
68
- add_action( 'wp_ajax_wcf_ca_preview_email_send', array( $this, 'send_preview_email' ) );
69
-
70
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
71
- if ( WCF_CA_PAGE_NAME === $page ) {
72
- // Adding filter to add new button to add custom fields.
73
- add_filter( 'mce_buttons', array( $this, 'wcf_filter_mce_button' ) );
74
- add_filter( 'mce_external_plugins', array( $this, 'wcf_filter_mce_plugin' ), 9 );
75
- }
76
-
77
- add_filter( 'cron_schedules', array( $this, 'cartflows_ca_update_order_status_action' ) );
78
-
79
- // Schedule an action if it's not already scheduled.
80
- if ( ! wp_next_scheduled( 'cartflows_ca_update_order_status_action' ) ) {
81
- wp_schedule_event( time(), 'every_fifteen_minutes', 'cartflows_ca_update_order_status_action' );
82
- }
83
- add_action( 'cartflows_ca_update_order_status_action', array( $this, 'update_order_status' ) );
84
-
85
- }
86
-
87
- }
88
-
89
- /**
90
- * Send preview emails.
91
- */
92
- public function send_preview_email() {
93
-
94
- check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, 'security' );
95
- $mail_result = $this->send_email_templates( null, true );
96
- if ( $mail_result ) {
97
- wp_send_json_success( __( 'Mail has been sent successfully!', 'cartflows-ca' ) );
98
- } else {
99
- wp_send_json_error( __( 'Mail sending failed!', 'cartflows-ca' ) );
100
- }
101
- }
102
-
103
-
104
- /**
105
- * Delete tracked data and set cookie for the user.
106
- */
107
- public function skip_cart_tracking_by_gdpr() {
108
- check_ajax_referer( 'cartflows_skip_cart_tracking_gdpr', 'security' );
109
-
110
- global $wpdb;
111
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
112
-
113
- $session_id = WC()->session->get( 'wcf_session_id' );
114
- if ( $session_id ) {
115
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
116
- }
117
-
118
- setcookie( 'wcf_ca_skip_track_data', 'true', 0, '/' );
119
- wp_send_json_success();
120
-
121
- }
122
-
123
-
124
- /**
125
- * Create custom schedule.
126
- *
127
- * @return mixed
128
- */
129
- function cartflows_ca_update_order_status_action() {
130
- $schedules['every_fifteen_minutes'] = array(
131
- 'interval' => 15 * MINUTE_IN_SECONDS,
132
- 'display' => __( 'Every Fifteen Minutes', 'cartflows-ca' ),
133
- );
134
- return $schedules;
135
- }
136
-
137
- /**
138
- * Generate new coupon code for abandoned cart.
139
- *
140
- * @param string $discount_type discount type.
141
- * @param float $amount amount.
142
- * @param string $expiry expiry.
143
- */
144
- function generate_coupon_code( $discount_type, $amount, $expiry = '' ) {
145
-
146
- $coupon_code = '';
147
-
148
- if ( $discount_type && $amount ) {
149
-
150
- $coupon_code = wp_generate_password( 8, false, false );
151
-
152
- $coupon = array(
153
- 'post_title' => $coupon_code,
154
- 'post_content' => '',
155
- 'post_status' => 'publish',
156
- 'post_author' => 1,
157
- 'post_type' => 'shop_coupon',
158
- );
159
-
160
- $new_coupon_id = wp_insert_post( $coupon );
161
-
162
- update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
163
- update_post_meta( $new_coupon_id, 'description', 'This coupon is for abandoned cart email templates.' );
164
- update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
165
- update_post_meta( $new_coupon_id, 'individual_use', 'no' );
166
- update_post_meta( $new_coupon_id, 'product_ids', '' );
167
- update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
168
- update_post_meta( $new_coupon_id, 'usage_limit', '1' );
169
- update_post_meta( $new_coupon_id, 'date_expires', $expiry );
170
- update_post_meta( $new_coupon_id, 'apply_before_tax', 'yes' );
171
- update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
172
-
173
- }
174
-
175
- return $coupon_code;
176
- }
177
-
178
- /**
179
- * Unsubscribe the user from the mailing list.
180
- */
181
- function unsubscribe_cart_abandonment_emails() {
182
-
183
- $unsubscribe = filter_input( INPUT_GET, 'unsubscribe', FILTER_VALIDATE_BOOLEAN );
184
- $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
185
- if ( $unsubscribe && $this->is_valid_token( $wcf_ac_token ) ) {
186
- $token_data = $this->wcf_decode_token( $wcf_ac_token );
187
- if ( isset( $token_data['wcf_session_id'] ) ) {
188
- $session_id = $token_data['wcf_session_id'];
189
-
190
- global $wpdb;
191
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
192
- $wpdb->update(
193
- $cart_abandonment_table,
194
- array( 'unsubscribed' => true ),
195
- array( 'session_id' => $session_id )
196
- );
197
- wp_die( __( 'You have successfully unsubscribed from our email list.', 'cartflows-ca' ), __( 'Unsubscribed', 'cartflows-ca' ) );
198
-
199
- }
200
- }
201
-
202
- }
203
-
204
-
205
- /**
206
- * Link JS to mce button.
207
- *
208
- * @param array $plugins mce pluggins.
209
- * @return mixed
210
- */
211
- function wcf_filter_mce_plugin( $plugins ) {
212
- $plugins['cartflows_ac'] = CARTFLOWS_CA_URL . 'admin/assets/js/admin-mce.js';
213
- return $plugins;
214
- }
215
-
216
- /**
217
- * Register button.
218
- *
219
- * @param array $buttons mce buttons.
220
- * @return mixed
221
- */
222
- function wcf_filter_mce_button( $buttons ) {
223
- array_push( $buttons, 'cartflows_ac' );
224
- return $buttons;
225
- }
226
-
227
- /**
228
- * Initialise all the constants
229
- */
230
- function define_cart_abandonment_constants() {
231
- define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
232
- define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
233
- define( 'WCF_CART_ABANDONED_ORDER', 'abandoned' );
234
- define( 'WCF_CART_COMPLETED_ORDER', 'completed' );
235
- define( 'WCF_CART_LOST_ORDER', 'lost' );
236
- define( 'WCF_CART_NORMAL_ORDER', 'normal' );
237
- define( 'CARTFLOWS_ZAPIER_ACTION_AFTER_TIME', 1800 );
238
-
239
- define( 'WCF_ACTION_ABANDONED_CARTS', 'abandoned_carts' );
240
- define( 'WCF_ACTION_RECOVERED_CARTS', 'recovered_carts' );
241
- define( 'WCF_ACTION_LOST_CARTS', 'lost_carts' );
242
- define( 'WCF_ACTION_SETTINGS', 'settings' );
243
- define( 'WCF_ACTION_REPORTS', 'reports' );
244
-
245
- define( 'WCF_SUB_ACTION_REPORTS_VIEW', 'view' );
246
- define( 'WCF_SUB_ACTION_REPORTS_RESCHEDULE', 'reschedule' );
247
-
248
- define( 'WCF_DEFAULT_CUT_OFF_TIME', 15 );
249
- define( 'WCF_DEFAULT_COUPON_AMOUNT', 10 );
250
-
251
- define( 'WCF_CA_DATETIME_FORMAT', 'Y-m-d H:i:s' );
252
- }
253
-
254
- /**
255
- * Restore cart abandonemnt data on checkout page.
256
- *
257
- * @param array $fields checkout fields values.
258
- * @return array field values
259
- */
260
- function restore_cart_abandonment_data( $fields = array() ) {
261
- global $woocommerce;
262
- $result = array();
263
- // Restore only of user is not logged in.
264
- $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
265
- if ( $this->is_valid_token( $wcf_ac_token ) ) {
266
-
267
- // Check if `wcf_restore_token` exists to restore cart data.
268
- $token_data = $this->wcf_decode_token( $wcf_ac_token );
269
-
270
- if ( is_array( $token_data ) && array_key_exists( 'wcf_session_id', $token_data ) ) {
271
- $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
272
- if ( isset( $result ) && WCF_CART_ABANDONED_ORDER === $result->order_status || WCF_CART_LOST_ORDER === $result->order_status ) {
273
- WC()->session->set( 'wcf_session_id', $token_data['wcf_session_id'] );
274
- }
275
- }
276
-
277
- if ( $result ) {
278
- $cart_content = unserialize( $result->cart_contents );
279
-
280
- if ( $cart_content ) {
281
- $woocommerce->cart->empty_cart();
282
- foreach ( $cart_content as $cart_item ) {
283
- $id = $cart_item['product_id'];
284
- $qty = $cart_item['quantity'];
285
-
286
- $cart_item_data = array();
287
- if ( isset( $cart_item['cartflows_bump'] ) ) {
288
- $cart_item_data['cartflows_bump'] = $cart_item['cartflows_bump'];
289
- }
290
-
291
- if ( isset( $cart_item['custom_price'] ) ) {
292
- $cart_item_data['custom_price'] = $cart_item['custom_price'];
293
- }
294
-
295
- $woocommerce->cart->add_to_cart( $id, $qty, $cart_item['variation_id'], array(), $cart_item_data );
296
- }
297
- }
298
- $other_fields = unserialize( $result->other_fields );
299
-
300
- $parts = explode( ',', $other_fields['wcf_location'] );
301
- if ( count( $parts ) > 1 ) {
302
- $country = $parts[0];
303
- $city = trim( $parts[1] );
304
- } else {
305
- $country = $parts[0];
306
- $city = '';
307
- }
308
-
309
- foreach ( $other_fields as $key => $value ) {
310
- $key = str_replace( 'wcf_', '', $key );
311
- $_POST[ $key ] = sanitize_text_field( $value );
312
- }
313
- $_POST['billing_first_name'] = sanitize_text_field( $other_fields['wcf_first_name'] );
314
- $_POST['billing_last_name'] = sanitize_text_field( $other_fields['wcf_last_name'] );
315
- $_POST['billing_phone'] = sanitize_text_field( $other_fields['wcf_phone_number'] );
316
- $_POST['billing_email'] = sanitize_email( $result->email );
317
- $_POST['billing_city'] = sanitize_text_field( $city );
318
- $_POST['billing_country'] = sanitize_text_field( $country );
319
-
320
- }
321
- }
322
- return $fields;
323
- }
324
- /**
325
- * Load cart abandonemnt tracking script.
326
- *
327
- * @return void
328
- */
329
- function cart_abandonment_tracking_script() {
330
-
331
- global $post;
332
- wp_enqueue_script(
333
- 'cartflows-cart-abandonment-tracking',
334
- CARTFLOWS_CART_ABANDONMENT_TRACKING_URL . 'assets/js/cart-abandonment-tracking.js',
335
- array( 'jquery' ),
336
- CARTFLOWS_CA_VER,
337
- true
338
- );
339
-
340
- $vars = array(
341
- 'ajaxurl' => admin_url( 'admin-ajax.php' ),
342
- '_nonce' => wp_create_nonce( 'cartflows_save_cart_abandonment_data' ),
343
- '_gdpr_nonce' => wp_create_nonce( 'cartflows_skip_cart_tracking_gdpr' ),
344
- '_post_id' => get_the_ID(),
345
- '_show_gdpr_message' => ( wcf_ca()->utils->is_gdpr_enabled() && ! isset( $_COOKIE['wcf_ca_skip_track_data'] ) ),
346
- '_gdpr_message' => get_option( 'wcf_ca_gdpr_message' ),
347
- '_gdpr_nothanks_msg' => __( 'No Thanks', 'cartflows-ca' ),
348
- '_gdpr_after_no_thanks_msg' => __( 'You won\'t receive further emails from us, thank you!', 'cartflows-ca' ),
349
- 'enable_ca_tracking' => true,
350
- );
351
-
352
- wp_localize_script( 'cartflows-cart-abandonment-tracking', 'CartFlowsProCAVars', $vars );
353
-
354
- }
355
-
356
- /**
357
- * Validate the token before use.
358
- *
359
- * @param string $token token form the url.
360
- * @return bool
361
- */
362
- function is_valid_token( $token ) {
363
- $is_valid = false;
364
- $token_data = $this->wcf_decode_token( $token );
365
- if ( is_array( $token_data ) && array_key_exists( 'wcf_session_id', $token_data ) ) {
366
- $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
367
- if ( isset( $result ) ) {
368
- $is_valid = true;
369
- }
370
- }
371
- return $is_valid;
372
- }
373
-
374
- /**
375
- * Execute Zapier webhook for further action inside Zapier.
376
- *
377
- * @since 1.0.0
378
- */
379
- function update_order_status() {
380
-
381
- global $wpdb;
382
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
383
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
384
- $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
385
-
386
- $wp_current_datetime = current_time( WCF_CA_DATETIME_FORMAT );
387
- $abandoned_ids = $wpdb->get_results(
388
- $wpdb->prepare('SELECT `session_id` FROM `' . $cart_abandonment_table . '` WHERE `order_status` = %s AND ADDDATE( `time`, INTERVAL %d MINUTE) <= %s', WCF_CART_NORMAL_ORDER, $minutes, $wp_current_datetime ), ARRAY_A // phpcs:ignore
389
- );
390
-
391
- foreach ( $abandoned_ids as $session_id ) {
392
-
393
- if ( isset( $session_id['session_id'] ) ) {
394
-
395
- $current_session_id = $session_id['session_id'];
396
- $this->schedule_emails( $current_session_id );
397
-
398
- $coupon_code = '';
399
- $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
400
-
401
- if ( 'on' === $wcf_ca_coupon_code_status ) {
402
- $discount_type = get_option( 'wcf_ca_discount_type' );
403
- $discount_type = $discount_type ? $discount_type : 'percent';
404
- $amount = get_option( 'wcf_ca_coupon_amount' );
405
- $amount = $amount ? $amount : WCF_DEFAULT_COUPON_AMOUNT;
406
- $coupon_expiry_date = get_option( 'wcf_ca_coupon_expiry' );
407
- $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
408
- $coupon_expiry_date = $coupon_expiry_date ? strtotime( $wp_current_datetime . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
409
- $coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date );
410
- }
411
-
412
- $wpdb->update(
413
- $cart_abandonment_table,
414
- array(
415
- 'order_status' => WCF_CART_ABANDONED_ORDER,
416
- 'coupon_code' => $coupon_code,
417
- ),
418
- array( 'session_id' => $current_session_id )
419
- );
420
-
421
- $this->trigger_zapier_webhook( $current_session_id, WCF_CART_ABANDONED_ORDER );
422
- }
423
- }
424
-
425
- /**
426
- * Send scheduled emails.
427
- */
428
- $this->send_emails_to_callback();
429
-
430
- // Update order status to lost after campaign complete.
431
- // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
432
- $wpdb->query(
433
- $wpdb->prepare(
434
- "UPDATE $cart_abandonment_table as ca SET order_status = 'lost' WHERE ca.order_status = %s AND DATE(ca.time) <= DATE_SUB( %s , INTERVAL 30 DAY)
435
- AND ( (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id ) =
436
- (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id AND email_sent = 1) )",
437
- WCF_CART_ABANDONED_ORDER,
438
- $wp_current_datetime
439
- )
440
- );
441
- // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
442
- }
443
-
444
- /**
445
- * Send zapier webhook.
446
- *
447
- * @param string $session_id session id.
448
- * @param string $order_status order status.
449
- */
450
- function trigger_zapier_webhook( $session_id, $order_status ) {
451
-
452
- $checkout_details = $this->get_checkout_details( $session_id );
453
-
454
- if ( $checkout_details && wcf_ca()->utils->is_zapier_trigger_enabled() ) {
455
- $trigger_details = array();
456
- $url = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
457
-
458
- $other_details = unserialize( $checkout_details->other_fields );
459
- $trigger_details['first_name'] = $other_details['wcf_first_name'];
460
- $trigger_details['last_name'] = $other_details['wcf_last_name'];
461
- $trigger_details['email'] = $checkout_details->email;
462
- $trigger_details['checkout_url'] = $this->get_checkout_url( $checkout_details->checkout_id, $checkout_details->session_id );
463
- $trigger_details['product_names'] = $this->get_comma_separated_products( $checkout_details->cart_contents );
464
- $trigger_details['coupon_code'] = $checkout_details->coupon_code;
465
- $trigger_details['order_status'] = $order_status;
466
- $trigger_details['cart_total'] = $checkout_details->cart_total;
467
-
468
- $parameters = http_build_query( $trigger_details );
469
- $args = array(
470
- 'body' => $parameters,
471
- 'timeout' => '5',
472
- 'redirection' => '5',
473
- 'httpversion' => '1.0',
474
- 'blocking' => true,
475
- 'headers' => array(),
476
- 'cookies' => array(),
477
- );
478
- wp_remote_post( $url, $args );
479
-
480
- }
481
- }
482
-
483
-
484
- /**
485
- * Sanitize post array.
486
- *
487
- * @return array
488
- */
489
- function sanitize_post_data() {
490
-
491
- $input_post_values = array(
492
- 'wcf_billing_company' => array(
493
- 'default' => '',
494
- 'sanitize' => FILTER_SANITIZE_STRING,
495
- ),
496
- 'wcf_email' => array(
497
- 'default' => '',
498
- 'sanitize' => FILTER_SANITIZE_EMAIL,
499
- ),
500
- 'wcf_billing_address_1' => array(
501
- 'default' => '',
502
- 'sanitize' => FILTER_SANITIZE_STRING,
503
- ),
504
- 'wcf_billing_address_2' => array(
505
- 'default' => '',
506
- 'sanitize' => FILTER_SANITIZE_STRING,
507
- ),
508
- 'wcf_billing_state' => array(
509
- 'default' => '',
510
- 'sanitize' => FILTER_SANITIZE_STRING,
511
- ),
512
- 'wcf_billing_postcode' => array(
513
- 'default' => '',
514
- 'sanitize' => FILTER_SANITIZE_STRING,
515
- ),
516
- 'wcf_shipping_first_name' => array(
517
- 'default' => '',
518
- 'sanitize' => FILTER_SANITIZE_STRING,
519
- ),
520
- 'wcf_shipping_last_name' => array(
521
- 'default' => '',
522
- 'sanitize' => FILTER_SANITIZE_STRING,
523
- ),
524
- 'wcf_shipping_company' => array(
525
- 'default' => '',
526
- 'sanitize' => FILTER_SANITIZE_STRING,
527
- ),
528
- 'wcf_shipping_country' => array(
529
- 'default' => '',
530
- 'sanitize' => FILTER_SANITIZE_STRING,
531
- ),
532
- 'wcf_shipping_address_1' => array(
533
- 'default' => '',
534
- 'sanitize' => FILTER_SANITIZE_STRING,
535
- ),
536
- 'wcf_shipping_address_2' => array(
537
- 'default' => '',
538
- 'sanitize' => FILTER_SANITIZE_STRING,
539
- ),
540
- 'wcf_shipping_city' => array(
541
- 'default' => '',
542
- 'sanitize' => FILTER_SANITIZE_STRING,
543
- ),
544
- 'wcf_shipping_state' => array(
545
- 'default' => '',
546
- 'sanitize' => FILTER_SANITIZE_STRING,
547
- ),
548
- 'wcf_shipping_postcode' => array(
549
- 'default' => '',
550
- 'sanitize' => FILTER_SANITIZE_STRING,
551
- ),
552
- 'wcf_order_comments' => array(
553
- 'default' => '',
554
- 'sanitize' => FILTER_SANITIZE_STRING,
555
- ),
556
- 'wcf_name' => array(
557
- 'default' => '',
558
- 'sanitize' => FILTER_SANITIZE_STRING,
559
- ),
560
- 'wcf_surname' => array(
561
- 'default' => '',
562
- 'sanitize' => FILTER_SANITIZE_STRING,
563
- ),
564
- 'wcf_phone' => array(
565
- 'default' => '',
566
- 'sanitize' => FILTER_SANITIZE_STRING,
567
- ),
568
- 'wcf_country' => array(
569
- 'default' => '',
570
- 'sanitize' => FILTER_SANITIZE_STRING,
571
- ),
572
- 'wcf_city' => array(
573
- 'default' => '',
574
- 'sanitize' => FILTER_SANITIZE_STRING,
575
- ),
576
- 'wcf_post_id' => array(
577
- 'default' => 0,
578
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
579
- ),
580
- );
581
-
582
- $sanitized_post = array();
583
- foreach ( $input_post_values as $key => $input_post_value ) {
584
-
585
- if ( isset( $_POST[ $key ] ) ) {
586
- $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
587
- } else {
588
- $sanitized_post[ $key ] = $input_post_value['default'];
589
- }
590
- }
591
- return $sanitized_post;
592
-
593
- }
594
-
595
-
596
- /**
597
- * Save cart abandonment tracking and schedule new event.
598
- *
599
- * @since 1.0.0
600
- */
601
- function save_cart_abandonment_data() {
602
-
603
- check_ajax_referer( 'cartflows_save_cart_abandonment_data', 'security' );
604
- $post_data = $this->sanitize_post_data();
605
- if ( isset( $post_data['wcf_email'] ) ) {
606
- $user_email = sanitize_email( $post_data['wcf_email'] );
607
- global $wpdb;
608
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
609
-
610
- // Verify if email is already exists.
611
- $session_id = WC()->session->get( 'wcf_session_id' );
612
- $session_checkout_details = null;
613
- if ( isset( $session_id ) ) {
614
- $session_checkout_details = $this->get_checkout_details( $session_id );
615
- } else {
616
- $session_checkout_details = $this->get_checkout_details_by_email( $user_email );
617
- if ( $session_checkout_details ) {
618
- $session_id = $session_checkout_details->session_id;
619
- WC()->session->set( 'wcf_session_id', $session_id );
620
- } else {
621
- $session_id = md5( uniqid( rand(), true ) );
622
- }
623
- }
624
-
625
- $checkout_details = $this->prepare_abandonment_data( $post_data );
626
-
627
- if ( isset( $session_checkout_details ) && WCF_CART_COMPLETED_ORDER === $session_checkout_details->order_status ) {
628
- WC()->session->__unset( 'wcf_session_id' );
629
- $session_id = md5( uniqid( rand(), true ) );
630
- }
631
-
632
- if ( ( ! is_null( $session_id ) ) && ! is_null( $session_checkout_details ) ) {
633
-
634
- // Updating row in the Database where users Session id = same as prevously saved in Session.
635
- $wpdb->update(
636
- $cart_abandonment_table,
637
- $checkout_details,
638
- array( 'session_id' => $session_id )
639
- );
640
-
641
- } else {
642
-
643
- $checkout_details['session_id'] = sanitize_text_field( $session_id );
644
- // Inserting row into Database.
645
- $wpdb->insert(
646
- $cart_abandonment_table,
647
- $checkout_details
648
- );
649
-
650
- // Storing session_id in WooCommerce session.
651
- WC()->session->set( 'wcf_session_id', $session_id );
652
-
653
- }
654
-
655
- wp_send_json_success();
656
- }
657
- }
658
-
659
-
660
- /**
661
- * Prepare cart data to save for abandonment.
662
- *
663
- * @param array $post_data post data.
664
- * @return array
665
- */
666
- function prepare_abandonment_data( $post_data = array() ) {
667
-
668
- if ( function_exists( 'WC' ) ) {
669
-
670
- // Retrieving cart total value and currency.
671
- $cart_total = WC()->cart->total;
672
-
673
- // Retrieving cart products and their quantities.
674
- $products = WC()->cart->get_cart();
675
- $current_time = current_time( WCF_CA_DATETIME_FORMAT );
676
- $other_fields = array(
677
- 'wcf_billing_company' => $post_data['wcf_billing_company'],
678
- 'wcf_billing_address_1' => $post_data['wcf_billing_address_1'],
679
- 'wcf_billing_address_2' => $post_data['wcf_billing_address_2'],
680
- 'wcf_billing_state' => $post_data['wcf_billing_state'],
681
- 'wcf_billing_postcode' => $post_data['wcf_billing_postcode'],
682
- 'wcf_shipping_first_name' => $post_data['wcf_shipping_first_name'],
683
- 'wcf_shipping_last_name' => $post_data['wcf_shipping_last_name'],
684
- 'wcf_shipping_company' => $post_data['wcf_shipping_company'],
685
- 'wcf_shipping_country' => $post_data['wcf_shipping_country'],
686
- 'wcf_shipping_address_1' => $post_data['wcf_shipping_address_1'],
687
- 'wcf_shipping_address_2' => $post_data['wcf_shipping_address_2'],
688
- 'wcf_shipping_city' => $post_data['wcf_shipping_city'],
689
- 'wcf_shipping_state' => $post_data['wcf_shipping_state'],
690
- 'wcf_shipping_postcode' => $post_data['wcf_shipping_postcode'],
691
- 'wcf_order_comments' => $post_data['wcf_order_comments'],
692
- 'wcf_first_name' => $post_data['wcf_name'],
693
- 'wcf_last_name' => $post_data['wcf_surname'],
694
- 'wcf_phone_number' => $post_data['wcf_phone'],
695
- 'wcf_location' => $post_data['wcf_country'] . ', ' . $post_data['wcf_city'],
696
- );
697
-
698
- $checkout_details = array(
699
- 'email' => $post_data['wcf_email'],
700
- 'cart_contents' => serialize( $products ),
701
- 'cart_total' => sanitize_text_field( $cart_total ),
702
- 'time' => sanitize_text_field( $current_time ),
703
- 'other_fields' => serialize( $other_fields ),
704
- 'checkout_id' => $post_data['wcf_post_id'],
705
- );
706
- }
707
- return $checkout_details;
708
- }
709
-
710
- /**
711
- * Deletes cart abandonment tracking and scheduled event.
712
- *
713
- * @param int $order_id Order ID.
714
- * @since 1.0.0
715
- */
716
- function delete_cart_abandonment_data( $order_id ) {
717
- global $wpdb;
718
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
719
-
720
- if ( isset( WC()->session ) ) {
721
- $session_id = WC()->session->get( 'wcf_session_id' );
722
-
723
- if ( isset( $session_id ) ) {
724
- $checkout_details = $this->get_checkout_details( $session_id );
725
-
726
- if ( $checkout_details && ( WCF_CART_ABANDONED_ORDER === $checkout_details->order_status || WCF_CART_LOST_ORDER === $checkout_details->order_status ) ) {
727
-
728
- // Update order status.
729
- $wpdb->update(
730
- $cart_abandonment_table,
731
- array(
732
- 'order_status' => WCF_CART_COMPLETED_ORDER,
733
- ),
734
- array(
735
- 'session_id' => $session_id,
736
- )
737
- );
738
-
739
- $this->trigger_zapier_webhook( $session_id, WCF_CART_COMPLETED_ORDER );
740
-
741
- $order = wc_get_order( $order_id );
742
- $note = __( 'CartFlows says: This order was abandoned & subsequently recovered.', 'cartflows-ca' );
743
- $order->add_order_note( $note );
744
- $order->save();
745
-
746
- } else {
747
- // Normal checkout.
748
-
749
- $billing_email = filter_input( INPUT_POST, 'billing_email', FILTER_SANITIZE_EMAIL );
750
-
751
- if ( $billing_email ) {
752
- $order_data = $this->get_captured_data_by_email( $billing_email );
753
-
754
- if ( ! is_null( $order_data ) ) {
755
- $existing_cart_contents = unserialize( $order_data->cart_contents );
756
- $order_cart_contents = unserialize( $checkout_details->cart_contents );
757
- $existing_cart_products = array_keys( (array) $existing_cart_contents );
758
- $order_cart_products = array_keys( (array) $order_cart_contents );
759
- if ( $this->check_if_similar_cart( $existing_cart_products, $order_cart_products ) ) {
760
- $wpdb->update(
761
- $cart_abandonment_table,
762
- array(
763
- 'order_status' => WCF_CART_COMPLETED_ORDER,
764
- ),
765
- array(
766
- 'session_id' => $order_data->session_id,
767
- )
768
- );
769
- }
770
- }
771
- }
772
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
773
- }
774
- }
775
- WC()->session->__unset( 'wcf_session_id' );
776
- }
777
- }
778
-
779
-
780
- /**
781
- * Compare cart if similar products.
782
- *
783
- * @param array $cart_a cart_a.
784
- * @param array $cart_b cart_b.
785
- * @return bool
786
- */
787
- function check_if_similar_cart( $cart_a, $cart_b ) {
788
- return (
789
- is_array( $cart_a )
790
- && is_array( $cart_b )
791
- && count( $cart_a ) === count( $cart_b )
792
- && array_diff( $cart_a, $cart_b ) === array_diff( $cart_b, $cart_a )
793
- );
794
- }
795
-
796
-
797
- /**
798
- * Get the checkout details for the user.
799
- *
800
- * @param string $wcf_session_id checkout page session id.
801
- * @since 1.0.0
802
- */
803
- function get_checkout_details( $wcf_session_id ) {
804
- global $wpdb;
805
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
806
- $result = $wpdb->get_row(
807
- $wpdb->prepare('SELECT * FROM `' . $cart_abandonment_table . '` WHERE session_id = %s', $wcf_session_id ) // phpcs:ignore
808
- );
809
- return $result;
810
- }
811
-
812
- /**
813
- * Get the checkout details for the user.
814
- *
815
- * @param string $email user email.
816
- * @since 1.0.0
817
- */
818
- function get_checkout_details_by_email( $email ) {
819
- global $wpdb;
820
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
821
- $result = $wpdb->get_row(
822
- $wpdb->prepare('SELECT * FROM `' . $cart_abandonment_table . '` WHERE email = %s AND `order_status` IN ( %s, %s )', $email, WCF_CART_ABANDONED_ORDER, WCF_CART_NORMAL_ORDER ) // phpcs:ignore
823
- );
824
- return $result;
825
- }
826
-
827
-
828
- /**
829
- * Get the checkout details for the user.
830
- *
831
- * @param string $value value.
832
- * @since 1.0.0
833
- */
834
- function get_captured_data_by_email( $value ) {
835
- global $wpdb;
836
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
837
- $result = $wpdb->get_row(
838
- $wpdb->prepare(
839
- 'SELECT * FROM `' . $cart_abandonment_table . '` WHERE email = %s AND `order_status` IN (%s, %s) ORDER BY `time` DESC LIMIT 1', $value, WCF_CART_ABANDONED_ORDER, WCF_CART_LOST_ORDER ) // phpcs:ignore
840
- );
841
- return $result;
842
- }
843
-
844
-
845
- /**
846
- * Add submenu to admin menu.
847
- *
848
- * @since 1.1.5
849
- */
850
- function abandoned_cart_tracking_menu() {
851
-
852
- $parent_slug = 'woocommerce';
853
- $page_title = __( 'Cart Abandonment', 'cartflows-ca' );
854
- $menu_title = __( 'Cart Abandonment', 'cartflows-ca' );
855
- $capability = 'manage_options';
856
- $menu_slug = WCF_CA_PAGE_NAME;
857
- $callback = array( $this, 'render_abandoned_cart_tracking' );
858
-
859
- add_submenu_page(
860
- $parent_slug,
861
- $page_title,
862
- $menu_title,
863
- $capability,
864
- $menu_slug,
865
- $callback
866
- );
867
- }
868
-
869
- /**
870
- * Render table view for cart abandonment tracking.
871
- *
872
- * @since 1.1.5
873
- */
874
- function render_abandoned_cart_tracking() {
875
-
876
- $wcf_list_table = new Cartflows_Ca_Cart_Abandonment_Table();
877
-
878
- if ( 'delete' === $wcf_list_table->current_action() ) {
879
-
880
- $ids = array();
881
- if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) {
882
- $ids = array_map( 'intval', $_REQUEST['id'] );
883
- }
884
- $deleted_row_count = empty( $ids ) ? 1 : count( $ids );
885
-
886
- $wcf_list_table->process_bulk_action();
887
- $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'Items deleted: %d', 'cartflows-ca' ), $deleted_row_count ) . '</p></div>'; // phpcs:ignore
888
- set_transient( 'wcf_ca_show_message', $message, 5 );
889
- if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
890
- wp_safe_redirect( $_SERVER['HTTP_REFERER'] );
891
- }
892
- } elseif ( 'unsubscribe' === $wcf_list_table->current_action() ) {
893
-
894
- global $wpdb;
895
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
896
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
897
-
898
- $wpdb->update(
899
- $cart_abandonment_table,
900
- array( 'unsubscribed' => true ),
901
- array( 'id' => $id )
902
- );
903
-
904
- $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'User unsubscribed successfully!', 'cartflows-ca' ) ) . '</p></div>'; // phpcs:ignore
905
- set_transient( 'wcf_ca_show_message', $message, 5 );
906
- if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
907
- wp_safe_redirect( $_SERVER['HTTP_REFERER'] );
908
- }
909
- }
910
- ?>
911
-
912
- <?php
913
- include_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-tabs.php';
914
- ?>
915
- <?php
916
- }
917
-
918
- /**
919
- * Count abandoned carts
920
- *
921
- * @since 1.1.5
922
- */
923
- function abandoned_cart_count() {
924
- global $wpdb;
925
- $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
926
-
927
- $query = $wpdb->prepare( "SELECT COUNT(`id`) FROM {$cart_abandonment_table_name} WHERE `order_status` = %s", WCF_CART_ABANDONED_ORDER ); // phpcs:ignore
928
- $total_items = $wpdb->get_var( $query ); // phpcs:ignore
929
- return $total_items;
930
- }
931
-
932
- /**
933
- * Load analytics scripts.
934
- */
935
- function load_admin_cart_abandonment_script() {
936
-
937
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
938
-
939
- if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
940
- return;
941
- }
942
-
943
- // Styles.
944
- wp_enqueue_style( 'cartflows-cart-abandonment-admin', CARTFLOWS_CA_URL . 'admin/assets/css/admin-cart-abandonment.css', array(), CARTFLOWS_CA_VER );
945
-
946
- }
947
-
948
-
949
- /**
950
- * Render Cart abandonment display button beside title.
951
- */
952
- public function setup_cart_abandonment_button() {
953
-
954
- if ( ! Cartflows_Admin::is_flow_edit_admin() ) {
955
- return;
956
- }
957
-
958
- $reports_btn_markup = '<style>.wrap{ position:relative;}</style>';
959
- $reports_btn_markup .= "<div class='wcf-reports-button-wrap'>";
960
- $reports_btn_markup .= "<button class='wcf-cart-abandonment-reports-popup button button-secondary'>";
961
- $reports_btn_markup .= esc_html( 'View Report', 'cartflows-ca' );
962
- $reports_btn_markup .= '</button>';
963
- $reports_btn_markup .= '</div>';
964
-
965
- echo $reports_btn_markup;
966
-
967
- }
968
-
969
- /**
970
- * Get start and end date for given interval.
971
- *
972
- * @param string $interval interval .
973
- * @return array
974
- */
975
- function get_start_end_by_interval( $interval ) {
976
-
977
- if ( 'today' === $interval ) {
978
- $start_date = date( 'Y-m-d' );
979
- $end_date = date( 'Y-m-d' );
980
- } else {
981
-
982
- $days = $interval;
983
-
984
- $start_date = date( 'Y-m-d', strtotime( '-' . $days . ' days' ) );
985
- $end_date = date( 'Y-m-d' );
986
- }
987
-
988
- return array(
989
- 'start' => $start_date,
990
- 'end' => $end_date,
991
- );
992
- }
993
-
994
-
995
- /**
996
- * Get Attributable revenue.
997
- * Represents the revenue generated by this campaign.
998
- *
999
- * @param string $type abondened|completed.
1000
- * @param string $from_date from date.
1001
- * @param string $to_date to date.
1002
- */
1003
- function get_report_by_type( $type = WCF_CART_ABANDONED_ORDER, $from_date, $to_date ) {
1004
- global $wpdb;
1005
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1006
- $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
1007
- $attributable_revenue = $wpdb->get_row(
1008
- $wpdb->prepare( "SELECT SUM(`cart_total`) as revenue, count('*') as no_of_orders FROM {$cart_abandonment_table} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s ", $type, $from_date, $to_date ), // phpcs:ignore
1009
- ARRAY_A
1010
- );
1011
- return $attributable_revenue;
1012
- }
1013
-
1014
-
1015
- /**
1016
- * Get checkout url.
1017
- *
1018
- * @param integer $post_id post id.
1019
- * @param string $session_id session id.
1020
- * @return string
1021
- */
1022
- function get_checkout_url( $post_id, $session_id ) {
1023
-
1024
- $token = $this->wcf_generate_token( array( 'wcf_session_id' => $session_id ) );
1025
- $checkout_url = get_permalink( $post_id ) . '?wcf_ac_token=' . $token;
1026
- return esc_url( $checkout_url );
1027
- }
1028
-
1029
- /**
1030
- * Geberate the token for the given data.
1031
- *
1032
- * @param array $data data.
1033
- */
1034
- function wcf_generate_token( $data ) {
1035
- return urlencode( base64_encode( http_build_query( $data ) ) );
1036
- }
1037
-
1038
- /**
1039
- * Decode and get the original contents.
1040
- *
1041
- * @param string $token token.
1042
- */
1043
- function wcf_decode_token( $token ) {
1044
- $token = sanitize_text_field( $token );
1045
- parse_str( base64_decode( urldecode( $token ) ), $token );
1046
- return $token;
1047
- }
1048
-
1049
- /**
1050
- * Render Cart abandonment tabs.
1051
- *
1052
- * @since 1.1.5
1053
- */
1054
- function wcf_display_tabs() {
1055
-
1056
- $action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
1057
- $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
1058
-
1059
- if ( ! $action ) {
1060
- $action = WCF_ACTION_REPORTS;
1061
- $active_settings = '';
1062
- $active_reports = '';
1063
- $active_email_templates = '';
1064
- }
1065
-
1066
- switch ( $action ) {
1067
- case WCF_ACTION_SETTINGS:
1068
- $active_settings = 'nav-tab-active';
1069
- break;
1070
- case WCF_ACTION_REPORTS:
1071
- $active_reports = 'nav-tab-active';
1072
- break;
1073
- case WCF_ACTION_EMAIL_TEMPLATES:
1074
- $active_email_templates = 'nav-tab-active';
1075
- break;
1076
- default:
1077
- $active_reports = 'nav-tab-active';
1078
- break;
1079
- }
1080
- // phpcs:disable
1081
- ?>
1082
-
1083
-
1084
- <div class="nav-tab-wrapper woo-nav-tab-wrapper">
1085
-
1086
- <?php
1087
- $url = add_query_arg( array(
1088
- 'page' => WCF_CA_PAGE_NAME,
1089
- 'action' => WCF_ACTION_REPORTS
1090
- ), admin_url( '/admin.php' ) )
1091
- ?>
1092
- <a href="<?php echo $url; ?>"
1093
- class="nav-tab
1094
- <?php
1095
- if ( isset( $active_reports ) ) {
1096
- echo $active_reports;}
1097
- ?>
1098
- ">
1099
- <?php _e( 'Report', 'cartflows-ca' ); ?>
1100
- </a>
1101
-
1102
- <?php
1103
- $url = add_query_arg( array(
1104
- 'page' => WCF_CA_PAGE_NAME,
1105
- 'action' => WCF_ACTION_EMAIL_TEMPLATES
1106
- ), admin_url( '/admin.php' ) )
1107
- ?>
1108
- <a href="<?php echo $url; ?>"
1109
- class="nav-tab
1110
- <?php
1111
- if ( isset( $active_email_templates ) ) {
1112
- echo $active_email_templates;}
1113
- ?>
1114
- ">
1115
- <?php _e( 'Emails', 'cartflows-ca' ); ?>
1116
- </a>
1117
-
1118
- <?php
1119
- $url = add_query_arg( array(
1120
- 'page' => WCF_CA_PAGE_NAME,
1121
- 'action' => WCF_ACTION_SETTINGS
1122
- ), admin_url( '/admin.php' ) )
1123
- ?>
1124
- <a href="<?php echo $url; ?>"
1125
- class="nav-tab
1126
- <?php
1127
- if ( isset( $active_settings ) ) {
1128
- echo $active_settings;}
1129
- ?>
1130
- ">
1131
- <?php _e( 'Settings', 'cartflows-ca' ); ?>
1132
- </a>
1133
-
1134
- </div>
1135
- <?php
1136
- // phpcs:enable
1137
- }
1138
-
1139
- /**
1140
- * Render Cart abandonment settings.
1141
- *
1142
- * @since 1.1.5
1143
- */
1144
- function wcf_display_settings() {
1145
- ?>
1146
-
1147
- <form method="post" action="options.php">
1148
- <?php settings_fields( WCF_CA_SETTINGS_OPTION_GROUP ); ?>
1149
- <?php do_settings_sections( WCF_CA_PAGE_NAME ); ?>
1150
- <?php submit_button(); ?>
1151
- </form>
1152
-
1153
- <?php
1154
- }
1155
-
1156
- /**
1157
- * Render Cart abandonment reports.
1158
- *
1159
- * @since 1.1.5
1160
- */
1161
- function wcf_display_reports() {
1162
-
1163
- $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
1164
- $filter_table = filter_input( INPUT_GET, 'filter_table', FILTER_SANITIZE_STRING );
1165
-
1166
- if ( ! $filter ) {
1167
- $filter = 'last_month';
1168
- }
1169
- if ( ! $filter_table ) {
1170
- $filter_table = WCF_CART_ABANDONED_ORDER;
1171
- }
1172
-
1173
- $from_date = filter_input( INPUT_GET, 'from_date', FILTER_SANITIZE_STRING );
1174
- $to_date = filter_input( INPUT_GET, 'to_date', FILTER_SANITIZE_STRING );
1175
-
1176
- switch ( $filter ) {
1177
-
1178
- case 'yesterday':
1179
- $to_date = date( 'Y-m-d', strtotime( '-1 days' ) );
1180
- $from_date = $to_date;
1181
- break;
1182
- case 'today':
1183
- $to_date = date( 'Y-m-d' );
1184
- $from_date = $to_date;
1185
- break;
1186
- case 'last_week':
1187
- $from_date = date( 'Y-m-d', strtotime( '-7 days' ) );
1188
- $to_date = date( 'Y-m-d' );
1189
- break;
1190
- case 'last_month':
1191
- $from_date = date( 'Y-m-d', strtotime( '-1 months' ) );
1192
- $to_date = date( 'Y-m-d' );
1193
- break;
1194
- case 'custom':
1195
- $to_date = $to_date ? $to_date : date( 'Y-m-d' );
1196
- $from_date = $from_date ? $from_date : $to_date;
1197
- break;
1198
-
1199
- }
1200
-
1201
- $abandoned_report = $this->get_report_by_type( WCF_CART_ABANDONED_ORDER, $from_date, $to_date );
1202
- $recovered_report = $this->get_report_by_type( WCF_CART_COMPLETED_ORDER, $from_date, $to_date );
1203
- $lost_report = $this->get_report_by_type( WCF_CART_LOST_ORDER, $from_date, $to_date );
1204
-
1205
- $wcf_list_table = new Cartflows_Ca_Cart_Abandonment_Table();
1206
- $wcf_list_table->prepare_items( $filter_table, $from_date, $to_date );
1207
-
1208
- $conversion_rate = 0;
1209
- $total_orders = ( $recovered_report['no_of_orders'] + $abandoned_report['no_of_orders'] + $lost_report['no_of_orders'] );
1210
- if ( $total_orders ) {
1211
- $conversion_rate = ( $recovered_report['no_of_orders'] / $total_orders ) * 100;
1212
- }
1213
-
1214
- global $woocommerce;
1215
- $conversion_rate = number_format_i18n( $conversion_rate, 2 );
1216
- $currency_symbol = get_woocommerce_currency_symbol();
1217
- require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-reports.php';
1218
- }
1219
-
1220
-
1221
- /**
1222
- * Show report details for specific order.
1223
- */
1224
- function wcf_display_report_details() {
1225
-
1226
- $sesson_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
1227
-
1228
- if ( $sesson_id ) {
1229
- $details = $this->get_checkout_details( $sesson_id );
1230
- $user_details = (object) unserialize( $details->other_fields );
1231
- $scheduled_emails = $this->fetch_scheduled_emails( $sesson_id );
1232
-
1233
- require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-ca-single-report-details.php';
1234
- }
1235
-
1236
- }
1237
-
1238
- /**
1239
- * Check and show warning message if cart abandonment is disabled.
1240
- */
1241
- function wcf_show_warning_ca() {
1242
- $settings_url = add_query_arg(
1243
- array(
1244
- 'page' => WCF_CA_PAGE_NAME,
1245
- 'action' => WCF_ACTION_SETTINGS,
1246
- ),
1247
- admin_url( '/admin.php' )
1248
- );
1249
-
1250
- if ( ! wcf_ca()->utils->is_cart_abandonment_tracking_enabled() ) {
1251
- ?>
1252
- <div class="notice notice-warning is-dismissible">
1253
- <p>
1254
- <?php echo __('Looks like abandonment tracking is disabled! Please enable it from <a href=' . esc_url($settings_url) . '> <strong>settings</strong></a>.', 'cartflows-ca'); // phpcs:ignore
1255
- ?>
1256
- </p>
1257
- </div>
1258
- <?php
1259
- }
1260
- }
1261
-
1262
- /**
1263
- * Callback trigger event to send the emails.
1264
- */
1265
- function send_emails_to_callback() {
1266
-
1267
- global $wpdb;
1268
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1269
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1270
- $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
1271
-
1272
- $current_time = current_time( WCF_CA_DATETIME_FORMAT );
1273
- // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1274
- $emails_send_to = $wpdb->get_results(
1275
-
1276
- $wpdb->prepare(
1277
- 'SELECT *, EHT.id as email_history_id, ETT.id as email_template_id FROM ' . $email_history_table . ' as EHT
1278
- INNER JOIN ' . $cart_abandonment_table . ' as CAT ON EHT.`ca_session_id` = CAT.`session_id`
1279
- INNER JOIN ' . $email_template_table . ' as ETT ON ETT.`id` = EHT.`template_id`
1280
- WHERE CAT.`order_status` = %s AND CAT.unsubscribed = 0 AND EHT.`email_sent` = 0 AND EHT.`scheduled_time` <= %s',
1281
- WCF_CART_ABANDONED_ORDER,
1282
- $current_time
1283
- )
1284
- );
1285
- // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1286
-
1287
- foreach ( $emails_send_to as $email_send_to ) {
1288
- $email_result = $this->send_email_templates( $email_send_to );
1289
- if ( $email_result ) {
1290
- $wpdb->update(
1291
- $email_history_table,
1292
- array( 'email_sent' => true ),
1293
- array( 'id' => $email_send_to->email_history_id )
1294
- );
1295
- }
1296
- }
1297
- }
1298
-
1299
-
1300
- /**
1301
- * Create a dummy object for the preview email.
1302
- *
1303
- * @return stdClass
1304
- */
1305
- public function create_dummy_session_for_preview_email() {
1306
-
1307
- $email_data = new stdClass();
1308
- $current_user = wp_get_current_user();
1309
- $user_data = array(
1310
- 'wcf_first_name' => $current_user->user_firstname,
1311
- 'wcf_last_name' => $current_user->user_lastname,
1312
- );
1313
- $email_data->checkout_id = wc_get_page_id( 'checkout' );
1314
- $email_data->session_id = 'dummy-session-id';
1315
-
1316
- $email_send_to = filter_input( INPUT_POST, 'email_send_to', FILTER_SANITIZE_EMAIL );
1317
- $email_data->email = $email_send_to ? $email_send_to : $current_user->user_email;
1318
- $email_data->email_body = filter_input( INPUT_POST, 'email_body', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1319
- $email_data->email_subject = filter_input( INPUT_POST, 'email_subject', FILTER_SANITIZE_STRING );
1320
- $email_data->email_body = html_entity_decode( $email_data->email_body );
1321
-
1322
- $email_data->other_fields = serialize( $user_data );
1323
- if ( ! WC()->cart->get_cart_contents_count() ) {
1324
- $args = array(
1325
- 'posts_per_page' => 1,
1326
- 'orderby' => 'rand',
1327
- 'post_type' => 'product',
1328
- 'meta_query' => array(
1329
- // Exclude out of stock products.
1330
- array(
1331
- 'key' => '_stock_status',
1332
- 'value' => 'outofstock',
1333
- 'compare' => 'NOT IN',
1334
- ),
1335
- ),
1336
- 'tax_query' => array(
1337
- array(
1338
- 'taxonomy' => 'product_type',
1339
- 'field' => 'slug',
1340
- 'terms' => 'simple',
1341
- ),
1342
- ),
1343
- );
1344
-
1345
- $random_products = get_posts( $args );
1346
- if ( ! empty( $random_products ) ) {
1347
- $random_product = reset( $random_products );
1348
- WC()->cart->add_to_cart( $random_product->ID );
1349
- }
1350
- }
1351
- $email_data->cart_total = WC()->cart->total + WC()->cart->get_cart_shipping_total();
1352
- $email_data->cart_contents = serialize( WC()->cart->get_cart() );
1353
- $email_data->time = current_time( WCF_CA_DATETIME_FORMAT );
1354
- return $email_data;
1355
- }
1356
-
1357
- /**
1358
- * Callback function to send email templates.
1359
- *
1360
- * @param array $email_data email data .
1361
- * @param boolean $preview_email preview email.
1362
- * @since 1.0.0
1363
- */
1364
- function send_email_templates( $email_data, $preview_email = false ) {
1365
-
1366
- if ( $preview_email ) {
1367
- $email_data = $this->create_dummy_session_for_preview_email();
1368
- }
1369
-
1370
- if ( filter_var( $email_data->email, FILTER_VALIDATE_EMAIL ) ) {
1371
-
1372
- $checkout_url = $this->get_checkout_url( $email_data->checkout_id, $email_data->session_id );
1373
- $other_fields = unserialize( $email_data->other_fields );
1374
-
1375
- $from_email_name = get_option( 'wcf_ca_from_name' );
1376
- $reply_name_preview = get_option( 'wcf_ca_from_email' );
1377
- $from_email_preview = get_option( 'wcf_ca_reply_email' );
1378
-
1379
- $user_first_name = ucfirst( $other_fields['wcf_first_name'] );
1380
- $user_first_name = $user_first_name ? $user_first_name : __( 'there', 'cartflows-ca' );
1381
- $user_last_name = ucfirst( $other_fields['wcf_last_name'] );
1382
- $user_full_name = trim( $user_first_name . ' ' . $user_last_name );
1383
-
1384
- $subject_email_preview = stripslashes( html_entity_decode( $email_data->email_subject, ENT_QUOTES ) );
1385
- $subject_email_preview = convert_smilies( $subject_email_preview );
1386
- $subject_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $subject_email_preview );
1387
- $body_email_preview = convert_smilies( $email_data->email_body );
1388
- $body_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $body_email_preview );
1389
- $body_email_preview = str_replace( '{{customer.lastname}}', $user_last_name, $body_email_preview );
1390
- $body_email_preview = str_replace( '{{customer.fullname}}', $user_full_name, $body_email_preview );
1391
-
1392
- if ( $preview_email ) {
1393
- $coupon_code = 'DUMMY-COUPON';
1394
- $checkout_url = $checkout_url . base64_encode( 'dummy-token-string' );
1395
- } else {
1396
- $email_instance = Cartflows_Ca_Email_Templates::get_instance();
1397
- $override_global_coupon = $email_instance->get_email_template_meta_by_key( $email_data->email_template_id, 'override_global_coupon' );
1398
- if ( $override_global_coupon->meta_value ) {
1399
- $email_history = $email_instance->get_email_history_by_id( $email_data->email_history_id );
1400
- $coupon_code = $email_history->coupon_code;
1401
- } else {
1402
- $coupon_code = $email_data->coupon_code;
1403
- }
1404
- }
1405
-
1406
- $body_email_preview = str_replace( '{{cart.coupon_code}}', $coupon_code, $body_email_preview );
1407
-
1408
- $current_time_stamp = $email_data->time;
1409
- $body_email_preview = str_replace( '{{cart.abandoned_date}}', $current_time_stamp, $body_email_preview );
1410
- $unsubscribe_element = '<a target="_blank" style="color: lightgray" href="' . $checkout_url . '&unsubscribe=true' . '">' . __( 'Unsubscribe', 'cartflows-ca' ) . '</a>';
1411
- $body_email_preview = str_replace( '{{cart.unsubscribe}}', $unsubscribe_element, $body_email_preview );
1412
- $body_email_preview = str_replace( '{{cart.checkout_url}}', $checkout_url, $body_email_preview );
1413
- $host = parse_url( get_site_url() );
1414
- $body_email_preview = str_replace( '{{site.url}}', $host['host'], $body_email_preview );
1415
- $body_email_preview = str_replace( '{{cart.product.names}}', $this->get_comma_separated_products( $email_data->cart_contents ), $body_email_preview );
1416
-
1417
- $admin_user = get_users(
1418
- array(
1419
- 'role' => 'Administrator',
1420
- 'number' => 1,
1421
- )
1422
- );
1423
- $admin_user = reset( $admin_user );
1424
- $admin_first_name = $admin_user->user_firstname ? $admin_user->user_firstname : 'Admin';
1425
- $body_email_preview = str_replace( '{{admin.firstname}}', $admin_first_name, $body_email_preview );
1426
- $body_email_preview = str_replace( '{{admin.company}}', get_bloginfo( 'name' ), $body_email_preview );
1427
-
1428
- $headers = 'From: ' . $from_email_name . ' <' . $from_email_preview . '>' . "\r\n";
1429
- $headers .= 'Content-Type: text/html' . "\r\n";
1430
- $headers .= 'Reply-To: ' . $reply_name_preview . ' ' . "\r\n";
1431
- $var = $this->get_email_product_block( $email_data->cart_contents, $email_data->cart_total );
1432
-
1433
- $body_email_preview = str_replace( '{{cart.product.table}}', $var, $body_email_preview );
1434
- $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1435
- if ( $mail_result ) {
1436
- return true;
1437
- } else {
1438
- // Retry sending mail.
1439
- $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1440
- if ( ! $preview_email ) {
1441
- return true;
1442
- }
1443
- return false;
1444
- }
1445
- } else {
1446
- return false;
1447
- }
1448
-
1449
- }
1450
-
1451
- /**
1452
- * Generate comma separated products.
1453
- *
1454
- * @param object $cart_contents user cart details.
1455
- */
1456
- function get_comma_separated_products( $cart_contents ) {
1457
- $cart_comma_string = '';
1458
- if ( ! $cart_contents ) {
1459
- return $cart_comma_string;
1460
- }
1461
- $cart_data = unserialize( $cart_contents );
1462
-
1463
- $cart_length = count( $cart_data );
1464
- $index = 0;
1465
- foreach ( $cart_data as $key => $product ) {
1466
-
1467
- $cart_comma_string = $cart_comma_string . $product['data']->get_title();
1468
- if ( ( $cart_length - 2 ) === $index ) {
1469
- $cart_comma_string = $cart_comma_string . ' & ';
1470
- } elseif ( ( $cart_length - 1 ) !== $index ) {
1471
- $cart_comma_string = $cart_comma_string . ', ';
1472
- }
1473
- $index++;
1474
- }
1475
- return $cart_comma_string;
1476
-
1477
- }
1478
-
1479
- /**
1480
- * Generate the view for email product cart block.
1481
- *
1482
- * @param object $cart_contents user cart contents details.
1483
- * @param float $cart_total user cart total.
1484
- * @return string
1485
- */
1486
- function get_email_product_block( $cart_contents, $cart_total ) {
1487
-
1488
- $cart_items = unserialize( $cart_contents );
1489
- $currency_symbol = get_woocommerce_currency_symbol();
1490
- $tr = '';
1491
- $style = 'style="color: #636363; border: 1px solid #e5e5e5; "';
1492
-
1493
- foreach ( $cart_items as $cart_item ) {
1494
-
1495
- $tr = $tr . '<tr style="color: #636363; border: 1px solid #e5e5e5;" align="center">
1496
- <td ' . $style . '><img class="demo_img" width="42" height="42" src=" ' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . ' "/></td>
1497
- <td ' . $style . '>' . $cart_item['data']->get_title() . '</td>
1498
- <td ' . $style . '> ' . $cart_item['quantity'] . ' </td>
1499
- <td ' . $style . '>' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1500
- <td ' . $style . ' >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1501
- </tr> ';
1502
- }
1503
-
1504
- return '<table align="left" cellpadding="10" cellspacing="0" style="float: none; border: 1px solid #e5e5e5;">
1505
- <tr align="center">
1506
- <th ' . $style . '>' . __( 'Item', 'cartflows-ca' ) . '</th>
1507
- <th ' . $style . '>' . __( 'Name', 'cartflows-ca' ) . '</th>
1508
- <th ' . $style . '>' . __( 'Quantity', 'cartflows-ca' ) . '</th>
1509
- <th ' . $style . '>' . __( 'Price', 'cartflows-ca' ) . '</th>
1510
- <th ' . $style . '>' . __( 'Line Subtotal', 'cartflows-ca' ) . '</th>
1511
- </tr> ' . $tr . '
1512
- </table>';
1513
-
1514
- }
1515
-
1516
- /**
1517
- * Generate the view for admin product cart block.
1518
- *
1519
- * @param object $cart_contents user cart contents details.
1520
- * @param float $cart_total user cart total.
1521
- * @return string
1522
- */
1523
- function get_admin_product_block( $cart_contents, $cart_total ) {
1524
-
1525
- $cart_items = unserialize( $cart_contents );
1526
- $currency_symbol = get_woocommerce_currency_symbol();
1527
- $tr = '';
1528
- $total = 0;
1529
- $discount = 0;
1530
- $tax = 0;
1531
-
1532
- foreach ( $cart_items as $cart_item ) {
1533
-
1534
- $discount = number_format_i18n( $discount + ( $cart_item['line_subtotal'] - $cart_item['line_total'] ), 2 );
1535
- $total = number_format_i18n( $total + $cart_item['line_subtotal'], 2 );
1536
- $tax = number_format_i18n( $tax + $cart_item['line_tax'], 2 );
1537
-
1538
- $tr = $tr . '<tr align="center">
1539
- <td ><img class="demo_img" width="42" height="42" src=" ' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . ' "/></td>
1540
- <td >' . $cart_item['data']->get_title() . '</td>
1541
- <td > ' . $cart_item['quantity'] . ' </td>
1542
- <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1543
- <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1544
- </tr> ';
1545
- }
1546
-
1547
- return '<table align="left" cellspacing="0" class="widefat fixed striped posts">
1548
- <thead>
1549
- <tr align="center">
1550
- <th >' . __( 'Item', 'cartflows-ca' ) . '</th>
1551
- <th >' . __( 'Name', 'cartflows-ca' ) . '</th>
1552
- <th >' . __( 'Quantity', 'cartflows-ca' ) . '</th>
1553
- <th >' . __( 'Price', 'cartflows-ca' ) . '</th>
1554
- <th >' . __( 'Line Subtotal', 'cartflows-ca' ) . '</th>
1555
- </tr>
1556
- </thead>
1557
- <tbody>
1558
- ' . $tr . '
1559
- <tr align="center" id="wcf-ca-discount">
1560
- <td colspan="4" >' . __( 'Discount', 'cartflows-ca' ) . '</td>
1561
- <td>' . $currency_symbol . ( $discount ) . '</td>
1562
- </tr>
1563
- <tr align="center" id="wcf-ca-other">
1564
- <td colspan="4" >' . __( 'Other', 'cartflows-ca' ) . '</td>
1565
- <td>' . $currency_symbol . ( $tax ) . '</td>
1566
- </tr>
1567
-
1568
- <tr align="center" id="wcf-ca-shipping">
1569
- <td colspan="4" >' . __( 'Shipping', 'cartflows-ca' ) . '</td>
1570
- <td>' . $currency_symbol . number_format_i18n( $discount + ( $cart_total - $total ) - $tax, 2 ) . '</td>
1571
- </tr>
1572
- <tr align="center" id="wcf-ca-cart-total">
1573
- <td colspan="4" >' . __( 'Cart Total', 'cartflows-ca' ) . '</td>
1574
- <td>' . $currency_symbol . $cart_total . '</td>
1575
- </tr>
1576
- </tbody>
1577
- </table>';
1578
- }
1579
-
1580
- /**
1581
- * Copied WC function for date parameter addition.
1582
- *
1583
- * @param string $customer_email customer email.
1584
- * @param int $product_id product id.
1585
- * @param int $days days.
1586
- * @return array|bool|mixed|void
1587
- */
1588
- function wcf_ca_wc_customer_bought_product( $customer_email, $product_id, $days = 365 ) {
1589
- global $wpdb;
1590
-
1591
- $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
1592
- // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1593
- $result = $wpdb->get_var(
1594
- $wpdb->prepare(
1595
- "SELECT COUNT(p.ID) FROM {$wpdb->prefix}posts AS p
1596
- INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
1597
- INNER JOIN {$wpdb->prefix}woocommerce_order_items AS woi ON p.ID = woi.order_id
1598
- INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS woim ON woi.order_item_id = woim.order_item_id
1599
- WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
1600
- AND pm.meta_key = '_billing_email'
1601
- AND pm.meta_value = %s
1602
- AND woim.meta_key IN ( '_product_id', '_variation_id' )
1603
- AND woim.meta_value = %s
1604
- AND p.post_date > '" . date( 'Y-m-d', strtotime( '-' . $days . ' days' ) ) . "'
1605
- ",
1606
- $customer_email,
1607
- $product_id
1608
- )
1609
- );
1610
-
1611
- // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1612
-
1613
- return intval( $result ) > 0 ? true : false;
1614
-
1615
- }
1616
-
1617
- /**
1618
- * Schedule events for the abadoned carts to send emails.
1619
- *
1620
- * @param integer $session_id user session id.
1621
- * @param boolean $force_reschedule force reschedule.
1622
- */
1623
- function schedule_emails( $session_id, $force_reschedule = false ) {
1624
-
1625
- $checkout_details = $this->get_checkout_details( $session_id );
1626
-
1627
- if ( ( $checkout_details->unsubscribed ) || ( WCF_CART_COMPLETED_ORDER === $checkout_details->order_status ) ) {
1628
- return;
1629
- }
1630
- $scheduled_time_from = current_time( WCF_CA_DATETIME_FORMAT );
1631
- $scheduled_emails = $this->fetch_scheduled_emails( $session_id );
1632
- $scheduled_templates = array_column( $scheduled_emails, 'template_id' );
1633
-
1634
- // Skip if forcfully rescheduled.
1635
- if ( ! $force_reschedule ) {
1636
- $scheduled_time_from = $checkout_details->time;
1637
- $user_exist = get_user_by( 'email', $checkout_details->email );
1638
- // Don't schedule emails if products are already purchased.
1639
- if ( $user_exist ) {
1640
- $purchasing_products = unserialize( $checkout_details->cart_contents );
1641
- $already_purchased = true;
1642
- foreach ( $purchasing_products as $purchasing_product ) {
1643
- if ( isset( $purchasing_product['product_id'] ) ) {
1644
- $has_already_purchased = $this->wcf_ca_wc_customer_bought_product( $user_exist->user_email, $purchasing_product['product_id'], 30 );
1645
- if ( ! $has_already_purchased ) {
1646
- $already_purchased = false;
1647
- break;
1648
- }
1649
- }
1650
- }
1651
- if ( $already_purchased ) {
1652
- return;
1653
- }
1654
- }
1655
- }
1656
-
1657
- $email_tmpl = Cartflows_Ca_Email_Templates::get_instance();
1658
- $templates = $email_tmpl->fetch_all_active_templates();
1659
-
1660
- global $wpdb;
1661
-
1662
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1663
-
1664
- foreach ( $templates as $template ) {
1665
-
1666
- if ( false !== array_search( $template->id, $scheduled_templates, true ) ) {
1667
- continue;
1668
- }
1669
-
1670
- $timestamp_str = '+' . $template->frequency . ' ' . $template->frequency_unit . 'S';
1671
- $scheduled_time = date( WCF_CA_DATETIME_FORMAT, strtotime( $scheduled_time_from . $timestamp_str ) );
1672
- $discount_type = $email_tmpl->get_email_template_meta_by_key( $template->id, 'discount_type' );
1673
- $discount_type = isset( $discount_type->meta_value ) ? $discount_type->meta_value : '';
1674
- $amount = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_amount' );
1675
- $amount = isset( $amount->meta_value ) ? $amount->meta_value : '';
1676
-
1677
- $coupon_expiry_date = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_date' );
1678
- $coupon_expiry_unit = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_unit' );
1679
- $coupon_expiry_date = isset( $coupon_expiry_date->meta_value ) ? $coupon_expiry_date->meta_value : '';
1680
- $coupon_expiry_unit = isset( $coupon_expiry_unit->meta_value ) ? $coupon_expiry_unit->meta_value : 'hours';
1681
-
1682
- $coupon_expiry_date = $coupon_expiry_date ? strtotime( $scheduled_time . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
1683
-
1684
- $override_global_coupon = $email_tmpl->get_email_template_meta_by_key( $template->id, 'override_global_coupon' );
1685
-
1686
- $new_coupon_code = '';
1687
- if ( $override_global_coupon->meta_value ) {
1688
- $new_coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date );
1689
- }
1690
-
1691
- $wpdb->replace(
1692
- $email_history_table,
1693
- array(
1694
- 'template_id' => $template->id,
1695
- 'ca_session_id' => $checkout_details->session_id,
1696
- 'coupon_code' => $new_coupon_code,
1697
- 'scheduled_time' => $scheduled_time,
1698
- )
1699
- );
1700
- }
1701
- }
1702
-
1703
- /**
1704
- * Fetch all the scheduled emails with templates for the specific session.
1705
- *
1706
- * @param string $session_id session id.
1707
- * @return array|object|null
1708
- */
1709
- function fetch_scheduled_emails( $session_id ) {
1710
- global $wpdb;
1711
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1712
- $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
1713
-
1714
- $result = $wpdb->get_results(
1715
- $wpdb->prepare("SELECT * FROM $email_history_table as eht INNER JOIN $email_template_table as ett ON eht.template_id = ett.id WHERE ca_session_id = %s", sanitize_text_field($session_id)) // phpcs:ignore
1716
- );
1717
- return $result;
1718
- }
1719
-
1720
- }
1721
-
1722
- Cartflows_Ca_Cart_Abandonment::get_instance();
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ /**
9
+ * Cart abandonment tracking class.
10
+ */
11
+ class Cartflows_Ca_Cart_Abandonment {
12
+
13
+
14
+
15
+ /**
16
+ * Member Variable
17
+ *
18
+ * @var object instance
19
+ */
20
+ private static $instance;
21
+
22
+ /**
23
+ * Initiator
24
+ */
25
+ public static function get_instance() {
26
+ if ( ! isset( self::$instance ) ) {
27
+ self::$instance = new self;
28
+ }
29
+ return self::$instance;
30
+ }
31
+
32
+ /**
33
+ * Constructor function that initializes required actions and hooks.
34
+ */
35
+ public function __construct() {
36
+
37
+ $this->define_cart_abandonment_constants();
38
+
39
+ // Adding menu to view cart abandonment report.
40
+ add_action( 'admin_menu', array( $this, 'abandoned_cart_tracking_menu' ), 999 );
41
+
42
+ // Adding the styles and scripts for the cart abandonment.
43
+ add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_cart_abandonment_script' ), 20 );
44
+
45
+ if ( wcf_ca()->utils->is_cart_abandonment_tracking_enabled() && ! isset( $_COOKIE['wcf_ca_skip_track_data'] ) ) {
46
+
47
+ add_action( 'woocommerce_update_cart_action_cart_updated', 'on_action_cart_updated', 20, 1 );
48
+
49
+ // Add script to track the cart abandonment.
50
+ add_action( 'woocommerce_after_checkout_form', array( $this, 'cart_abandonment_tracking_script' ) );
51
+
52
+ // Store user details from the current checkout page.
53
+ add_action( 'wp_ajax_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
54
+ add_action( 'wp_ajax_nopriv_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
55
+
56
+ // GDPR actions.
57
+ add_action( 'wp_ajax_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
58
+ add_action( 'wp_ajax_nopriv_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
59
+
60
+ // Delete the stored cart abandonment data once order gets created.
61
+ add_action( 'woocommerce_new_order', array( $this, 'delete_cart_abandonment_data' ) );
62
+ add_action( 'woocommerce_thankyou', array( $this, 'delete_cart_abandonment_data' ) );
63
+
64
+ // Adding filter to restore the data if recreating abandonment order.
65
+ add_filter( 'wp', array( $this, 'restore_cart_abandonment_data' ), 10 );
66
+ add_filter( 'wp', array( $this, 'unsubscribe_cart_abandonment_emails' ), 10 );
67
+
68
+ add_action( 'wp_ajax_wcf_ca_preview_email_send', array( $this, 'send_preview_email' ) );
69
+
70
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
71
+ if ( WCF_CA_PAGE_NAME === $page ) {
72
+ // Adding filter to add new button to add custom fields.
73
+ add_filter( 'mce_buttons', array( $this, 'wcf_filter_mce_button' ) );
74
+ add_filter( 'mce_external_plugins', array( $this, 'wcf_filter_mce_plugin' ), 9 );
75
+ }
76
+
77
+ add_filter( 'cron_schedules', array( $this, 'cartflows_ca_update_order_status_action' ) );
78
+
79
+ // Schedule an action if it's not already scheduled.
80
+ if ( ! wp_next_scheduled( 'cartflows_ca_update_order_status_action' ) ) {
81
+ wp_schedule_event( time(), 'every_fifteen_minutes', 'cartflows_ca_update_order_status_action' );
82
+ }
83
+ add_action( 'cartflows_ca_update_order_status_action', array( $this, 'update_order_status' ) );
84
+
85
+ }
86
+
87
+ }
88
+
89
+ /**
90
+ * Send preview emails.
91
+ */
92
+ public function send_preview_email() {
93
+
94
+ check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, 'security' );
95
+ $mail_result = $this->send_email_templates( null, true );
96
+ if ( $mail_result ) {
97
+ wp_send_json_success( __( 'Mail has been sent successfully!', 'cartflows-ca' ) );
98
+ } else {
99
+ wp_send_json_error( __( 'Mail sending failed!', 'cartflows-ca' ) );
100
+ }
101
+ }
102
+
103
+
104
+ /**
105
+ * Delete tracked data and set cookie for the user.
106
+ */
107
+ public function skip_cart_tracking_by_gdpr() {
108
+ check_ajax_referer( 'cartflows_skip_cart_tracking_gdpr', 'security' );
109
+
110
+ global $wpdb;
111
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
112
+
113
+ $session_id = WC()->session->get( 'wcf_session_id' );
114
+ if ( $session_id ) {
115
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
116
+ }
117
+
118
+ setcookie( 'wcf_ca_skip_track_data', 'true', 0, '/' );
119
+ wp_send_json_success();
120
+
121
+ }
122
+
123
+
124
+ /**
125
+ * Create custom schedule.
126
+ *
127
+ * @return mixed
128
+ */
129
+ function cartflows_ca_update_order_status_action() {
130
+ $schedules['every_fifteen_minutes'] = array(
131
+ 'interval' => 15 * MINUTE_IN_SECONDS,
132
+ 'display' => __( 'Every Fifteen Minutes', 'cartflows-ca' ),
133
+ );
134
+ return $schedules;
135
+ }
136
+
137
+ /**
138
+ * Generate new coupon code for abandoned cart.
139
+ *
140
+ * @param string $discount_type discount type.
141
+ * @param float $amount amount.
142
+ * @param string $expiry expiry.
143
+ */
144
+ function generate_coupon_code( $discount_type, $amount, $expiry = '' ) {
145
+
146
+ $coupon_code = '';
147
+
148
+ if ( $discount_type && $amount ) {
149
+
150
+ $coupon_code = wp_generate_password( 8, false, false );
151
+
152
+ $coupon = array(
153
+ 'post_title' => $coupon_code,
154
+ 'post_content' => '',
155
+ 'post_status' => 'publish',
156
+ 'post_author' => 1,
157
+ 'post_type' => 'shop_coupon',
158
+ );
159
+
160
+ $new_coupon_id = wp_insert_post( $coupon );
161
+
162
+ update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
163
+ update_post_meta( $new_coupon_id, 'description', 'This coupon is for abandoned cart email templates.' );
164
+ update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
165
+ update_post_meta( $new_coupon_id, 'individual_use', 'no' );
166
+ update_post_meta( $new_coupon_id, 'product_ids', '' );
167
+ update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
168
+ update_post_meta( $new_coupon_id, 'usage_limit', '1' );
169
+ update_post_meta( $new_coupon_id, 'date_expires', $expiry );
170
+ update_post_meta( $new_coupon_id, 'apply_before_tax', 'yes' );
171
+ update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
172
+
173
+ }
174
+
175
+ return $coupon_code;
176
+ }
177
+
178
+ /**
179
+ * Unsubscribe the user from the mailing list.
180
+ */
181
+ function unsubscribe_cart_abandonment_emails() {
182
+
183
+ $unsubscribe = filter_input( INPUT_GET, 'unsubscribe', FILTER_VALIDATE_BOOLEAN );
184
+ $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
185
+ if ( $unsubscribe && $this->is_valid_token( $wcf_ac_token ) ) {
186
+ $token_data = $this->wcf_decode_token( $wcf_ac_token );
187
+ if ( isset( $token_data['wcf_session_id'] ) ) {
188
+ $session_id = $token_data['wcf_session_id'];
189
+
190
+ global $wpdb;
191
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
192
+ $wpdb->update(
193
+ $cart_abandonment_table,
194
+ array( 'unsubscribed' => true ),
195
+ array( 'session_id' => $session_id )
196
+ );
197
+ wp_die( __( 'You have successfully unsubscribed from our email list.', 'cartflows-ca' ), __( 'Unsubscribed', 'cartflows-ca' ) );
198
+
199
+ }
200
+ }
201
+
202
+ }
203
+
204
+
205
+ /**
206
+ * Link JS to mce button.
207
+ *
208
+ * @param array $plugins mce pluggins.
209
+ * @return mixed
210
+ */
211
+ function wcf_filter_mce_plugin( $plugins ) {
212
+ $plugins['cartflows_ac'] = CARTFLOWS_CA_URL . 'admin/assets/js/admin-mce.js';
213
+ return $plugins;
214
+ }
215
+
216
+ /**
217
+ * Register button.
218
+ *
219
+ * @param array $buttons mce buttons.
220
+ * @return mixed
221
+ */
222
+ function wcf_filter_mce_button( $buttons ) {
223
+ array_push( $buttons, 'cartflows_ac' );
224
+ return $buttons;
225
+ }
226
+
227
+ /**
228
+ * Initialise all the constants
229
+ */
230
+ function define_cart_abandonment_constants() {
231
+ define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
232
+ define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
233
+ define( 'WCF_CART_ABANDONED_ORDER', 'abandoned' );
234
+ define( 'WCF_CART_COMPLETED_ORDER', 'completed' );
235
+ define( 'WCF_CART_LOST_ORDER', 'lost' );
236
+ define( 'WCF_CART_NORMAL_ORDER', 'normal' );
237
+ define( 'CARTFLOWS_ZAPIER_ACTION_AFTER_TIME', 1800 );
238
+
239
+ define( 'WCF_ACTION_ABANDONED_CARTS', 'abandoned_carts' );
240
+ define( 'WCF_ACTION_RECOVERED_CARTS', 'recovered_carts' );
241
+ define( 'WCF_ACTION_LOST_CARTS', 'lost_carts' );
242
+ define( 'WCF_ACTION_SETTINGS', 'settings' );
243
+ define( 'WCF_ACTION_REPORTS', 'reports' );
244
+
245
+ define( 'WCF_SUB_ACTION_REPORTS_VIEW', 'view' );
246
+ define( 'WCF_SUB_ACTION_REPORTS_RESCHEDULE', 'reschedule' );
247
+
248
+ define( 'WCF_DEFAULT_CUT_OFF_TIME', 15 );
249
+ define( 'WCF_DEFAULT_COUPON_AMOUNT', 10 );
250
+
251
+ define( 'WCF_CA_DATETIME_FORMAT', 'Y-m-d H:i:s' );
252
+ }
253
+
254
+ /**
255
+ * Restore cart abandonemnt data on checkout page.
256
+ *
257
+ * @param array $fields checkout fields values.
258
+ * @return array field values
259
+ */
260
+ function restore_cart_abandonment_data( $fields = array() ) {
261
+ global $woocommerce;
262
+ $result = array();
263
+ // Restore only of user is not logged in.
264
+ $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
265
+ if ( $this->is_valid_token( $wcf_ac_token ) ) {
266
+
267
+ // Check if `wcf_restore_token` exists to restore cart data.
268
+ $token_data = $this->wcf_decode_token( $wcf_ac_token );
269
+
270
+ if ( is_array( $token_data ) && array_key_exists( 'wcf_session_id', $token_data ) ) {
271
+ $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
272
+ if ( isset( $result ) && WCF_CART_ABANDONED_ORDER === $result->order_status || WCF_CART_LOST_ORDER === $result->order_status ) {
273
+ WC()->session->set( 'wcf_session_id', $token_data['wcf_session_id'] );
274
+ }
275
+ }
276
+
277
+ if ( $result ) {
278
+ $cart_content = unserialize( $result->cart_contents );
279
+
280
+ if ( $cart_content ) {
281
+ $woocommerce->cart->empty_cart();
282
+ wc_clear_notices();
283
+ foreach ( $cart_content as $cart_item ) {
284
+ $id = $cart_item['product_id'];
285
+ $qty = $cart_item['quantity'];
286
+
287
+ $cart_item_data = array();
288
+ if ( isset( $cart_item['cartflows_bump'] ) ) {
289
+ $cart_item_data['cartflows_bump'] = $cart_item['cartflows_bump'];
290
+ }
291
+
292
+ if ( isset( $cart_item['custom_price'] ) ) {
293
+ $cart_item_data['custom_price'] = $cart_item['custom_price'];
294
+ }
295
+
296
+ $woocommerce->cart->add_to_cart( $id, $qty, $cart_item['variation_id'], array(), $cart_item_data );
297
+ }
298
+ }
299
+ $other_fields = unserialize( $result->other_fields );
300
+
301
+ $parts = explode( ',', $other_fields['wcf_location'] );
302
+ if ( count( $parts ) > 1 ) {
303
+ $country = $parts[0];
304
+ $city = trim( $parts[1] );
305
+ } else {
306
+ $country = $parts[0];
307
+ $city = '';
308
+ }
309
+
310
+ foreach ( $other_fields as $key => $value ) {
311
+ $key = str_replace( 'wcf_', '', $key );
312
+ $_POST[ $key ] = sanitize_text_field( $value );
313
+ }
314
+ $_POST['billing_first_name'] = sanitize_text_field( $other_fields['wcf_first_name'] );
315
+ $_POST['billing_last_name'] = sanitize_text_field( $other_fields['wcf_last_name'] );
316
+ $_POST['billing_phone'] = sanitize_text_field( $other_fields['wcf_phone_number'] );
317
+ $_POST['billing_email'] = sanitize_email( $result->email );
318
+ $_POST['billing_city'] = sanitize_text_field( $city );
319
+ $_POST['billing_country'] = sanitize_text_field( $country );
320
+
321
+ }
322
+ }
323
+ return $fields;
324
+ }
325
+ /**
326
+ * Load cart abandonemnt tracking script.
327
+ *
328
+ * @return void
329
+ */
330
+ function cart_abandonment_tracking_script() {
331
+
332
+ global $post;
333
+ wp_enqueue_script(
334
+ 'cartflows-cart-abandonment-tracking',
335
+ CARTFLOWS_CART_ABANDONMENT_TRACKING_URL . 'assets/js/cart-abandonment-tracking.js',
336
+ array( 'jquery' ),
337
+ CARTFLOWS_CA_VER,
338
+ true
339
+ );
340
+
341
+ $vars = array(
342
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
343
+ '_nonce' => wp_create_nonce( 'cartflows_save_cart_abandonment_data' ),
344
+ '_gdpr_nonce' => wp_create_nonce( 'cartflows_skip_cart_tracking_gdpr' ),
345
+ '_post_id' => get_the_ID(),
346
+ '_show_gdpr_message' => ( wcf_ca()->utils->is_gdpr_enabled() && ! isset( $_COOKIE['wcf_ca_skip_track_data'] ) ),
347
+ '_gdpr_message' => get_option( 'wcf_ca_gdpr_message' ),
348
+ '_gdpr_nothanks_msg' => __( 'No Thanks', 'cartflows-ca' ),
349
+ '_gdpr_after_no_thanks_msg' => __( 'You won\'t receive further emails from us, thank you!', 'cartflows-ca' ),
350
+ 'enable_ca_tracking' => true,
351
+ );
352
+
353
+ wp_localize_script( 'cartflows-cart-abandonment-tracking', 'CartFlowsProCAVars', $vars );
354
+
355
+ }
356
+
357
+ /**
358
+ * Validate the token before use.
359
+ *
360
+ * @param string $token token form the url.
361
+ * @return bool
362
+ */
363
+ function is_valid_token( $token ) {
364
+ $is_valid = false;
365
+ $token_data = $this->wcf_decode_token( $token );
366
+ if ( is_array( $token_data ) && array_key_exists( 'wcf_session_id', $token_data ) ) {
367
+ $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
368
+ if ( isset( $result ) ) {
369
+ $is_valid = true;
370
+ }
371
+ }
372
+ return $is_valid;
373
+ }
374
+
375
+ /**
376
+ * Execute Zapier webhook for further action inside Zapier.
377
+ *
378
+ * @since 1.0.0
379
+ */
380
+ function update_order_status() {
381
+
382
+ global $wpdb;
383
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
384
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
385
+ $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
386
+
387
+ $wp_current_datetime = current_time( WCF_CA_DATETIME_FORMAT );
388
+ $abandoned_ids = $wpdb->get_results(
389
+ $wpdb->prepare('SELECT `session_id` FROM `' . $cart_abandonment_table . '` WHERE `order_status` = %s AND ADDDATE( `time`, INTERVAL %d MINUTE) <= %s', WCF_CART_NORMAL_ORDER, $minutes, $wp_current_datetime ), ARRAY_A // phpcs:ignore
390
+ );
391
+
392
+ foreach ( $abandoned_ids as $session_id ) {
393
+
394
+ if ( isset( $session_id['session_id'] ) ) {
395
+
396
+ $current_session_id = $session_id['session_id'];
397
+ $this->schedule_emails( $current_session_id );
398
+
399
+ $coupon_code = '';
400
+ $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
401
+
402
+ if ( 'on' === $wcf_ca_coupon_code_status ) {
403
+ $discount_type = get_option( 'wcf_ca_discount_type' );
404
+ $discount_type = $discount_type ? $discount_type : 'percent';
405
+ $amount = get_option( 'wcf_ca_coupon_amount' );
406
+ $amount = $amount ? $amount : WCF_DEFAULT_COUPON_AMOUNT;
407
+ $coupon_expiry_date = get_option( 'wcf_ca_coupon_expiry' );
408
+ $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
409
+ $coupon_expiry_date = $coupon_expiry_date ? strtotime( $wp_current_datetime . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
410
+ $coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date );
411
+ }
412
+
413
+ $wpdb->update(
414
+ $cart_abandonment_table,
415
+ array(
416
+ 'order_status' => WCF_CART_ABANDONED_ORDER,
417
+ 'coupon_code' => $coupon_code,
418
+ ),
419
+ array( 'session_id' => $current_session_id )
420
+ );
421
+
422
+ $this->trigger_zapier_webhook( $current_session_id, WCF_CART_ABANDONED_ORDER );
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Send scheduled emails.
428
+ */
429
+ $this->send_emails_to_callback();
430
+
431
+ // Update order status to lost after campaign complete.
432
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
433
+ $wpdb->query(
434
+ $wpdb->prepare(
435
+ "UPDATE $cart_abandonment_table as ca SET order_status = 'lost' WHERE ca.order_status = %s AND DATE(ca.time) <= DATE_SUB( %s , INTERVAL 30 DAY)
436
+ AND ( (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id ) =
437
+ (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id AND email_sent = 1) )",
438
+ WCF_CART_ABANDONED_ORDER,
439
+ $wp_current_datetime
440
+ )
441
+ );
442
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
443
+ }
444
+
445
+ /**
446
+ * Send zapier webhook.
447
+ *
448
+ * @param string $session_id session id.
449
+ * @param string $order_status order status.
450
+ */
451
+ function trigger_zapier_webhook( $session_id, $order_status ) {
452
+
453
+ $checkout_details = $this->get_checkout_details( $session_id );
454
+
455
+ if ( $checkout_details && wcf_ca()->utils->is_zapier_trigger_enabled() ) {
456
+ $trigger_details = array();
457
+ $url = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
458
+
459
+ $other_details = unserialize( $checkout_details->other_fields );
460
+ $trigger_details['first_name'] = $other_details['wcf_first_name'];
461
+ $trigger_details['last_name'] = $other_details['wcf_last_name'];
462
+ $trigger_details['email'] = $checkout_details->email;
463
+ $trigger_details['checkout_url'] = $this->get_checkout_url( $checkout_details->checkout_id, $checkout_details->session_id );
464
+ $trigger_details['product_names'] = $this->get_comma_separated_products( $checkout_details->cart_contents );
465
+ $trigger_details['coupon_code'] = $checkout_details->coupon_code;
466
+ $trigger_details['order_status'] = $order_status;
467
+ $trigger_details['cart_total'] = $checkout_details->cart_total;
468
+
469
+ $parameters = http_build_query( $trigger_details );
470
+ $args = array(
471
+ 'body' => $parameters,
472
+ 'timeout' => '5',
473
+ 'redirection' => '5',
474
+ 'httpversion' => '1.0',
475
+ 'blocking' => true,
476
+ 'headers' => array(),
477
+ 'cookies' => array(),
478
+ );
479
+ wp_remote_post( $url, $args );
480
+
481
+ }
482
+ }
483
+
484
+
485
+ /**
486
+ * Sanitize post array.
487
+ *
488
+ * @return array
489
+ */
490
+ function sanitize_post_data() {
491
+
492
+ $input_post_values = array(
493
+ 'wcf_billing_company' => array(
494
+ 'default' => '',
495
+ 'sanitize' => FILTER_SANITIZE_STRING,
496
+ ),
497
+ 'wcf_email' => array(
498
+ 'default' => '',
499
+ 'sanitize' => FILTER_SANITIZE_EMAIL,
500
+ ),
501
+ 'wcf_billing_address_1' => array(
502
+ 'default' => '',
503
+ 'sanitize' => FILTER_SANITIZE_STRING,
504
+ ),
505
+ 'wcf_billing_address_2' => array(
506
+ 'default' => '',
507
+ 'sanitize' => FILTER_SANITIZE_STRING,
508
+ ),
509
+ 'wcf_billing_state' => array(
510
+ 'default' => '',
511
+ 'sanitize' => FILTER_SANITIZE_STRING,
512
+ ),
513
+ 'wcf_billing_postcode' => array(
514
+ 'default' => '',
515
+ 'sanitize' => FILTER_SANITIZE_STRING,
516
+ ),
517
+ 'wcf_shipping_first_name' => array(
518
+ 'default' => '',
519
+ 'sanitize' => FILTER_SANITIZE_STRING,
520
+ ),
521
+ 'wcf_shipping_last_name' => array(
522
+ 'default' => '',
523
+ 'sanitize' => FILTER_SANITIZE_STRING,
524
+ ),
525
+ 'wcf_shipping_company' => array(
526
+ 'default' => '',
527
+ 'sanitize' => FILTER_SANITIZE_STRING,
528
+ ),
529
+ 'wcf_shipping_country' => array(
530
+ 'default' => '',
531
+ 'sanitize' => FILTER_SANITIZE_STRING,
532
+ ),
533
+ 'wcf_shipping_address_1' => array(
534
+ 'default' => '',
535
+ 'sanitize' => FILTER_SANITIZE_STRING,
536
+ ),
537
+ 'wcf_shipping_address_2' => array(
538
+ 'default' => '',
539
+ 'sanitize' => FILTER_SANITIZE_STRING,
540
+ ),
541
+ 'wcf_shipping_city' => array(
542
+ 'default' => '',
543
+ 'sanitize' => FILTER_SANITIZE_STRING,
544
+ ),
545
+ 'wcf_shipping_state' => array(
546
+ 'default' => '',
547
+ 'sanitize' => FILTER_SANITIZE_STRING,
548
+ ),
549
+ 'wcf_shipping_postcode' => array(
550
+ 'default' => '',
551
+ 'sanitize' => FILTER_SANITIZE_STRING,
552
+ ),
553
+ 'wcf_order_comments' => array(
554
+ 'default' => '',
555
+ 'sanitize' => FILTER_SANITIZE_STRING,
556
+ ),
557
+ 'wcf_name' => array(
558
+ 'default' => '',
559
+ 'sanitize' => FILTER_SANITIZE_STRING,
560
+ ),
561
+ 'wcf_surname' => array(
562
+ 'default' => '',
563
+ 'sanitize' => FILTER_SANITIZE_STRING,
564
+ ),
565
+ 'wcf_phone' => array(
566
+ 'default' => '',
567
+ 'sanitize' => FILTER_SANITIZE_STRING,
568
+ ),
569
+ 'wcf_country' => array(
570
+ 'default' => '',
571
+ 'sanitize' => FILTER_SANITIZE_STRING,
572
+ ),
573
+ 'wcf_city' => array(
574
+ 'default' => '',
575
+ 'sanitize' => FILTER_SANITIZE_STRING,
576
+ ),
577
+ 'wcf_post_id' => array(
578
+ 'default' => 0,
579
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
580
+ ),
581
+ );
582
+
583
+ $sanitized_post = array();
584
+ foreach ( $input_post_values as $key => $input_post_value ) {
585
+
586
+ if ( isset( $_POST[ $key ] ) ) {
587
+ $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
588
+ } else {
589
+ $sanitized_post[ $key ] = $input_post_value['default'];
590
+ }
591
+ }
592
+ return $sanitized_post;
593
+
594
+ }
595
+
596
+
597
+ /**
598
+ * Save cart abandonment tracking and schedule new event.
599
+ *
600
+ * @since 1.0.0
601
+ */
602
+ function save_cart_abandonment_data() {
603
+
604
+ check_ajax_referer( 'cartflows_save_cart_abandonment_data', 'security' );
605
+ $post_data = $this->sanitize_post_data();
606
+ if ( isset( $post_data['wcf_email'] ) ) {
607
+ $user_email = sanitize_email( $post_data['wcf_email'] );
608
+ global $wpdb;
609
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
610
+
611
+ // Verify if email is already exists.
612
+ $session_id = WC()->session->get( 'wcf_session_id' );
613
+ $session_checkout_details = null;
614
+ if ( isset( $session_id ) ) {
615
+ $session_checkout_details = $this->get_checkout_details( $session_id );
616
+ } else {
617
+ $session_checkout_details = $this->get_checkout_details_by_email( $user_email );
618
+ if ( $session_checkout_details ) {
619
+ $session_id = $session_checkout_details->session_id;
620
+ WC()->session->set( 'wcf_session_id', $session_id );
621
+ } else {
622
+ $session_id = md5( uniqid( rand(), true ) );
623
+ }
624
+ }
625
+
626
+ $checkout_details = $this->prepare_abandonment_data( $post_data );
627
+
628
+ if ( isset( $session_checkout_details ) && WCF_CART_COMPLETED_ORDER === $session_checkout_details->order_status ) {
629
+ WC()->session->__unset( 'wcf_session_id' );
630
+ $session_id = md5( uniqid( rand(), true ) );
631
+ }
632
+
633
+ if ( ( ! is_null( $session_id ) ) && ! is_null( $session_checkout_details ) ) {
634
+
635
+ // Updating row in the Database where users Session id = same as prevously saved in Session.
636
+ $wpdb->update(
637
+ $cart_abandonment_table,
638
+ $checkout_details,
639
+ array( 'session_id' => $session_id )
640
+ );
641
+
642
+ } else {
643
+
644
+ $checkout_details['session_id'] = sanitize_text_field( $session_id );
645
+ // Inserting row into Database.
646
+ $wpdb->insert(
647
+ $cart_abandonment_table,
648
+ $checkout_details
649
+ );
650
+
651
+ // Storing session_id in WooCommerce session.
652
+ WC()->session->set( 'wcf_session_id', $session_id );
653
+
654
+ }
655
+
656
+ wp_send_json_success();
657
+ }
658
+ }
659
+
660
+
661
+ /**
662
+ * Prepare cart data to save for abandonment.
663
+ *
664
+ * @param array $post_data post data.
665
+ * @return array
666
+ */
667
+ function prepare_abandonment_data( $post_data = array() ) {
668
+
669
+ if ( function_exists( 'WC' ) ) {
670
+
671
+ // Retrieving cart total value and currency.
672
+ $cart_total = WC()->cart->total;
673
+
674
+ // Retrieving cart products and their quantities.
675
+ $products = WC()->cart->get_cart();
676
+ $current_time = current_time( WCF_CA_DATETIME_FORMAT );
677
+ $other_fields = array(
678
+ 'wcf_billing_company' => $post_data['wcf_billing_company'],
679
+ 'wcf_billing_address_1' => $post_data['wcf_billing_address_1'],
680
+ 'wcf_billing_address_2' => $post_data['wcf_billing_address_2'],
681
+ 'wcf_billing_state' => $post_data['wcf_billing_state'],
682
+ 'wcf_billing_postcode' => $post_data['wcf_billing_postcode'],
683
+ 'wcf_shipping_first_name' => $post_data['wcf_shipping_first_name'],
684
+ 'wcf_shipping_last_name' => $post_data['wcf_shipping_last_name'],
685
+ 'wcf_shipping_company' => $post_data['wcf_shipping_company'],
686
+ 'wcf_shipping_country' => $post_data['wcf_shipping_country'],
687
+ 'wcf_shipping_address_1' => $post_data['wcf_shipping_address_1'],
688
+ 'wcf_shipping_address_2' => $post_data['wcf_shipping_address_2'],
689
+ 'wcf_shipping_city' => $post_data['wcf_shipping_city'],
690
+ 'wcf_shipping_state' => $post_data['wcf_shipping_state'],
691
+ 'wcf_shipping_postcode' => $post_data['wcf_shipping_postcode'],
692
+ 'wcf_order_comments' => $post_data['wcf_order_comments'],
693
+ 'wcf_first_name' => $post_data['wcf_name'],
694
+ 'wcf_last_name' => $post_data['wcf_surname'],
695
+ 'wcf_phone_number' => $post_data['wcf_phone'],
696
+ 'wcf_location' => $post_data['wcf_country'] . ', ' . $post_data['wcf_city'],
697
+ );
698
+
699
+ $checkout_details = array(
700
+ 'email' => $post_data['wcf_email'],
701
+ 'cart_contents' => serialize( $products ),
702
+ 'cart_total' => sanitize_text_field( $cart_total ),
703
+ 'time' => sanitize_text_field( $current_time ),
704
+ 'other_fields' => serialize( $other_fields ),
705
+ 'checkout_id' => $post_data['wcf_post_id'],
706
+ );
707
+ }
708
+ return $checkout_details;
709
+ }
710
+
711
+ /**
712
+ * Deletes cart abandonment tracking and scheduled event.
713
+ *
714
+ * @param int $order_id Order ID.
715
+ * @since 1.0.0
716
+ */
717
+ function delete_cart_abandonment_data( $order_id ) {
718
+ global $wpdb;
719
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
720
+
721
+ if ( isset( WC()->session ) ) {
722
+ $session_id = WC()->session->get( 'wcf_session_id' );
723
+
724
+ if ( isset( $session_id ) ) {
725
+ $checkout_details = $this->get_checkout_details( $session_id );
726
+
727
+ $has_mail_sent = count( $this->fetch_scheduled_emails( $session_id, true ) );
728
+
729
+ if ( ! $has_mail_sent ) {
730
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
731
+ } else {
732
+ if ( $checkout_details && ( WCF_CART_ABANDONED_ORDER === $checkout_details->order_status || WCF_CART_LOST_ORDER === $checkout_details->order_status ) ) {
733
+
734
+ // Update order status.
735
+ $wpdb->update(
736
+ $cart_abandonment_table,
737
+ array(
738
+ 'order_status' => WCF_CART_COMPLETED_ORDER,
739
+ ),
740
+ array(
741
+ 'session_id' => $session_id,
742
+ )
743
+ );
744
+
745
+ $this->trigger_zapier_webhook( $session_id, WCF_CART_COMPLETED_ORDER );
746
+
747
+ $order = wc_get_order( $order_id );
748
+ $note = __( 'CartFlows says: This order was abandoned & subsequently recovered.', 'cartflows-ca' );
749
+ $order->add_order_note( $note );
750
+ $order->save();
751
+
752
+ } else {
753
+ // Normal checkout.
754
+
755
+ $billing_email = filter_input( INPUT_POST, 'billing_email', FILTER_SANITIZE_EMAIL );
756
+
757
+ if ( $billing_email ) {
758
+ $order_data = $this->get_captured_data_by_email( $billing_email );
759
+
760
+ if ( ! is_null( $order_data ) ) {
761
+ $existing_cart_contents = unserialize( $order_data->cart_contents );
762
+ $order_cart_contents = unserialize( $checkout_details->cart_contents );
763
+ $existing_cart_products = array_keys( (array) $existing_cart_contents );
764
+ $order_cart_products = array_keys( (array) $order_cart_contents );
765
+ if ( $this->check_if_similar_cart( $existing_cart_products, $order_cart_products ) ) {
766
+ $wpdb->update(
767
+ $cart_abandonment_table,
768
+ array(
769
+ 'order_status' => WCF_CART_COMPLETED_ORDER,
770
+ ),
771
+ array(
772
+ 'session_id' => $order_data->session_id,
773
+ )
774
+ );
775
+ }
776
+ }
777
+ }
778
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
779
+ }
780
+ }
781
+ }
782
+ WC()->session->__unset( 'wcf_session_id' );
783
+ }
784
+ }
785
+
786
+
787
+ /**
788
+ * Compare cart if similar products.
789
+ *
790
+ * @param array $cart_a cart_a.
791
+ * @param array $cart_b cart_b.
792
+ * @return bool
793
+ */
794
+ function check_if_similar_cart( $cart_a, $cart_b ) {
795
+ return (
796
+ is_array( $cart_a )
797
+ && is_array( $cart_b )
798
+ && count( $cart_a ) === count( $cart_b )
799
+ && array_diff( $cart_a, $cart_b ) === array_diff( $cart_b, $cart_a )
800
+ );
801
+ }
802
+
803
+
804
+ /**
805
+ * Get the checkout details for the user.
806
+ *
807
+ * @param string $wcf_session_id checkout page session id.
808
+ * @since 1.0.0
809
+ */
810
+ function get_checkout_details( $wcf_session_id ) {
811
+ global $wpdb;
812
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
813
+ $result = $wpdb->get_row(
814
+ $wpdb->prepare('SELECT * FROM `' . $cart_abandonment_table . '` WHERE session_id = %s', $wcf_session_id ) // phpcs:ignore
815
+ );
816
+ return $result;
817
+ }
818
+
819
+ /**
820
+ * Get the checkout details for the user.
821
+ *
822
+ * @param string $email user email.
823
+ * @since 1.0.0
824
+ */
825
+ function get_checkout_details_by_email( $email ) {
826
+ global $wpdb;
827
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
828
+ $result = $wpdb->get_row(
829
+ $wpdb->prepare('SELECT * FROM `' . $cart_abandonment_table . '` WHERE email = %s AND `order_status` IN ( %s, %s )', $email, WCF_CART_ABANDONED_ORDER, WCF_CART_NORMAL_ORDER ) // phpcs:ignore
830
+ );
831
+ return $result;
832
+ }
833
+
834
+
835
+ /**
836
+ * Get the checkout details for the user.
837
+ *
838
+ * @param string $value value.
839
+ * @since 1.0.0
840
+ */
841
+ function get_captured_data_by_email( $value ) {
842
+ global $wpdb;
843
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
844
+ $result = $wpdb->get_row(
845
+ $wpdb->prepare(
846
+ 'SELECT * FROM `' . $cart_abandonment_table . '` WHERE email = %s AND `order_status` IN (%s, %s) ORDER BY `time` DESC LIMIT 1', $value, WCF_CART_ABANDONED_ORDER, WCF_CART_LOST_ORDER ) // phpcs:ignore
847
+ );
848
+ return $result;
849
+ }
850
+
851
+
852
+ /**
853
+ * Add submenu to admin menu.
854
+ *
855
+ * @since 1.1.5
856
+ */
857
+ function abandoned_cart_tracking_menu() {
858
+
859
+ $parent_slug = 'woocommerce';
860
+ $page_title = __( 'Cart Abandonment', 'cartflows-ca' );
861
+ $menu_title = __( 'Cart Abandonment', 'cartflows-ca' );
862
+ $capability = 'manage_options';
863
+ $menu_slug = WCF_CA_PAGE_NAME;
864
+ $callback = array( $this, 'render_abandoned_cart_tracking' );
865
+
866
+ add_submenu_page(
867
+ $parent_slug,
868
+ $page_title,
869
+ $menu_title,
870
+ $capability,
871
+ $menu_slug,
872
+ $callback
873
+ );
874
+ }
875
+
876
+ /**
877
+ * Render table view for cart abandonment tracking.
878
+ *
879
+ * @since 1.1.5
880
+ */
881
+ function render_abandoned_cart_tracking() {
882
+
883
+ $wcf_list_table = new Cartflows_Ca_Cart_Abandonment_Table();
884
+
885
+ if ( 'delete' === $wcf_list_table->current_action() ) {
886
+
887
+ $ids = array();
888
+ if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) {
889
+ $ids = array_map( 'intval', $_REQUEST['id'] );
890
+ }
891
+ $deleted_row_count = empty( $ids ) ? 1 : count( $ids );
892
+
893
+ $wcf_list_table->process_bulk_action();
894
+ $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'Items deleted: %d', 'cartflows-ca' ), $deleted_row_count ) . '</p></div>'; // phpcs:ignore
895
+ set_transient( 'wcf_ca_show_message', $message, 5 );
896
+ if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
897
+ wp_safe_redirect( $_SERVER['HTTP_REFERER'] );
898
+ }
899
+ } elseif ( 'unsubscribe' === $wcf_list_table->current_action() ) {
900
+
901
+ global $wpdb;
902
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
903
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
904
+
905
+ $wpdb->update(
906
+ $cart_abandonment_table,
907
+ array( 'unsubscribed' => true ),
908
+ array( 'id' => $id )
909
+ );
910
+
911
+ $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'User unsubscribed successfully!', 'cartflows-ca' ) ) . '</p></div>'; // phpcs:ignore
912
+ set_transient( 'wcf_ca_show_message', $message, 5 );
913
+ if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
914
+ wp_safe_redirect( $_SERVER['HTTP_REFERER'] );
915
+ }
916
+ }
917
+ ?>
918
+
919
+ <?php
920
+ include_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-tabs.php';
921
+ ?>
922
+ <?php
923
+ }
924
+
925
+ /**
926
+ * Count abandoned carts
927
+ *
928
+ * @since 1.1.5
929
+ */
930
+ function abandoned_cart_count() {
931
+ global $wpdb;
932
+ $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
933
+
934
+ $query = $wpdb->prepare( "SELECT COUNT(`id`) FROM {$cart_abandonment_table_name} WHERE `order_status` = %s", WCF_CART_ABANDONED_ORDER ); // phpcs:ignore
935
+ $total_items = $wpdb->get_var( $query ); // phpcs:ignore
936
+ return $total_items;
937
+ }
938
+
939
+ /**
940
+ * Load analytics scripts.
941
+ */
942
+ function load_admin_cart_abandonment_script() {
943
+
944
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
945
+
946
+ if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
947
+ return;
948
+ }
949
+
950
+ // Styles.
951
+ wp_enqueue_style( 'cartflows-cart-abandonment-admin', CARTFLOWS_CA_URL . 'admin/assets/css/admin-cart-abandonment.css', array(), CARTFLOWS_CA_VER );
952
+
953
+ }
954
+
955
+
956
+ /**
957
+ * Render Cart abandonment display button beside title.
958
+ */
959
+ public function setup_cart_abandonment_button() {
960
+
961
+ if ( ! Cartflows_Admin::is_flow_edit_admin() ) {
962
+ return;
963
+ }
964
+
965
+ $reports_btn_markup = '<style>.wrap{ position:relative;}</style>';
966
+ $reports_btn_markup .= "<div class='wcf-reports-button-wrap'>";
967
+ $reports_btn_markup .= "<button class='wcf-cart-abandonment-reports-popup button button-secondary'>";
968
+ $reports_btn_markup .= esc_html( 'View Report', 'cartflows-ca' );
969
+ $reports_btn_markup .= '</button>';
970
+ $reports_btn_markup .= '</div>';
971
+
972
+ echo $reports_btn_markup;
973
+
974
+ }
975
+
976
+ /**
977
+ * Get start and end date for given interval.
978
+ *
979
+ * @param string $interval interval .
980
+ * @return array
981
+ */
982
+ function get_start_end_by_interval( $interval ) {
983
+
984
+ if ( 'today' === $interval ) {
985
+ $start_date = date( 'Y-m-d' );
986
+ $end_date = date( 'Y-m-d' );
987
+ } else {
988
+
989
+ $days = $interval;
990
+
991
+ $start_date = date( 'Y-m-d', strtotime( '-' . $days . ' days' ) );
992
+ $end_date = date( 'Y-m-d' );
993
+ }
994
+
995
+ return array(
996
+ 'start' => $start_date,
997
+ 'end' => $end_date,
998
+ );
999
+ }
1000
+
1001
+
1002
+ /**
1003
+ * Get Attributable revenue.
1004
+ * Represents the revenue generated by this campaign.
1005
+ *
1006
+ * @param string $type abondened|completed.
1007
+ * @param string $from_date from date.
1008
+ * @param string $to_date to date.
1009
+ */
1010
+ function get_report_by_type( $type = WCF_CART_ABANDONED_ORDER, $from_date, $to_date ) {
1011
+ global $wpdb;
1012
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1013
+ $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
1014
+ $attributable_revenue = $wpdb->get_row(
1015
+ $wpdb->prepare( "SELECT SUM(`cart_total`) as revenue, count('*') as no_of_orders FROM {$cart_abandonment_table} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s ", $type, $from_date, $to_date ), // phpcs:ignore
1016
+ ARRAY_A
1017
+ );
1018
+ return $attributable_revenue;
1019
+ }
1020
+
1021
+
1022
+ /**
1023
+ * Get checkout url.
1024
+ *
1025
+ * @param integer $post_id post id.
1026
+ * @param string $session_id session id.
1027
+ * @return string
1028
+ */
1029
+ function get_checkout_url( $post_id, $session_id ) {
1030
+
1031
+ $token = $this->wcf_generate_token( array( 'wcf_session_id' => $session_id ) );
1032
+ $checkout_url = get_permalink( $post_id ) . '?wcf_ac_token=' . $token;
1033
+ return esc_url( $checkout_url );
1034
+ }
1035
+
1036
+ /**
1037
+ * Geberate the token for the given data.
1038
+ *
1039
+ * @param array $data data.
1040
+ */
1041
+ function wcf_generate_token( $data ) {
1042
+ return urlencode( base64_encode( http_build_query( $data ) ) );
1043
+ }
1044
+
1045
+ /**
1046
+ * Decode and get the original contents.
1047
+ *
1048
+ * @param string $token token.
1049
+ */
1050
+ function wcf_decode_token( $token ) {
1051
+ $token = sanitize_text_field( $token );
1052
+ parse_str( base64_decode( urldecode( $token ) ), $token );
1053
+ return $token;
1054
+ }
1055
+
1056
+ /**
1057
+ * Render Cart abandonment tabs.
1058
+ *
1059
+ * @since 1.1.5
1060
+ */
1061
+ function wcf_display_tabs() {
1062
+
1063
+ $action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
1064
+ $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
1065
+
1066
+ if ( ! $action ) {
1067
+ $action = WCF_ACTION_REPORTS;
1068
+ $active_settings = '';
1069
+ $active_reports = '';
1070
+ $active_email_templates = '';
1071
+ }
1072
+
1073
+ switch ( $action ) {
1074
+ case WCF_ACTION_SETTINGS:
1075
+ $active_settings = 'nav-tab-active';
1076
+ break;
1077
+ case WCF_ACTION_REPORTS:
1078
+ $active_reports = 'nav-tab-active';
1079
+ break;
1080
+ case WCF_ACTION_EMAIL_TEMPLATES:
1081
+ $active_email_templates = 'nav-tab-active';
1082
+ break;
1083
+ default:
1084
+ $active_reports = 'nav-tab-active';
1085
+ break;
1086
+ }
1087
+ // phpcs:disable
1088
+ ?>
1089
+
1090
+
1091
+ <div class="nav-tab-wrapper woo-nav-tab-wrapper">
1092
+
1093
+ <?php
1094
+ $url = add_query_arg( array(
1095
+ 'page' => WCF_CA_PAGE_NAME,
1096
+ 'action' => WCF_ACTION_REPORTS
1097
+ ), admin_url( '/admin.php' ) )
1098
+ ?>
1099
+ <a href="<?php echo $url; ?>"
1100
+ class="nav-tab
1101
+ <?php
1102
+ if ( isset( $active_reports ) ) {
1103
+ echo $active_reports;}
1104
+ ?>
1105
+ ">
1106
+ <?php _e( 'Report', 'cartflows-ca' ); ?>
1107
+ </a>
1108
+
1109
+ <?php
1110
+ $url = add_query_arg( array(
1111
+ 'page' => WCF_CA_PAGE_NAME,
1112
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES
1113
+ ), admin_url( '/admin.php' ) )
1114
+ ?>
1115
+ <a href="<?php echo $url; ?>"
1116
+ class="nav-tab
1117
+ <?php
1118
+ if ( isset( $active_email_templates ) ) {
1119
+ echo $active_email_templates;}
1120
+ ?>
1121
+ ">
1122
+ <?php _e( 'Emails', 'cartflows-ca' ); ?>
1123
+ </a>
1124
+
1125
+ <?php
1126
+ $url = add_query_arg( array(
1127
+ 'page' => WCF_CA_PAGE_NAME,
1128
+ 'action' => WCF_ACTION_SETTINGS
1129
+ ), admin_url( '/admin.php' ) )
1130
+ ?>
1131
+ <a href="<?php echo $url; ?>"
1132
+ class="nav-tab
1133
+ <?php
1134
+ if ( isset( $active_settings ) ) {
1135
+ echo $active_settings;}
1136
+ ?>
1137
+ ">
1138
+ <?php _e( 'Settings', 'cartflows-ca' ); ?>
1139
+ </a>
1140
+
1141
+ </div>
1142
+ <?php
1143
+ // phpcs:enable
1144
+ }
1145
+
1146
+ /**
1147
+ * Render Cart abandonment settings.
1148
+ *
1149
+ * @since 1.1.5
1150
+ */
1151
+ function wcf_display_settings() {
1152
+ ?>
1153
+
1154
+ <form method="post" action="options.php">
1155
+ <?php settings_fields( WCF_CA_SETTINGS_OPTION_GROUP ); ?>
1156
+ <?php do_settings_sections( WCF_CA_PAGE_NAME ); ?>
1157
+ <?php submit_button(); ?>
1158
+ </form>
1159
+
1160
+ <?php
1161
+ }
1162
+
1163
+ /**
1164
+ * Render Cart abandonment reports.
1165
+ *
1166
+ * @since 1.1.5
1167
+ */
1168
+ function wcf_display_reports() {
1169
+
1170
+ $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
1171
+ $filter_table = filter_input( INPUT_GET, 'filter_table', FILTER_SANITIZE_STRING );
1172
+
1173
+ if ( ! $filter ) {
1174
+ $filter = 'last_month';
1175
+ }
1176
+ if ( ! $filter_table ) {
1177
+ $filter_table = WCF_CART_ABANDONED_ORDER;
1178
+ }
1179
+
1180
+ $from_date = filter_input( INPUT_GET, 'from_date', FILTER_SANITIZE_STRING );
1181
+ $to_date = filter_input( INPUT_GET, 'to_date', FILTER_SANITIZE_STRING );
1182
+
1183
+ switch ( $filter ) {
1184
+
1185
+ case 'yesterday':
1186
+ $to_date = date( 'Y-m-d', strtotime( '-1 days' ) );
1187
+ $from_date = $to_date;
1188
+ break;
1189
+ case 'today':
1190
+ $to_date = date( 'Y-m-d' );
1191
+ $from_date = $to_date;
1192
+ break;
1193
+ case 'last_week':
1194
+ $from_date = date( 'Y-m-d', strtotime( '-7 days' ) );
1195
+ $to_date = date( 'Y-m-d' );
1196
+ break;
1197
+ case 'last_month':
1198
+ $from_date = date( 'Y-m-d', strtotime( '-1 months' ) );
1199
+ $to_date = date( 'Y-m-d' );
1200
+ break;
1201
+ case 'custom':
1202
+ $to_date = $to_date ? $to_date : date( 'Y-m-d' );
1203
+ $from_date = $from_date ? $from_date : $to_date;
1204
+ break;
1205
+
1206
+ }
1207
+
1208
+ $abandoned_report = $this->get_report_by_type( WCF_CART_ABANDONED_ORDER, $from_date, $to_date );
1209
+ $recovered_report = $this->get_report_by_type( WCF_CART_COMPLETED_ORDER, $from_date, $to_date );
1210
+ $lost_report = $this->get_report_by_type( WCF_CART_LOST_ORDER, $from_date, $to_date );
1211
+
1212
+ $wcf_list_table = new Cartflows_Ca_Cart_Abandonment_Table();
1213
+ $wcf_list_table->prepare_items( $filter_table, $from_date, $to_date );
1214
+
1215
+ $conversion_rate = 0;
1216
+ $total_orders = ( $recovered_report['no_of_orders'] + $abandoned_report['no_of_orders'] + $lost_report['no_of_orders'] );
1217
+ if ( $total_orders ) {
1218
+ $conversion_rate = ( $recovered_report['no_of_orders'] / $total_orders ) * 100;
1219
+ }
1220
+
1221
+ global $woocommerce;
1222
+ $conversion_rate = number_format_i18n( $conversion_rate, 2 );
1223
+ $currency_symbol = get_woocommerce_currency_symbol();
1224
+ require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-reports.php';
1225
+ }
1226
+
1227
+
1228
+ /**
1229
+ * Show report details for specific order.
1230
+ */
1231
+ function wcf_display_report_details() {
1232
+
1233
+ $sesson_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
1234
+
1235
+ if ( $sesson_id ) {
1236
+ $details = $this->get_checkout_details( $sesson_id );
1237
+ $user_details = (object) unserialize( $details->other_fields );
1238
+ $scheduled_emails = $this->fetch_scheduled_emails( $sesson_id );
1239
+
1240
+ require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-ca-single-report-details.php';
1241
+ }
1242
+
1243
+ }
1244
+
1245
+ /**
1246
+ * Check and show warning message if cart abandonment is disabled.
1247
+ */
1248
+ function wcf_show_warning_ca() {
1249
+ $settings_url = add_query_arg(
1250
+ array(
1251
+ 'page' => WCF_CA_PAGE_NAME,
1252
+ 'action' => WCF_ACTION_SETTINGS,
1253
+ ),
1254
+ admin_url( '/admin.php' )
1255
+ );
1256
+
1257
+ if ( ! wcf_ca()->utils->is_cart_abandonment_tracking_enabled() ) {
1258
+ ?>
1259
+ <div class="notice notice-warning is-dismissible">
1260
+ <p>
1261
+ <?php echo __('Looks like abandonment tracking is disabled! Please enable it from <a href=' . esc_url($settings_url) . '> <strong>settings</strong></a>.', 'cartflows-ca'); // phpcs:ignore
1262
+ ?>
1263
+ </p>
1264
+ </div>
1265
+ <?php
1266
+ }
1267
+ }
1268
+
1269
+ /**
1270
+ * Callback trigger event to send the emails.
1271
+ */
1272
+ function send_emails_to_callback() {
1273
+
1274
+ global $wpdb;
1275
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1276
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1277
+ $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
1278
+
1279
+ $current_time = current_time( WCF_CA_DATETIME_FORMAT );
1280
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1281
+ $emails_send_to = $wpdb->get_results(
1282
+
1283
+ $wpdb->prepare(
1284
+ 'SELECT *, EHT.id as email_history_id, ETT.id as email_template_id FROM ' . $email_history_table . ' as EHT
1285
+ INNER JOIN ' . $cart_abandonment_table . ' as CAT ON EHT.`ca_session_id` = CAT.`session_id`
1286
+ INNER JOIN ' . $email_template_table . ' as ETT ON ETT.`id` = EHT.`template_id`
1287
+ WHERE CAT.`order_status` = %s AND CAT.unsubscribed = 0 AND EHT.`email_sent` = 0 AND EHT.`scheduled_time` <= %s',
1288
+ WCF_CART_ABANDONED_ORDER,
1289
+ $current_time
1290
+ )
1291
+ );
1292
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1293
+
1294
+ foreach ( $emails_send_to as $email_send_to ) {
1295
+ $email_result = $this->send_email_templates( $email_send_to );
1296
+ if ( $email_result ) {
1297
+ $wpdb->update(
1298
+ $email_history_table,
1299
+ array( 'email_sent' => true ),
1300
+ array( 'id' => $email_send_to->email_history_id )
1301
+ );
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+
1307
+ /**
1308
+ * Create a dummy object for the preview email.
1309
+ *
1310
+ * @return stdClass
1311
+ */
1312
+ public function create_dummy_session_for_preview_email() {
1313
+
1314
+ $email_data = new stdClass();
1315
+ $current_user = wp_get_current_user();
1316
+ $user_data = array(
1317
+ 'wcf_first_name' => $current_user->user_firstname,
1318
+ 'wcf_last_name' => $current_user->user_lastname,
1319
+ );
1320
+ $email_data->checkout_id = wc_get_page_id( 'checkout' );
1321
+ $email_data->session_id = 'dummy-session-id';
1322
+
1323
+ $email_send_to = filter_input( INPUT_POST, 'email_send_to', FILTER_SANITIZE_EMAIL );
1324
+ $email_data->email = $email_send_to ? $email_send_to : $current_user->user_email;
1325
+ $email_data->email_body = filter_input( INPUT_POST, 'email_body', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1326
+ $email_data->email_subject = filter_input( INPUT_POST, 'email_subject', FILTER_SANITIZE_STRING );
1327
+ $email_data->email_body = html_entity_decode( $email_data->email_body );
1328
+
1329
+ $email_data->other_fields = serialize( $user_data );
1330
+ if ( ! WC()->cart->get_cart_contents_count() ) {
1331
+ $args = array(
1332
+ 'posts_per_page' => 1,
1333
+ 'orderby' => 'rand',
1334
+ 'post_type' => 'product',
1335
+ 'meta_query' => array(
1336
+ // Exclude out of stock products.
1337
+ array(
1338
+ 'key' => '_stock_status',
1339
+ 'value' => 'outofstock',
1340
+ 'compare' => 'NOT IN',
1341
+ ),
1342
+ ),
1343
+ 'tax_query' => array(
1344
+ array(
1345
+ 'taxonomy' => 'product_type',
1346
+ 'field' => 'slug',
1347
+ 'terms' => 'simple',
1348
+ ),
1349
+ ),
1350
+ );
1351
+
1352
+ $random_products = get_posts( $args );
1353
+ if ( ! empty( $random_products ) ) {
1354
+ $random_product = reset( $random_products );
1355
+ WC()->cart->add_to_cart( $random_product->ID );
1356
+ }
1357
+ }
1358
+ $email_data->cart_total = WC()->cart->total + WC()->cart->get_cart_shipping_total();
1359
+ $email_data->cart_contents = serialize( WC()->cart->get_cart() );
1360
+ $email_data->time = current_time( WCF_CA_DATETIME_FORMAT );
1361
+ return $email_data;
1362
+ }
1363
+
1364
+ /**
1365
+ * Callback function to send email templates.
1366
+ *
1367
+ * @param array $email_data email data .
1368
+ * @param boolean $preview_email preview email.
1369
+ * @since 1.0.0
1370
+ */
1371
+ function send_email_templates( $email_data, $preview_email = false ) {
1372
+
1373
+ if ( $preview_email ) {
1374
+ $email_data = $this->create_dummy_session_for_preview_email();
1375
+ }
1376
+
1377
+ if ( filter_var( $email_data->email, FILTER_VALIDATE_EMAIL ) ) {
1378
+
1379
+ $checkout_url = $this->get_checkout_url( $email_data->checkout_id, $email_data->session_id );
1380
+ $other_fields = unserialize( $email_data->other_fields );
1381
+
1382
+ $from_email_name = get_option( 'wcf_ca_from_name' );
1383
+ $reply_name_preview = get_option( 'wcf_ca_from_email' );
1384
+ $from_email_preview = get_option( 'wcf_ca_reply_email' );
1385
+
1386
+ $user_first_name = ucfirst( $other_fields['wcf_first_name'] );
1387
+ $user_first_name = $user_first_name ? $user_first_name : __( 'there', 'cartflows-ca' );
1388
+ $user_last_name = ucfirst( $other_fields['wcf_last_name'] );
1389
+ $user_full_name = trim( $user_first_name . ' ' . $user_last_name );
1390
+
1391
+ $subject_email_preview = stripslashes( html_entity_decode( $email_data->email_subject, ENT_QUOTES ) );
1392
+ $subject_email_preview = convert_smilies( $subject_email_preview );
1393
+ $subject_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $subject_email_preview );
1394
+ $body_email_preview = convert_smilies( $email_data->email_body );
1395
+ $body_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $body_email_preview );
1396
+ $body_email_preview = str_replace( '{{customer.lastname}}', $user_last_name, $body_email_preview );
1397
+ $body_email_preview = str_replace( '{{customer.fullname}}', $user_full_name, $body_email_preview );
1398
+
1399
+ if ( $preview_email ) {
1400
+ $coupon_code = 'DUMMY-COUPON';
1401
+ $checkout_url = $checkout_url . base64_encode( 'dummy-token-string' );
1402
+ } else {
1403
+ $email_instance = Cartflows_Ca_Email_Templates::get_instance();
1404
+ $override_global_coupon = $email_instance->get_email_template_meta_by_key( $email_data->email_template_id, 'override_global_coupon' );
1405
+ if ( $override_global_coupon->meta_value ) {
1406
+ $email_history = $email_instance->get_email_history_by_id( $email_data->email_history_id );
1407
+ $coupon_code = $email_history->coupon_code;
1408
+ } else {
1409
+ $coupon_code = $email_data->coupon_code;
1410
+ }
1411
+ }
1412
+
1413
+ $body_email_preview = str_replace( '{{cart.coupon_code}}', $coupon_code, $body_email_preview );
1414
+
1415
+ $current_time_stamp = $email_data->time;
1416
+ $body_email_preview = str_replace( '{{cart.abandoned_date}}', $current_time_stamp, $body_email_preview );
1417
+ $unsubscribe_element = '<a target="_blank" style="color: lightgray" href="' . $checkout_url . '&unsubscribe=true' . '">' . __( 'Unsubscribe', 'cartflows-ca' ) . '</a>';
1418
+ $body_email_preview = str_replace( '{{cart.unsubscribe}}', $unsubscribe_element, $body_email_preview );
1419
+ $body_email_preview = str_replace( '{{cart.checkout_url}}', $checkout_url, $body_email_preview );
1420
+ $host = parse_url( get_site_url() );
1421
+ $body_email_preview = str_replace( '{{site.url}}', $host['host'], $body_email_preview );
1422
+ $body_email_preview = str_replace( '{{cart.product.names}}', $this->get_comma_separated_products( $email_data->cart_contents ), $body_email_preview );
1423
+
1424
+ $admin_user = get_users(
1425
+ array(
1426
+ 'role' => 'Administrator',
1427
+ 'number' => 1,
1428
+ )
1429
+ );
1430
+ $admin_user = reset( $admin_user );
1431
+ $admin_first_name = $admin_user->user_firstname ? $admin_user->user_firstname : 'Admin';
1432
+ $body_email_preview = str_replace( '{{admin.firstname}}', $admin_first_name, $body_email_preview );
1433
+ $body_email_preview = str_replace( '{{admin.company}}', get_bloginfo( 'name' ), $body_email_preview );
1434
+
1435
+ $headers = 'From: ' . $from_email_name . ' <' . $from_email_preview . '>' . "\r\n";
1436
+ $headers .= 'Content-Type: text/html' . "\r\n";
1437
+ $headers .= 'Reply-To: ' . $reply_name_preview . ' ' . "\r\n";
1438
+ $var = $this->get_email_product_block( $email_data->cart_contents, $email_data->cart_total );
1439
+
1440
+ $body_email_preview = str_replace( '{{cart.product.table}}', $var, $body_email_preview );
1441
+ $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1442
+ if ( $mail_result ) {
1443
+ return true;
1444
+ } else {
1445
+ // Retry sending mail.
1446
+ $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1447
+ if ( ! $preview_email ) {
1448
+ return true;
1449
+ }
1450
+ return false;
1451
+ }
1452
+ } else {
1453
+ return false;
1454
+ }
1455
+
1456
+ }
1457
+
1458
+ /**
1459
+ * Generate comma separated products.
1460
+ *
1461
+ * @param object $cart_contents user cart details.
1462
+ */
1463
+ function get_comma_separated_products( $cart_contents ) {
1464
+ $cart_comma_string = '';
1465
+ if ( ! $cart_contents ) {
1466
+ return $cart_comma_string;
1467
+ }
1468
+ $cart_data = unserialize( $cart_contents );
1469
+
1470
+ $cart_length = count( $cart_data );
1471
+ $index = 0;
1472
+ foreach ( $cart_data as $key => $product ) {
1473
+
1474
+ $cart_comma_string = $cart_comma_string . $product['data']->get_title();
1475
+ if ( ( $cart_length - 2 ) === $index ) {
1476
+ $cart_comma_string = $cart_comma_string . ' & ';
1477
+ } elseif ( ( $cart_length - 1 ) !== $index ) {
1478
+ $cart_comma_string = $cart_comma_string . ', ';
1479
+ }
1480
+ $index++;
1481
+ }
1482
+ return $cart_comma_string;
1483
+
1484
+ }
1485
+
1486
+ /**
1487
+ * Generate the view for email product cart block.
1488
+ *
1489
+ * @param object $cart_contents user cart contents details.
1490
+ * @param float $cart_total user cart total.
1491
+ * @return string
1492
+ */
1493
+ function get_email_product_block( $cart_contents, $cart_total ) {
1494
+
1495
+ $cart_items = unserialize( $cart_contents );
1496
+ $currency_symbol = get_woocommerce_currency_symbol();
1497
+ $tr = '';
1498
+ $style = 'style="color: #636363; border: 1px solid #e5e5e5; "';
1499
+
1500
+ foreach ( $cart_items as $cart_item ) {
1501
+
1502
+ $tr = $tr . '<tr style="color: #636363; border: 1px solid #e5e5e5;" align="center">
1503
+ <td ' . $style . '><img class="demo_img" width="42" height="42" src=" ' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . ' "/></td>
1504
+ <td ' . $style . '>' . $cart_item['data']->get_title() . '</td>
1505
+ <td ' . $style . '> ' . $cart_item['quantity'] . ' </td>
1506
+ <td ' . $style . '>' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1507
+ <td ' . $style . ' >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1508
+ </tr> ';
1509
+ }
1510
+
1511
+ return '<table align="left" cellpadding="10" cellspacing="0" style="float: none; border: 1px solid #e5e5e5;">
1512
+ <tr align="center">
1513
+ <th ' . $style . '>' . __( 'Item', 'cartflows-ca' ) . '</th>
1514
+ <th ' . $style . '>' . __( 'Name', 'cartflows-ca' ) . '</th>
1515
+ <th ' . $style . '>' . __( 'Quantity', 'cartflows-ca' ) . '</th>
1516
+ <th ' . $style . '>' . __( 'Price', 'cartflows-ca' ) . '</th>
1517
+ <th ' . $style . '>' . __( 'Line Subtotal', 'cartflows-ca' ) . '</th>
1518
+ </tr> ' . $tr . '
1519
+ </table>';
1520
+
1521
+ }
1522
+
1523
+ /**
1524
+ * Generate the view for admin product cart block.
1525
+ *
1526
+ * @param object $cart_contents user cart contents details.
1527
+ * @param float $cart_total user cart total.
1528
+ * @return string
1529
+ */
1530
+ function get_admin_product_block( $cart_contents, $cart_total ) {
1531
+
1532
+ $cart_items = unserialize( $cart_contents );
1533
+ $currency_symbol = get_woocommerce_currency_symbol();
1534
+ $tr = '';
1535
+ $total = 0;
1536
+ $discount = 0;
1537
+ $tax = 0;
1538
+
1539
+ foreach ( $cart_items as $cart_item ) {
1540
+
1541
+ $discount = number_format_i18n( $discount + ( $cart_item['line_subtotal'] - $cart_item['line_total'] ), 2 );
1542
+ $total = number_format_i18n( $total + $cart_item['line_subtotal'], 2 );
1543
+ $tax = number_format_i18n( $tax + $cart_item['line_tax'], 2 );
1544
+
1545
+ $tr = $tr . '<tr align="center">
1546
+ <td ><img class="demo_img" width="42" height="42" src=" ' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . ' "/></td>
1547
+ <td >' . $cart_item['data']->get_title() . '</td>
1548
+ <td > ' . $cart_item['quantity'] . ' </td>
1549
+ <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1550
+ <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1551
+ </tr> ';
1552
+ }
1553
+
1554
+ return '<table align="left" cellspacing="0" class="widefat fixed striped posts">
1555
+ <thead>
1556
+ <tr align="center">
1557
+ <th >' . __( 'Item', 'cartflows-ca' ) . '</th>
1558
+ <th >' . __( 'Name', 'cartflows-ca' ) . '</th>
1559
+ <th >' . __( 'Quantity', 'cartflows-ca' ) . '</th>
1560
+ <th >' . __( 'Price', 'cartflows-ca' ) . '</th>
1561
+ <th >' . __( 'Line Subtotal', 'cartflows-ca' ) . '</th>
1562
+ </tr>
1563
+ </thead>
1564
+ <tbody>
1565
+ ' . $tr . '
1566
+ <tr align="center" id="wcf-ca-discount">
1567
+ <td colspan="4" >' . __( 'Discount', 'cartflows-ca' ) . '</td>
1568
+ <td>' . $currency_symbol . ( $discount ) . '</td>
1569
+ </tr>
1570
+ <tr align="center" id="wcf-ca-other">
1571
+ <td colspan="4" >' . __( 'Other', 'cartflows-ca' ) . '</td>
1572
+ <td>' . $currency_symbol . ( $tax ) . '</td>
1573
+ </tr>
1574
+
1575
+ <tr align="center" id="wcf-ca-shipping">
1576
+ <td colspan="4" >' . __( 'Shipping', 'cartflows-ca' ) . '</td>
1577
+ <td>' . $currency_symbol . number_format_i18n( $discount + ( $cart_total - $total ) - $tax, 2 ) . '</td>
1578
+ </tr>
1579
+ <tr align="center" id="wcf-ca-cart-total">
1580
+ <td colspan="4" >' . __( 'Cart Total', 'cartflows-ca' ) . '</td>
1581
+ <td>' . $currency_symbol . $cart_total . '</td>
1582
+ </tr>
1583
+ </tbody>
1584
+ </table>';
1585
+ }
1586
+
1587
+ /**
1588
+ * Copied WC function for date parameter addition.
1589
+ *
1590
+ * @param string $customer_email customer email.
1591
+ * @param int $product_id product id.
1592
+ * @param int $days days.
1593
+ * @return array|bool|mixed|void
1594
+ */
1595
+ function wcf_ca_wc_customer_bought_product( $customer_email, $product_id, $days = 365 ) {
1596
+ global $wpdb;
1597
+
1598
+ $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
1599
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1600
+ $result = $wpdb->get_var(
1601
+ $wpdb->prepare(
1602
+ "SELECT COUNT(p.ID) FROM {$wpdb->prefix}posts AS p
1603
+ INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
1604
+ INNER JOIN {$wpdb->prefix}woocommerce_order_items AS woi ON p.ID = woi.order_id
1605
+ INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS woim ON woi.order_item_id = woim.order_item_id
1606
+ WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
1607
+ AND pm.meta_key = '_billing_email'
1608
+ AND pm.meta_value = %s
1609
+ AND woim.meta_key IN ( '_product_id', '_variation_id' )
1610
+ AND woim.meta_value = %s
1611
+ AND p.post_date > '" . date( 'Y-m-d', strtotime( '-' . $days . ' days' ) ) . "'
1612
+ ",
1613
+ $customer_email,
1614
+ $product_id
1615
+ )
1616
+ );
1617
+
1618
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1619
+
1620
+ return intval( $result ) > 0 ? true : false;
1621
+
1622
+ }
1623
+
1624
+ /**
1625
+ * Schedule events for the abadoned carts to send emails.
1626
+ *
1627
+ * @param integer $session_id user session id.
1628
+ * @param boolean $force_reschedule force reschedule.
1629
+ */
1630
+ function schedule_emails( $session_id, $force_reschedule = false ) {
1631
+
1632
+ $checkout_details = $this->get_checkout_details( $session_id );
1633
+
1634
+ if ( ( $checkout_details->unsubscribed ) || ( WCF_CART_COMPLETED_ORDER === $checkout_details->order_status ) ) {
1635
+ return;
1636
+ }
1637
+ $scheduled_time_from = current_time( WCF_CA_DATETIME_FORMAT );
1638
+ $scheduled_emails = $this->fetch_scheduled_emails( $session_id );
1639
+ $scheduled_templates = array_column( $scheduled_emails, 'template_id' );
1640
+
1641
+ // Skip if forcfully rescheduled.
1642
+ if ( ! $force_reschedule ) {
1643
+ $scheduled_time_from = $checkout_details->time;
1644
+ $user_exist = get_user_by( 'email', $checkout_details->email );
1645
+ // Don't schedule emails if products are already purchased.
1646
+ if ( $user_exist ) {
1647
+ $purchasing_products = unserialize( $checkout_details->cart_contents );
1648
+ $already_purchased = true;
1649
+ foreach ( $purchasing_products as $purchasing_product ) {
1650
+ if ( isset( $purchasing_product['product_id'] ) ) {
1651
+ $has_already_purchased = $this->wcf_ca_wc_customer_bought_product( $user_exist->user_email, $purchasing_product['product_id'], 30 );
1652
+ if ( ! $has_already_purchased ) {
1653
+ $already_purchased = false;
1654
+ break;
1655
+ }
1656
+ }
1657
+ }
1658
+ if ( $already_purchased ) {
1659
+ return;
1660
+ }
1661
+ }
1662
+ }
1663
+
1664
+ $email_tmpl = Cartflows_Ca_Email_Templates::get_instance();
1665
+ $templates = $email_tmpl->fetch_all_active_templates();
1666
+
1667
+ global $wpdb;
1668
+
1669
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1670
+
1671
+ foreach ( $templates as $template ) {
1672
+
1673
+ if ( false !== array_search( $template->id, $scheduled_templates, true ) ) {
1674
+ continue;
1675
+ }
1676
+
1677
+ $timestamp_str = '+' . $template->frequency . ' ' . $template->frequency_unit . 'S';
1678
+ $scheduled_time = date( WCF_CA_DATETIME_FORMAT, strtotime( $scheduled_time_from . $timestamp_str ) );
1679
+ $discount_type = $email_tmpl->get_email_template_meta_by_key( $template->id, 'discount_type' );
1680
+ $discount_type = isset( $discount_type->meta_value ) ? $discount_type->meta_value : '';
1681
+ $amount = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_amount' );
1682
+ $amount = isset( $amount->meta_value ) ? $amount->meta_value : '';
1683
+
1684
+ $coupon_expiry_date = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_date' );
1685
+ $coupon_expiry_unit = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_unit' );
1686
+ $coupon_expiry_date = isset( $coupon_expiry_date->meta_value ) ? $coupon_expiry_date->meta_value : '';
1687
+ $coupon_expiry_unit = isset( $coupon_expiry_unit->meta_value ) ? $coupon_expiry_unit->meta_value : 'hours';
1688
+
1689
+ $coupon_expiry_date = $coupon_expiry_date ? strtotime( $scheduled_time . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
1690
+
1691
+ $override_global_coupon = $email_tmpl->get_email_template_meta_by_key( $template->id, 'override_global_coupon' );
1692
+
1693
+ $new_coupon_code = '';
1694
+ if ( $override_global_coupon->meta_value ) {
1695
+ $new_coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date );
1696
+ }
1697
+
1698
+ $wpdb->replace(
1699
+ $email_history_table,
1700
+ array(
1701
+ 'template_id' => $template->id,
1702
+ 'ca_session_id' => $checkout_details->session_id,
1703
+ 'coupon_code' => $new_coupon_code,
1704
+ 'scheduled_time' => $scheduled_time,
1705
+ )
1706
+ );
1707
+ }
1708
+ }
1709
+
1710
+ /**
1711
+ * Fetch all the scheduled emails with templates for the specific session.
1712
+ *
1713
+ * @param string $session_id session id.
1714
+ * @param boolean $fetch_sent sfetch sent emails.
1715
+ * @return array|object|null
1716
+ */
1717
+ function fetch_scheduled_emails( $session_id, $fetch_sent = false ) {
1718
+ global $wpdb;
1719
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1720
+ $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
1721
+
1722
+ $query = $wpdb->prepare("SELECT * FROM $email_history_table as eht INNER JOIN $email_template_table as ett ON eht.template_id = ett.id WHERE ca_session_id = %s", sanitize_text_field($session_id)); // phpcs:ignore
1723
+
1724
+ if ( $fetch_sent ) {
1725
+ $query .= ' AND email_sent = 1';
1726
+ }
1727
+
1728
+ $result = $wpdb->get_results( $query ); // phpcs:ignore
1729
+ return $result;
1730
+ }
1731
+
1732
+ }
1733
+
1734
+ Cartflows_Ca_Cart_Abandonment::get_instance();
modules/cart-abandonment/class-cartflows-ca-email-templates-table.php CHANGED
@@ -1,258 +1,258 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'WP_List_Table' ) ) {
9
- include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
- }
11
-
12
- /**
13
- * Cart abandonment templates table class.
14
- */
15
- class Cartflows_Ca_Email_Templates_Table extends WP_List_Table {
16
-
17
-
18
-
19
-
20
- /**
21
- * URL of this page
22
- *
23
- * @var string
24
- * @since 2.5.2
25
- */
26
- public $base_url;
27
-
28
- /**
29
- * Constructor function.
30
- */
31
- function __construct() {
32
- global $status, $page;
33
-
34
- parent::__construct(
35
- array(
36
- 'singular' => 'id',
37
- 'plural' => 'ids',
38
- )
39
- );
40
-
41
- $this->base_url = admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME . '&action=' . WCF_ACTION_EMAIL_TEMPLATES );
42
-
43
- }
44
-
45
- /**
46
- * Default columns.
47
- *
48
- * @param object $item item.
49
- * @param string $column_name column name.
50
- */
51
- function column_default( $item, $column_name ) {
52
- return $item[ $column_name ];
53
- }
54
-
55
- /**
56
- * This is how id column renders.
57
- *
58
- * @param object $item item.
59
- * @return HTML
60
- */
61
- function column_template_name( $item ) {
62
-
63
- $row_actions['edit'] = '<a href="' . wp_nonce_url(
64
- add_query_arg(
65
- array(
66
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
67
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
68
- 'id' => $item['id'],
69
- ),
70
- $this->base_url
71
- ),
72
- WCF_EMAIL_TEMPLATES_NONCE
73
- ) . '">' . __( 'Edit', 'cartflows-ca' ) . '</a>';
74
-
75
- $row_actions['delete'] = '<a onclick="return confirm(\'Are you sure to delete this email template?\');" href="' . wp_nonce_url(
76
- add_query_arg(
77
- array(
78
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
79
- 'sub_action' => WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES,
80
- 'id' => $item['id'],
81
- ),
82
- $this->base_url
83
- ),
84
- WCF_EMAIL_TEMPLATES_NONCE
85
- ) . '">' . __( 'Delete', 'cartflows-ca' ) . '</a>';
86
-
87
- $row_actions['clone'] = '<a href="' . wp_nonce_url(
88
- add_query_arg(
89
- array(
90
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
91
- 'sub_action' => WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES,
92
- 'id' => $item['id'],
93
- ),
94
- $this->base_url
95
- ),
96
- WCF_EMAIL_TEMPLATES_NONCE
97
- ) . '">' . __( 'Clone', 'cartflows-ca' ) . '</a>';
98
-
99
- return sprintf( '%s %s', esc_html( $item['template_name'] ), $this->row_actions( $row_actions ) );
100
- }
101
-
102
- /**
103
- * This is how checkbox column renders.
104
- *
105
- * @param object $item item.
106
- * @return HTML
107
- */
108
- function column_cb( $item ) {
109
- return sprintf( '<input type="checkbox" name="id[]" value="%s" />', esc_html( $item['id'] ) );
110
- }
111
-
112
- /**
113
- * [OPTIONAL] Return array of bult actions if has any
114
- *
115
- * @return array
116
- */
117
- function get_bulk_actions() {
118
- $actions = array(
119
- WCF_ACTION_EMAIL_TEMPLATES => __( 'Delete', 'cartflows-ca' ),
120
- );
121
- return $actions;
122
- }
123
-
124
- /**
125
- * Whether the table has items to display or not
126
- *
127
- * @return bool
128
- */
129
- public function has_items() {
130
- return ! empty( $this->items );
131
- }
132
-
133
- /**
134
- * Fetch data from the database to render on view.
135
- *
136
- * @param string $cart_type abandoned|completed.
137
- */
138
- function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER ) {
139
- global $wpdb;
140
- $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
141
-
142
- $per_page = 10;
143
-
144
- $columns = $this->get_columns();
145
- $hidden = array();
146
- $sortable = $this->get_sortable_columns();
147
-
148
- $this->_column_headers = array( $columns, $hidden, $sortable );
149
-
150
- $this->process_bulk_action();
151
-
152
- $total_items = $wpdb->get_var("SELECT COUNT(id) FROM $cart_abandonment_template_table_name"); // phpcs:ignore
153
-
154
- $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
155
- $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
156
- $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
157
-
158
- $paged = $paged ? max( 0, $paged - 1 ) : 0;
159
- $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
160
- $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
161
-
162
- // [REQUIRED] configure pagination
163
- $this->set_pagination_args(
164
- array(
165
- 'total_items' => $total_items,
166
- 'per_page' => $per_page,
167
- 'total_pages' => ceil( $total_items / $per_page ),
168
- )
169
- );
170
-
171
- $this->items = $wpdb->get_results(
172
- $wpdb->prepare("SELECT * FROM $cart_abandonment_template_table_name ORDER BY $orderby $order LIMIT %d OFFSET %d", $per_page, $paged * $per_page), ARRAY_A); // phpcs:ignore
173
- }
174
-
175
- /**
176
- * Table columns.
177
- *
178
- * @return array
179
- */
180
- function get_columns() {
181
- $columns = array(
182
- 'cb' => '<input type="checkbox" />',
183
- 'template_name' => __( 'Template Name', 'cartflows-ca' ),
184
- 'email_subject' => __( 'Email Subject', 'cartflows-ca' ),
185
- 'trigger_time' => __( 'Trigger After', 'cartflows-ca' ),
186
- 'is_activated' => __( 'Is Activated?', 'cartflows-ca' ),
187
-
188
- );
189
- return $columns;
190
- }
191
-
192
-
193
- /**
194
- * Column name trigger_time.
195
- *
196
- * @param object $item item.
197
- * @return string
198
- */
199
- function column_trigger_time( $item ) {
200
-
201
- return sprintf(
202
- '%d %s',
203
- esc_html( $item['frequency'] ),
204
- ' - ' . esc_html( $item['frequency_unit'] )
205
- );
206
- }
207
-
208
- /**
209
- * Column name trigger_time.
210
- *
211
- * @param object $item item.
212
- * @return string
213
- */
214
- function column_is_activated( $item ) {
215
-
216
- return sprintf( '%s', esc_html( $item['is_activated'] ? 'YES' : 'NO' ) );
217
- }
218
-
219
- /**
220
- * Table sortable columns.
221
- *
222
- * @return array
223
- */
224
- public function get_sortable_columns() {
225
- $sortable = array(
226
- 'id' => array( 'id', true ),
227
- 'template_name' => array( 'Template Name', true ),
228
- 'email_subject' => array( 'Email Subject', true ),
229
- );
230
- return $sortable;
231
- }
232
-
233
- /**
234
- * Processes bulk actions
235
- */
236
- function process_bulk_action() {
237
- global $wpdb;
238
- $table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
239
- $action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
240
-
241
- if ( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES === $action ) {
242
- $ids = array();
243
- if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) {
244
- $ids = array_map( 'intval', $_REQUEST['id'] );
245
- }
246
- $ids = implode( ',', $ids );
247
-
248
- if ( ! empty( $ids ) ) {
249
- $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
250
- }
251
- }
252
-
253
- }
254
-
255
-
256
- }
257
-
258
-
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'WP_List_Table' ) ) {
9
+ include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
+ }
11
+
12
+ /**
13
+ * Cart abandonment templates table class.
14
+ */
15
+ class Cartflows_Ca_Email_Templates_Table extends WP_List_Table {
16
+
17
+
18
+
19
+
20
+ /**
21
+ * URL of this page
22
+ *
23
+ * @var string
24
+ * @since 2.5.2
25
+ */
26
+ public $base_url;
27
+
28
+ /**
29
+ * Constructor function.
30
+ */
31
+ function __construct() {
32
+ global $status, $page;
33
+
34
+ parent::__construct(
35
+ array(
36
+ 'singular' => 'id',
37
+ 'plural' => 'ids',
38
+ )
39
+ );
40
+
41
+ $this->base_url = admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME . '&action=' . WCF_ACTION_EMAIL_TEMPLATES );
42
+
43
+ }
44
+
45
+ /**
46
+ * Default columns.
47
+ *
48
+ * @param object $item item.
49
+ * @param string $column_name column name.
50
+ */
51
+ function column_default( $item, $column_name ) {
52
+ return $item[ $column_name ];
53
+ }
54
+
55
+ /**
56
+ * This is how id column renders.
57
+ *
58
+ * @param object $item item.
59
+ * @return HTML
60
+ */
61
+ function column_template_name( $item ) {
62
+
63
+ $row_actions['edit'] = '<a href="' . wp_nonce_url(
64
+ add_query_arg(
65
+ array(
66
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
67
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
68
+ 'id' => $item['id'],
69
+ ),
70
+ $this->base_url
71
+ ),
72
+ WCF_EMAIL_TEMPLATES_NONCE
73
+ ) . '">' . __( 'Edit', 'cartflows-ca' ) . '</a>';
74
+
75
+ $row_actions['delete'] = '<a onclick="return confirm(\'Are you sure to delete this email template?\');" href="' . wp_nonce_url(
76
+ add_query_arg(
77
+ array(
78
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
79
+ 'sub_action' => WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES,
80
+ 'id' => $item['id'],
81
+ ),
82
+ $this->base_url
83
+ ),
84
+ WCF_EMAIL_TEMPLATES_NONCE
85
+ ) . '">' . __( 'Delete', 'cartflows-ca' ) . '</a>';
86
+
87
+ $row_actions['clone'] = '<a href="' . wp_nonce_url(
88
+ add_query_arg(
89
+ array(
90
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
91
+ 'sub_action' => WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES,
92
+ 'id' => $item['id'],
93
+ ),
94
+ $this->base_url
95
+ ),
96
+ WCF_EMAIL_TEMPLATES_NONCE
97
+ ) . '">' . __( 'Clone', 'cartflows-ca' ) . '</a>';
98
+
99
+ return sprintf( '%s %s', esc_html( $item['template_name'] ), $this->row_actions( $row_actions ) );
100
+ }
101
+
102
+ /**
103
+ * This is how checkbox column renders.
104
+ *
105
+ * @param object $item item.
106
+ * @return HTML
107
+ */
108
+ function column_cb( $item ) {
109
+ return sprintf( '<input type="checkbox" name="id[]" value="%s" />', esc_html( $item['id'] ) );
110
+ }
111
+
112
+ /**
113
+ * [OPTIONAL] Return array of bult actions if has any
114
+ *
115
+ * @return array
116
+ */
117
+ function get_bulk_actions() {
118
+ $actions = array(
119
+ WCF_ACTION_EMAIL_TEMPLATES => __( 'Delete', 'cartflows-ca' ),
120
+ );
121
+ return $actions;
122
+ }
123
+
124
+ /**
125
+ * Whether the table has items to display or not
126
+ *
127
+ * @return bool
128
+ */
129
+ public function has_items() {
130
+ return ! empty( $this->items );
131
+ }
132
+
133
+ /**
134
+ * Fetch data from the database to render on view.
135
+ *
136
+ * @param string $cart_type abandoned|completed.
137
+ */
138
+ function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER ) {
139
+ global $wpdb;
140
+ $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
141
+
142
+ $per_page = 10;
143
+
144
+ $columns = $this->get_columns();
145
+ $hidden = array();
146
+ $sortable = $this->get_sortable_columns();
147
+
148
+ $this->_column_headers = array( $columns, $hidden, $sortable );
149
+
150
+ $this->process_bulk_action();
151
+
152
+ $total_items = $wpdb->get_var("SELECT COUNT(id) FROM $cart_abandonment_template_table_name"); // phpcs:ignore
153
+
154
+ $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
155
+ $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
156
+ $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
157
+
158
+ $paged = $paged ? max( 0, $paged - 1 ) : 0;
159
+ $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
160
+ $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
161
+
162
+ // [REQUIRED] configure pagination
163
+ $this->set_pagination_args(
164
+ array(
165
+ 'total_items' => $total_items,
166
+ 'per_page' => $per_page,
167
+ 'total_pages' => ceil( $total_items / $per_page ),
168
+ )
169
+ );
170
+
171
+ $this->items = $wpdb->get_results(
172
+ $wpdb->prepare("SELECT * FROM $cart_abandonment_template_table_name ORDER BY $orderby $order LIMIT %d OFFSET %d", $per_page, $paged * $per_page), ARRAY_A); // phpcs:ignore
173
+ }
174
+
175
+ /**
176
+ * Table columns.
177
+ *
178
+ * @return array
179
+ */
180
+ function get_columns() {
181
+ $columns = array(
182
+ 'cb' => '<input type="checkbox" />',
183
+ 'template_name' => __( 'Template Name', 'cartflows-ca' ),
184
+ 'email_subject' => __( 'Email Subject', 'cartflows-ca' ),
185
+ 'trigger_time' => __( 'Trigger After', 'cartflows-ca' ),
186
+ 'is_activated' => __( 'Is Activated?', 'cartflows-ca' ),
187
+
188
+ );
189
+ return $columns;
190
+ }
191
+
192
+
193
+ /**
194
+ * Column name trigger_time.
195
+ *
196
+ * @param object $item item.
197
+ * @return string
198
+ */
199
+ function column_trigger_time( $item ) {
200
+
201
+ return sprintf(
202
+ '%d %s',
203
+ esc_html( $item['frequency'] ),
204
+ ' - ' . esc_html( $item['frequency_unit'] )
205
+ );
206
+ }
207
+
208
+ /**
209
+ * Column name trigger_time.
210
+ *
211
+ * @param object $item item.
212
+ * @return string
213
+ */
214
+ function column_is_activated( $item ) {
215
+
216
+ return sprintf( '%s', esc_html( $item['is_activated'] ? 'YES' : 'NO' ) );
217
+ }
218
+
219
+ /**
220
+ * Table sortable columns.
221
+ *
222
+ * @return array
223
+ */
224
+ public function get_sortable_columns() {
225
+ $sortable = array(
226
+ 'id' => array( 'id', true ),
227
+ 'template_name' => array( 'Template Name', true ),
228
+ 'email_subject' => array( 'Email Subject', true ),
229
+ );
230
+ return $sortable;
231
+ }
232
+
233
+ /**
234
+ * Processes bulk actions
235
+ */
236
+ function process_bulk_action() {
237
+ global $wpdb;
238
+ $table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
239
+ $action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
240
+
241
+ if ( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES === $action ) {
242
+ $ids = array();
243
+ if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) {
244
+ $ids = array_map( 'intval', $_REQUEST['id'] );
245
+ }
246
+ $ids = implode( ',', $ids );
247
+
248
+ if ( ! empty( $ids ) ) {
249
+ $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
250
+ }
251
+ }
252
+
253
+ }
254
+
255
+
256
+ }
257
+
258
+
modules/cart-abandonment/class-cartflows-ca-email-templates.php CHANGED
@@ -1,983 +1,983 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- define( 'CARTFLOWS_EMAIL_TEMPLATE_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
9
- define( 'CARTFLOWS_EMAIL_TEMPLATE_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
10
-
11
- /**
12
- * Class for analytics tracking.
13
- */
14
- class Cartflows_Ca_Email_Templates {
15
-
16
-
17
-
18
- /**
19
- * Member Variable
20
- *
21
- * @var object instance
22
- */
23
- private $wpdb;
24
-
25
- /**
26
- * Member Variable
27
- *
28
- * @var object instance
29
- */
30
- private static $instance;
31
-
32
- /**
33
- * Member Variable
34
- *
35
- * @var object instance
36
- */
37
- public $email_history_table;
38
-
39
- /**
40
- * Table name for email templates
41
- *
42
- * @var string
43
- */
44
- public $cart_abandonment_template_table_name;
45
-
46
- /**
47
- * Table name for email templates meta table
48
- *
49
- * @var string
50
- */
51
- public $email_templates_meta_table;
52
-
53
- /**
54
- * Initiator
55
- */
56
- public static function get_instance() {
57
- if ( ! isset( self::$instance ) ) {
58
- self::$instance = new self;
59
- }
60
- return self::$instance;
61
- }
62
-
63
- /**
64
- * Constructor function that initializes required actions and hooks
65
- */
66
- public function __construct() {
67
- $this->define_template_constants();
68
- global $wpdb;
69
- $this->cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
70
- $this->email_templates_meta_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
71
- $this->email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
72
- $this->wpdb = $wpdb;
73
-
74
- $this->fetch_all_active_templates();
75
- add_action( 'admin_enqueue_scripts', __class__ . '::load_email_templates_script', 15 );
76
- }
77
-
78
-
79
- /**
80
- * Add email template JS script.
81
- */
82
- public static function load_email_templates_script() {
83
-
84
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
85
-
86
- if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
87
- return;
88
- }
89
-
90
- wp_enqueue_script( 'jquery-ui-datepicker' );
91
- wp_enqueue_style( 'jquery-ui-style' );
92
-
93
- wp_enqueue_script(
94
- 'cartflows-ca-email-tmpl-settings',
95
- CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
96
- array( 'jquery' ),
97
- CARTFLOWS_CA_VER
98
- );
99
-
100
- $vars = array(
101
- 'settings_url' => add_query_arg(
102
- array(
103
- 'page' => WCF_CA_PAGE_NAME,
104
- 'action' => WCF_ACTION_SETTINGS,
105
- ),
106
- admin_url( '/admin.php' )
107
- ),
108
- );
109
-
110
- wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'CAEmailTemplate', $vars );
111
-
112
- $current_user = wp_get_current_user();
113
- $vars = array(
114
- 'email' => $current_user->user_email,
115
- 'name' => $current_user->user_firstname,
116
- 'surname' => $current_user->user_lastname,
117
- 'phone' => get_user_meta( $current_user->ID, 'billing_phone', true ),
118
- 'billing_company' => get_user_meta( $current_user->ID, 'billing_company', true ),
119
- 'billing_address_1' => get_user_meta( $current_user->ID, 'billing_address_1', true ),
120
- 'billing_address_2' => get_user_meta( $current_user->ID, 'billing_address_2', true ),
121
- 'billing_state' => get_user_meta( $current_user->ID, 'billing_state', true ),
122
- 'billing_postcode' => get_user_meta( $current_user->ID, 'billing_postcode', true ),
123
- 'shipping_first_name' => $current_user->user_firstname,
124
- 'shipping_last_name' => $current_user->user_lastname,
125
- 'shipping_company' => get_user_meta( $current_user->ID, 'shipping_company', true ),
126
- 'shipping_address_1' => get_user_meta( $current_user->ID, 'shipping_address_1', true ),
127
- 'shipping_address_2' => get_user_meta( $current_user->ID, 'shipping_address_2', true ),
128
- 'shipping_city' => get_user_meta( $current_user->ID, 'shipping_city', true ),
129
- 'shipping_state' => get_user_meta( $current_user->ID, 'shipping_state', true ),
130
- 'shipping_postcode' => get_user_meta( $current_user->ID, 'shipping_postcode', true ),
131
- 'woo_currency_symbol' => get_woocommerce_currency_symbol(),
132
- );
133
- wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'CartFlowsCADetails', $vars );
134
-
135
- }
136
-
137
- /**
138
- * Initialise all the constants
139
- */
140
- public function define_template_constants() {
141
- define( 'WCF_CA_PAGE_NAME', 'cartflows_abandoned_cart_tracking' );
142
-
143
- define( 'WCF_CA_GENERAL_SETTINGS_SECTION', 'cartflows_cart_abandonment_settings_section' );
144
- define( 'WCF_CA_EMAIL_SETTINGS_SECTION', 'cartflows_email_template_settings_section' );
145
- define( 'WCF_CA_COUPON_CODE_SECTION', 'cartflows_coupon_code_settings_section' );
146
- define( 'WCF_CA_ZAPIER_SETTINGS_SECTION', 'cartflows_zapier_settings_section' );
147
- define( 'WCF_CA_GDPR_SETTINGS_SECTION', 'cartflows_gdpr_settings_section' );
148
-
149
- define( 'WCF_CA_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-settings' );
150
- define( 'WCF_CA_EMAIL_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-email-settings' );
151
-
152
- define( 'WCF_ACTION_EMAIL_TEMPLATES', 'email_tmpl' );
153
-
154
- define( 'WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES', 'add_email_tmpl' );
155
- define( 'WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES', 'edit_email_tmpl' );
156
- define( 'WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES', 'delete_email_tmpl' );
157
- define( 'WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES', 'clone_email_tmpl' );
158
- define( 'WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES', 'delete_bulk_email_tmpl' );
159
- define( 'WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES', 'save_email_template' );
160
- define( 'WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES', 'restore_default_email_tmpl' );
161
-
162
- define( 'WCF_SUB_ACTION_CART_ABANDONMENT_SETTINGS', 'cart_abandonment_settings' );
163
- define( 'WCF_SUB_ACTION_EMAIL_SETTINGS', 'email_settings' );
164
- define( 'WCF_SUB_ACTION_COUPON_CODE_SETTINGS', 'coupon_code_settings' );
165
- define( 'WCF_SUB_ACTION_ZAPIER_SETTINGS', 'zapier_settings' );
166
-
167
- define( 'WCF_EMAIL_TEMPLATES_NONCE', 'email_template_nonce' );
168
-
169
- }
170
-
171
- /**
172
- * Show success messages for email templates.
173
- */
174
- function show_messages() {
175
-
176
- $wcf_ca_template_created = filter_input( INPUT_GET, 'wcf_ca_template_created', FILTER_SANITIZE_STRING );
177
- $wcf_ca_template_cloned = filter_input( INPUT_GET, 'wcf_ca_template_cloned', FILTER_SANITIZE_STRING );
178
- $wcf_ca_template_deleted = filter_input( INPUT_GET, 'wcf_ca_template_deleted', FILTER_SANITIZE_STRING );
179
- $wcf_ca_template_updated = filter_input( INPUT_GET, 'wcf_ca_template_updated', FILTER_SANITIZE_STRING );
180
- $wcf_ca_template_restored = filter_input( INPUT_GET, 'wcf_ca_template_restored', FILTER_SANITIZE_STRING );
181
-
182
- ?>
183
- <?php if ( 'YES' === $wcf_ca_template_created ) { ?>
184
- <div id="message" class="notice notice-success is-dismissible">
185
- <p>
186
- <strong>
187
- <?php _e( 'The Email Template has been successfully added.', 'cartflows-ca' ); ?>
188
- </strong>
189
- </p>
190
- </div>
191
- <?php } ?>
192
-
193
- <?php if ( 'YES' === $wcf_ca_template_cloned ) { ?>
194
- <div id="message" class="notice notice-success is-dismissible">
195
- <p>
196
- <strong>
197
- <?php _e( 'The Email Template has been cloned successfully.', 'cartflows-ca' ); ?>
198
- </strong>
199
- </p>
200
- </div>
201
- <?php } ?>
202
-
203
- <?php if ( 'YES' === $wcf_ca_template_deleted ) { ?>
204
- <div id="message" class="notice notice-success is-dismissible">
205
- <p>
206
- <strong>
207
- <?php _e( 'The Email Template has been successfully deleted.', 'cartflows-ca' ); ?>
208
- </strong>
209
- </p>
210
- </div>
211
- <?php } ?>
212
- <?php if ( 'YES' === $wcf_ca_template_updated ) { ?>
213
- <div id="message" class="notice notice-success is-dismissible">
214
- <p>
215
- <strong>
216
- <?php _e( 'The Email Template has been successfully updated.', 'cartflows-ca' ); ?>
217
- </strong>
218
- </p>
219
- </div>
220
- <?php } ?>
221
-
222
- <?php if ( 'YES' === $wcf_ca_template_restored ) { ?>
223
- <div id="message" class="notice notice-success is-dismissible">
224
- <p>
225
- <strong>
226
- <?php _e( 'Default Email Templates has been restored successfully.', 'cartflows-ca' ); ?>
227
- </strong>
228
- </p>
229
- </div>
230
- <?php } ?>
231
- <?php
232
-
233
- }
234
-
235
- /**
236
- * Delete bulk email templates.
237
- */
238
- function delete_bulk_templates() {
239
- $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
240
- $wcf_template_list->process_bulk_action();
241
- $param = array(
242
- 'page' => WCF_CA_PAGE_NAME,
243
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
244
- 'wcf_ca_template_deleted' => 'YES',
245
- );
246
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
247
- wp_safe_redirect( $redirect_url );
248
- }
249
-
250
-
251
- /**
252
- * Delete email templates.
253
- */
254
- function delete_single_template() {
255
-
256
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
257
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
258
-
259
- if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
260
-
261
- $this->wpdb->delete(
262
- $this->cart_abandonment_template_table_name,
263
- array( 'id' => $id ),
264
- '%d'
265
- );
266
- $param = array(
267
- 'page' => WCF_CA_PAGE_NAME,
268
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
269
- 'wcf_ca_template_deleted' => 'YES',
270
- );
271
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
272
- wp_safe_redirect( $redirect_url );
273
-
274
- }
275
- }
276
-
277
- /**
278
- * Delete email templates.
279
- */
280
- function clone_email_template() {
281
-
282
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
283
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
284
-
285
- if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
286
-
287
- $email_template = $this->get_template_by_id( $id );
288
-
289
- $this->wpdb->insert(
290
- $this->cart_abandonment_template_table_name,
291
- array(
292
- 'template_name' => sanitize_text_field( $email_template->template_name ),
293
- 'email_subject' => sanitize_text_field( $email_template->email_subject ),
294
- 'email_body' => $email_template->email_body,
295
- 'frequency' => intval( sanitize_text_field( $email_template->frequency ) ),
296
- 'frequency_unit' => sanitize_text_field( $email_template->frequency_unit ),
297
-
298
- ),
299
- array( '%s', '%s', '%s', '%d', '%s' )
300
- );
301
-
302
- $email_template_id = $this->wpdb->insert_id;
303
- $meta_data = array(
304
- 'override_global_coupon' => false,
305
- 'discount_type' => 'percent',
306
- 'coupon_amount' => 10,
307
- 'coupon_expiry_date' => '',
308
- 'coupon_expiry_unit' => 'hours',
309
- );
310
-
311
- foreach ( $meta_data as $mera_key => $meta_value ) {
312
- $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
313
- }
314
-
315
- $param = array(
316
- 'page' => WCF_CA_PAGE_NAME,
317
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
318
- 'wcf_ca_template_cloned' => 'YES',
319
- );
320
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
321
- wp_safe_redirect( $redirect_url );
322
-
323
- }
324
- }
325
-
326
- /**
327
- * Get email template by id.
328
- *
329
- * @param int $email_tmpl_id template id.
330
- */
331
- function get_email_template_by_id( $email_tmpl_id ) {
332
-
333
- $query = 'SELECT * FROM ' . $this->cart_abandonment_template_table_name . ' WHERE id = %d ';
334
- return $this->wpdb->get_row($this->wpdb->prepare($query, $email_tmpl_id)); // phpcs:ignore
335
-
336
- }
337
-
338
- /**
339
- * Render email template add/edit form.
340
- *
341
- * @param string $sub_action sub_action.
342
- */
343
- function render_email_template_form( $sub_action = WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES ) {
344
-
345
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
346
-
347
- if ( $id ) {
348
- $results = $this->get_email_template_by_id( $id );
349
- }
350
-
351
- ?>
352
-
353
- <div id="content">
354
-
355
- <?php
356
- $param = array(
357
- 'page' => WCF_CA_PAGE_NAME,
358
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
359
- 'sub_action' => WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES,
360
- );
361
- $save_template_url = esc_url( add_query_arg( $param, admin_url( '/admin.php' ) ) );
362
- ?>
363
-
364
- <form method="post" action="<?php echo $save_template_url; ?>" id="wcf_settings">
365
- <input type="hidden" name="sub_action" value="<?php echo $sub_action; ?>"/>
366
- <?php
367
- $id_by = '';
368
- if ( isset( $id ) ) {
369
- $id_by = $id;
370
- }
371
- ?>
372
- <input type="hidden" name="id" value="<?php echo $id_by; ?>"/>
373
- <?php
374
-
375
- $button_sub_action = 'save';
376
- $display_message = 'Add New Email Template:';
377
-
378
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
379
- $button_sub_action = 'update';
380
- $display_message = 'Edit Email Template:';
381
- }
382
- print'<input type="hidden" name="wcf_settings_frm" value="' . $button_sub_action . '">';
383
- ?>
384
- <div id="poststuff">
385
- <div> <!-- <div class="postbox" > -->
386
- <h3><?php _e($display_message, 'cartflows-ca'); // phpcs:ignore ?></h3>
387
- <hr/>
388
- <div>
389
- <table class="form-table" id="addedit_template">
390
- <tr>
391
- <th>
392
- <label for="wcf_email_subject"><b><?php _e( 'Activate Template now?', 'cartflows-ca' ); ?></b></label>
393
- </th>
394
- <td>
395
- <?php
396
- $is_activated = '';
397
- $active_status = 0;
398
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->is_activated ) ) {
399
- $active_status = stripslashes( $results->is_activated );
400
- $is_activated = $active_status ? 'on' : 'off';
401
-
402
- }
403
- print'<button type="button" class="wcf-ca-switch wcf-toggle-template-status" wcf-template-id="1" wcf-ca-template-switch="' . $is_activated . '"> ' . $is_activated . ' </button>';
404
- print'<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . $active_status . '" />';
405
- ?>
406
-
407
- </td>
408
- </tr>
409
-
410
- <tr>
411
- <th>
412
- <label for="wcf_template_name"><b><?php _e( 'Template Name:', 'cartflows-ca' ); ?></b></label>
413
- </th>
414
- <td>
415
- <?php
416
- $template_name = '';
417
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->template_name ) ) {
418
- $template_name = $results->template_name;
419
- }
420
- print'<input type="text" name="wcf_template_name" id="wcf_template_name" class="wcf-ca-trigger-input" value="' . $template_name . '">';
421
- ?>
422
- </td>
423
- </tr>
424
-
425
- <tr>
426
- <th>
427
- <label for="wcf_email_subject"><b><?php _e( 'Email Subject:', 'cartflows-ca' ); ?></b></label>
428
- </th>
429
- <td>
430
- <?php
431
- $subject_edit = '';
432
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_subject ) ) {
433
- $subject_edit = stripslashes( $results->email_subject );
434
- }
435
- print'<input type="text" name="wcf_email_subject" id="wcf_email_subject" class="wcf-ca-trigger-input" value="' . $subject_edit . '">';
436
- ?>
437
- </td>
438
- </tr>
439
-
440
- <tr>
441
- <th>
442
- <label for="wcf_email_body"><b><?php _e( 'Email Body:', 'cartflows-ca' ); ?></b></label>
443
- </th>
444
- <td>
445
- <?php
446
- $initial_data = '';
447
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_body ) ) {
448
- $initial_data = stripslashes( $results->email_body );
449
- }
450
-
451
- wp_editor(
452
- $initial_data,
453
- 'wcf_email_body',
454
- array(
455
- 'media_buttons' => true,
456
- 'textarea_rows' => 15,
457
- 'tabindex' => 4,
458
- 'tinymce' => array(
459
- 'theme_advanced_buttons1' => 'bold,italic,underline,|,bullist,numlist,blockquote,|,link,unlink,|,spellchecker,fullscreen,|,formatselect,styleselect',
460
- ),
461
- )
462
- );
463
-
464
- ?>
465
- <?php echo stripslashes( get_option( 'wcf_email_body' ) ); ?>
466
- </td>
467
- </tr>
468
-
469
- <tr>
470
- <th>
471
- <label for="wcf_override_global_coupon"><b><?php _e( 'Create Coupon', 'cartflows-ca' ); ?></b></label>
472
- </th>
473
- <td>
474
- <?php
475
-
476
- $wcf_override_global_coupon = '';
477
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
478
- $wcf_override_global_coupon = $this->get_email_template_meta_by_key( $results->id, 'override_global_coupon' );
479
- if ( isset( $wcf_override_global_coupon->meta_value ) ) {
480
- $wcf_override_global_coupon = $wcf_override_global_coupon->meta_value ? 'checked' : '';
481
- }
482
- }
483
-
484
- print'<input ' . $wcf_override_global_coupon . ' id="wcf_override_global_coupon" name="wcf_override_global_coupon" type="checkbox" value="" /><label for="wcf_override_global_coupon"> Allows you to send new coupon only for this template. </label>';
485
- ?>
486
- </td>
487
- </tr>
488
-
489
- <tr>
490
- <th>
491
- <label for="wcf_email_discount_type"><b><?php _e( 'Discount Type', 'cartflows-ca' ); ?></b></label>
492
- </th>
493
- <td>
494
- <?php
495
-
496
- $wcf_email_discount_type = 'percent';
497
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
498
- $wcf_email_discount_type = $this->get_email_template_meta_by_key( $results->id, 'discount_type' );
499
- if ( isset( $wcf_email_discount_type->meta_value ) ) {
500
- $wcf_email_discount_type = $wcf_email_discount_type->meta_value;
501
- }
502
- }
503
-
504
- $dropdown_options = array(
505
- 'percent' => 'Percentage discount',
506
- 'fixed_cart' => 'Fixed cart discount',
507
- );
508
-
509
- echo '<select id="wcf_email_discount_type" name="wcf_email_discount_type">';
510
- foreach ( $dropdown_options as $key => $value ) {
511
- $is_selected = $key === $wcf_email_discount_type ? 'selected' : '';
512
- echo '<option ' . $is_selected . ' value=' . $key . '>' . $value . '</option>';
513
-
514
- }
515
- echo '</select>';
516
-
517
- ?>
518
- </td>
519
- </tr>
520
-
521
- <tr>
522
- <th>
523
- <label for="wcf_email_discount_amount"><b><?php _e( 'Coupon Amount', 'cartflows-ca' ); ?></b></label>
524
- </th>
525
- <td>
526
- <?php
527
- $wcf_email_discount_amount = 10;
528
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
529
- $wcf_email_discount_amount = $this->get_email_template_meta_by_key( $results->id, 'coupon_amount' );
530
- if ( isset( $wcf_email_discount_amount->meta_value ) ) {
531
- $wcf_email_discount_amount = $wcf_email_discount_amount->meta_value;
532
- }
533
- }
534
- print'<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="number" id="wcf_email_discount_amount" name="wcf_email_discount_amount" value="' . $wcf_email_discount_amount . '">';
535
- ?>
536
- </td>
537
- </tr>
538
-
539
- <tr>
540
- <th>
541
- <label for="wcf_email_coupon_expiry_date"><b><?php _e( 'Coupon expiry date', 'cartflows-ca' ); ?></b></label>
542
- </th>
543
- <td>
544
- <?php
545
- $wcf_email_coupon_expiry_date = 0;
546
- $coupon_expiry_unit = 'hours';
547
-
548
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
549
- $wcf_email_coupon_expiry_date = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_date' );
550
- $wcf_email_coupon_expiry_unit = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_unit' );
551
-
552
- if ( isset( $wcf_email_coupon_expiry_date->meta_value ) ) {
553
- $wcf_email_coupon_expiry_date = $wcf_email_coupon_expiry_date->meta_value;
554
- }
555
- if ( isset( $wcf_email_coupon_expiry_unit->meta_value ) ) {
556
- $coupon_expiry_unit = $wcf_email_coupon_expiry_unit->meta_value;
557
- }
558
- }
559
- print'<input type="number" class="wcf-ca-trigger-input wcf-ca-coupon-inputs" id="wcf_email_coupon_expiry_date" name="wcf_email_coupon_expiry_date" value="' . intval( $wcf_email_coupon_expiry_date ) . '" autocomplete="off" />';
560
- $items = array(
561
- 'hours' => 'Hour(s)',
562
- 'days' => 'Day(s)',
563
- );
564
- echo "<select id='wcf_coupon_expiry_unit' name='wcf_coupon_expiry_unit'>";
565
- foreach ( $items as $key => $item ) {
566
- $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
567
- echo "<option value='$key' $selected>$item</option>";
568
- }
569
- echo '</select>';
570
-
571
- echo " <span class='description'> Enter zero (0) to restrict coupon from expiring </span>"
572
- ?>
573
- </td>
574
- </tr>
575
-
576
- <tr>
577
- <th>
578
- <label for="wcf_email_subject"><b><?php _e( 'Send This Email', 'cartflows-ca' ); ?></b></label>
579
- </th>
580
- <td>
581
- <?php
582
- $frequency_edit = '';
583
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency ) ) {
584
- $frequency_edit = $results->frequency;
585
- }
586
- print'<input style="width:15%" type="number" name="wcf_email_frequency" id="wcf_email_frequency" class="wcf-ca-trigger-input" value="' . $frequency_edit . '">';
587
- ?>
588
-
589
- <select name="wcf_email_frequency_unit" id="wcf_email_frequency_unit">
590
- <?php
591
- $frequency_unit = '';
592
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency_unit ) ) {
593
- $frequency_unit = $results->frequency_unit;
594
- }
595
- $days_or_hours = array(
596
- 'MINUTE' => 'Minute(s)',
597
- 'HOUR' => 'Hour(s)',
598
- 'DAY' => 'Day(s)',
599
- );
600
- foreach ( $days_or_hours as $k => $v ) {
601
- printf(
602
- "<option %s value='%s'>%s</option>\n",
603
- selected( $k, $frequency_unit, false ),
604
- esc_attr( $k ),
605
- $v
606
- );
607
- }
608
- ?>
609
- </select>
610
- <span class="description">
611
- <?php _e( 'after cart is abandoned.', 'cartflows-ca' ); ?>
612
- </span>
613
-
614
-
615
- </td>
616
- </tr>
617
-
618
- <tr>
619
- <?php $current_user = wp_get_current_user(); ?>
620
- <th>
621
- <label for="wcf_email_preview"><b><?php _e( 'Send Test Email To:', 'cartflows-ca' ); ?></b></label>
622
- </th>
623
- <td>
624
- <input class="wcf-ca-trigger-input" type="text" id="wcf_send_test_email" name="send_test_email" value="<?php echo $current_user->user_email; ?>" class="wcf-ca-trigger-input">
625
- <input class="button" type="button" value="Send a test email" id="wcf_preview_email"/> <br/>
626
-
627
- <label id="mail_response_msg"> </label>
628
- </td>
629
- </tr>
630
-
631
- </table>
632
- </div>
633
- </div>
634
- </div>
635
- <?php wp_nonce_field( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' ); ?>
636
- <p class="submit">
637
- <?php
638
- $button_value = 'Save Changes';
639
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
640
- $button_value = 'Update Changes';
641
- }
642
- ?>
643
- <input type="submit" name="Submit" class="button-primary" value="<?php echo $button_value; ?>"/>
644
- </p>
645
- </form>
646
- </div>
647
- <?php
648
-
649
- }
650
-
651
-
652
- /**
653
- * Sanitize email post data.
654
- *
655
- * @return array
656
- */
657
- function sanitize_email_post_data() {
658
-
659
- $input_post_values = array(
660
- 'wcf_email_subject' => array(
661
- 'default' => '',
662
- 'sanitize' => FILTER_SANITIZE_STRING,
663
- ),
664
- 'wcf_email_body' => array(
665
- 'default' => '',
666
- 'sanitize' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
667
- ),
668
- 'wcf_template_name' => array(
669
- 'default' => '',
670
- 'sanitize' => FILTER_SANITIZE_STRING,
671
- ),
672
- 'wcf_email_frequency' => array(
673
- 'default' => 30,
674
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
675
- ),
676
- 'wcf_email_frequency_unit' => array(
677
- 'default' => 'MINUTE',
678
- 'sanitize' => FILTER_SANITIZE_STRING,
679
- ),
680
- 'wcf_activate_email_template' => array(
681
- 'default' => 0,
682
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
683
- ),
684
-
685
- 'wcf_email_discount_type' => array(
686
- 'default' => 'percent',
687
- 'sanitize' => FILTER_SANITIZE_STRING,
688
- ),
689
- 'wcf_email_discount_amount' => array(
690
- 'default' => 10,
691
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
692
- ),
693
- 'wcf_email_coupon_expiry_date' => array(
694
- 'default' => '',
695
- 'sanitize' => FILTER_SANITIZE_STRING,
696
- ),
697
- 'wcf_coupon_expiry_unit' => array(
698
- 'default' => 'hours',
699
- 'sanitize' => FILTER_SANITIZE_STRING,
700
- ),
701
- 'id' => array(
702
- 'default' => null,
703
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
704
- ),
705
- );
706
-
707
- $sanitized_post = array();
708
- foreach ( $input_post_values as $key => $input_post_value ) {
709
-
710
- if ( isset( $_POST[ $key ] ) ) {
711
- $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
712
- } else {
713
- $sanitized_post[ $key ] = $input_post_value['default'];
714
- }
715
- }
716
-
717
- $sanitized_post['wcf_override_global_coupon'] = isset( $_POST['wcf_override_global_coupon'] ) ? true : false;
718
- $sanitized_post['wcf_email_body'] = html_entity_decode( $sanitized_post['wcf_email_body'] );
719
-
720
- return $sanitized_post;
721
-
722
- }
723
-
724
-
725
- /**
726
- * Add email template callback ajax.
727
- */
728
- function add_email_template() {
729
-
730
- $sanitized_post = $this->sanitize_email_post_data();
731
- $this->wpdb->insert(
732
- $this->cart_abandonment_template_table_name,
733
- array(
734
- 'template_name' => $sanitized_post['wcf_template_name'],
735
- 'email_subject' => $sanitized_post['wcf_email_subject'],
736
- 'email_body' => wpautop( $sanitized_post['wcf_email_body'] ),
737
- 'frequency' => $sanitized_post['wcf_email_frequency'],
738
- 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
739
- 'is_activated' => $sanitized_post['wcf_activate_email_template'],
740
- ),
741
- array( '%s', '%s', '%s', '%d', '%s', '%d' )
742
- );
743
-
744
- $email_template_id = $this->wpdb->insert_id;
745
- $meta_data = array(
746
- 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
747
- 'discount_type' => $sanitized_post['wcf_email_discount_type'],
748
- 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
749
- 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
750
- 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
751
- );
752
-
753
- foreach ( $meta_data as $mera_key => $meta_value ) {
754
- $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
755
- }
756
-
757
- $param = array(
758
- 'page' => WCF_CA_PAGE_NAME,
759
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
760
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
761
- 'id' => $email_template_id,
762
- 'wcf_ca_template_created' => 'YES',
763
- );
764
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
765
- wp_safe_redirect( $redirect_url );
766
-
767
- }
768
-
769
- /**
770
- * Edit email template callback ajax.
771
- */
772
- function edit_email_template() {
773
- $sanitized_post = $this->sanitize_email_post_data();
774
- $email_template_id = $sanitized_post['id'];
775
-
776
- $this->wpdb->update(
777
- $this->cart_abandonment_template_table_name,
778
- array(
779
- 'template_name' => $sanitized_post['wcf_template_name'],
780
- 'email_subject' => $sanitized_post['wcf_email_subject'],
781
- 'email_body' => wpautop( $sanitized_post['wcf_email_body'] ),
782
- 'frequency' => $sanitized_post['wcf_email_frequency'],
783
- 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
784
- 'is_activated' => $sanitized_post['wcf_activate_email_template'],
785
- ),
786
- array( 'id' => $email_template_id ),
787
- array( '%s', '%s', '%s', '%d', '%s', '%d' ),
788
- array( '%d' )
789
- );
790
-
791
- $meta_data = array(
792
- 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
793
- 'discount_type' => $sanitized_post['wcf_email_discount_type'],
794
- 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
795
- 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
796
- 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
797
- );
798
- foreach ( $meta_data as $mera_key => $meta_value ) {
799
- $this->update_email_template_meta( $email_template_id, $mera_key, $meta_value );
800
- }
801
-
802
- $param = array(
803
- 'page' => WCF_CA_PAGE_NAME,
804
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
805
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
806
- 'id' => $email_template_id,
807
- 'wcf_ca_template_updated' => 'YES',
808
- );
809
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
810
-
811
- wp_safe_redirect( $redirect_url );
812
-
813
- }
814
-
815
- /**
816
- * Restore default email templates.
817
- */
818
- public function restore_email_templates() {
819
-
820
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
821
-
822
- if ( $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
823
-
824
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
825
- $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
826
- $db->template_table_seeder( true );
827
-
828
- $param = array(
829
- 'page' => WCF_CA_PAGE_NAME,
830
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
831
- 'wcf_ca_template_restored' => 'YES',
832
- );
833
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
834
- wp_safe_redirect( $redirect_url );
835
- }
836
-
837
- }
838
-
839
- /**
840
- * Update the meta values.
841
- *
842
- * @param integer $email_template_id email template id.
843
- * @param string $meta_key meta key.
844
- * @param string $meta_value meta value.
845
- */
846
- function update_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
847
-
848
- $template_meta = $this->get_email_template_meta_by_key( $email_template_id, $meta_key );
849
-
850
- if ( $template_meta ) {
851
- $this->wpdb->update(
852
- $this->email_templates_meta_table,
853
- array(
854
- 'meta_value' => sanitize_text_field( $meta_value ),
855
- ),
856
- array(
857
- 'email_template_id' => $email_template_id,
858
- 'meta_key' => sanitize_text_field( $meta_key ),
859
- )
860
- );
861
- } else {
862
- $this->add_email_template_meta( $email_template_id, $meta_key, $meta_value );
863
- }
864
-
865
- }
866
-
867
-
868
- /**
869
- * Add the meta values.
870
- *
871
- * @param integer $email_template_id email template id.
872
- * @param string $meta_key meta key.
873
- * @param string $meta_value meta value.
874
- */
875
- function add_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
876
- $this->wpdb->insert(
877
- $this->email_templates_meta_table,
878
- array(
879
- 'email_template_id' => $email_template_id,
880
- 'meta_key' => sanitize_text_field( $meta_key ),
881
- 'meta_value' => sanitize_text_field( $meta_value ),
882
- )
883
- );
884
- }
885
-
886
- /**
887
- * Get the meta values.
888
- *
889
- * @param integer $email_template_id email template id.
890
- * @param string $meta_key meta key.
891
- */
892
- function get_email_template_meta_by_key( $email_template_id, $meta_key ) {
893
- return $this->wpdb->get_row(
894
- $this->wpdb->prepare( "select * from $this->email_templates_meta_table where email_template_id = %d AND meta_key = %s", $email_template_id, $meta_key ) // phpcs:ignore
895
- );
896
- }
897
-
898
- /**
899
- * Render email template grid.
900
- */
901
- function show_email_template_data_table() {
902
- $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
903
- $wcf_template_list->prepare_items();
904
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
905
- ?>
906
- <div class="wrap">
907
- <form id="wcf-cart-abandonment-template-table" method="GET">
908
- <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
909
- <input type="hidden" name="action" value="<?php echo esc_html( WCF_ACTION_EMAIL_TEMPLATES ); ?>"/>
910
- <input type="hidden" name="sub_action" value="<?php echo esc_html( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES ); ?>"/>
911
- <?php $wcf_template_list->display(); ?>
912
- </form>
913
- </div>
914
- <?php
915
- }
916
-
917
- /**
918
- * Render 'Add Email Template button'.
919
- */
920
- public function show_add_new_template_button() {
921
- $param = array(
922
- 'page' => WCF_CA_PAGE_NAME,
923
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
924
- 'sub_action' => WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES,
925
- );
926
-
927
- $add_new_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
928
-
929
- $param['sub_action'] = WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES;
930
- $restore_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
931
-
932
- ?>
933
- <div class="wcf-ca-report-btn">
934
- <div class="wcf-ca-left-report-field-group">
935
- <a style="cursor: pointer" href="<?php echo $add_new_template_url; ?>" class="button-secondary"><?php _e( 'Create New Template', 'cartflows-ca' ); ?></a>
936
- </div>
937
- <div class="wcf-ca-right-report-field-group">
938
- <a onclick="return confirm('Are you sure to restore email templates?');" style="cursor: pointer" href="<?php echo $restore_template_url; ?>" class="button-secondary"><?php _e( ' Restore Default Templates', 'cartflows-ca' ); ?></a>
939
- </div>
940
- </div>
941
- <?php
942
- }
943
-
944
- /**
945
- * Get all active templates.
946
- *
947
- * @return array|object|null
948
- */
949
- public function fetch_all_active_templates() {
950
- $result = $this->wpdb->get_results(
951
- $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE is_activated = %s', true) // phpcs:ignore
952
- );
953
- return $result;
954
- }
955
-
956
- /**
957
- * Get specific template by id.
958
- *
959
- * @param integer $tmpl_id template id.
960
- * @return array|object|void|null
961
- */
962
- public function get_template_by_id( $tmpl_id ) {
963
- $result = $this->wpdb->get_row(
964
- $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE id = %s', $tmpl_id) // phpcs:ignore
965
- );
966
- return $result;
967
- }
968
-
969
- /**
970
- * Get the email history.
971
- *
972
- * @param integer $email_history_id email history id.
973
- * @return array|object|void|null
974
- */
975
- public function get_email_history_by_id( $email_history_id ) {
976
- $result = $this->wpdb->get_row(
977
- $this->wpdb->prepare('SELECT * FROM `' . $this->email_history_table . '` WHERE id = %s', $email_history_id) // phpcs:ignore
978
- );
979
- return $result;
980
- }
981
- }
982
-
983
- Cartflows_Ca_Email_Templates::get_instance();
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ define( 'CARTFLOWS_EMAIL_TEMPLATE_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
9
+ define( 'CARTFLOWS_EMAIL_TEMPLATE_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
10
+
11
+ /**
12
+ * Class for analytics tracking.
13
+ */
14
+ class Cartflows_Ca_Email_Templates {
15
+
16
+
17
+
18
+ /**
19
+ * Member Variable
20
+ *
21
+ * @var object instance
22
+ */
23
+ private $wpdb;
24
+
25
+ /**
26
+ * Member Variable
27
+ *
28
+ * @var object instance
29
+ */
30
+ private static $instance;
31
+
32
+ /**
33
+ * Member Variable
34
+ *
35
+ * @var object instance
36
+ */
37
+ public $email_history_table;
38
+
39
+ /**
40
+ * Table name for email templates
41
+ *
42
+ * @var string
43
+ */
44
+ public $cart_abandonment_template_table_name;
45
+
46
+ /**
47
+ * Table name for email templates meta table
48
+ *
49
+ * @var string
50
+ */
51
+ public $email_templates_meta_table;
52
+
53
+ /**
54
+ * Initiator
55
+ */
56
+ public static function get_instance() {
57
+ if ( ! isset( self::$instance ) ) {
58
+ self::$instance = new self;
59
+ }
60
+ return self::$instance;
61
+ }
62
+
63
+ /**
64
+ * Constructor function that initializes required actions and hooks
65
+ */
66
+ public function __construct() {
67
+ $this->define_template_constants();
68
+ global $wpdb;
69
+ $this->cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
70
+ $this->email_templates_meta_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
71
+ $this->email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
72
+ $this->wpdb = $wpdb;
73
+
74
+ $this->fetch_all_active_templates();
75
+ add_action( 'admin_enqueue_scripts', __class__ . '::load_email_templates_script', 15 );
76
+ }
77
+
78
+
79
+ /**
80
+ * Add email template JS script.
81
+ */
82
+ public static function load_email_templates_script() {
83
+
84
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
85
+
86
+ if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
87
+ return;
88
+ }
89
+
90
+ wp_enqueue_script( 'jquery-ui-datepicker' );
91
+ wp_enqueue_style( 'jquery-ui-style' );
92
+
93
+ wp_enqueue_script(
94
+ 'cartflows-ca-email-tmpl-settings',
95
+ CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
96
+ array( 'jquery' ),
97
+ CARTFLOWS_CA_VER
98
+ );
99
+
100
+ $vars = array(
101
+ 'settings_url' => add_query_arg(
102
+ array(
103
+ 'page' => WCF_CA_PAGE_NAME,
104
+ 'action' => WCF_ACTION_SETTINGS,
105
+ ),
106
+ admin_url( '/admin.php' )
107
+ ),
108
+ );
109
+
110
+ wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'CAEmailTemplate', $vars );
111
+
112
+ $current_user = wp_get_current_user();
113
+ $vars = array(
114
+ 'email' => $current_user->user_email,
115
+ 'name' => $current_user->user_firstname,
116
+ 'surname' => $current_user->user_lastname,
117
+ 'phone' => get_user_meta( $current_user->ID, 'billing_phone', true ),
118
+ 'billing_company' => get_user_meta( $current_user->ID, 'billing_company', true ),
119
+ 'billing_address_1' => get_user_meta( $current_user->ID, 'billing_address_1', true ),
120
+ 'billing_address_2' => get_user_meta( $current_user->ID, 'billing_address_2', true ),
121
+ 'billing_state' => get_user_meta( $current_user->ID, 'billing_state', true ),
122
+ 'billing_postcode' => get_user_meta( $current_user->ID, 'billing_postcode', true ),
123
+ 'shipping_first_name' => $current_user->user_firstname,
124
+ 'shipping_last_name' => $current_user->user_lastname,
125
+ 'shipping_company' => get_user_meta( $current_user->ID, 'shipping_company', true ),
126
+ 'shipping_address_1' => get_user_meta( $current_user->ID, 'shipping_address_1', true ),
127
+ 'shipping_address_2' => get_user_meta( $current_user->ID, 'shipping_address_2', true ),
128
+ 'shipping_city' => get_user_meta( $current_user->ID, 'shipping_city', true ),
129
+ 'shipping_state' => get_user_meta( $current_user->ID, 'shipping_state', true ),
130
+ 'shipping_postcode' => get_user_meta( $current_user->ID, 'shipping_postcode', true ),
131
+ 'woo_currency_symbol' => get_woocommerce_currency_symbol(),
132
+ );
133
+ wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'CartFlowsCADetails', $vars );
134
+
135
+ }
136
+
137
+ /**
138
+ * Initialise all the constants
139
+ */
140
+ public function define_template_constants() {
141
+ define( 'WCF_CA_PAGE_NAME', 'cartflows_abandoned_cart_tracking' );
142
+
143
+ define( 'WCF_CA_GENERAL_SETTINGS_SECTION', 'cartflows_cart_abandonment_settings_section' );
144
+ define( 'WCF_CA_EMAIL_SETTINGS_SECTION', 'cartflows_email_template_settings_section' );
145
+ define( 'WCF_CA_COUPON_CODE_SECTION', 'cartflows_coupon_code_settings_section' );
146
+ define( 'WCF_CA_ZAPIER_SETTINGS_SECTION', 'cartflows_zapier_settings_section' );
147
+ define( 'WCF_CA_GDPR_SETTINGS_SECTION', 'cartflows_gdpr_settings_section' );
148
+
149
+ define( 'WCF_CA_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-settings' );
150
+ define( 'WCF_CA_EMAIL_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-email-settings' );
151
+
152
+ define( 'WCF_ACTION_EMAIL_TEMPLATES', 'email_tmpl' );
153
+
154
+ define( 'WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES', 'add_email_tmpl' );
155
+ define( 'WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES', 'edit_email_tmpl' );
156
+ define( 'WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES', 'delete_email_tmpl' );
157
+ define( 'WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES', 'clone_email_tmpl' );
158
+ define( 'WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES', 'delete_bulk_email_tmpl' );
159
+ define( 'WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES', 'save_email_template' );
160
+ define( 'WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES', 'restore_default_email_tmpl' );
161
+
162
+ define( 'WCF_SUB_ACTION_CART_ABANDONMENT_SETTINGS', 'cart_abandonment_settings' );
163
+ define( 'WCF_SUB_ACTION_EMAIL_SETTINGS', 'email_settings' );
164
+ define( 'WCF_SUB_ACTION_COUPON_CODE_SETTINGS', 'coupon_code_settings' );
165
+ define( 'WCF_SUB_ACTION_ZAPIER_SETTINGS', 'zapier_settings' );
166
+
167
+ define( 'WCF_EMAIL_TEMPLATES_NONCE', 'email_template_nonce' );
168
+
169
+ }
170
+
171
+ /**
172
+ * Show success messages for email templates.
173
+ */
174
+ function show_messages() {
175
+
176
+ $wcf_ca_template_created = filter_input( INPUT_GET, 'wcf_ca_template_created', FILTER_SANITIZE_STRING );
177
+ $wcf_ca_template_cloned = filter_input( INPUT_GET, 'wcf_ca_template_cloned', FILTER_SANITIZE_STRING );
178
+ $wcf_ca_template_deleted = filter_input( INPUT_GET, 'wcf_ca_template_deleted', FILTER_SANITIZE_STRING );
179
+ $wcf_ca_template_updated = filter_input( INPUT_GET, 'wcf_ca_template_updated', FILTER_SANITIZE_STRING );
180
+ $wcf_ca_template_restored = filter_input( INPUT_GET, 'wcf_ca_template_restored', FILTER_SANITIZE_STRING );
181
+
182
+ ?>
183
+ <?php if ( 'YES' === $wcf_ca_template_created ) { ?>
184
+ <div id="message" class="notice notice-success is-dismissible">
185
+ <p>
186
+ <strong>
187
+ <?php _e( 'The Email Template has been successfully added.', 'cartflows-ca' ); ?>
188
+ </strong>
189
+ </p>
190
+ </div>
191
+ <?php } ?>
192
+
193
+ <?php if ( 'YES' === $wcf_ca_template_cloned ) { ?>
194
+ <div id="message" class="notice notice-success is-dismissible">
195
+ <p>
196
+ <strong>
197
+ <?php _e( 'The Email Template has been cloned successfully.', 'cartflows-ca' ); ?>
198
+ </strong>
199
+ </p>
200
+ </div>
201
+ <?php } ?>
202
+
203
+ <?php if ( 'YES' === $wcf_ca_template_deleted ) { ?>
204
+ <div id="message" class="notice notice-success is-dismissible">
205
+ <p>
206
+ <strong>
207
+ <?php _e( 'The Email Template has been successfully deleted.', 'cartflows-ca' ); ?>
208
+ </strong>
209
+ </p>
210
+ </div>
211
+ <?php } ?>
212
+ <?php if ( 'YES' === $wcf_ca_template_updated ) { ?>
213
+ <div id="message" class="notice notice-success is-dismissible">
214
+ <p>
215
+ <strong>
216
+ <?php _e( 'The Email Template has been successfully updated.', 'cartflows-ca' ); ?>
217
+ </strong>
218
+ </p>
219
+ </div>
220
+ <?php } ?>
221
+
222
+ <?php if ( 'YES' === $wcf_ca_template_restored ) { ?>
223
+ <div id="message" class="notice notice-success is-dismissible">
224
+ <p>
225
+ <strong>
226
+ <?php _e( 'Default Email Templates has been restored successfully.', 'cartflows-ca' ); ?>
227
+ </strong>
228
+ </p>
229
+ </div>
230
+ <?php } ?>
231
+ <?php
232
+
233
+ }
234
+
235
+ /**
236
+ * Delete bulk email templates.
237
+ */
238
+ function delete_bulk_templates() {
239
+ $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
240
+ $wcf_template_list->process_bulk_action();
241
+ $param = array(
242
+ 'page' => WCF_CA_PAGE_NAME,
243
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
244
+ 'wcf_ca_template_deleted' => 'YES',
245
+ );
246
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
247
+ wp_safe_redirect( $redirect_url );
248
+ }
249
+
250
+
251
+ /**
252
+ * Delete email templates.
253
+ */
254
+ function delete_single_template() {
255
+
256
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
257
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
258
+
259
+ if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
260
+
261
+ $this->wpdb->delete(
262
+ $this->cart_abandonment_template_table_name,
263
+ array( 'id' => $id ),
264
+ '%d'
265
+ );
266
+ $param = array(
267
+ 'page' => WCF_CA_PAGE_NAME,
268
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
269
+ 'wcf_ca_template_deleted' => 'YES',
270
+ );
271
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
272
+ wp_safe_redirect( $redirect_url );
273
+
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Delete email templates.
279
+ */
280
+ function clone_email_template() {
281
+
282
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
283
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
284
+
285
+ if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
286
+
287
+ $email_template = $this->get_template_by_id( $id );
288
+
289
+ $this->wpdb->insert(
290
+ $this->cart_abandonment_template_table_name,
291
+ array(
292
+ 'template_name' => sanitize_text_field( $email_template->template_name ),
293
+ 'email_subject' => sanitize_text_field( $email_template->email_subject ),
294
+ 'email_body' => $email_template->email_body,
295
+ 'frequency' => intval( sanitize_text_field( $email_template->frequency ) ),
296
+ 'frequency_unit' => sanitize_text_field( $email_template->frequency_unit ),
297
+
298
+ ),
299
+ array( '%s', '%s', '%s', '%d', '%s' )
300
+ );
301
+
302
+ $email_template_id = $this->wpdb->insert_id;
303
+ $meta_data = array(
304
+ 'override_global_coupon' => false,
305
+ 'discount_type' => 'percent',
306
+ 'coupon_amount' => 10,
307
+ 'coupon_expiry_date' => '',
308
+ 'coupon_expiry_unit' => 'hours',
309
+ );
310
+
311
+ foreach ( $meta_data as $mera_key => $meta_value ) {
312
+ $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
313
+ }
314
+
315
+ $param = array(
316
+ 'page' => WCF_CA_PAGE_NAME,
317
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
318
+ 'wcf_ca_template_cloned' => 'YES',
319
+ );
320
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
321
+ wp_safe_redirect( $redirect_url );
322
+
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Get email template by id.
328
+ *
329
+ * @param int $email_tmpl_id template id.
330
+ */
331
+ function get_email_template_by_id( $email_tmpl_id ) {
332
+
333
+ $query = 'SELECT * FROM ' . $this->cart_abandonment_template_table_name . ' WHERE id = %d ';
334
+ return $this->wpdb->get_row($this->wpdb->prepare($query, $email_tmpl_id)); // phpcs:ignore
335
+
336
+ }
337
+
338
+ /**
339
+ * Render email template add/edit form.
340
+ *
341
+ * @param string $sub_action sub_action.
342
+ */
343
+ function render_email_template_form( $sub_action = WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES ) {
344
+
345
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
346
+
347
+ if ( $id ) {
348
+ $results = $this->get_email_template_by_id( $id );
349
+ }
350
+
351
+ ?>
352
+
353
+ <div id="content">
354
+
355
+ <?php
356
+ $param = array(
357
+ 'page' => WCF_CA_PAGE_NAME,
358
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
359
+ 'sub_action' => WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES,
360
+ );
361
+ $save_template_url = esc_url( add_query_arg( $param, admin_url( '/admin.php' ) ) );
362
+ ?>
363
+
364
+ <form method="post" action="<?php echo $save_template_url; ?>" id="wcf_settings">
365
+ <input type="hidden" name="sub_action" value="<?php echo $sub_action; ?>"/>
366
+ <?php
367
+ $id_by = '';
368
+ if ( isset( $id ) ) {
369
+ $id_by = $id;
370
+ }
371
+ ?>
372
+ <input type="hidden" name="id" value="<?php echo $id_by; ?>"/>
373
+ <?php
374
+
375
+ $button_sub_action = 'save';
376
+ $display_message = 'Add New Email Template:';
377
+
378
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
379
+ $button_sub_action = 'update';
380
+ $display_message = 'Edit Email Template:';
381
+ }
382
+ print'<input type="hidden" name="wcf_settings_frm" value="' . $button_sub_action . '">';
383
+ ?>
384
+ <div id="poststuff">
385
+ <div> <!-- <div class="postbox" > -->
386
+ <h3><?php _e($display_message, 'cartflows-ca'); // phpcs:ignore ?></h3>
387
+ <hr/>
388
+ <div>
389
+ <table class="form-table" id="addedit_template">
390
+ <tr>
391
+ <th>
392
+ <label for="wcf_email_subject"><b><?php _e( 'Activate Template now?', 'cartflows-ca' ); ?></b></label>
393
+ </th>
394
+ <td>
395
+ <?php
396
+ $is_activated = '';
397
+ $active_status = 0;
398
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->is_activated ) ) {
399
+ $active_status = stripslashes( $results->is_activated );
400
+ $is_activated = $active_status ? 'on' : 'off';
401
+
402
+ }
403
+ print'<button type="button" class="wcf-ca-switch wcf-toggle-template-status" wcf-template-id="1" wcf-ca-template-switch="' . $is_activated . '"> ' . $is_activated . ' </button>';
404
+ print'<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . $active_status . '" />';
405
+ ?>
406
+
407
+ </td>
408
+ </tr>
409
+
410
+ <tr>
411
+ <th>
412
+ <label for="wcf_template_name"><b><?php _e( 'Template Name:', 'cartflows-ca' ); ?></b></label>
413
+ </th>
414
+ <td>
415
+ <?php
416
+ $template_name = '';
417
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->template_name ) ) {
418
+ $template_name = $results->template_name;
419
+ }
420
+ print'<input type="text" name="wcf_template_name" id="wcf_template_name" class="wcf-ca-trigger-input" value="' . $template_name . '">';
421
+ ?>
422
+ </td>
423
+ </tr>
424
+
425
+ <tr>
426
+ <th>
427
+ <label for="wcf_email_subject"><b><?php _e( 'Email Subject:', 'cartflows-ca' ); ?></b></label>
428
+ </th>
429
+ <td>
430
+ <?php
431
+ $subject_edit = '';
432
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_subject ) ) {
433
+ $subject_edit = stripslashes( $results->email_subject );
434
+ }
435
+ print'<input type="text" name="wcf_email_subject" id="wcf_email_subject" class="wcf-ca-trigger-input" value="' . $subject_edit . '">';
436
+ ?>
437
+ </td>
438
+ </tr>
439
+
440
+ <tr>
441
+ <th>
442
+ <label for="wcf_email_body"><b><?php _e( 'Email Body:', 'cartflows-ca' ); ?></b></label>
443
+ </th>
444
+ <td>
445
+ <?php
446
+ $initial_data = '';
447
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_body ) ) {
448
+ $initial_data = stripslashes( $results->email_body );
449
+ }
450
+
451
+ wp_editor(
452
+ $initial_data,
453
+ 'wcf_email_body',
454
+ array(
455
+ 'media_buttons' => true,
456
+ 'textarea_rows' => 15,
457
+ 'tabindex' => 4,
458
+ 'tinymce' => array(
459
+ 'theme_advanced_buttons1' => 'bold,italic,underline,|,bullist,numlist,blockquote,|,link,unlink,|,spellchecker,fullscreen,|,formatselect,styleselect',
460
+ ),
461
+ )
462
+ );
463
+
464
+ ?>
465
+ <?php echo stripslashes( get_option( 'wcf_email_body' ) ); ?>
466
+ </td>
467
+ </tr>
468
+
469
+ <tr>
470
+ <th>
471
+ <label for="wcf_override_global_coupon"><b><?php _e( 'Create Coupon', 'cartflows-ca' ); ?></b></label>
472
+ </th>
473
+ <td>
474
+ <?php
475
+
476
+ $wcf_override_global_coupon = '';
477
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
478
+ $wcf_override_global_coupon = $this->get_email_template_meta_by_key( $results->id, 'override_global_coupon' );
479
+ if ( isset( $wcf_override_global_coupon->meta_value ) ) {
480
+ $wcf_override_global_coupon = $wcf_override_global_coupon->meta_value ? 'checked' : '';
481
+ }
482
+ }
483
+
484
+ print'<input ' . $wcf_override_global_coupon . ' id="wcf_override_global_coupon" name="wcf_override_global_coupon" type="checkbox" value="" /><label for="wcf_override_global_coupon"> Allows you to send new coupon only for this template. </label>';
485
+ ?>
486
+ </td>
487
+ </tr>
488
+
489
+ <tr>
490
+ <th>
491
+ <label for="wcf_email_discount_type"><b><?php _e( 'Discount Type', 'cartflows-ca' ); ?></b></label>
492
+ </th>
493
+ <td>
494
+ <?php
495
+
496
+ $wcf_email_discount_type = 'percent';
497
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
498
+ $wcf_email_discount_type = $this->get_email_template_meta_by_key( $results->id, 'discount_type' );
499
+ if ( isset( $wcf_email_discount_type->meta_value ) ) {
500
+ $wcf_email_discount_type = $wcf_email_discount_type->meta_value;
501
+ }
502
+ }
503
+
504
+ $dropdown_options = array(
505
+ 'percent' => 'Percentage discount',
506
+ 'fixed_cart' => 'Fixed cart discount',
507
+ );
508
+
509
+ echo '<select id="wcf_email_discount_type" name="wcf_email_discount_type">';
510
+ foreach ( $dropdown_options as $key => $value ) {
511
+ $is_selected = $key === $wcf_email_discount_type ? 'selected' : '';
512
+ echo '<option ' . $is_selected . ' value=' . $key . '>' . $value . '</option>';
513
+
514
+ }
515
+ echo '</select>';
516
+
517
+ ?>
518
+ </td>
519
+ </tr>
520
+
521
+ <tr>
522
+ <th>
523
+ <label for="wcf_email_discount_amount"><b><?php _e( 'Coupon Amount', 'cartflows-ca' ); ?></b></label>
524
+ </th>
525
+ <td>
526
+ <?php
527
+ $wcf_email_discount_amount = 10;
528
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
529
+ $wcf_email_discount_amount = $this->get_email_template_meta_by_key( $results->id, 'coupon_amount' );
530
+ if ( isset( $wcf_email_discount_amount->meta_value ) ) {
531
+ $wcf_email_discount_amount = $wcf_email_discount_amount->meta_value;
532
+ }
533
+ }
534
+ print'<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="number" id="wcf_email_discount_amount" name="wcf_email_discount_amount" value="' . $wcf_email_discount_amount . '">';
535
+ ?>
536
+ </td>
537
+ </tr>
538
+
539
+ <tr>
540
+ <th>
541
+ <label for="wcf_email_coupon_expiry_date"><b><?php _e( 'Coupon expiry date', 'cartflows-ca' ); ?></b></label>
542
+ </th>
543
+ <td>
544
+ <?php
545
+ $wcf_email_coupon_expiry_date = 0;
546
+ $coupon_expiry_unit = 'hours';
547
+
548
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
549
+ $wcf_email_coupon_expiry_date = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_date' );
550
+ $wcf_email_coupon_expiry_unit = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_unit' );
551
+
552
+ if ( isset( $wcf_email_coupon_expiry_date->meta_value ) ) {
553
+ $wcf_email_coupon_expiry_date = $wcf_email_coupon_expiry_date->meta_value;
554
+ }
555
+ if ( isset( $wcf_email_coupon_expiry_unit->meta_value ) ) {
556
+ $coupon_expiry_unit = $wcf_email_coupon_expiry_unit->meta_value;
557
+ }
558
+ }
559
+ print'<input type="number" class="wcf-ca-trigger-input wcf-ca-coupon-inputs" id="wcf_email_coupon_expiry_date" name="wcf_email_coupon_expiry_date" value="' . intval( $wcf_email_coupon_expiry_date ) . '" autocomplete="off" />';
560
+ $items = array(
561
+ 'hours' => 'Hour(s)',
562
+ 'days' => 'Day(s)',
563
+ );
564
+ echo "<select id='wcf_coupon_expiry_unit' name='wcf_coupon_expiry_unit'>";
565
+ foreach ( $items as $key => $item ) {
566
+ $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
567
+ echo "<option value='$key' $selected>$item</option>";
568
+ }
569
+ echo '</select>';
570
+
571
+ echo " <span class='description'> Enter zero (0) to restrict coupon from expiring </span>"
572
+ ?>
573
+ </td>
574
+ </tr>
575
+
576
+ <tr>
577
+ <th>
578
+ <label for="wcf_email_subject"><b><?php _e( 'Send This Email', 'cartflows-ca' ); ?></b></label>
579
+ </th>
580
+ <td>
581
+ <?php
582
+ $frequency_edit = '';
583
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency ) ) {
584
+ $frequency_edit = $results->frequency;
585
+ }
586
+ print'<input style="width:15%" type="number" name="wcf_email_frequency" id="wcf_email_frequency" class="wcf-ca-trigger-input" value="' . $frequency_edit . '">';
587
+ ?>
588
+
589
+ <select name="wcf_email_frequency_unit" id="wcf_email_frequency_unit">
590
+ <?php
591
+ $frequency_unit = '';
592
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency_unit ) ) {
593
+ $frequency_unit = $results->frequency_unit;
594
+ }
595
+ $days_or_hours = array(
596
+ 'MINUTE' => 'Minute(s)',
597
+ 'HOUR' => 'Hour(s)',
598
+ 'DAY' => 'Day(s)',
599
+ );
600
+ foreach ( $days_or_hours as $k => $v ) {
601
+ printf(
602
+ "<option %s value='%s'>%s</option>\n",
603
+ selected( $k, $frequency_unit, false ),
604
+ esc_attr( $k ),
605
+ $v
606
+ );
607
+ }
608
+ ?>
609
+ </select>
610
+ <span class="description">
611
+ <?php _e( 'after cart is abandoned.', 'cartflows-ca' ); ?>
612
+ </span>
613
+
614
+
615
+ </td>
616
+ </tr>
617
+
618
+ <tr>
619
+ <?php $current_user = wp_get_current_user(); ?>
620
+ <th>
621
+ <label for="wcf_email_preview"><b><?php _e( 'Send Test Email To:', 'cartflows-ca' ); ?></b></label>
622
+ </th>
623
+ <td>
624
+ <input class="wcf-ca-trigger-input" type="text" id="wcf_send_test_email" name="send_test_email" value="<?php echo $current_user->user_email; ?>" class="wcf-ca-trigger-input">
625
+ <input class="button" type="button" value="Send a test email" id="wcf_preview_email"/> <br/>
626
+
627
+ <label id="mail_response_msg"> </label>
628
+ </td>
629
+ </tr>
630
+
631
+ </table>
632
+ </div>
633
+ </div>
634
+ </div>
635
+ <?php wp_nonce_field( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' ); ?>
636
+ <p class="submit">
637
+ <?php
638
+ $button_value = 'Save Changes';
639
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
640
+ $button_value = 'Update Changes';
641
+ }
642
+ ?>
643
+ <input type="submit" name="Submit" class="button-primary" value="<?php echo $button_value; ?>"/>
644
+ </p>
645
+ </form>
646
+ </div>
647
+ <?php
648
+
649
+ }
650
+
651
+
652
+ /**
653
+ * Sanitize email post data.
654
+ *
655
+ * @return array
656
+ */
657
+ function sanitize_email_post_data() {
658
+
659
+ $input_post_values = array(
660
+ 'wcf_email_subject' => array(
661
+ 'default' => '',
662
+ 'sanitize' => FILTER_SANITIZE_STRING,
663
+ ),
664
+ 'wcf_email_body' => array(
665
+ 'default' => '',
666
+ 'sanitize' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
667
+ ),
668
+ 'wcf_template_name' => array(
669
+ 'default' => '',
670
+ 'sanitize' => FILTER_SANITIZE_STRING,
671
+ ),
672
+ 'wcf_email_frequency' => array(
673
+ 'default' => 30,
674
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
675
+ ),
676
+ 'wcf_email_frequency_unit' => array(
677
+ 'default' => 'MINUTE',
678
+ 'sanitize' => FILTER_SANITIZE_STRING,
679
+ ),
680
+ 'wcf_activate_email_template' => array(
681
+ 'default' => 0,
682
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
683
+ ),
684
+
685
+ 'wcf_email_discount_type' => array(
686
+ 'default' => 'percent',
687
+ 'sanitize' => FILTER_SANITIZE_STRING,
688
+ ),
689
+ 'wcf_email_discount_amount' => array(
690
+ 'default' => 10,
691
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
692
+ ),
693
+ 'wcf_email_coupon_expiry_date' => array(
694
+ 'default' => '',
695
+ 'sanitize' => FILTER_SANITIZE_STRING,
696
+ ),
697
+ 'wcf_coupon_expiry_unit' => array(
698
+ 'default' => 'hours',
699
+ 'sanitize' => FILTER_SANITIZE_STRING,
700
+ ),
701
+ 'id' => array(
702
+ 'default' => null,
703
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
704
+ ),
705
+ );
706
+
707
+ $sanitized_post = array();
708
+ foreach ( $input_post_values as $key => $input_post_value ) {
709
+
710
+ if ( isset( $_POST[ $key ] ) ) {
711
+ $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
712
+ } else {
713
+ $sanitized_post[ $key ] = $input_post_value['default'];
714
+ }
715
+ }
716
+
717
+ $sanitized_post['wcf_override_global_coupon'] = isset( $_POST['wcf_override_global_coupon'] ) ? true : false;
718
+ $sanitized_post['wcf_email_body'] = html_entity_decode( $sanitized_post['wcf_email_body'] );
719
+
720
+ return $sanitized_post;
721
+
722
+ }
723
+
724
+
725
+ /**
726
+ * Add email template callback ajax.
727
+ */
728
+ function add_email_template() {
729
+
730
+ $sanitized_post = $this->sanitize_email_post_data();
731
+ $this->wpdb->insert(
732
+ $this->cart_abandonment_template_table_name,
733
+ array(
734
+ 'template_name' => $sanitized_post['wcf_template_name'],
735
+ 'email_subject' => $sanitized_post['wcf_email_subject'],
736
+ 'email_body' => wpautop( $sanitized_post['wcf_email_body'] ),
737
+ 'frequency' => $sanitized_post['wcf_email_frequency'],
738
+ 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
739
+ 'is_activated' => $sanitized_post['wcf_activate_email_template'],
740
+ ),
741
+ array( '%s', '%s', '%s', '%d', '%s', '%d' )
742
+ );
743
+
744
+ $email_template_id = $this->wpdb->insert_id;
745
+ $meta_data = array(
746
+ 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
747
+ 'discount_type' => $sanitized_post['wcf_email_discount_type'],
748
+ 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
749
+ 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
750
+ 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
751
+ );
752
+
753
+ foreach ( $meta_data as $mera_key => $meta_value ) {
754
+ $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
755
+ }
756
+
757
+ $param = array(
758
+ 'page' => WCF_CA_PAGE_NAME,
759
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
760
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
761
+ 'id' => $email_template_id,
762
+ 'wcf_ca_template_created' => 'YES',
763
+ );
764
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
765
+ wp_safe_redirect( $redirect_url );
766
+
767
+ }
768
+
769
+ /**
770
+ * Edit email template callback ajax.
771
+ */
772
+ function edit_email_template() {
773
+ $sanitized_post = $this->sanitize_email_post_data();
774
+ $email_template_id = $sanitized_post['id'];
775
+
776
+ $this->wpdb->update(
777
+ $this->cart_abandonment_template_table_name,
778
+ array(
779
+ 'template_name' => $sanitized_post['wcf_template_name'],
780
+ 'email_subject' => $sanitized_post['wcf_email_subject'],
781
+ 'email_body' => wpautop( $sanitized_post['wcf_email_body'] ),
782
+ 'frequency' => $sanitized_post['wcf_email_frequency'],
783
+ 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
784
+ 'is_activated' => $sanitized_post['wcf_activate_email_template'],
785
+ ),
786
+ array( 'id' => $email_template_id ),
787
+ array( '%s', '%s', '%s', '%d', '%s', '%d' ),
788
+ array( '%d' )
789
+ );
790
+
791
+ $meta_data = array(
792
+ 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
793
+ 'discount_type' => $sanitized_post['wcf_email_discount_type'],
794
+ 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
795
+ 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
796
+ 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
797
+ );
798
+ foreach ( $meta_data as $mera_key => $meta_value ) {
799
+ $this->update_email_template_meta( $email_template_id, $mera_key, $meta_value );
800
+ }
801
+
802
+ $param = array(
803
+ 'page' => WCF_CA_PAGE_NAME,
804
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
805
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
806
+ 'id' => $email_template_id,
807
+ 'wcf_ca_template_updated' => 'YES',
808
+ );
809
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
810
+
811
+ wp_safe_redirect( $redirect_url );
812
+
813
+ }
814
+
815
+ /**
816
+ * Restore default email templates.
817
+ */
818
+ public function restore_email_templates() {
819
+
820
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
821
+
822
+ if ( $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
823
+
824
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
825
+ $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
826
+ $db->template_table_seeder( true );
827
+
828
+ $param = array(
829
+ 'page' => WCF_CA_PAGE_NAME,
830
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
831
+ 'wcf_ca_template_restored' => 'YES',
832
+ );
833
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
834
+ wp_safe_redirect( $redirect_url );
835
+ }
836
+
837
+ }
838
+
839
+ /**
840
+ * Update the meta values.
841
+ *
842
+ * @param integer $email_template_id email template id.
843
+ * @param string $meta_key meta key.
844
+ * @param string $meta_value meta value.
845
+ */
846
+ function update_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
847
+
848
+ $template_meta = $this->get_email_template_meta_by_key( $email_template_id, $meta_key );
849
+
850
+ if ( $template_meta ) {
851
+ $this->wpdb->update(
852
+ $this->email_templates_meta_table,
853
+ array(
854
+ 'meta_value' => sanitize_text_field( $meta_value ),
855
+ ),
856
+ array(
857
+ 'email_template_id' => $email_template_id,
858
+ 'meta_key' => sanitize_text_field( $meta_key ),
859
+ )
860
+ );
861
+ } else {
862
+ $this->add_email_template_meta( $email_template_id, $meta_key, $meta_value );
863
+ }
864
+
865
+ }
866
+
867
+
868
+ /**
869
+ * Add the meta values.
870
+ *
871
+ * @param integer $email_template_id email template id.
872
+ * @param string $meta_key meta key.
873
+ * @param string $meta_value meta value.
874
+ */
875
+ function add_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
876
+ $this->wpdb->insert(
877
+ $this->email_templates_meta_table,
878
+ array(
879
+ 'email_template_id' => $email_template_id,
880
+ 'meta_key' => sanitize_text_field( $meta_key ),
881
+ 'meta_value' => sanitize_text_field( $meta_value ),
882
+ )
883
+ );
884
+ }
885
+
886
+ /**
887
+ * Get the meta values.
888
+ *
889
+ * @param integer $email_template_id email template id.
890
+ * @param string $meta_key meta key.
891
+ */
892
+ function get_email_template_meta_by_key( $email_template_id, $meta_key ) {
893
+ return $this->wpdb->get_row(
894
+ $this->wpdb->prepare( "select * from $this->email_templates_meta_table where email_template_id = %d AND meta_key = %s", $email_template_id, $meta_key ) // phpcs:ignore
895
+ );
896
+ }
897
+
898
+ /**
899
+ * Render email template grid.
900
+ */
901
+ function show_email_template_data_table() {
902
+ $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
903
+ $wcf_template_list->prepare_items();
904
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
905
+ ?>
906
+ <div class="wrap">
907
+ <form id="wcf-cart-abandonment-template-table" method="GET">
908
+ <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
909
+ <input type="hidden" name="action" value="<?php echo esc_html( WCF_ACTION_EMAIL_TEMPLATES ); ?>"/>
910
+ <input type="hidden" name="sub_action" value="<?php echo esc_html( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES ); ?>"/>
911
+ <?php $wcf_template_list->display(); ?>
912
+ </form>
913
+ </div>
914
+ <?php
915
+ }
916
+
917
+ /**
918
+ * Render 'Add Email Template button'.
919
+ */
920
+ public function show_add_new_template_button() {
921
+ $param = array(
922
+ 'page' => WCF_CA_PAGE_NAME,
923
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
924
+ 'sub_action' => WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES,
925
+ );
926
+
927
+ $add_new_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
928
+
929
+ $param['sub_action'] = WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES;
930
+ $restore_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
931
+
932
+ ?>
933
+ <div class="wcf-ca-report-btn">
934
+ <div class="wcf-ca-left-report-field-group">
935
+ <a style="cursor: pointer" href="<?php echo $add_new_template_url; ?>" class="button-secondary"><?php _e( 'Create New Template', 'cartflows-ca' ); ?></a>
936
+ </div>
937
+ <div class="wcf-ca-right-report-field-group">
938
+ <a onclick="return confirm('Are you sure to restore email templates?');" style="cursor: pointer" href="<?php echo $restore_template_url; ?>" class="button-secondary"><?php _e( ' Restore Default Templates', 'cartflows-ca' ); ?></a>
939
+ </div>
940
+ </div>
941
+ <?php
942
+ }
943
+
944
+ /**
945
+ * Get all active templates.
946
+ *
947
+ * @return array|object|null
948
+ */
949
+ public function fetch_all_active_templates() {
950
+ $result = $this->wpdb->get_results(
951
+ $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE is_activated = %s', true) // phpcs:ignore
952
+ );
953
+ return $result;
954
+ }
955
+
956
+ /**
957
+ * Get specific template by id.
958
+ *
959
+ * @param integer $tmpl_id template id.
960
+ * @return array|object|void|null
961
+ */
962
+ public function get_template_by_id( $tmpl_id ) {
963
+ $result = $this->wpdb->get_row(
964
+ $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE id = %s', $tmpl_id) // phpcs:ignore
965
+ );
966
+ return $result;
967
+ }
968
+
969
+ /**
970
+ * Get the email history.
971
+ *
972
+ * @param integer $email_history_id email history id.
973
+ * @return array|object|void|null
974
+ */
975
+ public function get_email_history_by_id( $email_history_id ) {
976
+ $result = $this->wpdb->get_row(
977
+ $this->wpdb->prepare('SELECT * FROM `' . $this->email_history_table . '` WHERE id = %s', $email_history_id) // phpcs:ignore
978
+ );
979
+ return $result;
980
+ }
981
+ }
982
+
983
+ Cartflows_Ca_Email_Templates::get_instance();
modules/cart-abandonment/class-cartflows-ca-module-loader.php CHANGED
@@ -1,62 +1,62 @@
1
- <?php
2
- /**
3
- * Cart Abandonment DB
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- /**
9
- * Cart Abandonment DB class.
10
- */
11
- class Cartflows_Ca_Module_Loader {
12
-
13
-
14
-
15
- /**
16
- * Member Variable
17
- *
18
- * @var object instance
19
- */
20
- private static $instance;
21
-
22
- /**
23
- * Initiator
24
- */
25
- public static function get_instance() {
26
- if ( ! isset( self::$instance ) ) {
27
- self::$instance = new self;
28
- }
29
- return self::$instance;
30
- }
31
-
32
- /**
33
- * Constructor
34
- */
35
- public function __construct() {
36
-
37
- $this->load_module_files();
38
- }
39
-
40
-
41
- /**
42
- * Load required files for module.
43
- */
44
- function load_module_files() {
45
-
46
- /* Cart abandonment templates class */
47
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates.php';
48
-
49
- /* Cart abandonment templates table */
50
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates-table.php';
51
-
52
- /* Cart abandonment tracking */
53
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php';
54
-
55
- /* Cart abandonment tracking table */
56
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php';
57
-
58
- }
59
-
60
- }
61
-
62
- Cartflows_Ca_Module_Loader::get_instance();
1
+ <?php
2
+ /**
3
+ * Cart Abandonment DB
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ /**
9
+ * Cart Abandonment DB class.
10
+ */
11
+ class Cartflows_Ca_Module_Loader {
12
+
13
+
14
+
15
+ /**
16
+ * Member Variable
17
+ *
18
+ * @var object instance
19
+ */
20
+ private static $instance;
21
+
22
+ /**
23
+ * Initiator
24
+ */
25
+ public static function get_instance() {
26
+ if ( ! isset( self::$instance ) ) {
27
+ self::$instance = new self;
28
+ }
29
+ return self::$instance;
30
+ }
31
+
32
+ /**
33
+ * Constructor
34
+ */
35
+ public function __construct() {
36
+
37
+ $this->load_module_files();
38
+ }
39
+
40
+
41
+ /**
42
+ * Load required files for module.
43
+ */
44
+ function load_module_files() {
45
+
46
+ /* Cart abandonment templates class */
47
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates.php';
48
+
49
+ /* Cart abandonment templates table */
50
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates-table.php';
51
+
52
+ /* Cart abandonment tracking */
53
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php';
54
+
55
+ /* Cart abandonment tracking table */
56
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php';
57
+
58
+ }
59
+
60
+ }
61
+
62
+ Cartflows_Ca_Module_Loader::get_instance();
modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php CHANGED
@@ -1,222 +1,229 @@
1
- <?php
2
- /**
3
- * Cartflows view for single cart abandonment report details.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- ?>
9
-
10
-
11
- <div class="wcf-ca-report-btn">
12
- <div class="wcf-ca-left-report-field-group">
13
- <?php
14
- if ( wp_get_referer() ) {
15
- $back_link = wp_get_referer();
16
- } else {
17
- $back_link = add_query_arg(
18
- array(
19
- 'page' => WCF_CA_PAGE_NAME,
20
- 'action' => WCF_ACTION_REPORTS,
21
- ),
22
- admin_url( '/admin.php' )
23
- );
24
- }
25
- ?>
26
- <a href="<?php echo $back_link; ?>" class="button button-secondary back-button"><span
27
- class="dashicons dashicons-arrow-left"></span> Back to Reports </a>
28
- </div>
29
- </div>
30
-
31
- <!-- First panel Start -->
32
- <div class="wcf-ca-panel">
33
- <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-right">
34
- <div class="wcf-ca-email-data">
35
-
36
- <div class="wcf-ca-report-btn" style="padding: 0px">
37
- <div class="wcf-ca-left-report-field-group">
38
- <h2> <?php _e( 'Email Details:', 'cartflows-ca' ); ?> </h2>
39
- </div>
40
- <div class="wcf-ca-right-report-field-group">
41
-
42
- <?php if ( WCF_CART_ABANDONED_ORDER === $details->order_status && ! $details->unsubscribed ) : ?>
43
- <?php add_thickbox(); ?>
44
- <div id="wcf-ca-confirm-email-reschedule" style="display:none;">
45
- <div style="text-align:center;">
46
- <p>
47
- All new activated emails will be reschedule for this abandoned order. <br/>New emails will
48
- be sent to user according to schedule time.
49
- </p>
50
- <p>
51
- <strong>Are your sure?</strong>
52
- </p>
53
- <p>
54
- <button onclick="window.location.search += '&sub_action=<?php echo WCF_SUB_ACTION_REPORTS_RESCHEDULE; ?>';"
55
- class="button button-secondary"> Reschedule
56
- </button>
57
- <button type="button"
58
- onclick='document.getElementById("TB_closeWindowButton").click()'
59
- class="button button-secondary"> Close
60
- </button>
61
- </p>
62
- </div>
63
- </div>
64
- <a name="Do you really want to reschedule emails?" href="#TB_inline?&width=500&height=200&inlineId=wcf-ca-confirm-email-reschedule" class="thickbox button button-secondary"> Reschedule Emails </a>
65
- <?php endif; ?>
66
- </div>
67
- </div>
68
-
69
- <?php if ( empty( $scheduled_emails ) ) : ?>
70
- <div style="text-align: center;"><strong> <?php _e( ' No Email Scheduled.', 'cartflows-ca' ); ?></strong>
71
- </div>
72
- <?php else : ?>
73
- <table cellpadding="15" cellspacing="0" class="wcf-table wcf-table-striped fixed posts">
74
- <thead>
75
- <tr>
76
-
77
- <th class="wcf-ca-report-table-row"> Scheduled Template</th>
78
- <th class="wcf-ca-report-table-row"> Email Subject</th>
79
- <th class="wcf-ca-report-table-row"> Email Coupon</th>
80
- <th class="wcf-ca-report-table-row"> Email Sent</th>
81
- <th class="wcf-ca-report-table-row"><span class="dashicons dashicons-clock"></span> Scheduled At
82
- </th>
83
-
84
- </tr>
85
- </thead>
86
-
87
- <tbody>
88
- <?php foreach ( $scheduled_emails as $scheduled_email ) : ?>
89
-
90
- <?php
91
- $email_tmpl_url = wp_nonce_url(
92
- add_query_arg(
93
- array(
94
- 'page' => WCF_CA_PAGE_NAME,
95
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
96
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
97
- 'id' => $scheduled_email->template_id,
98
- ),
99
- admin_url( '/admin.php' )
100
- ),
101
- WCF_EMAIL_TEMPLATES_NONCE
102
- );
103
-
104
- if ( $details->unsubscribed && ! $scheduled_email->email_sent ) {
105
- $icon = '<span class="dashicons dashicons-dismiss" title="" ></span>';
106
- $title = __( 'The email has unsubscribed and won\'t be sent further.', 'cartflows-ca' );
107
- } elseif ( $scheduled_email->email_sent ) {
108
- $icon = '<span class="dashicons dashicons-yes wp-ui-text-highlight" ></span>';
109
- $title = __( 'The email has been sent.', 'cartflows-ca' );
110
- } else {
111
- $icon = '<span class="dashicons dashicons-no" ></span>';
112
- $title = __( 'Email is in the queue and will be sent at the scheduled time.', 'cartflows-ca' );
113
- }
114
-
115
- $scheduled_time = date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $scheduled_email->scheduled_time ) );
116
- ?>
117
-
118
- <tr class="wcf-ca-report-table-row">
119
- <td class="wcf-ca-report-table-row"><a
120
- href="<?php echo $email_tmpl_url; ?>"
121
- class="wp-ui-text-highlight"> <?php echo( $scheduled_email->template_name ); ?> </a>
122
- </td>
123
- <td class="wcf-ca-report-table-row"> <?php echo( $scheduled_email->email_subject ); ?> </td>
124
- <td class="wcf-ca-report-table-row"> <?php echo( $scheduled_email->coupon_code ? $scheduled_email->coupon_code : '--' ); ?> </td>
125
- <td class="wcf-ca-report-table-row wcf-ca-icon-row"> <?php echo $icon; ?>
126
- <span class="wcf-ca-tooltip-text"><?php echo $title; ?></span>
127
- </td>
128
- <td class="wcf-ca-report-table-row"> <?php echo( $scheduled_time ); ?> </td>
129
- </tr>
130
- <?php endforeach; ?>
131
- </tbody>
132
- </table>
133
- <?php endif; ?>
134
-
135
- </div>
136
- </div>
137
-
138
- <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-left">
139
- <div class="wcf-ca-user-detail ">
140
-
141
- <div class="wcf-ca-report-btn" style="padding: 0px">
142
- <div class="wcf-ca-left-report-field-group">
143
- <h2> <?php _e( 'User Address Details:', 'cartflows-ca' ); ?> </h2>
144
- </div>
145
- <div class="wcf-ca-right-report-field-group">
146
- <?php if ( $details->unsubscribed ) : ?>
147
- <span class="wcf-ca-tag"> <?php _e( 'Unsubscribed', 'cartflows-ca' ); ?> </span>
148
- <?php endif; ?>
149
-
150
- <span class="wcf-ca-tag"> <?php echo ucfirst( $details->order_status ); ?> </span>
151
- </div>
152
- </div>
153
-
154
- <div class="wcf-ca-user-address wcf-pull-left">
155
- <h3> <?php _e( 'Billing Address', 'cartflows-ca' ); ?> </h3>
156
- <p><strong> <?php _e( 'Name', 'cartflows-ca' ); ?> </strong>
157
- <?php echo $user_details->wcf_first_name . ' ' . $user_details->wcf_last_name; ?> </p>
158
- <p>
159
- <strong> <?php _e( 'Email address', 'cartflows-ca' ); ?> </strong>
160
- <a href="mailto:<?php echo( $details->email ); ?>"><?php echo( $details->email ); ?></a>
161
- </p>
162
-
163
- <p>
164
- <strong> <?php _e( 'Phone', 'cartflows-ca' ); ?> </strong>
165
- <a href="tel:<?php echo( $user_details->wcf_phone_number ); ?>"><?php echo( $user_details->wcf_phone_number ); ?></a>
166
- </p>
167
-
168
- <p>
169
- <strong> <?php _e( 'Address 1:', 'cartflows-ca' ); ?> </strong> <?php echo $user_details->wcf_billing_address_1; ?>
170
- </p>
171
- <p>
172
- <strong> <?php _e( 'Address 2:', 'cartflows-ca' ); ?> </strong> <?php echo $user_details->wcf_billing_address_2; ?>
173
- </p>
174
- <p>
175
- <strong> <?php _e( 'Country, City:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_location ); ?>
176
- </p>
177
- <p>
178
- <strong> <?php _e( 'State:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_billing_state ); ?>
179
- </p>
180
-
181
- <p>
182
- <strong> <?php _e( 'Postcode:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_billing_postcode ); ?>
183
- </p>
184
- </div>
185
-
186
- <div class="wcf-ca-user-address wcf-pull-left">
187
- <h3> <?php _e( 'Shipping Address', 'cartflows-ca' ); ?> </h3>
188
- <p>
189
- <strong> <?php _e( 'Address 1:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_address_1 ); ?>
190
- </p>
191
- <p>
192
- <strong> <?php _e( 'Address 2:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_address_2 ); ?>
193
- </p>
194
- <p>
195
- <strong> <?php _e( 'City:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_city ); ?>
196
- </p>
197
- <p>
198
- <strong> <?php _e( 'State:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_state ); ?>
199
- </p>
200
- <p>
201
- <strong> <?php _e( 'Country:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_country ); ?>
202
- </p>
203
- <p>
204
- <strong> <?php _e( 'Postcode:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_postcode ); ?>
205
- </p>
206
- </div>
207
-
208
- </div>
209
- </div>
210
- </div>
211
- <!-- First panel closed -->
212
-
213
- <!-- Second panel Start -->
214
- <div class="wcf-ca-panel">
215
- <div class="wcf-ca-column wcf-ca-column-one">
216
- <div class="wcf-ca-user-order">
217
- <h2> <?php _e( 'User Order Details:', 'cartflows-ca' ); ?> </h2>
218
- <?php echo( $this->get_admin_product_block( $details->cart_contents, $details->cart_total ) ); ?>
219
- </div>
220
- </div>
221
- </div>
222
- <!-- Second panel closed -->
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Cartflows view for single cart abandonment report details.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ ?>
9
+
10
+
11
+ <div class="wcf-ca-report-btn">
12
+ <div class="wcf-ca-left-report-field-group">
13
+ <?php
14
+ if ( wp_get_referer() ) {
15
+ $back_link = wp_get_referer();
16
+ } else {
17
+ $back_link = add_query_arg(
18
+ array(
19
+ 'page' => WCF_CA_PAGE_NAME,
20
+ 'action' => WCF_ACTION_REPORTS,
21
+ ),
22
+ admin_url( '/admin.php' )
23
+ );
24
+ }
25
+ ?>
26
+ <a href="<?php echo $back_link; ?>" class="button button-secondary back-button"><span
27
+ class="dashicons dashicons-arrow-left"></span> Back to Reports </a>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- First panel Start -->
32
+ <div class="wcf-ca-panel">
33
+ <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-right">
34
+ <div class="wcf-ca-email-data">
35
+
36
+ <div class="wcf-ca-report-btn" style="padding: 0px">
37
+ <div class="wcf-ca-left-report-field-group">
38
+ <h2> <?php _e( 'Email Details:', 'cartflows-ca' ); ?> </h2>
39
+ </div>
40
+ <div class="wcf-ca-right-report-field-group">
41
+
42
+ <?php if ( WCF_CART_ABANDONED_ORDER === $details->order_status && ! $details->unsubscribed ) : ?>
43
+ <?php add_thickbox(); ?>
44
+ <div id="wcf-ca-confirm-email-reschedule" style="display:none;">
45
+ <div style="text-align:center;">
46
+ <p>
47
+ All new activated emails will be reschedule for this abandoned order. <br/>New emails will
48
+ be sent to user according to schedule time.
49
+ </p>
50
+ <p>
51
+ <strong>Are your sure?</strong>
52
+ </p>
53
+ <p>
54
+ <button onclick="window.location.search += '&sub_action=<?php echo WCF_SUB_ACTION_REPORTS_RESCHEDULE; ?>';"
55
+ class="button button-secondary"> Reschedule
56
+ </button>
57
+ <button type="button"
58
+ onclick='document.getElementById("TB_closeWindowButton").click()'
59
+ class="button button-secondary"> Close
60
+ </button>
61
+ </p>
62
+ </div>
63
+ </div>
64
+ <a name="Do you really want to reschedule emails?" href="#TB_inline?&width=500&height=200&inlineId=wcf-ca-confirm-email-reschedule" class="thickbox button button-secondary"> Reschedule Emails </a>
65
+ <?php endif; ?>
66
+ </div>
67
+ </div>
68
+
69
+ <?php if ( empty( $scheduled_emails ) ) : ?>
70
+ <div style="text-align: center;"><strong> <?php _e( ' No Email Scheduled.', 'cartflows-ca' ); ?></strong>
71
+ </div>
72
+ <?php else : ?>
73
+ <table cellpadding="15" cellspacing="0" class="wcf-table wcf-table-striped fixed posts">
74
+ <thead>
75
+ <tr>
76
+
77
+ <th class="wcf-ca-report-table-row"> Scheduled Template</th>
78
+ <th class="wcf-ca-report-table-row"> Email Subject</th>
79
+ <th class="wcf-ca-report-table-row"> Email Coupon</th>
80
+ <th class="wcf-ca-report-table-row"> Email Sent</th>
81
+ <th class="wcf-ca-report-table-row"><span class="dashicons dashicons-clock"></span> Scheduled At
82
+ </th>
83
+
84
+ </tr>
85
+ </thead>
86
+
87
+ <tbody>
88
+ <?php foreach ( $scheduled_emails as $scheduled_email ) : ?>
89
+
90
+ <?php
91
+ $email_tmpl_url = wp_nonce_url(
92
+ add_query_arg(
93
+ array(
94
+ 'page' => WCF_CA_PAGE_NAME,
95
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
96
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
97
+ 'id' => $scheduled_email->template_id,
98
+ ),
99
+ admin_url( '/admin.php' )
100
+ ),
101
+ WCF_EMAIL_TEMPLATES_NONCE
102
+ );
103
+
104
+ if ( $details->unsubscribed && ! $scheduled_email->email_sent ) {
105
+ $icon = '<span class="dashicons dashicons-dismiss" title="" ></span>';
106
+ $title = __( 'The email has unsubscribed and won\'t be sent further.', 'cartflows-ca' );
107
+ } elseif ( $scheduled_email->email_sent ) {
108
+ $icon = '<span class="dashicons dashicons-yes wp-ui-text-highlight" ></span>';
109
+ $title = __( 'The email has been sent.', 'cartflows-ca' );
110
+ } else {
111
+ $icon = '<span class="dashicons dashicons-no" ></span>';
112
+ $title = __( 'Email is in the queue and will be sent at the scheduled time.', 'cartflows-ca' );
113
+ }
114
+
115
+ $scheduled_time = date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $scheduled_email->scheduled_time ) );
116
+ ?>
117
+
118
+ <tr class="wcf-ca-report-table-row">
119
+ <td class="wcf-ca-report-table-row"><a
120
+ href="<?php echo $email_tmpl_url; ?>"
121
+ class="wp-ui-text-highlight"> <?php echo( $scheduled_email->template_name ); ?> </a>
122
+ </td>
123
+ <td class="wcf-ca-report-table-row"> <?php echo( $scheduled_email->email_subject ); ?> </td>
124
+ <td class="wcf-ca-report-table-row"> <?php echo( $scheduled_email->coupon_code ? $scheduled_email->coupon_code : '--' ); ?> </td>
125
+ <td class="wcf-ca-report-table-row wcf-ca-icon-row"> <?php echo $icon; ?>
126
+ <span class="wcf-ca-tooltip-text"><?php echo $title; ?></span>
127
+ </td>
128
+ <td class="wcf-ca-report-table-row"> <?php echo( $scheduled_time ); ?> </td>
129
+ </tr>
130
+ <?php endforeach; ?>
131
+ </tbody>
132
+ </table>
133
+ <?php endif; ?>
134
+
135
+ </div>
136
+ </div>
137
+
138
+ <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-left">
139
+ <div class="wcf-ca-user-detail ">
140
+
141
+ <div class="wcf-ca-report-btn" style="padding: 0px">
142
+ <div class="wcf-ca-left-report-field-group">
143
+ <h2> <?php _e( 'User Address Details:', 'cartflows-ca' ); ?> </h2>
144
+ </div>
145
+ <div class="wcf-ca-right-report-field-group">
146
+ <?php if ( $details->unsubscribed ) : ?>
147
+ <span class="wcf-ca-tag"> <?php _e( 'Unsubscribed', 'cartflows-ca' ); ?> </span>
148
+ <?php endif; ?>
149
+
150
+ <span class="wcf-ca-tag"> <?php echo ucfirst( $details->order_status ); ?> </span>
151
+ </div>
152
+ </div>
153
+
154
+ <div class="wcf-ca-user-address wcf-pull-left">
155
+ <h3> <?php _e( 'Billing Address', 'cartflows-ca' ); ?> </h3>
156
+ <p><strong> <?php _e( 'Name', 'cartflows-ca' ); ?> </strong>
157
+ <?php echo $user_details->wcf_first_name . ' ' . $user_details->wcf_last_name; ?> </p>
158
+ <p>
159
+ <strong> <?php _e( 'Email address', 'cartflows-ca' ); ?> </strong>
160
+ <a href="mailto:<?php echo( $details->email ); ?>"><?php echo( $details->email ); ?></a>
161
+ </p>
162
+
163
+ <p>
164
+ <strong> <?php _e( 'Phone', 'cartflows-ca' ); ?> </strong>
165
+ <a href="tel:<?php echo( $user_details->wcf_phone_number ); ?>"><?php echo( $user_details->wcf_phone_number ); ?></a>
166
+ </p>
167
+
168
+ <p>
169
+ <strong> <?php _e( 'Address 1:', 'cartflows-ca' ); ?> </strong> <?php echo $user_details->wcf_billing_address_1; ?>
170
+ </p>
171
+ <p>
172
+ <strong> <?php _e( 'Address 2:', 'cartflows-ca' ); ?> </strong> <?php echo $user_details->wcf_billing_address_2; ?>
173
+ </p>
174
+ <p>
175
+ <strong> <?php _e( 'Country, City:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_location ); ?>
176
+ </p>
177
+ <p>
178
+ <strong> <?php _e( 'State:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_billing_state ); ?>
179
+ </p>
180
+
181
+ <p>
182
+ <strong> <?php _e( 'Postcode:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_billing_postcode ); ?>
183
+ </p>
184
+ </div>
185
+
186
+ <div class="wcf-ca-user-address wcf-pull-left">
187
+ <h3> <?php _e( 'Shipping Address', 'cartflows-ca' ); ?> </h3>
188
+ <p>
189
+ <strong> <?php _e( 'Address 1:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_address_1 ); ?>
190
+ </p>
191
+ <p>
192
+ <strong> <?php _e( 'Address 2:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_address_2 ); ?>
193
+ </p>
194
+ <p>
195
+ <strong> <?php _e( 'City:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_city ); ?>
196
+ </p>
197
+ <p>
198
+ <strong> <?php _e( 'State:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_state ); ?>
199
+ </p>
200
+ <p>
201
+ <strong> <?php _e( 'Country:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_country ); ?>
202
+ </p>
203
+ <p>
204
+ <strong> <?php _e( 'Postcode:', 'cartflows-ca' ); ?> </strong> <?php echo( $user_details->wcf_shipping_postcode ); ?>
205
+ </p>
206
+ <p>
207
+ <?php $cart_abandonment = Cartflows_Ca_Cart_Abandonment::get_instance(); ?>
208
+ <strong> <a target="_blank" href=" <?php echo $cart_abandonment->get_checkout_url( $details->checkout_id, $details->session_id ); ?> ">
209
+ <?php _e( 'Checkout Link', 'cartflows-ca' ); ?>
210
+ </a>
211
+ </strong>
212
+ </p>
213
+ </div>
214
+
215
+ </div>
216
+ </div>
217
+ </div>
218
+ <!-- First panel closed -->
219
+
220
+ <!-- Second panel Start -->
221
+ <div class="wcf-ca-panel">
222
+ <div class="wcf-ca-column wcf-ca-column-one">
223
+ <div class="wcf-ca-user-order">
224
+ <h2> <?php _e( 'User Order Details:', 'cartflows-ca' ); ?> </h2>
225
+ <?php echo( $this->get_admin_product_block( $details->cart_contents, $details->cart_total ) ); ?>
226
+ </div>
227
+ </div>
228
+ </div>
229
+ <!-- Second panel closed -->
modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php CHANGED
@@ -1,139 +1,139 @@
1
- <?php
2
- /**
3
- * Cartflows view for cart abandonment reports.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- ?>
9
-
10
- <div class="wcf-ca-report-btn">
11
-
12
- <div class="wcf-ca-left-report-field-group">
13
- <button onclick="window.location.search += '&filter=today';"
14
- class="button <?php echo 'today' === $filter ? 'button-primary' : 'button-secondary'; ?>"> Today
15
- </button>
16
-
17
- <button onclick="window.location.search += '&filter=yesterday';"
18
- class="button <?php echo 'yesterday' === $filter ? 'button-primary' : 'button-secondary'; ?>"> Yesterday
19
- </button>
20
-
21
- <button onclick="window.location.search += '&filter=last_week';"
22
- class="button <?php echo 'last_week' === $filter ? 'button-primary' : 'button-secondary'; ?>"> Last Week
23
- </button>
24
-
25
- <button onclick="window.location.search += '&filter=last_month';"
26
- class="button <?php echo 'last_month' === $filter ? 'button-primary' : 'button-secondary'; ?> "> Last Month
27
- </button>
28
- </div>
29
-
30
- <div class="wcf-ca-right-report-field-group">
31
-
32
- <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_from" placeholder="YYYY-MM-DD" value="<?php echo $from_date; ?>"/>
33
- <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_to" placeholder="YYYY-MM-DD" value="<?php echo $to_date; ?>" />
34
- <button id="wcf_ca_custom_filter"
35
- class="button <?php echo 'custom' === $filter ? 'button-primary' : 'button-secondary'; ?> "> Custom Filter
36
- </button>
37
-
38
- </div>
39
-
40
- </div>
41
-
42
- <div class="wcf-ca-grid-container">
43
-
44
- <div class="wcf-ca-ibox">
45
- <div class="wcf-ca-ibox-title">
46
- <h3> <?php _e( 'Recoverable Orders', 'cartflows-ca' ); ?> </h3>
47
- </div>
48
- <div class="wcf-ca-ibox-content">
49
- <h1> <?php echo $abandoned_report['no_of_orders']; ?> </h1>
50
- <small> <?php _e( 'Total Recoverable Orders.', 'cartflows-ca' ); ?> </small>
51
- </div>
52
- </div>
53
-
54
- <div class="wcf-ca-ibox">
55
- <div class="wcf-ca-ibox-title"><h3><?php _e( 'Recovered Orders', 'cartflows-ca' ); ?></h3></div>
56
- <div class="wcf-ca-ibox-content"><h1><?php echo $recovered_report['no_of_orders']; ?></h1>
57
- <small> <?php _e( 'Total Recovered Orders.', 'cartflows-ca' ); ?> </small>
58
- </div>
59
- </div>
60
-
61
- <div class="wcf-ca-ibox">
62
- <div class="wcf-ca-ibox-title"><h3><?php _e( 'Lost Orders', 'cartflows-ca' ); ?></h3></div>
63
- <div class="wcf-ca-ibox-content"><h1
64
- ><?php echo $lost_report['no_of_orders']; ?></h1>
65
- <small> <?php _e( 'Total Lost Orders.', 'cartflows-ca' ); ?> </small>
66
- </div>
67
- </div>
68
-
69
- </div>
70
-
71
- <div class="wcf-ca-grid-container">
72
-
73
- <div class="wcf-ca-ibox">
74
- <div class="wcf-ca-ibox-title"><h3> <?php _e( 'Recoverable Revenue', 'cartflows-ca' ); ?> </h3></div>
75
- <div class="wcf-ca-ibox-content">
76
- <h1>
77
- <?php echo $currency_symbol . number_format_i18n( $abandoned_report['revenue'], 2 ); ?>
78
- </h1>
79
- <small> <?php _e( 'Total Recoverable Revenue.', 'cartflows-ca' ); ?> </small>
80
- </div>
81
- </div>
82
-
83
- <div class="wcf-ca-ibox">
84
- <div class="wcf-ca-ibox-title"><h3><?php _e( 'Recovered Revenue', 'cartflows-ca' ); ?></h3></div>
85
- <div class="wcf-ca-ibox-content"><h1>
86
- <?php
87
- echo $currency_symbol . number_format_i18n( $recovered_report['revenue'], 2 );
88
- ?>
89
- </h1>
90
- <small> <?php _e( 'Total Recovered Revenue.', 'cartflows-ca' ); ?> </small>
91
- </div>
92
- </div>
93
-
94
- <div class="wcf-ca-ibox">
95
- <div class="wcf-ca-ibox-title"><h3> <?php _e( 'Recovery Rate', 'cartflows-ca' ); ?> </h3></div>
96
- <div class="wcf-ca-ibox-content"><h1><?php echo $conversion_rate . '%'; ?></h1>
97
- <small><?php _e( 'Total Percentage Of Recovered Orders After Abandonment.', 'cartflows-ca' ); ?> </small>
98
- </div>
99
- </div>
100
-
101
- </div>
102
-
103
- <hr/>
104
-
105
- <div class="wcf-ca-report-btn">
106
- <div class="wcf-ca-left-report-field-group">
107
- <button onclick="window.location.search += '&filter_table=<?php echo WCF_CART_ABANDONED_ORDER; ?>';"
108
- class="button <?php echo WCF_CART_ABANDONED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?> "> Recoverable Orders
109
- </button>
110
- <button onclick="window.location.search += '&filter_table=<?php echo WCF_CART_COMPLETED_ORDER; ?>';"
111
- class="button <?php echo WCF_CART_COMPLETED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"> Recovered Orders
112
- </button>
113
- <button onclick="window.location.search += '&filter_table=<?php echo WCF_CART_LOST_ORDER; ?>';"
114
- class="button <?php echo WCF_CART_LOST_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"> Lost Orders
115
- </button>
116
- </div>
117
- </div>
118
-
119
-
120
-
121
- <?php
122
- if ( count( $wcf_list_table->items ) ) {
123
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
124
-
125
- ?>
126
-
127
- <form id="wcf-cart-abandonment-table" method="GET">
128
- <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
129
- <?php $wcf_list_table->display(); ?>
130
- </form>
131
-
132
- <?php
133
- } else {
134
-
135
- echo "<div style='text-align: center;'> <strong> " . __( 'No Orders Found.', 'cartflows-ca' ) . '</strong> </div>';
136
-
137
- }
138
-
139
- ?>
1
+ <?php
2
+ /**
3
+ * Cartflows view for cart abandonment reports.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ ?>
9
+
10
+ <div class="wcf-ca-report-btn">
11
+
12
+ <div class="wcf-ca-left-report-field-group">
13
+ <button onclick="window.location.search += '&filter=today';"
14
+ class="button <?php echo 'today' === $filter ? 'button-primary' : 'button-secondary'; ?>"> Today
15
+ </button>
16
+
17
+ <button onclick="window.location.search += '&filter=yesterday';"
18
+ class="button <?php echo 'yesterday' === $filter ? 'button-primary' : 'button-secondary'; ?>"> Yesterday
19
+ </button>
20
+
21
+ <button onclick="window.location.search += '&filter=last_week';"
22
+ class="button <?php echo 'last_week' === $filter ? 'button-primary' : 'button-secondary'; ?>"> Last Week
23
+ </button>
24
+
25
+ <button onclick="window.location.search += '&filter=last_month';"
26
+ class="button <?php echo 'last_month' === $filter ? 'button-primary' : 'button-secondary'; ?> "> Last Month
27
+ </button>
28
+ </div>
29
+
30
+ <div class="wcf-ca-right-report-field-group">
31
+
32
+ <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_from" placeholder="YYYY-MM-DD" value="<?php echo $from_date; ?>"/>
33
+ <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_to" placeholder="YYYY-MM-DD" value="<?php echo $to_date; ?>" />
34
+ <button id="wcf_ca_custom_filter"
35
+ class="button <?php echo 'custom' === $filter ? 'button-primary' : 'button-secondary'; ?> "> Custom Filter
36
+ </button>
37
+
38
+ </div>
39
+
40
+ </div>
41
+
42
+ <div class="wcf-ca-grid-container">
43
+
44
+ <div class="wcf-ca-ibox">
45
+ <div class="wcf-ca-ibox-title">
46
+ <h3> <?php _e( 'Recoverable Orders', 'cartflows-ca' ); ?> </h3>
47
+ </div>
48
+ <div class="wcf-ca-ibox-content">
49
+ <h1> <?php echo $abandoned_report['no_of_orders']; ?> </h1>
50
+ <small> <?php _e( 'Total Recoverable Orders.', 'cartflows-ca' ); ?> </small>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="wcf-ca-ibox">
55
+ <div class="wcf-ca-ibox-title"><h3><?php _e( 'Recovered Orders', 'cartflows-ca' ); ?></h3></div>
56
+ <div class="wcf-ca-ibox-content"><h1><?php echo $recovered_report['no_of_orders']; ?></h1>
57
+ <small> <?php _e( 'Total Recovered Orders.', 'cartflows-ca' ); ?> </small>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="wcf-ca-ibox">
62
+ <div class="wcf-ca-ibox-title"><h3><?php _e( 'Lost Orders', 'cartflows-ca' ); ?></h3></div>
63
+ <div class="wcf-ca-ibox-content"><h1
64
+ ><?php echo $lost_report['no_of_orders']; ?></h1>
65
+ <small> <?php _e( 'Total Lost Orders.', 'cartflows-ca' ); ?> </small>
66
+ </div>
67
+ </div>
68
+
69
+ </div>
70
+
71
+ <div class="wcf-ca-grid-container">
72
+
73
+ <div class="wcf-ca-ibox">
74
+ <div class="wcf-ca-ibox-title"><h3> <?php _e( 'Recoverable Revenue', 'cartflows-ca' ); ?> </h3></div>
75
+ <div class="wcf-ca-ibox-content">
76
+ <h1>
77
+ <?php echo $currency_symbol . number_format_i18n( $abandoned_report['revenue'], 2 ); ?>
78
+ </h1>
79
+ <small> <?php _e( 'Total Recoverable Revenue.', 'cartflows-ca' ); ?> </small>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="wcf-ca-ibox">
84
+ <div class="wcf-ca-ibox-title"><h3><?php _e( 'Recovered Revenue', 'cartflows-ca' ); ?></h3></div>
85
+ <div class="wcf-ca-ibox-content"><h1>
86
+ <?php
87
+ echo $currency_symbol . number_format_i18n( $recovered_report['revenue'], 2 );
88
+ ?>
89
+ </h1>
90
+ <small> <?php _e( 'Total Recovered Revenue.', 'cartflows-ca' ); ?> </small>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="wcf-ca-ibox">
95
+ <div class="wcf-ca-ibox-title"><h3> <?php _e( 'Recovery Rate', 'cartflows-ca' ); ?> </h3></div>
96
+ <div class="wcf-ca-ibox-content"><h1><?php echo $conversion_rate . '%'; ?></h1>
97
+ <small><?php _e( 'Total Percentage Of Recovered Orders After Abandonment.', 'cartflows-ca' ); ?> </small>
98
+ </div>
99
+ </div>
100
+
101
+ </div>
102
+
103
+ <hr/>
104
+
105
+ <div class="wcf-ca-report-btn">
106
+ <div class="wcf-ca-left-report-field-group">
107
+ <button onclick="window.location.search += '&filter_table=<?php echo WCF_CART_ABANDONED_ORDER; ?>';"
108
+ class="button <?php echo WCF_CART_ABANDONED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?> "> Recoverable Orders
109
+ </button>
110
+ <button onclick="window.location.search += '&filter_table=<?php echo WCF_CART_COMPLETED_ORDER; ?>';"
111
+ class="button <?php echo WCF_CART_COMPLETED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"> Recovered Orders
112
+ </button>
113
+ <button onclick="window.location.search += '&filter_table=<?php echo WCF_CART_LOST_ORDER; ?>';"
114
+ class="button <?php echo WCF_CART_LOST_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"> Lost Orders
115
+ </button>
116
+ </div>
117
+ </div>
118
+
119
+
120
+
121
+ <?php
122
+ if ( count( $wcf_list_table->items ) ) {
123
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
124
+
125
+ ?>
126
+
127
+ <form id="wcf-cart-abandonment-table" method="GET">
128
+ <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
129
+ <?php $wcf_list_table->display(); ?>
130
+ </form>
131
+
132
+ <?php
133
+ } else {
134
+
135
+ echo "<div style='text-align: center;'> <strong> " . __( 'No Orders Found.', 'cartflows-ca' ) . '</strong> </div>';
136
+
137
+ }
138
+
139
+ ?>
modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php CHANGED
@@ -1,118 +1,118 @@
1
- <?php
2
- /**
3
- * Cartflows view for cart abandonment tabs.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- ?>
9
- <div class="wrap">
10
- <h1 id="wcf_cart_abandonment_tracking_table"><?php echo __( 'Woocommerce Cart Abandonment Recovery ', 'cartflows-ca' ); ?></h1>
11
- <?php
12
-
13
- $action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
14
- $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
15
-
16
-
17
- if ( ! $action ) {
18
- $action = WCF_ACTION_REPORTS;
19
- }
20
-
21
- $this->wcf_display_tabs();
22
- $this->wcf_show_warning_ca();
23
- ?>
24
- <?php
25
- echo get_transient( 'wcf_ca_show_message' );
26
- ?>
27
-
28
- <?php if ( WCF_ACTION_SETTINGS === $action ) : ?>
29
- <?php
30
- $this->wcf_display_settings();
31
- ?>
32
- <?php endif; ?>
33
-
34
- <?php if ( WCF_ACTION_REPORTS === $action ) : ?>
35
-
36
- <?php
37
-
38
- switch ( $sub_action ) {
39
-
40
- case WCF_SUB_ACTION_REPORTS_VIEW:
41
- $this->wcf_display_report_details();
42
- break;
43
- case WCF_SUB_ACTION_REPORTS_RESCHEDULE:
44
- $ca_obj = Cartflows_Ca_Cart_Abandonment::get_instance();
45
-
46
- $session_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
47
- if ( $session_id ) {
48
- $ca_obj->schedule_emails( $session_id, true );
49
- }
50
-
51
- $param = array(
52
- 'page' => WCF_CA_PAGE_NAME,
53
- 'action' => WCF_ACTION_REPORTS,
54
- 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
55
- 'session_id' => $session_id,
56
- );
57
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
58
-
59
- wp_safe_redirect( $redirect_url );
60
-
61
- break;
62
- default:
63
- $this->wcf_display_reports();
64
- break;
65
-
66
- }
67
-
68
- ?>
69
-
70
- <?php endif; ?>
71
-
72
- <?php if ( WCF_ACTION_EMAIL_TEMPLATES === $action ) : ?>
73
-
74
- <?php
75
- $email_template_class_inst = Cartflows_Ca_Email_Templates::get_instance();
76
- $email_template_class_inst->show_messages();
77
- switch ( $sub_action ) {
78
- case WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES:
79
- $email_template_class_inst->delete_bulk_templates();
80
- break;
81
- case WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES:
82
- $email_template_class_inst->delete_single_template();
83
- break;
84
- case WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES:
85
- $email_template_class_inst->clone_email_template();
86
- break;
87
- case WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES:
88
- case WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES:
89
- $email_template_class_inst->render_email_template_form( $sub_action );
90
- break;
91
- case WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES:
92
- $email_template_class_inst->restore_email_templates();
93
- break;
94
-
95
- case WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES:
96
- check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' );
97
-
98
- $wcf_settings_frm = filter_input( INPUT_POST, 'wcf_settings_frm', FILTER_SANITIZE_STRING );
99
- $id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
100
-
101
- if ( 'save' === $wcf_settings_frm ) {
102
- $email_template_class_inst->add_email_template();
103
- } elseif ( 'update' === $wcf_settings_frm && $id ) {
104
- $email_template_class_inst->edit_email_template();
105
- }
106
- break;
107
- default:
108
- $email_template_class_inst->show_add_new_template_button();
109
- $email_template_class_inst->show_email_template_data_table();
110
- break;
111
- }
112
-
113
- ?>
114
-
115
-
116
- <?php endif; ?>
117
-
118
- </div>
1
+ <?php
2
+ /**
3
+ * Cartflows view for cart abandonment tabs.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ ?>
9
+ <div class="wrap">
10
+ <h1 id="wcf_cart_abandonment_tracking_table"><?php echo __( 'Woocommerce Cart Abandonment Recovery ', 'cartflows-ca' ); ?></h1>
11
+ <?php
12
+
13
+ $action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
14
+ $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
15
+
16
+
17
+ if ( ! $action ) {
18
+ $action = WCF_ACTION_REPORTS;
19
+ }
20
+
21
+ $this->wcf_display_tabs();
22
+ $this->wcf_show_warning_ca();
23
+ ?>
24
+ <?php
25
+ echo get_transient( 'wcf_ca_show_message' );
26
+ ?>
27
+
28
+ <?php if ( WCF_ACTION_SETTINGS === $action ) : ?>
29
+ <?php
30
+ $this->wcf_display_settings();
31
+ ?>
32
+ <?php endif; ?>
33
+
34
+ <?php if ( WCF_ACTION_REPORTS === $action ) : ?>
35
+
36
+ <?php
37
+
38
+ switch ( $sub_action ) {
39
+
40
+ case WCF_SUB_ACTION_REPORTS_VIEW:
41
+ $this->wcf_display_report_details();
42
+ break;
43
+ case WCF_SUB_ACTION_REPORTS_RESCHEDULE:
44
+ $ca_obj = Cartflows_Ca_Cart_Abandonment::get_instance();
45
+
46
+ $session_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
47
+ if ( $session_id ) {
48
+ $ca_obj->schedule_emails( $session_id, true );
49
+ }
50
+
51
+ $param = array(
52
+ 'page' => WCF_CA_PAGE_NAME,
53
+ 'action' => WCF_ACTION_REPORTS,
54
+ 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
55
+ 'session_id' => $session_id,
56
+ );
57
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
58
+
59
+ wp_safe_redirect( $redirect_url );
60
+
61
+ break;
62
+ default:
63
+ $this->wcf_display_reports();
64
+ break;
65
+
66
+ }
67
+
68
+ ?>
69
+
70
+ <?php endif; ?>
71
+
72
+ <?php if ( WCF_ACTION_EMAIL_TEMPLATES === $action ) : ?>
73
+
74
+ <?php
75
+ $email_template_class_inst = Cartflows_Ca_Email_Templates::get_instance();
76
+ $email_template_class_inst->show_messages();
77
+ switch ( $sub_action ) {
78
+ case WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES:
79
+ $email_template_class_inst->delete_bulk_templates();
80
+ break;
81
+ case WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES:
82
+ $email_template_class_inst->delete_single_template();
83
+ break;
84
+ case WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES:
85
+ $email_template_class_inst->clone_email_template();
86
+ break;
87
+ case WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES:
88
+ case WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES:
89
+ $email_template_class_inst->render_email_template_form( $sub_action );
90
+ break;
91
+ case WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES:
92
+ $email_template_class_inst->restore_email_templates();
93
+ break;
94
+
95
+ case WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES:
96
+ check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' );
97
+
98
+ $wcf_settings_frm = filter_input( INPUT_POST, 'wcf_settings_frm', FILTER_SANITIZE_STRING );
99
+ $id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
100
+
101
+ if ( 'save' === $wcf_settings_frm ) {
102
+ $email_template_class_inst->add_email_template();
103
+ } elseif ( 'update' === $wcf_settings_frm && $id ) {
104
+ $email_template_class_inst->edit_email_template();
105
+ }
106
+ break;
107
+ default:
108
+ $email_template_class_inst->show_add_new_template_button();
109
+ $email_template_class_inst->show_email_template_data_table();
110
+ break;
111
+ }
112
+
113
+ ?>
114
+
115
+
116
+ <?php endif; ?>
117
+
118
+ </div>
readme.txt CHANGED
@@ -1,50 +1,55 @@
1
- === WooCommerce Cart Abandonment Recovery ===
2
- Contributors: brainstormforce, wpcrafter
3
- Donate link: https://www.paypal.me/BrainstormForce
4
- Tags: woocommerce, cart abandonment, cart recovery
5
- Requires at least: 4.4
6
- Tested up to: 5.2
7
- Stable tag: 1.1.2
8
- Requires PHP: 5.6
9
- License: GPLv2 or later
10
- License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
-
12
- Recover your lost revenue. Capture email address of users on the checkout page and send follow up emails if they don't complete the purchase.
13
-
14
- == Description ==
15
- WooCommerce Cart Abandonment Recovery plugin is best plugin to capture email address of users on the checkout page and send follow up emails if they don't complete the purchase. Ultimately, it will recover your lost revenue.
16
-
17
-
18
- == Installation ==
19
-
20
- 1. Upload `woocommerce-cart-abandonment-recovery.zip` to the `/wp-content/plugins/` directory
21
- 2. Activate the plugin through the 'Plugins' menu in WordPress
22
-
23
- == Frequently Asked Questions ==
24
-
25
- = Does this plugin work with CartFlows? =
26
-
27
- Yes, of course. We have built it in a way that it will work with CartFlows as well as with WooCommerce.
28
-
29
- == Screenshots ==
30
-
31
- == Changelog ==
32
-
33
- = Version 1.1.2 - Wednesday, 12th June 2019 =
34
- * Fix: Issue of timezone while sending mail through cron.
35
- * Fix: Delete single cart abandonment order.
36
- * Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
37
-
38
- = Version 1.1.1 - Thursday, 06th June 2019 =
39
- * New: Added feature to reschedule emails for Admin.
40
- * Fix: Coupon expiry time issue.
41
- * Fix: Email issue for a user who has an already purchased order.
42
- * Fix: Translatable strings updated.
43
-
44
- = Version 1.1.0 - Thursday, 30th May 2019 =
45
- * Added a view for admin to check email status specific to the particular abandoned user.
46
-
47
- = Version 1.0.0 - Monday, 27th May 2019 =
48
- * Initial Release
49
-
 
 
 
 
 
50
  == Upgrade Notice ==
1
+ === WooCommerce Cart Abandonment Recovery ===
2
+ Contributors: brainstormforce, wpcrafter
3
+ Donate link: https://www.paypal.me/BrainstormForce
4
+ Tags: woocommerce, cart abandonment, cart recovery
5
+ Requires at least: 4.4
6
+ Tested up to: 5.2
7
+ Stable tag: 1.1.3
8
+ Requires PHP: 5.6
9
+ License: GPLv2 or later
10
+ License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
+
12
+ Recover your lost revenue. Capture email address of users on the checkout page and send follow up emails if they don't complete the purchase.
13
+
14
+ == Description ==
15
+ WooCommerce Cart Abandonment Recovery plugin is best plugin to capture email address of users on the checkout page and send follow up emails if they don't complete the purchase. Ultimately, it will recover your lost revenue.
16
+
17
+
18
+ == Installation ==
19
+
20
+ 1. Upload `woocommerce-cart-abandonment-recovery.zip` to the `/wp-content/plugins/` directory
21
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
22
+
23
+ == Frequently Asked Questions ==
24
+
25
+ = Does this plugin work with CartFlows? =
26
+
27
+ Yes, of course. We have built it in a way that it will work with CartFlows as well as with WooCommerce.
28
+
29
+ == Screenshots ==
30
+
31
+ == Changelog ==
32
+ = Version 1.1.3 - Thursday, 27th June 2019
33
+ * Improvement: Added checkout link for abandoned cart inside the admin section.
34
+ * Fix: Added pagination for reports.
35
+ * Fix: Recover report calculations before campaign triggers.
36
+ * Fix: Empty cart notice when CartFlows checkout is set global.
37
+
38
+ = Version 1.1.2 - Wednesday, 12th June 2019 =
39
+ * Fix: Issue of timezone while sending mail through cron.
40
+ * Fix: Delete single cart abandonment order.
41
+ * Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
42
+
43
+ = Version 1.1.1 - Thursday, 06th June 2019 =
44
+ * New: Added feature to reschedule emails for Admin.
45
+ * Fix: Coupon expiry time issue.
46
+ * Fix: Email issue for a user who has an already purchased order.
47
+ * Fix: Translatable strings updated.
48
+
49
+ = Version 1.1.0 - Thursday, 30th May 2019 =
50
+ * Added a view for admin to check email status specific to the particular abandoned user.
51
+
52
+ = Version 1.0.0 - Monday, 27th May 2019 =
53
+ * Initial Release
54
+
55
  == Upgrade Notice ==
uninstall.php CHANGED
@@ -1,14 +1,14 @@
1
- <?php
2
- /**
3
- * Woocommerce Cart Abandonment Recovery
4
- * Unscheduling the events.
5
- *
6
- * @package Woocommerce-Cart-Abandonment-Recovery
7
- */
8
-
9
- if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
- exit;
11
- }
12
-
13
-
14
- wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
1
+ <?php
2
+ /**
3
+ * Woocommerce Cart Abandonment Recovery
4
+ * Unscheduling the events.
5
+ *
6
+ * @package Woocommerce-Cart-Abandonment-Recovery
7
+ */
8
+
9
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
+ exit;
11
+ }
12
+
13
+
14
+ wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
woo-cart-abandonment-recovery.php CHANGED
@@ -1,24 +1,24 @@
1
- <?php
2
- /**
3
- * Plugin Name: WooCommerce Cart Abandonment Recovery
4
- * Plugin URI: https://cartflows.com/
5
- * Description: Recover your lost revenue. Capture email address of users on the checkout page and send follow up emails if they don't complete the purchase.
6
- * Version: 1.1.2
7
- * Author: CartFlows Inc
8
- * Author URI: https://cartflows.com/
9
- * Text Domain: cartflows-ca
10
- * WC requires at least: 3.0
11
- * WC tested up to: 3.6.3
12
- *
13
- * @package Woocommerce-Cart-Abandonment-Recovery
14
- */
15
-
16
- /**
17
- * Set constants.
18
- */
19
- define( 'CARTFLOWS_CA_FILE', __FILE__ );
20
-
21
- /**
22
- * Loader
23
- */
24
- require_once 'classes/class-cartflows-ca-loader.php';
1
+ <?php
2
+ /**
3
+ * Plugin Name: WooCommerce Cart Abandonment Recovery
4
+ * Plugin URI: https://cartflows.com/
5
+ * Description: Recover your lost revenue. Capture email address of users on the checkout page and send follow up emails if they don't complete the purchase.
6
+ * Version: 1.1.3
7
+ * Author: CartFlows Inc
8
+ * Author URI: https://cartflows.com/
9
+ * Text Domain: cartflows-ca
10
+ * WC requires at least: 3.0
11
+ * WC tested up to: 3.6.3
12
+ *
13
+ * @package Woocommerce-Cart-Abandonment-Recovery
14
+ */
15
+
16
+ /**
17
+ * Set constants.
18
+ */
19
+ define( 'CARTFLOWS_CA_FILE', __FILE__ );
20
+
21
+ /**
22
+ * Loader
23
+ */
24
+ require_once 'classes/class-cartflows-ca-loader.php';