WooCommerce Cart Abandonment Recovery - Version 1.2.5

Version Description

Download this release

Release Info

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

Code changes from version 1.2.4 to 1.2.5

admin/assets/css/admin-cart-abandonment-rtl.css CHANGED
@@ -1,430 +1,430 @@
1
- .wcf-ca-ibox {
2
- clear: both;
3
- margin-bottom: 25px;
4
- margin-top: 0;
5
- padding: 0;
6
- }
7
-
8
- .wcf-ca-ibox-title {
9
- background-color: white;
10
- border-image: none;
11
- border-width: 3px 0px 0;
12
- color: inherit;
13
- margin-bottom: 0;
14
- padding: 14px 15px 7px;
15
- min-height: 48px;
16
- }
17
-
18
- .wcf-ca-ibox-content {
19
- background-color: white;
20
- color: inherit;
21
- padding: 15px 20px 20px 20px;
22
- border-color: #d7dadc;
23
- border-image: none;
24
- border-style: solid solid none;
25
- border-width: 1px 0px;
26
- }
27
-
28
- .wcf-ca-raw {
29
- margin-right: -15px;
30
- margin-left: -15px;
31
- }
32
-
33
- .wcf-ca-grid-container {
34
- display: grid;
35
- grid-template-columns: 1fr 1fr 1fr;
36
- grid-gap: 20px;
37
- }
38
-
39
- .grid-container > div {
40
- background-color: rgba(255, 255, 255, 0.8);
41
- text-align: center;
42
- padding: 20px 0;
43
- font-size: 30px;
44
- }
45
-
46
-
47
- .wcf-ca-center-msg {
48
- margin: auto;
49
- width: 50%;
50
- padding: 10px;
51
- margin-top: 20px;
52
- text-align: center;
53
- }
54
-
55
-
56
- .wcf-ca-switch {
57
- cursor: pointer;
58
- text-indent: -999em;
59
- display: block;
60
- width: 38px;
61
- height: 22px;
62
- border-radius: 30px;
63
- border: none;
64
- position: relative;
65
- box-sizing: border-box;
66
- -webkit-transition: all .3s ease;
67
- transition: all .3s ease;
68
- box-shadow: inset 0 0 0 0 transparent;
69
- }
70
- .wcf-ca-switch:focus {
71
- outline: none;
72
- }
73
- .wcf-ca-switch:before {
74
- border-radius: 50%;
75
- background: #ffffff;
76
- content: '';
77
- position: absolute;
78
- display: block;
79
- width: 18px;
80
- height: 18px;
81
- top: 2px;
82
- right: 2px;
83
- -webkit-transition: all .15s ease;
84
- transition: all .15s ease;
85
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
86
- }
87
- .wcf-ca-switch[wcf-ca-template-switch="on"] {
88
- box-shadow: inset 0 0 0 11px #008000;
89
- }
90
- .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
91
- -webkit-transform: translateX(-16px);
92
- transform: translateX(-16px);
93
- }
94
- .wcf-ca-switch[wcf-ca-template-switch="off"] {
95
- background: #ccc;
96
- }
97
- .wcf-ca-switch.wcap-loading {
98
- cursor: default;
99
- opacity: 0.5;
100
- }
101
-
102
- .wcf-ca-trigger-input{
103
- height: 28px;
104
- width: 40%;
105
- margin-left: 10px;
106
- }
107
-
108
- .wcf-ca-report-btn {
109
- padding: 15px 0px 15px 0px;
110
- display: flex;
111
- width: 100%;
112
- position: relative;
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
- flex: 1;
133
- margin-top: 0px;
134
- }
135
- .wcf-ca-right-report-field-group {
136
- flex: 1;
137
- text-align: left;
138
-
139
- }
140
- .wcf-search-orders{
141
- display: inline-block;
142
- }
143
- .wcf_export_orders{
144
- display: inline-block;
145
- vertical-align: bottom;
146
- padding-right: 5px;
147
- }
148
-
149
- .wcf-ca-report-table-row {
150
- color: #636363;
151
- border: 1px solid #e5e5e5;
152
- }
153
-
154
- /* Newly Added for the modification of the User Order detail window UI */
155
-
156
- /* Column Classes */
157
-
158
- .wcf-ca-column-one{
159
- width: 100%;
160
- }
161
-
162
- .wcf-ca-column-two,
163
- .wcf-ca-user-address{
164
- width: 50%;
165
- }
166
-
167
- .wcf-pull-left{
168
- float: right;
169
- }
170
- .wcf-ca-email-data,
171
- .wcf-ca-user-detail{
172
- border-radius: 3px;
173
- padding: 20px 25px;
174
- min-height: 330px;
175
- max-height: 420px;
176
- width: 100%;
177
- overflow: auto;
178
- }
179
-
180
- .wcf-ca-user-detail{
181
- max-height: 100%;
182
- }
183
-
184
- .wcf-ca-user-order{
185
- border-radius: 3px;
186
- padding: 25px 25px 30px 25px;
187
- overflow: hidden;
188
- height: auto;
189
- width: 100%;
190
- }
191
-
192
- /* Column Classes */
193
-
194
- /* Section classes */
195
-
196
- .wcf-ca-margin-right{
197
- margin-left: 13px;
198
- }
199
- .wcf-ca-margin-left{
200
- margin-right: 13px;
201
- }
202
-
203
- .wcf-ca-column{
204
- background-color: #fff;
205
- border-radius: 3px;
206
- display: flex;
207
- }
208
-
209
- /* Section Classes */
210
-
211
-
212
- .wcf-ca-right-report-field-group .back-button{
213
- height: auto;
214
- padding: 3px 5px 3px 10px;
215
- }
216
-
217
- .wcf-ca-left-report-field-group .back-button .dashicons{
218
- vertical-align: middle;
219
- }
220
-
221
- .wcf-ca-panel{
222
- cursor: default;
223
- /*background-color: #fff;*/
224
- border-radius: 5px;
225
- display: flex;
226
- padding: 0px;
227
- margin: 10px 0 25px;
228
- }
229
-
230
- .wcf-table{
231
- border: none;
232
- text-align: right;
233
- width: 100%;
234
- }
235
- .wcf-table tr,
236
- .wcf-table tr th,
237
- .wcf-table tr td{
238
- border: none;
239
- }
240
-
241
- .wcf-table tr th a,
242
- .wcf-table tr td a{
243
- text-decoration: none;
244
- cursor: pointer;
245
- }
246
-
247
- .wcf-table tr th{
248
- vertical-align: bottom;
249
- border-bottom: 2px solid #ddd;
250
- }
251
-
252
- .wcf-table tr td{
253
- border-bottom: 1px solid #ddd;
254
- line-height: 1.42857143;
255
- vertical-align: top;
256
- position: relative;
257
- }
258
-
259
- .wcf-ca-panel h2{
260
- margin: 0;
261
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
262
- font-size: 21px;
263
- font-weight: 400;
264
- line-height: 1.2;
265
- text-shadow: -1px 1px 1px #fff;
266
- padding: 10px 0 15px;
267
- margin: 0;
268
- }
269
-
270
- .wcf-ca-user-order table{
271
- width: 100%;
272
- }
273
-
274
- .wcf-ca-user-order table thead th{
275
- text-align: center;
276
- padding: 1em 3em;
277
- font-weight: 400;
278
- color: #999;
279
- /*background: #f8f8f8;*/
280
- -webkit-touch-callout: none;
281
- -webkit-user-select: none;
282
- -moz-user-select: none;
283
- -ms-user-select: none;
284
- user-select: none;
285
- }
286
-
287
- .wcf-ca-user-order table thead th:first-of-type{
288
- padding-right: 3.6em;
289
- text-align: right;
290
- }
291
-
292
- .wcf-ca-user-order table tbody tr td {
293
- text-align: center;
294
- padding: 1em 3em;
295
- vertical-align: middle;
296
- }
297
-
298
- .wcf-ca-user-order table tbody tr td:first-of-type{
299
- text-align: right;
300
- /*width: 38px;*/
301
- padding-right: 3em;
302
- }
303
-
304
-
305
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
306
- .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
307
- .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
308
- .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
309
- text-align: left;
310
- font-weight: 600;
311
- width: 82%;
312
- }
313
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
314
- border-top: 1px solid #ccc;
315
- }
316
-
317
- .wcf-ca-tooltip-text.display_tool_tip{
318
- display: block;
319
- }
320
-
321
- .wcf-ca-tooltip-text::before {
322
- border-right: 5px solid transparent;
323
- border-left: 5px solid transparent;
324
- border-top: 5px solid transparent;
325
- border-bottom: 5px solid #444;
326
- bottom: auto;
327
- content: " ";
328
- font-size: 0;
329
- right: 25px;
330
- line-height: 0;
331
- margin-right: -5px;
332
- position: absolute;
333
- top: -10px;
334
- width: 0;
335
- }
336
-
337
- .wcf-ca-tooltip-text {
338
- background: #444;
339
- border-radius: 3px;
340
- color: #fff;
341
- height: auto;
342
- right: 0;
343
- margin-top: 10px;
344
- max-width: 150px;
345
- position: absolute;
346
- padding: 6px 10px;
347
- width: 100%;
348
- display: none;
349
- z-index: 10000;
350
- }
351
- /* Newly Added for the modification of the User Order detail window UI */
352
-
353
-
354
-
355
- .wcf-ca-tags {
356
- list-style: none;
357
- margin: 0;
358
- overflow: hidden;
359
- padding: 0;
360
- }
361
-
362
- .wcf-ca-tags li {
363
- float: right;
364
- }
365
-
366
- .wcf-ca-tag {
367
- background-color: #f16334;
368
- border-radius: 0 3px 3px 0;
369
- color: #fff;
370
- display: inline-block;
371
- height: 26px;
372
- line-height: 26px;
373
- padding: 0 23px 0 20px;
374
- position: relative;
375
- margin: 0 0 0px 5px;
376
- text-decoration: none;
377
- -webkit-transition: color 0.2s;
378
- }
379
-
380
- .wcf-ca-tag::before {
381
- background: #fff;
382
- border-radius: 10px;
383
- box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
384
- content: '';
385
- height: 6px;
386
- right: 10px;
387
- position: absolute;
388
- width: 6px;
389
- top: 10px;
390
- }
391
-
392
- .wcf-ca-tag::after {
393
- background: #fff;
394
- border-bottom: 13px solid transparent;
395
- border-right: 10px solid #f16334;;
396
- border-top: 13px solid transparent;
397
- content: '';
398
- position: absolute;
399
- left: 0;
400
- top: 0;
401
- }
402
-
403
- .wcf-ca-tag:hover {
404
- background-color: #f16334;
405
- color: white;
406
- }
407
-
408
- .wcf-ca-tag:hover::after {
409
- border-right-color: #f16334;
410
- }
411
-
412
- .wcf-sub-heading {
413
- font-weight: 400;
414
- }
415
-
416
- .wcf-ca-spinner{
417
- float:unset;
418
- }
419
-
420
- .wcf-ca-response-msg{
421
- vertical-align: sub;
422
- line-height: 28px;
423
- margin-right: 10px;
424
- font-weight: bold;
425
- }
426
-
427
- .wcf-ca-export-icon{
428
- line-height: 1.8;
429
- font-size:17px;
430
- }
1
+ .wcf-ca-ibox {
2
+ clear: both;
3
+ margin-bottom: 25px;
4
+ margin-top: 0;
5
+ padding: 0;
6
+ }
7
+
8
+ .wcf-ca-ibox-title {
9
+ background-color: white;
10
+ border-image: none;
11
+ border-width: 3px 0px 0;
12
+ color: inherit;
13
+ margin-bottom: 0;
14
+ padding: 14px 15px 7px;
15
+ min-height: 48px;
16
+ }
17
+
18
+ .wcf-ca-ibox-content {
19
+ background-color: white;
20
+ color: inherit;
21
+ padding: 15px 20px 20px 20px;
22
+ border-color: #d7dadc;
23
+ border-image: none;
24
+ border-style: solid solid none;
25
+ border-width: 1px 0px;
26
+ }
27
+
28
+ .wcf-ca-raw {
29
+ margin-right: -15px;
30
+ margin-left: -15px;
31
+ }
32
+
33
+ .wcf-ca-grid-container {
34
+ display: grid;
35
+ grid-template-columns: 1fr 1fr 1fr;
36
+ grid-gap: 20px;
37
+ }
38
+
39
+ .grid-container > div {
40
+ background-color: rgba(255, 255, 255, 0.8);
41
+ text-align: center;
42
+ padding: 20px 0;
43
+ font-size: 30px;
44
+ }
45
+
46
+
47
+ .wcf-ca-center-msg {
48
+ margin: auto;
49
+ width: 50%;
50
+ padding: 10px;
51
+ margin-top: 20px;
52
+ text-align: center;
53
+ }
54
+
55
+
56
+ .wcf-ca-switch {
57
+ cursor: pointer;
58
+ text-indent: -999em;
59
+ display: block;
60
+ width: 38px;
61
+ height: 22px;
62
+ border-radius: 30px;
63
+ border: none;
64
+ position: relative;
65
+ box-sizing: border-box;
66
+ -webkit-transition: all .3s ease;
67
+ transition: all .3s ease;
68
+ box-shadow: inset 0 0 0 0 transparent;
69
+ }
70
+ .wcf-ca-switch:focus {
71
+ outline: none;
72
+ }
73
+ .wcf-ca-switch:before {
74
+ border-radius: 50%;
75
+ background: #ffffff;
76
+ content: '';
77
+ position: absolute;
78
+ display: block;
79
+ width: 18px;
80
+ height: 18px;
81
+ top: 2px;
82
+ right: 2px;
83
+ -webkit-transition: all .15s ease;
84
+ transition: all .15s ease;
85
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
86
+ }
87
+ .wcf-ca-switch[wcf-ca-template-switch="on"] {
88
+ box-shadow: inset 0 0 0 11px #008000;
89
+ }
90
+ .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
91
+ -webkit-transform: translateX(-16px);
92
+ transform: translateX(-16px);
93
+ }
94
+ .wcf-ca-switch[wcf-ca-template-switch="off"] {
95
+ background: #ccc;
96
+ }
97
+ .wcf-ca-switch.wcap-loading {
98
+ cursor: default;
99
+ opacity: 0.5;
100
+ }
101
+
102
+ .wcf-ca-trigger-input{
103
+ height: 28px;
104
+ width: 40%;
105
+ margin-left: 10px;
106
+ }
107
+
108
+ .wcf-ca-report-btn {
109
+ padding: 15px 0px 15px 0px;
110
+ display: flex;
111
+ width: 100%;
112
+ position: relative;
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
+ flex: 1;
133
+ margin-top: 0px;
134
+ }
135
+ .wcf-ca-right-report-field-group {
136
+ flex: 1;
137
+ text-align: left;
138
+
139
+ }
140
+ .wcf-search-orders{
141
+ display: inline-block;
142
+ }
143
+ .wcf_export_orders{
144
+ display: inline-block;
145
+ vertical-align: bottom;
146
+ padding-right: 5px;
147
+ }
148
+
149
+ .wcf-ca-report-table-row {
150
+ color: #636363;
151
+ border: 1px solid #e5e5e5;
152
+ }
153
+
154
+ /* Newly Added for the modification of the User Order detail window UI */
155
+
156
+ /* Column Classes */
157
+
158
+ .wcf-ca-column-one{
159
+ width: 100%;
160
+ }
161
+
162
+ .wcf-ca-column-two,
163
+ .wcf-ca-user-address{
164
+ width: 50%;
165
+ }
166
+
167
+ .wcf-pull-left{
168
+ float: right;
169
+ }
170
+ .wcf-ca-email-data,
171
+ .wcf-ca-user-detail{
172
+ border-radius: 3px;
173
+ padding: 20px 25px;
174
+ min-height: 330px;
175
+ max-height: 420px;
176
+ width: 100%;
177
+ overflow: auto;
178
+ }
179
+
180
+ .wcf-ca-user-detail{
181
+ max-height: 100%;
182
+ }
183
+
184
+ .wcf-ca-user-order{
185
+ border-radius: 3px;
186
+ padding: 25px 25px 30px 25px;
187
+ overflow: hidden;
188
+ height: auto;
189
+ width: 100%;
190
+ }
191
+
192
+ /* Column Classes */
193
+
194
+ /* Section classes */
195
+
196
+ .wcf-ca-margin-right{
197
+ margin-left: 13px;
198
+ }
199
+ .wcf-ca-margin-left{
200
+ margin-right: 13px;
201
+ }
202
+
203
+ .wcf-ca-column{
204
+ background-color: #fff;
205
+ border-radius: 3px;
206
+ display: flex;
207
+ }
208
+
209
+ /* Section Classes */
210
+
211
+
212
+ .wcf-ca-right-report-field-group .back-button{
213
+ height: auto;
214
+ padding: 3px 5px 3px 10px;
215
+ }
216
+
217
+ .wcf-ca-left-report-field-group .back-button .dashicons{
218
+ vertical-align: middle;
219
+ }
220
+
221
+ .wcf-ca-panel{
222
+ cursor: default;
223
+ /*background-color: #fff;*/
224
+ border-radius: 5px;
225
+ display: flex;
226
+ padding: 0px;
227
+ margin: 10px 0 25px;
228
+ }
229
+
230
+ .wcf-table{
231
+ border: none;
232
+ text-align: right;
233
+ width: 100%;
234
+ }
235
+ .wcf-table tr,
236
+ .wcf-table tr th,
237
+ .wcf-table tr td{
238
+ border: none;
239
+ }
240
+
241
+ .wcf-table tr th a,
242
+ .wcf-table tr td a{
243
+ text-decoration: none;
244
+ cursor: pointer;
245
+ }
246
+
247
+ .wcf-table tr th{
248
+ vertical-align: bottom;
249
+ border-bottom: 2px solid #ddd;
250
+ }
251
+
252
+ .wcf-table tr td{
253
+ border-bottom: 1px solid #ddd;
254
+ line-height: 1.42857143;
255
+ vertical-align: top;
256
+ position: relative;
257
+ }
258
+
259
+ .wcf-ca-panel h2{
260
+ margin: 0;
261
+ font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
262
+ font-size: 21px;
263
+ font-weight: 400;
264
+ line-height: 1.2;
265
+ text-shadow: -1px 1px 1px #fff;
266
+ padding: 10px 0 15px;
267
+ margin: 0;
268
+ }
269
+
270
+ .wcf-ca-user-order table{
271
+ width: 100%;
272
+ }
273
+
274
+ .wcf-ca-user-order table thead th{
275
+ text-align: center;
276
+ padding: 1em 3em;
277
+ font-weight: 400;
278
+ color: #999;
279
+ /*background: #f8f8f8;*/
280
+ -webkit-touch-callout: none;
281
+ -webkit-user-select: none;
282
+ -moz-user-select: none;
283
+ -ms-user-select: none;
284
+ user-select: none;
285
+ }
286
+
287
+ .wcf-ca-user-order table thead th:first-of-type{
288
+ padding-right: 3.6em;
289
+ text-align: right;
290
+ }
291
+
292
+ .wcf-ca-user-order table tbody tr td {
293
+ text-align: center;
294
+ padding: 1em 3em;
295
+ vertical-align: middle;
296
+ }
297
+
298
+ .wcf-ca-user-order table tbody tr td:first-of-type{
299
+ text-align: right;
300
+ /*width: 38px;*/
301
+ padding-right: 3em;
302
+ }
303
+
304
+
305
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
306
+ .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
307
+ .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
308
+ .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
309
+ text-align: left;
310
+ font-weight: 600;
311
+ width: 82%;
312
+ }
313
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
314
+ border-top: 1px solid #ccc;
315
+ }
316
+
317
+ .wcf-ca-tooltip-text.display_tool_tip{
318
+ display: block;
319
+ }
320
+
321
+ .wcf-ca-tooltip-text::before {
322
+ border-right: 5px solid transparent;
323
+ border-left: 5px solid transparent;
324
+ border-top: 5px solid transparent;
325
+ border-bottom: 5px solid #444;
326
+ bottom: auto;
327
+ content: " ";
328
+ font-size: 0;
329
+ right: 25px;
330
+ line-height: 0;
331
+ margin-right: -5px;
332
+ position: absolute;
333
+ top: -10px;
334
+ width: 0;
335
+ }
336
+
337
+ .wcf-ca-tooltip-text {
338
+ background: #444;
339
+ border-radius: 3px;
340
+ color: #fff;
341
+ height: auto;
342
+ right: 0;
343
+ margin-top: 10px;
344
+ max-width: 150px;
345
+ position: absolute;
346
+ padding: 6px 10px;
347
+ width: 100%;
348
+ display: none;
349
+ z-index: 10000;
350
+ }
351
+ /* Newly Added for the modification of the User Order detail window UI */
352
+
353
+
354
+
355
+ .wcf-ca-tags {
356
+ list-style: none;
357
+ margin: 0;
358
+ overflow: hidden;
359
+ padding: 0;
360
+ }
361
+
362
+ .wcf-ca-tags li {
363
+ float: right;
364
+ }
365
+
366
+ .wcf-ca-tag {
367
+ background-color: #f16334;
368
+ border-radius: 0 3px 3px 0;
369
+ color: #fff;
370
+ display: inline-block;
371
+ height: 26px;
372
+ line-height: 26px;
373
+ padding: 0 23px 0 20px;
374
+ position: relative;
375
+ margin: 0 0 0px 5px;
376
+ text-decoration: none;
377
+ -webkit-transition: color 0.2s;
378
+ }
379
+
380
+ .wcf-ca-tag::before {
381
+ background: #fff;
382
+ border-radius: 10px;
383
+ box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
384
+ content: '';
385
+ height: 6px;
386
+ right: 10px;
387
+ position: absolute;
388
+ width: 6px;
389
+ top: 10px;
390
+ }
391
+
392
+ .wcf-ca-tag::after {
393
+ background: #fff;
394
+ border-bottom: 13px solid transparent;
395
+ border-right: 10px solid #f16334;;
396
+ border-top: 13px solid transparent;
397
+ content: '';
398
+ position: absolute;
399
+ left: 0;
400
+ top: 0;
401
+ }
402
+
403
+ .wcf-ca-tag:hover {
404
+ background-color: #f16334;
405
+ color: white;
406
+ }
407
+
408
+ .wcf-ca-tag:hover::after {
409
+ border-right-color: #f16334;
410
+ }
411
+
412
+ .wcf-sub-heading {
413
+ font-weight: 400;
414
+ }
415
+
416
+ .wcf-ca-spinner{
417
+ float:unset;
418
+ }
419
+
420
+ .wcf-ca-response-msg{
421
+ vertical-align: sub;
422
+ line-height: 28px;
423
+ margin-right: 10px;
424
+ font-weight: bold;
425
+ }
426
+
427
+ .wcf-ca-export-icon{
428
+ line-height: 1.8;
429
+ font-size:17px;
430
+ }
admin/assets/css/admin-cart-abandonment.css CHANGED
@@ -1,430 +1,430 @@
1
- .wcf-ca-ibox {
2
- clear: both;
3
- margin-bottom: 25px;
4
- margin-top: 0;
5
- padding: 0;
6
- }
7
-
8
- .wcf-ca-ibox-title {
9
- background-color: white;
10
- border-image: none;
11
- border-width: 3px 0px 0;
12
- color: inherit;
13
- margin-bottom: 0;
14
- padding: 14px 15px 7px;
15
- min-height: 48px;
16
- }
17
-
18
- .wcf-ca-ibox-content {
19
- background-color: white;
20
- color: inherit;
21
- padding: 15px 20px 20px 20px;
22
- border-color: #d7dadc;
23
- border-image: none;
24
- border-style: solid solid none;
25
- border-width: 1px 0px;
26
- }
27
-
28
- .wcf-ca-raw {
29
- margin-left: -15px;
30
- margin-right: -15px;
31
- }
32
-
33
- .wcf-ca-grid-container {
34
- display: grid;
35
- grid-template-columns: 1fr 1fr 1fr;
36
- grid-gap: 20px;
37
- }
38
-
39
- .grid-container > div {
40
- background-color: rgba(255, 255, 255, 0.8);
41
- text-align: center;
42
- padding: 20px 0;
43
- font-size: 30px;
44
- }
45
-
46
-
47
- .wcf-ca-center-msg {
48
- margin: auto;
49
- width: 50%;
50
- padding: 10px;
51
- margin-top: 20px;
52
- text-align: center;
53
- }
54
-
55
-
56
- .wcf-ca-switch {
57
- cursor: pointer;
58
- text-indent: -999em;
59
- display: block;
60
- width: 38px;
61
- height: 22px;
62
- border-radius: 30px;
63
- border: none;
64
- position: relative;
65
- box-sizing: border-box;
66
- -webkit-transition: all .3s ease;
67
- transition: all .3s ease;
68
- box-shadow: inset 0 0 0 0 transparent;
69
- }
70
- .wcf-ca-switch:focus {
71
- outline: none;
72
- }
73
- .wcf-ca-switch:before {
74
- border-radius: 50%;
75
- background: #ffffff;
76
- content: '';
77
- position: absolute;
78
- display: block;
79
- width: 18px;
80
- height: 18px;
81
- top: 2px;
82
- left: 2px;
83
- -webkit-transition: all .15s ease;
84
- transition: all .15s ease;
85
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
86
- }
87
- .wcf-ca-switch[wcf-ca-template-switch="on"] {
88
- box-shadow: inset 0 0 0 11px #008000;
89
- }
90
- .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
91
- -webkit-transform: translateX(16px);
92
- transform: translateX(16px);
93
- }
94
- .wcf-ca-switch[wcf-ca-template-switch="off"] {
95
- background: #ccc;
96
- }
97
- .wcf-ca-switch.wcap-loading {
98
- cursor: default;
99
- opacity: 0.5;
100
- }
101
-
102
- .wcf-ca-trigger-input{
103
- height: 28px;
104
- width: 40%;
105
- margin-right: 10px;
106
- }
107
-
108
- .wcf-ca-report-btn {
109
- padding: 15px 0px 15px 0px;
110
- display: flex;
111
- width: 100%;
112
- position: relative;
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
- flex: 1;
133
- margin-top: 0px;
134
- }
135
- .wcf-ca-right-report-field-group {
136
- flex: 1;
137
- text-align: right;
138
-
139
- }
140
- .wcf-search-orders{
141
- display: inline-block;
142
- }
143
- .wcf_export_orders{
144
- display: inline-block;
145
- vertical-align: bottom;
146
- padding-left: 5px;
147
- }
148
-
149
- .wcf-ca-report-table-row {
150
- color: #636363;
151
- border: 1px solid #e5e5e5;
152
- }
153
-
154
- /* Newly Added for the modification of the User Order detail window UI */
155
-
156
- /* Column Classes */
157
-
158
- .wcf-ca-column-one{
159
- width: 100%;
160
- }
161
-
162
- .wcf-ca-column-two,
163
- .wcf-ca-user-address{
164
- width: 50%;
165
- }
166
-
167
- .wcf-pull-left{
168
- float: left;
169
- }
170
- .wcf-ca-email-data,
171
- .wcf-ca-user-detail{
172
- border-radius: 3px;
173
- padding: 20px 25px;
174
- min-height: 330px;
175
- max-height: 420px;
176
- width: 100%;
177
- overflow: auto;
178
- }
179
-
180
- .wcf-ca-user-detail{
181
- max-height: 100%;
182
- }
183
-
184
- .wcf-ca-user-order{
185
- border-radius: 3px;
186
- padding: 25px 25px 30px 25px;
187
- overflow: hidden;
188
- height: auto;
189
- width: 100%;
190
- }
191
-
192
- /* Column Classes */
193
-
194
- /* Section classes */
195
-
196
- .wcf-ca-margin-right{
197
- margin-right: 13px;
198
- }
199
- .wcf-ca-margin-left{
200
- margin-left: 13px;
201
- }
202
-
203
- .wcf-ca-column{
204
- background-color: #fff;
205
- border-radius: 3px;
206
- display: flex;
207
- }
208
-
209
- /* Section Classes */
210
-
211
-
212
- .wcf-ca-right-report-field-group .back-button{
213
- height: auto;
214
- padding: 3px 10px 3px 5px;
215
- }
216
-
217
- .wcf-ca-left-report-field-group .back-button .dashicons{
218
- vertical-align: middle;
219
- }
220
-
221
- .wcf-ca-panel{
222
- cursor: default;
223
- /*background-color: #fff;*/
224
- border-radius: 5px;
225
- display: flex;
226
- padding: 0px;
227
- margin: 10px 0 25px;
228
- }
229
-
230
- .wcf-table{
231
- border: none;
232
- text-align: left;
233
- width: 100%;
234
- }
235
- .wcf-table tr,
236
- .wcf-table tr th,
237
- .wcf-table tr td{
238
- border: none;
239
- }
240
-
241
- .wcf-table tr th a,
242
- .wcf-table tr td a{
243
- text-decoration: none;
244
- cursor: pointer;
245
- }
246
-
247
- .wcf-table tr th{
248
- vertical-align: bottom;
249
- border-bottom: 2px solid #ddd;
250
- }
251
-
252
- .wcf-table tr td{
253
- border-bottom: 1px solid #ddd;
254
- line-height: 1.42857143;
255
- vertical-align: top;
256
- position: relative;
257
- }
258
-
259
- .wcf-ca-panel h2{
260
- margin: 0;
261
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
262
- font-size: 21px;
263
- font-weight: 400;
264
- line-height: 1.2;
265
- text-shadow: 1px 1px 1px #fff;
266
- padding: 10px 0 15px;
267
- margin: 0;
268
- }
269
-
270
- .wcf-ca-user-order table{
271
- width: 100%;
272
- }
273
-
274
- .wcf-ca-user-order table thead th{
275
- text-align: center;
276
- padding: 1em 3em;
277
- font-weight: 400;
278
- color: #999;
279
- /*background: #f8f8f8;*/
280
- -webkit-touch-callout: none;
281
- -webkit-user-select: none;
282
- -moz-user-select: none;
283
- -ms-user-select: none;
284
- user-select: none;
285
- }
286
-
287
- .wcf-ca-user-order table thead th:first-of-type{
288
- padding-left: 3.6em;
289
- text-align: left;
290
- }
291
-
292
- .wcf-ca-user-order table tbody tr td {
293
- text-align: center;
294
- padding: 1em 3em;
295
- vertical-align: middle;
296
- }
297
-
298
- .wcf-ca-user-order table tbody tr td:first-of-type{
299
- text-align: left;
300
- /*width: 38px;*/
301
- padding-left: 3em;
302
- }
303
-
304
-
305
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
306
- .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
307
- .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
308
- .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
309
- text-align: right;
310
- font-weight: 600;
311
- width: 82%;
312
- }
313
- .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
314
- border-top: 1px solid #ccc;
315
- }
316
-
317
- .wcf-ca-tooltip-text.display_tool_tip{
318
- display: block;
319
- }
320
-
321
- .wcf-ca-tooltip-text::before {
322
- border-left: 5px solid transparent;
323
- border-right: 5px solid transparent;
324
- border-top: 5px solid transparent;
325
- border-bottom: 5px solid #444;
326
- bottom: auto;
327
- content: " ";
328
- font-size: 0;
329
- left: 25px;
330
- line-height: 0;
331
- margin-left: -5px;
332
- position: absolute;
333
- top: -10px;
334
- width: 0;
335
- }
336
-
337
- .wcf-ca-tooltip-text {
338
- background: #444;
339
- border-radius: 3px;
340
- color: #fff;
341
- height: auto;
342
- left: 0;
343
- margin-top: 10px;
344
- max-width: 150px;
345
- position: absolute;
346
- padding: 6px 10px;
347
- width: 100%;
348
- display: none;
349
- z-index: 10000;
350
- }
351
- /* Newly Added for the modification of the User Order detail window UI */
352
-
353
-
354
-
355
- .wcf-ca-tags {
356
- list-style: none;
357
- margin: 0;
358
- overflow: hidden;
359
- padding: 0;
360
- }
361
-
362
- .wcf-ca-tags li {
363
- float: left;
364
- }
365
-
366
- .wcf-ca-tag {
367
- background-color: #f16334;
368
- border-radius: 3px 0 0 3px;
369
- color: #fff;
370
- display: inline-block;
371
- height: 26px;
372
- line-height: 26px;
373
- padding: 0 20px 0 23px;
374
- position: relative;
375
- margin: 0 5px 0px 0;
376
- text-decoration: none;
377
- -webkit-transition: color 0.2s;
378
- }
379
-
380
- .wcf-ca-tag::before {
381
- background: #fff;
382
- border-radius: 10px;
383
- box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
384
- content: '';
385
- height: 6px;
386
- left: 10px;
387
- position: absolute;
388
- width: 6px;
389
- top: 10px;
390
- }
391
-
392
- .wcf-ca-tag::after {
393
- background: #fff;
394
- border-bottom: 13px solid transparent;
395
- border-left: 10px solid #f16334;;
396
- border-top: 13px solid transparent;
397
- content: '';
398
- position: absolute;
399
- right: 0;
400
- top: 0;
401
- }
402
-
403
- .wcf-ca-tag:hover {
404
- background-color: #f16334;
405
- color: white;
406
- }
407
-
408
- .wcf-ca-tag:hover::after {
409
- border-left-color: #f16334;
410
- }
411
-
412
- .wcf-sub-heading {
413
- font-weight: 400;
414
- }
415
-
416
- .wcf-ca-spinner{
417
- float:unset;
418
- }
419
-
420
- .wcf-ca-response-msg{
421
- vertical-align: sub;
422
- line-height: 28px;
423
- margin-left: 10px;
424
- font-weight: bold;
425
- }
426
-
427
- .wcf-ca-export-icon{
428
- line-height: 1.8;
429
- font-size:17px;
430
- }
1
+ .wcf-ca-ibox {
2
+ clear: both;
3
+ margin-bottom: 25px;
4
+ margin-top: 0;
5
+ padding: 0;
6
+ }
7
+
8
+ .wcf-ca-ibox-title {
9
+ background-color: white;
10
+ border-image: none;
11
+ border-width: 3px 0px 0;
12
+ color: inherit;
13
+ margin-bottom: 0;
14
+ padding: 14px 15px 7px;
15
+ min-height: 48px;
16
+ }
17
+
18
+ .wcf-ca-ibox-content {
19
+ background-color: white;
20
+ color: inherit;
21
+ padding: 15px 20px 20px 20px;
22
+ border-color: #d7dadc;
23
+ border-image: none;
24
+ border-style: solid solid none;
25
+ border-width: 1px 0px;
26
+ }
27
+
28
+ .wcf-ca-raw {
29
+ margin-left: -15px;
30
+ margin-right: -15px;
31
+ }
32
+
33
+ .wcf-ca-grid-container {
34
+ display: grid;
35
+ grid-template-columns: 1fr 1fr 1fr;
36
+ grid-gap: 20px;
37
+ }
38
+
39
+ .grid-container > div {
40
+ background-color: rgba(255, 255, 255, 0.8);
41
+ text-align: center;
42
+ padding: 20px 0;
43
+ font-size: 30px;
44
+ }
45
+
46
+
47
+ .wcf-ca-center-msg {
48
+ margin: auto;
49
+ width: 50%;
50
+ padding: 10px;
51
+ margin-top: 20px;
52
+ text-align: center;
53
+ }
54
+
55
+
56
+ .wcf-ca-switch {
57
+ cursor: pointer;
58
+ text-indent: -999em;
59
+ display: block;
60
+ width: 38px;
61
+ height: 22px;
62
+ border-radius: 30px;
63
+ border: none;
64
+ position: relative;
65
+ box-sizing: border-box;
66
+ -webkit-transition: all .3s ease;
67
+ transition: all .3s ease;
68
+ box-shadow: inset 0 0 0 0 transparent;
69
+ }
70
+ .wcf-ca-switch:focus {
71
+ outline: none;
72
+ }
73
+ .wcf-ca-switch:before {
74
+ border-radius: 50%;
75
+ background: #ffffff;
76
+ content: '';
77
+ position: absolute;
78
+ display: block;
79
+ width: 18px;
80
+ height: 18px;
81
+ top: 2px;
82
+ left: 2px;
83
+ -webkit-transition: all .15s ease;
84
+ transition: all .15s ease;
85
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
86
+ }
87
+ .wcf-ca-switch[wcf-ca-template-switch="on"] {
88
+ box-shadow: inset 0 0 0 11px #008000;
89
+ }
90
+ .wcf-ca-switch[wcf-ca-template-switch="on"]:before {
91
+ -webkit-transform: translateX(16px);
92
+ transform: translateX(16px);
93
+ }
94
+ .wcf-ca-switch[wcf-ca-template-switch="off"] {
95
+ background: #ccc;
96
+ }
97
+ .wcf-ca-switch.wcap-loading {
98
+ cursor: default;
99
+ opacity: 0.5;
100
+ }
101
+
102
+ .wcf-ca-trigger-input{
103
+ height: 28px;
104
+ width: 40%;
105
+ margin-right: 10px;
106
+ }
107
+
108
+ .wcf-ca-report-btn {
109
+ padding: 15px 0px 15px 0px;
110
+ display: flex;
111
+ width: 100%;
112
+ position: relative;
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
+ flex: 1;
133
+ margin-top: 0px;
134
+ }
135
+ .wcf-ca-right-report-field-group {
136
+ flex: 1;
137
+ text-align: right;
138
+
139
+ }
140
+ .wcf-search-orders{
141
+ display: inline-block;
142
+ }
143
+ .wcf_export_orders{
144
+ display: inline-block;
145
+ vertical-align: bottom;
146
+ padding-left: 5px;
147
+ }
148
+
149
+ .wcf-ca-report-table-row {
150
+ color: #636363;
151
+ border: 1px solid #e5e5e5;
152
+ }
153
+
154
+ /* Newly Added for the modification of the User Order detail window UI */
155
+
156
+ /* Column Classes */
157
+
158
+ .wcf-ca-column-one{
159
+ width: 100%;
160
+ }
161
+
162
+ .wcf-ca-column-two,
163
+ .wcf-ca-user-address{
164
+ width: 50%;
165
+ }
166
+
167
+ .wcf-pull-left{
168
+ float: left;
169
+ }
170
+ .wcf-ca-email-data,
171
+ .wcf-ca-user-detail{
172
+ border-radius: 3px;
173
+ padding: 20px 25px;
174
+ min-height: 330px;
175
+ max-height: 420px;
176
+ width: 100%;
177
+ overflow: auto;
178
+ }
179
+
180
+ .wcf-ca-user-detail{
181
+ max-height: 100%;
182
+ }
183
+
184
+ .wcf-ca-user-order{
185
+ border-radius: 3px;
186
+ padding: 25px 25px 30px 25px;
187
+ overflow: hidden;
188
+ height: auto;
189
+ width: 100%;
190
+ }
191
+
192
+ /* Column Classes */
193
+
194
+ /* Section classes */
195
+
196
+ .wcf-ca-margin-right{
197
+ margin-right: 13px;
198
+ }
199
+ .wcf-ca-margin-left{
200
+ margin-left: 13px;
201
+ }
202
+
203
+ .wcf-ca-column{
204
+ background-color: #fff;
205
+ border-radius: 3px;
206
+ display: flex;
207
+ }
208
+
209
+ /* Section Classes */
210
+
211
+
212
+ .wcf-ca-right-report-field-group .back-button{
213
+ height: auto;
214
+ padding: 3px 10px 3px 5px;
215
+ }
216
+
217
+ .wcf-ca-left-report-field-group .back-button .dashicons{
218
+ vertical-align: middle;
219
+ }
220
+
221
+ .wcf-ca-panel{
222
+ cursor: default;
223
+ /*background-color: #fff;*/
224
+ border-radius: 5px;
225
+ display: flex;
226
+ padding: 0px;
227
+ margin: 10px 0 25px;
228
+ }
229
+
230
+ .wcf-table{
231
+ border: none;
232
+ text-align: left;
233
+ width: 100%;
234
+ }
235
+ .wcf-table tr,
236
+ .wcf-table tr th,
237
+ .wcf-table tr td{
238
+ border: none;
239
+ }
240
+
241
+ .wcf-table tr th a,
242
+ .wcf-table tr td a{
243
+ text-decoration: none;
244
+ cursor: pointer;
245
+ }
246
+
247
+ .wcf-table tr th{
248
+ vertical-align: bottom;
249
+ border-bottom: 2px solid #ddd;
250
+ }
251
+
252
+ .wcf-table tr td{
253
+ border-bottom: 1px solid #ddd;
254
+ line-height: 1.42857143;
255
+ vertical-align: top;
256
+ position: relative;
257
+ }
258
+
259
+ .wcf-ca-panel h2{
260
+ margin: 0;
261
+ font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
262
+ font-size: 21px;
263
+ font-weight: 400;
264
+ line-height: 1.2;
265
+ text-shadow: 1px 1px 1px #fff;
266
+ padding: 10px 0 15px;
267
+ margin: 0;
268
+ }
269
+
270
+ .wcf-ca-user-order table{
271
+ width: 100%;
272
+ }
273
+
274
+ .wcf-ca-user-order table thead th{
275
+ text-align: center;
276
+ padding: 1em 3em;
277
+ font-weight: 400;
278
+ color: #999;
279
+ /*background: #f8f8f8;*/
280
+ -webkit-touch-callout: none;
281
+ -webkit-user-select: none;
282
+ -moz-user-select: none;
283
+ -ms-user-select: none;
284
+ user-select: none;
285
+ }
286
+
287
+ .wcf-ca-user-order table thead th:first-of-type{
288
+ padding-left: 3.6em;
289
+ text-align: left;
290
+ }
291
+
292
+ .wcf-ca-user-order table tbody tr td {
293
+ text-align: center;
294
+ padding: 1em 3em;
295
+ vertical-align: middle;
296
+ }
297
+
298
+ .wcf-ca-user-order table tbody tr td:first-of-type{
299
+ text-align: left;
300
+ /*width: 38px;*/
301
+ padding-left: 3em;
302
+ }
303
+
304
+
305
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td:first-of-type,
306
+ .wcf-ca-user-order table tbody tr#wcf-ca-other td:first-of-type,
307
+ .wcf-ca-user-order table tbody tr#wcf-ca-shipping td:first-of-type,
308
+ .wcf-ca-user-order table tbody tr#wcf-ca-cart-total td:first-of-type {
309
+ text-align: right;
310
+ font-weight: 600;
311
+ width: 82%;
312
+ }
313
+ .wcf-ca-user-order table tbody tr#wcf-ca-discount td {
314
+ border-top: 1px solid #ccc;
315
+ }
316
+
317
+ .wcf-ca-tooltip-text.display_tool_tip{
318
+ display: block;
319
+ }
320
+
321
+ .wcf-ca-tooltip-text::before {
322
+ border-left: 5px solid transparent;
323
+ border-right: 5px solid transparent;
324
+ border-top: 5px solid transparent;
325
+ border-bottom: 5px solid #444;
326
+ bottom: auto;
327
+ content: " ";
328
+ font-size: 0;
329
+ left: 25px;
330
+ line-height: 0;
331
+ margin-left: -5px;
332
+ position: absolute;
333
+ top: -10px;
334
+ width: 0;
335
+ }
336
+
337
+ .wcf-ca-tooltip-text {
338
+ background: #444;
339
+ border-radius: 3px;
340
+ color: #fff;
341
+ height: auto;
342
+ left: 0;
343
+ margin-top: 10px;
344
+ max-width: 150px;
345
+ position: absolute;
346
+ padding: 6px 10px;
347
+ width: 100%;
348
+ display: none;
349
+ z-index: 10000;
350
+ }
351
+ /* Newly Added for the modification of the User Order detail window UI */
352
+
353
+
354
+
355
+ .wcf-ca-tags {
356
+ list-style: none;
357
+ margin: 0;
358
+ overflow: hidden;
359
+ padding: 0;
360
+ }
361
+
362
+ .wcf-ca-tags li {
363
+ float: left;
364
+ }
365
+
366
+ .wcf-ca-tag {
367
+ background-color: #f16334;
368
+ border-radius: 3px 0 0 3px;
369
+ color: #fff;
370
+ display: inline-block;
371
+ height: 26px;
372
+ line-height: 26px;
373
+ padding: 0 20px 0 23px;
374
+ position: relative;
375
+ margin: 0 5px 0px 0;
376
+ text-decoration: none;
377
+ -webkit-transition: color 0.2s;
378
+ }
379
+
380
+ .wcf-ca-tag::before {
381
+ background: #fff;
382
+ border-radius: 10px;
383
+ box-shadow: inset 0 1px rgba(0, 0, 0, 0.25);
384
+ content: '';
385
+ height: 6px;
386
+ left: 10px;
387
+ position: absolute;
388
+ width: 6px;
389
+ top: 10px;
390
+ }
391
+
392
+ .wcf-ca-tag::after {
393
+ background: #fff;
394
+ border-bottom: 13px solid transparent;
395
+ border-left: 10px solid #f16334;;
396
+ border-top: 13px solid transparent;
397
+ content: '';
398
+ position: absolute;
399
+ right: 0;
400
+ top: 0;
401
+ }
402
+
403
+ .wcf-ca-tag:hover {
404
+ background-color: #f16334;
405
+ color: white;
406
+ }
407
+
408
+ .wcf-ca-tag:hover::after {
409
+ border-left-color: #f16334;
410
+ }
411
+
412
+ .wcf-sub-heading {
413
+ font-weight: 400;
414
+ }
415
+
416
+ .wcf-ca-spinner{
417
+ float:unset;
418
+ }
419
+
420
+ .wcf-ca-response-msg{
421
+ vertical-align: sub;
422
+ line-height: 28px;
423
+ margin-left: 10px;
424
+ font-weight: bold;
425
+ }
426
+
427
+ .wcf-ca-export-icon{
428
+ line-height: 1.8;
429
+ font-size:17px;
430
+ }
admin/assets/js/admin-email-templates.js CHANGED
@@ -1,303 +1,303 @@
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
- $("#wcf_search_id_submit").click( function () {
33
- var search = $("#wcf_search_id_search_input").val().trim();
34
- window.location.href = window.location.search + "&search_term=" + search;
35
- } );
36
-
37
- // Hide initially.
38
- $("#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();
39
-
40
-
41
- if( $("#wcf_ca_gdpr_status:checked").length ) {
42
- $("#wcf_ca_gdpr_message").closest('tr').show();
43
- }
44
-
45
- if ($("#wcf_ca_zapier_tracking_status:checked").length) {
46
- $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').show();
47
- }
48
-
49
- if ( $("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length ) {
50
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').show();
51
- }
52
-
53
- $("#wcf_ca_coupon_code_status").click(
54
- function () {
55
- if (!$("#wcf_ca_coupon_code_status:checked").length) {
56
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
57
- } else {
58
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
59
- }
60
- }
61
- );
62
-
63
- $("#wcf_ca_gdpr_status").click(
64
- function () {
65
- if (!$("#wcf_ca_gdpr_status:checked").length) {
66
- $("#wcf_ca_gdpr_message").closest('tr').fadeOut();
67
- } else {
68
- $("#wcf_ca_gdpr_message").closest('tr').fadeIn();
69
- }
70
- }
71
- );
72
-
73
- $("#wcf_ca_zapier_tracking_status").click(
74
- function () {
75
- if (!$("#wcf_ca_zapier_tracking_status:checked").length) {
76
- $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeOut();
77
- } else {
78
- $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeIn();
79
- }
80
-
81
- if ($("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length) {
82
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
83
- } else {
84
- $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
85
- }
86
- }
87
- );
88
-
89
- }
90
- }
91
-
92
-
93
- EmailTemplatesAdmin = {
94
-
95
-
96
- init: function () {
97
-
98
- $(document).on('click', '#wcf_preview_email', EmailTemplatesAdmin.send_test_email);
99
- $(document).on('click', '.wcf-ca-switch.wcf-toggle-template-status', EmailTemplatesAdmin.toggle_activate_template);
100
- $(document).on('click', '#wcf_ca_delete_coupons', EmailTemplatesAdmin.delete_coupons);
101
- $(document).on('click', '#wcf_ca_export_orders', EmailTemplatesAdmin.export_orders);
102
- $(document).on('click', '.wcar-switch-grid', EmailTemplatesAdmin.toggle_activate_template_on_grid);
103
- var coupon_child_fields = "#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date, #wcf_free_shipping_coupon, #wcf_auto_coupon_apply, #wcf_individual_use_only";
104
- $(coupon_child_fields).closest('tr').toggle($("#wcf_override_global_coupon").is(":checked"));
105
- $(document).on('click', '#wcf_override_global_coupon', function () {
106
- $(coupon_child_fields).closest('tr').fadeToggle($("#wcf_override_global_coupon").is(":checked"));
107
- });
108
- },
109
-
110
- send_test_email: function () {
111
-
112
- var email_body = '';
113
- if (jQuery("#wp-wcf_email_body-wrap").hasClass("tmce-active")) {
114
- email_body = tinyMCE.get('wcf_email_body').getContent();
115
- } else {
116
- email_body = jQuery('#wcf_email_body').val();
117
- }
118
-
119
- var email_subject = $('#wcf_email_subject').val();
120
- var email_send_to = $('#wcf_send_test_email').val();
121
- var wp_nonce = $("#_wpnonce").val();
122
-
123
- $(this).next('div.error').remove();
124
-
125
- if (!$.trim(email_body)) {
126
- $(this).after('<div class="error-message wcf-ca-error-msg"> Email body is required! </div>');
127
- } else if (!$.trim(email_subject)) {
128
- $(this).after('<div class="error-message wcf-ca-error-msg"> Email subject is required! </div>');
129
- } else if (!$.trim(email_send_to)) {
130
- $(this).after('<div class="error-message wcf-ca-error-msg"> You must add your email id! </div>');
131
- }
132
- else {
133
-
134
- var data = {
135
- email_subject: email_subject,
136
- email_body: email_body,
137
- email_send_to: email_send_to,
138
- action: 'wcf_ca_preview_email_send',
139
- security: wp_nonce,
140
- };
141
- $("#wcf_preview_email").css('cursor', 'wait').attr("disabled", true);
142
-
143
- // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
144
- $.post(
145
- ajaxurl, data, function (response) {
146
- $("#mail_response_msg").empty().fadeIn();;
147
-
148
- if (response.success) {
149
- var htmlString = "<strong> Email has been sent successfully! </strong>";
150
- $("#mail_response_msg").css('color','green').html(htmlString).delay(3000).fadeOut();
151
-
152
- } else {
153
- var htmlString = "<strong> Email sending failed! Please check your <a href='"+ CAEmailTemplate.settings_url +"'> email settings! </a></strong>"
154
- $("#mail_response_msg").css('color','red').html(htmlString).delay(3000).fadeOut();;
155
- }
156
- $("#wcf_preview_email").css('cursor', '').attr("disabled", false);
157
-
158
- }
159
- );
160
- }
161
-
162
- $(".wcf-ca-error-msg").delay(2000).fadeOut();
163
- },
164
-
165
- delete_coupons: function () {
166
- if (confirm(wcf_ca_localized_vars._confirm_msg)) {
167
- var data = {
168
- action: 'wcf_ca_delete_garbage_coupons',
169
- security: wcf_ca_localized_vars._delete_coupon_nonce
170
- };
171
- $('.wcf-ca-spinner').show();
172
-
173
- $('.wcf-ca-spinner').addClass("is-active");
174
- $("#wcf_ca_delete_coupons").css('cursor', 'wait').attr("disabled", true);
175
- $.post(
176
- ajaxurl, data, function (response) {
177
- $(".wcf-ca-response-msg").empty().fadeIn();;
178
- if (response.success) {
179
- $('.wcf-ca-spinner').hide();
180
- $(".wcf-ca-response-msg").css('color','green').html(response.data).delay(5000).fadeOut();
181
- }
182
-
183
- $("#wcf_ca_delete_coupons").css('cursor', '').attr("disabled", false);
184
- }
185
- );
186
- }
187
- },
188
- export_orders: function () {
189
- if( confirm( wcf_ca_localized_vars._confirm_msg_export ) ) {
190
- window.location.href = window.location.search + "&export_data=true";
191
- }
192
- },
193
- toggle_activate_template_on_grid: function () {
194
- var $switch, state, new_state;
195
- $switch = $(this);
196
- state = $switch.attr('wcf-ca-template-switch');
197
- var css = (state === 'on') ? 'green' : 'red';
198
-
199
- $.post(
200
- ajaxurl, {
201
- action: 'activate_email_templates',
202
- id: $(this).attr('id'),
203
- state: state,
204
- security: wcf_ca_details.email_toggle_button_nonce
205
- }, function (response) {
206
-
207
- $("#wcf_activate_email_template").val(new_state == 'on' ? 1 : 0);
208
-
209
- $(".wcar_tmpl_response_msg").remove();
210
-
211
- $("<span class='wcar_tmpl_response_msg'> " + response.data + " </span>").insertAfter($switch).delay(2000).fadeOut().css('color', css);
212
-
213
- }
214
- );
215
- },
216
-
217
-
218
- toggle_activate_template: function () {
219
- var $switch, state, new_state;
220
- $switch = $(this);
221
- state = $switch.attr('wcf-ca-template-switch');
222
- new_state = state === 'on' ? 'off' : 'on';
223
- $("#wcf_activate_email_template").val(new_state == 'on' ? 1 : 0);
224
- $switch.attr('wcf-ca-template-switch', new_state);
225
- }
226
- }
227
-
228
- ZapierSettings = {
229
- init: function () {
230
-
231
- $(document).delegate("#wcf_ca_trigger_web_hook_abandoned_btn", "click",
232
- { 'order_status': 'abandoned' },
233
- ZapierSettings.zapier_trigger_sample);
234
- },
235
- zapier_trigger_sample: function( event ) {
236
-
237
- var zapier_webhook_url = $("#wcf_ca_zapier_cart_"+ event.data.order_status +"_webhook").val().trim();
238
-
239
- if ( ! zapier_webhook_url.length ) {
240
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Webhook URL is required.").fadeIn().css('color', '#dc3232').delay(2000).fadeOut();
241
- return;
242
- }
243
-
244
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Triggering...").fadeIn();
245
-
246
- var now = new Date();
247
- var datetime = now.getFullYear()+'/'+(now.getMonth()+1)+'/'+now.getDate();
248
- datetime += ' '+now.getHours()+':'+now.getMinutes()+':'+now.getSeconds();
249
- if ($.trim(zapier_webhook_url) !== "") {
250
- var sample_data = {
251
- "first_name": wcf_ca_details.name,
252
- "last_name": wcf_ca_details.surname,
253
- "email": wcf_ca_details.email,
254
- "order_status": event.data.order_status,
255
- "checkout_url": window.location.origin + "/checkout/?wcf_ac_token=something",
256
- "coupon_code": "abcgefgh",
257
- "product_names": "Product1, Product2 & Product3",
258
- "cart_total": wcf_ca_details.woo_currency_symbol + "20",
259
- "product_table": '<table align= left; cellpadding="10" cellspacing="0" style="float: none; border: 1px solid #e5e5e5;"> <tr align="center"> <th style="color: #636363; border: 1px solid #e5e5e5;">Item</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Name</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Quantity</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Price</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Line Subtotal</th> </tr> <tr style=color: #636363; border: 1px solid #e5e5e5; align="center"> <td style="color: #636363; border: 1px solid #e5e5e5;"><img class="demo_img" style="height: 42px; width: 42px;" src="http://localhost/wp-local/wp-content/uploads/2019/11/wGdyS_Zgz1A.jpg"></td> <td style="color: #636363; border: 1px solid #e5e5e5;">Product1</td> <td style="color: #636363; border: 1px solid #e5e5e5;"> 1 </td> <td style="color: #636363; border: 1px solid #e5e5e5;">&pound;85.00</td> <td style="color: #636363; border: 1px solid #e5e5e5;" >&pound;85.00</td> </tr> </table>'
260
- };
261
- $.ajax({
262
- url: zapier_webhook_url,
263
- type: 'POST',
264
- data: sample_data,
265
- success: function(data) {
266
- if (data.status == "success") {
267
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Success!").css('color', '#46b450');
268
- } else {
269
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
270
- }
271
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").fadeIn().delay(2000).fadeOut();
272
- },
273
- error: function() {
274
- $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
275
- }
276
- });
277
- } else {
278
- $("wcf_ca"+ event.data.order_status +"_btn_message").text("Please verify webhook URL.").fadeIn().delay(2000).fadeOut();;
279
- }
280
- },
281
- }
282
-
283
- ToolTipHover = {
284
- init: function () {
285
-
286
- $(".wcf-ca-report-table-row .wcf-ca-icon-row").hover(function(){
287
- $(this).find('.wcf-ca-tooltip-text').toggleClass("display_tool_tip");
288
- });
289
- },
290
- }
291
-
292
- $(document).ready(
293
- function () {
294
- EmailTemplatesAdmin.init();
295
- CartAbandonmentSettings.init();
296
- ZapierSettings.init();
297
-
298
- ToolTipHover.init();
299
- }
300
- );
301
-
302
-
303
  })(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
+ $("#wcf_search_id_submit").click( function () {
33
+ var search = $("#wcf_search_id_search_input").val().trim();
34
+ window.location.href = window.location.search + "&search_term=" + search;
35
+ } );
36
+
37
+ // Hide initially.
38
+ $("#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();
39
+
40
+
41
+ if( $("#wcf_ca_gdpr_status:checked").length ) {
42
+ $("#wcf_ca_gdpr_message").closest('tr').show();
43
+ }
44
+
45
+ if ($("#wcf_ca_zapier_tracking_status:checked").length) {
46
+ $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').show();
47
+ }
48
+
49
+ if ( $("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length ) {
50
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').show();
51
+ }
52
+
53
+ $("#wcf_ca_coupon_code_status").click(
54
+ function () {
55
+ if (!$("#wcf_ca_coupon_code_status:checked").length) {
56
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
57
+ } else {
58
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
59
+ }
60
+ }
61
+ );
62
+
63
+ $("#wcf_ca_gdpr_status").click(
64
+ function () {
65
+ if (!$("#wcf_ca_gdpr_status:checked").length) {
66
+ $("#wcf_ca_gdpr_message").closest('tr').fadeOut();
67
+ } else {
68
+ $("#wcf_ca_gdpr_message").closest('tr').fadeIn();
69
+ }
70
+ }
71
+ );
72
+
73
+ $("#wcf_ca_zapier_tracking_status").click(
74
+ function () {
75
+ if (!$("#wcf_ca_zapier_tracking_status:checked").length) {
76
+ $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeOut();
77
+ } else {
78
+ $("#wcf_ca_zapier_cart_abandoned_webhook, #wcf_ca_coupon_code_status").closest('tr').fadeIn();
79
+ }
80
+
81
+ if ($("#wcf_ca_coupon_code_status:checked").length && $("#wcf_ca_zapier_tracking_status:checked").length) {
82
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeIn();
83
+ } else {
84
+ $("#wcf_ca_discount_type, #wcf_ca_coupon_amount, #wcf_ca_coupon_expiry").closest('tr').fadeOut();
85
+ }
86
+ }
87
+ );
88
+
89
+ }
90
+ }
91
+
92
+
93
+ EmailTemplatesAdmin = {
94
+
95
+
96
+ init: function () {
97
+
98
+ $(document).on('click', '#wcf_preview_email', EmailTemplatesAdmin.send_test_email);
99
+ $(document).on('click', '.wcf-ca-switch.wcf-toggle-template-status', EmailTemplatesAdmin.toggle_activate_template);
100
+ $(document).on('click', '#wcf_ca_delete_coupons', EmailTemplatesAdmin.delete_coupons);
101
+ $(document).on('click', '#wcf_ca_export_orders', EmailTemplatesAdmin.export_orders);
102
+ $(document).on('click', '.wcar-switch-grid', EmailTemplatesAdmin.toggle_activate_template_on_grid);
103
+ var coupon_child_fields = "#wcf_email_discount_type, #wcf_email_discount_amount, #wcf_email_coupon_expiry_date, #wcf_free_shipping_coupon, #wcf_auto_coupon_apply, #wcf_individual_use_only";
104
+ $(coupon_child_fields).closest('tr').toggle($("#wcf_override_global_coupon").is(":checked"));
105
+ $(document).on('click', '#wcf_override_global_coupon', function () {
106
+ $(coupon_child_fields).closest('tr').fadeToggle($("#wcf_override_global_coupon").is(":checked"));
107
+ });
108
+ },
109
+
110
+ send_test_email: function () {
111
+
112
+ var email_body = '';
113
+ if (jQuery("#wp-wcf_email_body-wrap").hasClass("tmce-active")) {
114
+ email_body = tinyMCE.get('wcf_email_body').getContent();
115
+ } else {
116
+ email_body = jQuery('#wcf_email_body').val();
117
+ }
118
+
119
+ var email_subject = $('#wcf_email_subject').val();
120
+ var email_send_to = $('#wcf_send_test_email').val();
121
+ var wp_nonce = $("#_wpnonce").val();
122
+
123
+ $(this).next('div.error').remove();
124
+
125
+ if (!$.trim(email_body)) {
126
+ $(this).after('<div class="error-message wcf-ca-error-msg"> Email body is required! </div>');
127
+ } else if (!$.trim(email_subject)) {
128
+ $(this).after('<div class="error-message wcf-ca-error-msg"> Email subject is required! </div>');
129
+ } else if (!$.trim(email_send_to)) {
130
+ $(this).after('<div class="error-message wcf-ca-error-msg"> You must add your email id! </div>');
131
+ }
132
+ else {
133
+
134
+ var data = {
135
+ email_subject: email_subject,
136
+ email_body: email_body,
137
+ email_send_to: email_send_to,
138
+ action: 'wcf_ca_preview_email_send',
139
+ security: wp_nonce,
140
+ };
141
+ $("#wcf_preview_email").css('cursor', 'wait').attr("disabled", true);
142
+
143
+ // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
144
+ $.post(
145
+ ajaxurl, data, function (response) {
146
+ $("#mail_response_msg").empty().fadeIn();;
147
+
148
+ if (response.success) {
149
+ var htmlString = "<strong> Email has been sent successfully! </strong>";
150
+ $("#mail_response_msg").css('color','green').html(htmlString).delay(3000).fadeOut();
151
+
152
+ } else {
153
+ var htmlString = "<strong> Email sending failed! Please check your SMTP settings! </a></strong>"
154
+ $("#mail_response_msg").css('color','red').html(htmlString).delay(3000).fadeOut();;
155
+ }
156
+ $("#wcf_preview_email").css('cursor', '').attr("disabled", false);
157
+
158
+ }
159
+ );
160
+ }
161
+
162
+ $(".wcf-ca-error-msg").delay(2000).fadeOut();
163
+ },
164
+
165
+ delete_coupons: function () {
166
+ if (confirm(wcf_ca_localized_vars._confirm_msg)) {
167
+ var data = {
168
+ action: 'wcf_ca_delete_garbage_coupons',
169
+ security: wcf_ca_localized_vars._delete_coupon_nonce
170
+ };
171
+ $('.wcf-ca-spinner').show();
172
+
173
+ $('.wcf-ca-spinner').addClass("is-active");
174
+ $("#wcf_ca_delete_coupons").css('cursor', 'wait').attr("disabled", true);
175
+ $.post(
176
+ ajaxurl, data, function (response) {
177
+ $(".wcf-ca-response-msg").empty().fadeIn();;
178
+ if (response.success) {
179
+ $('.wcf-ca-spinner').hide();
180
+ $(".wcf-ca-response-msg").css('color','green').html(response.data).delay(5000).fadeOut();
181
+ }
182
+
183
+ $("#wcf_ca_delete_coupons").css('cursor', '').attr("disabled", false);
184
+ }
185
+ );
186
+ }
187
+ },
188
+ export_orders: function () {
189
+ if( confirm( wcf_ca_localized_vars._confirm_msg_export ) ) {
190
+ window.location.href = window.location.search + "&export_data=true";
191
+ }
192
+ },
193
+ toggle_activate_template_on_grid: function () {
194
+ var $switch, state, new_state;
195
+ $switch = $(this);
196
+ state = $switch.attr('wcf-ca-template-switch');
197
+ var css = (state === 'on') ? 'green' : 'red';
198
+
199
+ $.post(
200
+ ajaxurl, {
201
+ action: 'activate_email_templates',
202
+ id: $(this).attr('id'),
203
+ state: state,
204
+ security: wcf_ca_details.email_toggle_button_nonce
205
+ }, function (response) {
206
+
207
+ $("#wcf_activate_email_template").val(new_state == 'on' ? 1 : 0);
208
+
209
+ $(".wcar_tmpl_response_msg").remove();
210
+
211
+ $("<span class='wcar_tmpl_response_msg'> " + response.data + " </span>").insertAfter($switch).delay(2000).fadeOut().css('color', css);
212
+
213
+ }
214
+ );
215
+ },
216
+
217
+
218
+ toggle_activate_template: function () {
219
+ var $switch, state, new_state;
220
+ $switch = $(this);
221
+ state = $switch.attr('wcf-ca-template-switch');
222
+ new_state = state === 'on' ? 'off' : 'on';
223
+ $("#wcf_activate_email_template").val(new_state == 'on' ? 1 : 0);
224
+ $switch.attr('wcf-ca-template-switch', new_state);
225
+ }
226
+ }
227
+
228
+ ZapierSettings = {
229
+ init: function () {
230
+
231
+ $(document).delegate("#wcf_ca_trigger_web_hook_abandoned_btn", "click",
232
+ { 'order_status': 'abandoned' },
233
+ ZapierSettings.zapier_trigger_sample);
234
+ },
235
+ zapier_trigger_sample: function( event ) {
236
+
237
+ var zapier_webhook_url = $("#wcf_ca_zapier_cart_"+ event.data.order_status +"_webhook").val().trim();
238
+
239
+ if ( ! zapier_webhook_url.length ) {
240
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Webhook URL is required.").fadeIn().css('color', '#dc3232').delay(2000).fadeOut();
241
+ return;
242
+ }
243
+
244
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Triggering...").fadeIn();
245
+
246
+ var now = new Date();
247
+ var datetime = now.getFullYear()+'/'+(now.getMonth()+1)+'/'+now.getDate();
248
+ datetime += ' '+now.getHours()+':'+now.getMinutes()+':'+now.getSeconds();
249
+ if ($.trim(zapier_webhook_url) !== "") {
250
+ var sample_data = {
251
+ "first_name": wcf_ca_details.name,
252
+ "last_name": wcf_ca_details.surname,
253
+ "email": wcf_ca_details.email,
254
+ "order_status": event.data.order_status,
255
+ "checkout_url": window.location.origin + "/checkout/?wcf_ac_token=something",
256
+ "coupon_code": "abcgefgh",
257
+ "product_names": "Product1, Product2 & Product3",
258
+ "cart_total": wcf_ca_details.woo_currency_symbol + "20",
259
+ "product_table": '<table align= left; cellpadding="10" cellspacing="0" style="float: none; border: 1px solid #e5e5e5;"> <tr align="center"> <th style="color: #636363; border: 1px solid #e5e5e5;">Item</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Name</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Quantity</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Price</th> <th style="color: #636363; border: 1px solid #e5e5e5;">Line Subtotal</th> </tr> <tr style=color: #636363; border: 1px solid #e5e5e5; align="center"> <td style="color: #636363; border: 1px solid #e5e5e5;"><img class="demo_img" style="height: 42px; width: 42px;" src="http://localhost/wp-local/wp-content/uploads/2019/11/wGdyS_Zgz1A.jpg"></td> <td style="color: #636363; border: 1px solid #e5e5e5;">Product1</td> <td style="color: #636363; border: 1px solid #e5e5e5;"> 1 </td> <td style="color: #636363; border: 1px solid #e5e5e5;">&pound;85.00</td> <td style="color: #636363; border: 1px solid #e5e5e5;" >&pound;85.00</td> </tr> </table>'
260
+ };
261
+ $.ajax({
262
+ url: zapier_webhook_url,
263
+ type: 'POST',
264
+ data: sample_data,
265
+ success: function(data) {
266
+ if (data.status == "success") {
267
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Success!").css('color', '#46b450');
268
+ } else {
269
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
270
+ }
271
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").fadeIn().delay(2000).fadeOut();
272
+ },
273
+ error: function() {
274
+ $("#wcf_ca_"+ event.data.order_status +"_btn_message").text("Trigger Failed!").css('color', '#dc3232');
275
+ }
276
+ });
277
+ } else {
278
+ $("wcf_ca"+ event.data.order_status +"_btn_message").text("Please verify webhook URL.").fadeIn().delay(2000).fadeOut();;
279
+ }
280
+ },
281
+ }
282
+
283
+ ToolTipHover = {
284
+ init: function () {
285
+
286
+ $(".wcf-ca-report-table-row .wcf-ca-icon-row").hover(function(){
287
+ $(this).find('.wcf-ca-tooltip-text').toggleClass("display_tool_tip");
288
+ });
289
+ },
290
+ }
291
+
292
+ $(document).ready(
293
+ function () {
294
+ EmailTemplatesAdmin.init();
295
+ CartAbandonmentSettings.init();
296
+ ZapierSettings.init();
297
+
298
+ ToolTipHover.init();
299
+ }
300
+ );
301
+
302
+
303
  })(jQuery);
admin/assets/js/admin-mce.js CHANGED
@@ -1,108 +1,108 @@
1
- (function ($) {
2
- $(document).ready(
3
- function () {
4
- tinymce.PluginManager.add(
5
- 'cartflows_ac', function (editor, url) {
6
-
7
- editor.addButton(
8
- 'cartflows_ac', {
9
- type: 'menubutton',
10
- text: 'WCAR Fields',
11
- icon: false,
12
- menu: [
13
- {
14
- text: wcf_ca_details.admin_firstname,
15
- value: '{{admin.firstname}}',
16
- onclick: function () {
17
- editor.insertContent(this.value());
18
- }
19
- },
20
- {
21
- text: wcf_ca_details.admin_company,
22
- value: '{{admin.company}}',
23
- onclick: function () {
24
- editor.insertContent(this.value());
25
- }
26
- },
27
- {
28
- text: wcf_ca_details.abandoned_product_details_table,
29
- value: '{{cart.product.table}}',
30
- onclick: function () {
31
- editor.insertContent(this.value());
32
- }
33
- },
34
- {
35
- text: wcf_ca_details.abandoned_product_names,
36
- value: '{{cart.product.names}}',
37
- onclick: function () {
38
- editor.insertContent(this.value());
39
- }
40
- },
41
- {
42
- text: wcf_ca_details.cart_checkout_url,
43
- value: '{{cart.checkout_url}}',
44
- onclick: function () {
45
- editor.insertContent(this.value());
46
- }
47
- },
48
- {
49
- text: wcf_ca_details.coupon_code,
50
- value: '{{cart.coupon_code}}',
51
- onclick: function () {
52
- editor.insertContent(this.value());
53
- }
54
- },
55
- {
56
- text: wcf_ca_details.customer_firstname,
57
- value: '{{customer.firstname}}',
58
- onclick: function () {
59
- editor.insertContent(this.value());
60
- }
61
- },
62
- {
63
- text: wcf_ca_details.customer_lastname,
64
- value: '{{customer.lastname}}',
65
- onclick: function () {
66
- editor.insertContent(this.value());
67
- }
68
- },
69
- {
70
- text: wcf_ca_details.customer_full_name,
71
- value: '{{customer.fullname}}',
72
- onclick: function () {
73
- editor.insertContent(this.value());
74
- }
75
- },
76
- {
77
- text: wcf_ca_details.cart_abandonment_date,
78
- value: '{{cart.abandoned_date}}',
79
- onclick: function () {
80
- editor.insertContent(this.value());
81
- }
82
- },
83
- {
84
- text: wcf_ca_details.site_url,
85
- value: '{{site.url}}',
86
- onclick: function () {
87
- editor.insertContent(this.value());
88
- }
89
- },
90
- {
91
- text: wcf_ca_details.unsubscribe_link,
92
- value: '{{cart.unsubscribe}}',
93
- onclick: function () {
94
- editor.insertContent(this.value());
95
- }
96
- },
97
- ].sort(function(a,b){
98
- return a.text.localeCompare(b.text);
99
- })
100
- }
101
- );
102
- }
103
- );
104
- }
105
- );
106
-
107
- })(jQuery);
108
-
1
+ (function ($) {
2
+ $(document).ready(
3
+ function () {
4
+ tinymce.PluginManager.add(
5
+ 'cartflows_ac', function (editor, url) {
6
+
7
+ editor.addButton(
8
+ 'cartflows_ac', {
9
+ type: 'menubutton',
10
+ text: 'WCAR Fields',
11
+ icon: false,
12
+ menu: [
13
+ {
14
+ text: wcf_ca_details.admin_firstname,
15
+ value: '{{admin.firstname}}',
16
+ onclick: function () {
17
+ editor.insertContent(this.value());
18
+ }
19
+ },
20
+ {
21
+ text: wcf_ca_details.admin_company,
22
+ value: '{{admin.company}}',
23
+ onclick: function () {
24
+ editor.insertContent(this.value());
25
+ }
26
+ },
27
+ {
28
+ text: wcf_ca_details.abandoned_product_details_table,
29
+ value: '{{cart.product.table}}',
30
+ onclick: function () {
31
+ editor.insertContent(this.value());
32
+ }
33
+ },
34
+ {
35
+ text: wcf_ca_details.abandoned_product_names,
36
+ value: '{{cart.product.names}}',
37
+ onclick: function () {
38
+ editor.insertContent(this.value());
39
+ }
40
+ },
41
+ {
42
+ text: wcf_ca_details.cart_checkout_url,
43
+ value: '{{cart.checkout_url}}',
44
+ onclick: function () {
45
+ editor.insertContent(this.value());
46
+ }
47
+ },
48
+ {
49
+ text: wcf_ca_details.coupon_code,
50
+ value: '{{cart.coupon_code}}',
51
+ onclick: function () {
52
+ editor.insertContent(this.value());
53
+ }
54
+ },
55
+ {
56
+ text: wcf_ca_details.customer_firstname,
57
+ value: '{{customer.firstname}}',
58
+ onclick: function () {
59
+ editor.insertContent(this.value());
60
+ }
61
+ },
62
+ {
63
+ text: wcf_ca_details.customer_lastname,
64
+ value: '{{customer.lastname}}',
65
+ onclick: function () {
66
+ editor.insertContent(this.value());
67
+ }
68
+ },
69
+ {
70
+ text: wcf_ca_details.customer_full_name,
71
+ value: '{{customer.fullname}}',
72
+ onclick: function () {
73
+ editor.insertContent(this.value());
74
+ }
75
+ },
76
+ {
77
+ text: wcf_ca_details.cart_abandonment_date,
78
+ value: '{{cart.abandoned_date}}',
79
+ onclick: function () {
80
+ editor.insertContent(this.value());
81
+ }
82
+ },
83
+ {
84
+ text: wcf_ca_details.site_url,
85
+ value: '{{site.url}}',
86
+ onclick: function () {
87
+ editor.insertContent(this.value());
88
+ }
89
+ },
90
+ {
91
+ text: wcf_ca_details.unsubscribe_link,
92
+ value: '{{cart.unsubscribe}}',
93
+ onclick: function () {
94
+ editor.insertContent(this.value());
95
+ }
96
+ },
97
+ ].sort(function(a,b){
98
+ return a.text.localeCompare(b.text);
99
+ })
100
+ }
101
+ );
102
+ }
103
+ );
104
+ }
105
+ );
106
+
107
+ })(jQuery);
108
+
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,83 +1,89 @@
1
- Version 1.2.4 - Thursday, 06th February 2020
2
- - New: Added option to export abandoned orders.
3
- - New: Added option to search abandoned orders.
4
- - Improvement: Compatibility with the latest WordPress PHP_CodeSniffer rules.
5
- - Fix: Get id error while sending emails.
6
-
7
- Version 1.2.3 - Thursday, 12th December 2019
8
- - New: Added option to unsubscribe users in bulk.
9
- - New: Added filter 'woo_ca_exclude_on_hold_order_from_tracking' to exclude on hold orders from the tracking.
10
- - New: Added product table shortcode for webhook.
11
- - Improvement: Updated filter 'woo_ca_email_template_table_style' for product table alignment.
12
- - Fix: Sometimes test emails are not sending.
13
-
14
- Version 1.2.2 - Tuesday, 12th November 2019
15
- - Fix: Duplicate order issue for variation products.
16
-
17
- Version 1.2.1 - Tuesday, 5th November 2019
18
- - New: Added delete option for used & expired coupons which will be created now onwards.
19
- - Fix: Sometimes order status remains "abandoned" for initially failed orders.
20
- - Fix: Strings updated for translation.
21
-
22
- Version 1.2.0 - Monday, 14th October 2019
23
- - New: Added support for PPOM products.
24
- - Improvement: Added email activate toggle button on grid.
25
- - Improvement: Added notice on the checkout page for test emails.
26
- - Fix: Zero-value orders getting tracked.
27
- - Fix: Disable tracking for the custom user roles.
28
-
29
- Version 1.1.9 - Thursday, 19th September 2019
30
- - New: Option added to ignore users from cart abandonment process.
31
- - New: Filter added to customize the styling of email template table.
32
- - Improvement: Added compatibility with Razorpay plugin.
33
- - Fix: Email template markup was breaking after save.
34
- - Fix: Failed orders were getting marked as completed.
35
- - Fix: Empty order was getting tracked and email sending for it.
36
- - Fix: Email settings options were swapping value of from and reply-to.
37
-
38
- Version 1.1.8 - Tuesday, 3rd September 2019
39
- - New: Option added to auto-apply coupon on the checkout.
40
- - New: Option added to apply coupon individually.
41
- - New: Option added to create free shipping coupons.
42
-
43
- Version 1.1.7 - Monday, 12th August 2019
44
- - New: Filter added to show the cart total inside the email template.
45
- - New: Filter added to change the cart abandoned time.
46
- - Improvement: Order tracking logic updated for automated payments.
47
- - Improvement: Update report dashboard DateTime format to WordPress format.
48
- - Fix: Broken image in the email template.
49
-
50
- Version 1.1.6 - Friday, 19th July 2019
51
- - New: Bundled product support for email checkout URL.
52
- - Improvement: Added phone number and address while triggering the to webhook.
53
- - Fix: Creating tables and default settings on activation.
54
-
55
- Version 1.1.5 - Tuesday, 9th July 2019
56
- - Fix: Other crons disappearing issue.
57
-
58
- Version 1.1.4 - Tuesday, 9th July 2019
59
- - Fix: Follow up emails were getting sent even after the completion of the order.
60
- - Fix: Email template variable 'Abandoned Product Names' warning issue.
61
-
62
- Version 1.1.3 - Thursday, 27th June 2019
63
- - Improvement: Added checkout link for abandoned cart inside the admin section.
64
- - Fix: Added pagination for reports.
65
- - Fix: Recover report calculations before campaign triggers.
66
- - Fix: Empty cart notice when CartFlows checkout is set global.
67
-
68
- Version 1.1.2 - Wednesday, 12th June 2019
69
- - Fix: Issue of timezone while sending mail through cron.
70
- - Fix: Delete single cart abandonment order.
71
- - Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
72
-
73
- Version 1.1.1 - Thursday, 06th June 2019
74
- - New: Added feature to reschedule emails for Admin.
75
- - Fix: Coupon expiry time issue.
76
- - Fix: Email issue for a user who has an already purchased order.
77
- - Fix: Translatable strings updated.
78
-
79
- Version 1.1.0 - Thursday, 30th May 2019
80
- - Added a view for admin to check email status specific to the particular abandoned user.
81
-
82
- Version 1.0.0 - Monday, 27th May 2019
 
 
 
 
 
 
83
  - Initial Release
1
+ Version 1.2.5 - Wednesday, 11th March 2020
2
+ - Improvement: Allowed plugin access to the shop manager.
3
+ - Fix: Variable product name not showing in the product table.
4
+ - Fix: All orders are not exporting due to the wrong pagination.
5
+ - Fix: Not showing the next page's orders.
6
+
7
+ Version 1.2.4 - Thursday, 06th February 2020
8
+ - New: Added option to export abandoned orders.
9
+ - New: Added option to search abandoned orders.
10
+ - Improvement: Compatibility with the latest WordPress PHP_CodeSniffer rules.
11
+ - Fix: Get id error while sending emails.
12
+
13
+ Version 1.2.3 - Thursday, 12th December 2019
14
+ - New: Added option to unsubscribe users in bulk.
15
+ - New: Added filter 'woo_ca_exclude_on_hold_order_from_tracking' to exclude on hold orders from the tracking.
16
+ - New: Added product table shortcode for webhook.
17
+ - Improvement: Updated filter 'woo_ca_email_template_table_style' for product table alignment.
18
+ - Fix: Sometimes test emails are not sending.
19
+
20
+ Version 1.2.2 - Tuesday, 12th November 2019
21
+ - Fix: Duplicate order issue for variation products.
22
+
23
+ Version 1.2.1 - Tuesday, 5th November 2019
24
+ - New: Added delete option for used & expired coupons which will be created now onwards.
25
+ - Fix: Sometimes order status remains "abandoned" for initially failed orders.
26
+ - Fix: Strings updated for translation.
27
+
28
+ Version 1.2.0 - Monday, 14th October 2019
29
+ - New: Added support for PPOM products.
30
+ - Improvement: Added email activate toggle button on grid.
31
+ - Improvement: Added notice on the checkout page for test emails.
32
+ - Fix: Zero-value orders getting tracked.
33
+ - Fix: Disable tracking for the custom user roles.
34
+
35
+ Version 1.1.9 - Thursday, 19th September 2019
36
+ - New: Option added to ignore users from cart abandonment process.
37
+ - New: Filter added to customize the styling of email template table.
38
+ - Improvement: Added compatibility with Razorpay plugin.
39
+ - Fix: Email template markup was breaking after save.
40
+ - Fix: Failed orders were getting marked as completed.
41
+ - Fix: Empty order was getting tracked and email sending for it.
42
+ - Fix: Email settings options were swapping value of from and reply-to.
43
+
44
+ Version 1.1.8 - Tuesday, 3rd September 2019
45
+ - New: Option added to auto-apply coupon on the checkout.
46
+ - New: Option added to apply coupon individually.
47
+ - New: Option added to create free shipping coupons.
48
+
49
+ Version 1.1.7 - Monday, 12th August 2019
50
+ - New: Filter added to show the cart total inside the email template.
51
+ - New: Filter added to change the cart abandoned time.
52
+ - Improvement: Order tracking logic updated for automated payments.
53
+ - Improvement: Update report dashboard DateTime format to WordPress format.
54
+ - Fix: Broken image in the email template.
55
+
56
+ Version 1.1.6 - Friday, 19th July 2019
57
+ - New: Bundled product support for email checkout URL.
58
+ - Improvement: Added phone number and address while triggering the to webhook.
59
+ - Fix: Creating tables and default settings on activation.
60
+
61
+ Version 1.1.5 - Tuesday, 9th July 2019
62
+ - Fix: Other crons disappearing issue.
63
+
64
+ Version 1.1.4 - Tuesday, 9th July 2019
65
+ - Fix: Follow up emails were getting sent even after the completion of the order.
66
+ - Fix: Email template variable 'Abandoned Product Names' warning issue.
67
+
68
+ Version 1.1.3 - Thursday, 27th June 2019
69
+ - Improvement: Added checkout link for abandoned cart inside the admin section.
70
+ - Fix: Added pagination for reports.
71
+ - Fix: Recover report calculations before campaign triggers.
72
+ - Fix: Empty cart notice when CartFlows checkout is set global.
73
+
74
+ Version 1.1.2 - Wednesday, 12th June 2019
75
+ - Fix: Issue of timezone while sending mail through cron.
76
+ - Fix: Delete single cart abandonment order.
77
+ - Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
78
+
79
+ Version 1.1.1 - Thursday, 06th June 2019
80
+ - New: Added feature to reschedule emails for Admin.
81
+ - Fix: Coupon expiry time issue.
82
+ - Fix: Email issue for a user who has an already purchased order.
83
+ - Fix: Translatable strings updated.
84
+
85
+ Version 1.1.0 - Thursday, 30th May 2019
86
+ - Added a view for admin to check email status specific to the particular abandoned user.
87
+
88
+ Version 1.0.0 - Monday, 27th May 2019
89
  - Initial Release
classes/class-cartflows-ca-loader.php CHANGED
@@ -1,351 +1,351 @@
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
- /**
73
- * Defines all constants
74
- *
75
- * @since 1.0.0
76
- */
77
- public function define_constants() {
78
- define( 'CARTFLOWS_CA_BASE', plugin_basename( CARTFLOWS_CA_FILE ) );
79
- define( 'CARTFLOWS_CA_DIR', plugin_dir_path( CARTFLOWS_CA_FILE ) );
80
- define( 'CARTFLOWS_CA_URL', plugins_url( '/', CARTFLOWS_CA_FILE ) );
81
- define( 'CARTFLOWS_CA_VER', '1.2.4' );
82
- define( 'CARTFLOWS_CA_SLUG', 'cartflows_ca' );
83
-
84
- define( 'CARTFLOWS_CA_CART_ABANDONMENT_TABLE', 'cartflows_ca_cart_abandonment' );
85
- define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE', 'cartflows_ca_email_templates' );
86
- define( 'CARTFLOWS_CA_EMAIL_HISTORY_TABLE', 'cartflows_ca_email_history' );
87
- define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE', 'cartflows_ca_email_templates_meta' );
88
- }
89
-
90
- /**
91
- * Loads plugin files.
92
- *
93
- * @since 1.0.0
94
- *
95
- * @return void
96
- */
97
- public function load_plugin() {
98
-
99
- if ( ! function_exists( 'WC' ) ) {
100
- add_action( 'admin_notices', array( $this, 'fails_to_load' ) );
101
- return;
102
- }
103
-
104
- $this->load_helper_files_components();
105
- $this->load_core_files();
106
- $this->load_core_components();
107
-
108
- /**
109
- * CartFlows Init.
110
- *
111
- * Fires when Cartflows is instantiated.
112
- *
113
- * @since 1.0.0
114
- */
115
- do_action( 'cartflows_ca_init' );
116
- }
117
-
118
- /**
119
- * Fires admin notice when Elementor is not installed and activated.
120
- *
121
- * @since 1.0.0
122
- *
123
- * @return void
124
- */
125
- public function fails_to_load() {
126
-
127
- $screen = get_current_screen();
128
-
129
- if ( isset( $screen->parent_file ) && 'plugins.php' === $screen->parent_file && 'update' === $screen->id ) {
130
- return;
131
- }
132
-
133
- $class = 'notice notice-error';
134
- /* translators: %s: html tags */
135
- $message = sprintf( __( 'The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires %1$sWooCommerce%2$s plugin installed & activated.', 'woo-cart-abandonment-recovery' ), '<strong>', '</strong>' );
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', 'woo-cart-abandonment-recovery' );
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', 'woo-cart-abandonment-recovery' );
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 ), wp_kses_post( $message ), wp_kses_post( $button ) );
158
- }
159
-
160
-
161
- /**
162
- * Is woocommerce plugin installed.
163
- *
164
- * @since 1.0.0
165
- *
166
- * @access public
167
- */
168
- public 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
- public 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
- public 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
- public 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, 'woo-cart-abandonment-recovery' );
253
- $mofile = sprintf( '%1$s-%2$s.mo', 'woo-cart-abandonment-recovery', $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( 'woo-cart-abandonment-recovery', $mofile_global );
262
- } elseif ( file_exists( $mofile_local ) ) {
263
- // Look in local /wp-content/plugins/%plugin-folder-name%/languages/ folder.
264
- load_textdomain( 'woo-cart-abandonment-recovery', $mofile_local );
265
- } else {
266
- // Load the default language files.
267
- load_plugin_textdomain( 'woo-cart-abandonment-recovery', false, $lang_dir );
268
- }
269
- }
270
- /**
271
- * Load Core Components.
272
- *
273
- * @since 1.0.0
274
- *
275
- * @return void
276
- */
277
- public 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
- public 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
- public 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
- public function deactivation_reset() {
329
- wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
330
- }
331
- }
332
-
333
- /**
334
- * Prepare if class 'CARTFLOWS_CA_Loader' exist.
335
- * Kicking this off by calling 'get_instance()' method
336
- */
337
- CARTFLOWS_CA_Loader::get_instance();
338
- }
339
-
340
-
341
- if ( ! function_exists( 'wcf_ca' ) ) {
342
- /**
343
- * Get global class.
344
- *
345
- * @return object
346
- */
347
- function wcf_ca() {
348
- return CARTFLOWS_CA_Loader::get_instance();
349
- }
350
- }
351
-
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
+ /**
73
+ * Defines all constants
74
+ *
75
+ * @since 1.0.0
76
+ */
77
+ public function define_constants() {
78
+ define( 'CARTFLOWS_CA_BASE', plugin_basename( CARTFLOWS_CA_FILE ) );
79
+ define( 'CARTFLOWS_CA_DIR', plugin_dir_path( CARTFLOWS_CA_FILE ) );
80
+ define( 'CARTFLOWS_CA_URL', plugins_url( '/', CARTFLOWS_CA_FILE ) );
81
+ define( 'CARTFLOWS_CA_VER', '1.2.5' );
82
+ define( 'CARTFLOWS_CA_SLUG', 'cartflows_ca' );
83
+
84
+ define( 'CARTFLOWS_CA_CART_ABANDONMENT_TABLE', 'cartflows_ca_cart_abandonment' );
85
+ define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE', 'cartflows_ca_email_templates' );
86
+ define( 'CARTFLOWS_CA_EMAIL_HISTORY_TABLE', 'cartflows_ca_email_history' );
87
+ define( 'CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE', 'cartflows_ca_email_templates_meta' );
88
+ }
89
+
90
+ /**
91
+ * Loads plugin files.
92
+ *
93
+ * @since 1.0.0
94
+ *
95
+ * @return void
96
+ */
97
+ public function load_plugin() {
98
+
99
+ if ( ! function_exists( 'WC' ) ) {
100
+ add_action( 'admin_notices', array( $this, 'fails_to_load' ) );
101
+ return;
102
+ }
103
+
104
+ $this->load_helper_files_components();
105
+ $this->load_core_files();
106
+ $this->load_core_components();
107
+
108
+ /**
109
+ * CartFlows Init.
110
+ *
111
+ * Fires when Cartflows is instantiated.
112
+ *
113
+ * @since 1.0.0
114
+ */
115
+ do_action( 'cartflows_ca_init' );
116
+ }
117
+
118
+ /**
119
+ * Fires admin notice when Elementor is not installed and activated.
120
+ *
121
+ * @since 1.0.0
122
+ *
123
+ * @return void
124
+ */
125
+ public function fails_to_load() {
126
+
127
+ $screen = get_current_screen();
128
+
129
+ if ( isset( $screen->parent_file ) && 'plugins.php' === $screen->parent_file && 'update' === $screen->id ) {
130
+ return;
131
+ }
132
+
133
+ $class = 'notice notice-error';
134
+ /* translators: %s: html tags */
135
+ $message = sprintf( __( 'The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires %1$sWooCommerce%2$s plugin installed & activated.', 'woo-cart-abandonment-recovery' ), '<strong>', '</strong>' );
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', 'woo-cart-abandonment-recovery' );
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', 'woo-cart-abandonment-recovery' );
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 ), wp_kses_post( $message ), wp_kses_post( $button ) );
158
+ }
159
+
160
+
161
+ /**
162
+ * Is woocommerce plugin installed.
163
+ *
164
+ * @since 1.0.0
165
+ *
166
+ * @access public
167
+ */
168
+ public 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
+ public 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
+ public 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
+ public 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, 'woo-cart-abandonment-recovery' );
253
+ $mofile = sprintf( '%1$s-%2$s.mo', 'woo-cart-abandonment-recovery', $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( 'woo-cart-abandonment-recovery', $mofile_global );
262
+ } elseif ( file_exists( $mofile_local ) ) {
263
+ // Look in local /wp-content/plugins/%plugin-folder-name%/languages/ folder.
264
+ load_textdomain( 'woo-cart-abandonment-recovery', $mofile_local );
265
+ } else {
266
+ // Load the default language files.
267
+ load_plugin_textdomain( 'woo-cart-abandonment-recovery', false, $lang_dir );
268
+ }
269
+ }
270
+ /**
271
+ * Load Core Components.
272
+ *
273
+ * @since 1.0.0
274
+ *
275
+ * @return void
276
+ */
277
+ public 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
+ public 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
+ public 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
+ public function deactivation_reset() {
329
+ wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Prepare if class 'CARTFLOWS_CA_Loader' exist.
335
+ * Kicking this off by calling 'get_instance()' method
336
+ */
337
+ CARTFLOWS_CA_Loader::get_instance();
338
+ }
339
+
340
+
341
+ if ( ! function_exists( 'wcf_ca' ) ) {
342
+ /**
343
+ * Get global class.
344
+ *
345
+ * @return object
346
+ */
347
+ function wcf_ca() {
348
+ return CARTFLOWS_CA_Loader::get_instance();
349
+ }
350
+ }
351
+
classes/class-cartflows-ca-settings.php CHANGED
@@ -1,693 +1,693 @@
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
- /**
32
- * Adding action links for plugin list page.
33
- *
34
- * @param array $links links.
35
- * @return array
36
- */
37
- public function add_action_links( $links ) {
38
- $mylinks = array(
39
- '<a href="' . admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME ) . '">Settings</a>',
40
- );
41
-
42
- return array_merge( $mylinks, $links );
43
- }
44
- /**
45
- * Add new settings for cart abandonment settings.
46
- *
47
- * @since 1.1.5
48
- */
49
- public function wcf_initialize_settings() {
50
-
51
- // Start: Settings for cart abandonment.
52
- add_settings_section(
53
- WCF_CA_GENERAL_SETTINGS_SECTION,
54
- __( 'Cart Abandonment Settings', 'woo-cart-abandonment-recovery' ),
55
- array( $this, 'wcf_cart_abandonment_options_callback' ),
56
- WCF_CA_PAGE_NAME
57
- );
58
-
59
- add_settings_field(
60
- 'wcf_ca_status',
61
- __( 'Enable Tracking', 'woo-cart-abandonment-recovery' ),
62
- array( $this, 'wcf_ca_status_callback' ),
63
- WCF_CA_PAGE_NAME,
64
- WCF_CA_GENERAL_SETTINGS_SECTION,
65
- 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>', 'woo-cart-abandonment-recovery' ) )
66
- );
67
-
68
- register_setting(
69
- WCF_CA_SETTINGS_OPTION_GROUP,
70
- 'wcf_ca_status'
71
- );
72
-
73
- add_settings_field(
74
- 'wcf_ca_ignore_users',
75
- __( 'Disable Tracking For', 'woo-cart-abandonment-recovery' ),
76
- array( $this, 'wcf_ca_ignore_users_callback' ),
77
- WCF_CA_PAGE_NAME,
78
- WCF_CA_GENERAL_SETTINGS_SECTION,
79
- array( '<br><span class="description"><strong>Note:</strong>' . __( ' It will ignore selected users from abandonment process when they logged in, and hence they can not receive mail for cart abandoned by themselves.', 'woo-cart-abandonment-recovery' ) . '</span>' )
80
- );
81
-
82
- register_setting(
83
- WCF_CA_SETTINGS_OPTION_GROUP,
84
- 'wcf_ca_ignore_users'
85
- );
86
-
87
- // End: General Settings for cart abandonment.
88
- // Start: Delete coupons settings for cart abandonment.
89
-
90
- add_settings_section(
91
- WCF_CA_COUPONS_SETTINGS_SECTION,
92
- __( 'Coupons Settings', 'woo-cart-abandonment-recovery' ),
93
- array( $this, 'wcf_cart_abandonment_options_callback' ),
94
- WCF_CA_PAGE_NAME
95
- );
96
-
97
- add_settings_field(
98
- 'wcf_ca_auto_delete_coupons',
99
- __( 'Delete Coupons Automatically', 'woo-cart-abandonment-recovery' ),
100
- array( $this, 'wcf_ca_auto_delete_coupons_callback' ),
101
- WCF_CA_PAGE_NAME,
102
- WCF_CA_COUPONS_SETTINGS_SECTION,
103
- array( __( 'Delete coupons automatically on weekly basis.<br><span class="description"><br/><strong>Note:</strong> This option will set a weekly cron to delete all <strong>expired</strong> and <strong>used</strong> coupons automatically in the background.</p>', 'woo-cart-abandonment-recovery' ) )
104
- );
105
-
106
- register_setting(
107
- WCF_CA_SETTINGS_OPTION_GROUP,
108
- 'wcf_ca_auto_delete_coupons'
109
- );
110
-
111
- add_settings_field(
112
- 'wcf_ca_delete_coupons',
113
- __( 'Delete Coupons Manually', 'woo-cart-abandonment-recovery' ),
114
- array( $this, 'wcf_ca_delete_coupons_callback' ),
115
- WCF_CA_PAGE_NAME,
116
- WCF_CA_COUPONS_SETTINGS_SECTION,
117
- array( '<br><span class="description"> ' . __( '<br><strong>Note:</strong> This will delete all <strong>expired</strong> and <strong>used</strong> coupons that were created by Woo Cart Abandonment Recovery.</p>', 'woo-cart-abandonment-recovery' ) )
118
- );
119
-
120
- register_setting(
121
- WCF_CA_SETTINGS_OPTION_GROUP,
122
- 'wcf_ca_delete_coupons'
123
- );
124
-
125
- // End: Delete coupons settings for cart abandonment.
126
- // Start: Settings for email templates.
127
- add_settings_section(
128
- WCF_CA_EMAIL_SETTINGS_SECTION,
129
- __( 'Email Settings', 'woo-cart-abandonment-recovery' ),
130
- array( $this, 'wcf_cart_abandonment_options_callback' ),
131
- WCF_CA_PAGE_NAME
132
- );
133
-
134
- add_settings_field(
135
- 'wcf_ca_from_name',
136
- __( '"From" Name', 'woo-cart-abandonment-recovery' ),
137
- array( $this, 'wcf_ca_from_name_callback' ),
138
- WCF_CA_PAGE_NAME,
139
- WCF_CA_EMAIL_SETTINGS_SECTION,
140
- array( __( 'Name will appear in email sent.', 'woo-cart-abandonment-recovery' ) )
141
- );
142
-
143
- add_settings_field(
144
- 'wcf_ca_from_email',
145
- __( '"From" Address', 'woo-cart-abandonment-recovery' ),
146
- array( $this, 'wcf_ca_from_email_callback' ),
147
- WCF_CA_PAGE_NAME,
148
- WCF_CA_EMAIL_SETTINGS_SECTION,
149
- array( __( 'Email which send from.', 'woo-cart-abandonment-recovery' ) )
150
- );
151
-
152
- add_settings_field(
153
- 'wcf_ca_reply_email',
154
- __( '"Reply To" Address', 'woo-cart-abandonment-recovery' ),
155
- array( $this, 'wcf_ca_reply_email_callback' ),
156
- WCF_CA_PAGE_NAME,
157
- WCF_CA_EMAIL_SETTINGS_SECTION,
158
- array( __( 'When a user clicks reply, which email address should that reply be sent to?', 'woo-cart-abandonment-recovery' ) )
159
- );
160
-
161
- register_setting(
162
- WCF_CA_SETTINGS_OPTION_GROUP,
163
- 'wcf_ca_from_name'
164
- );
165
-
166
- register_setting(
167
- WCF_CA_SETTINGS_OPTION_GROUP,
168
- 'wcf_ca_from_email',
169
- array( $this, 'wcf_ca_from_email_validation' )
170
- );
171
-
172
- register_setting(
173
- WCF_CA_SETTINGS_OPTION_GROUP,
174
- 'wcf_ca_reply_email',
175
- array( $this, 'wcf_ca_reply_email_validation' )
176
- );
177
- // End: Settings for email templates.
178
- // Start: Settings for coupon code.
179
- add_settings_field(
180
- 'wcf_ca_zapier_tracking_status',
181
- __( 'Enable Webhook', 'woo-cart-abandonment-recovery' ),
182
- array( $this, 'wcf_ca_zapier_tracking_status_callback' ),
183
- WCF_CA_PAGE_NAME,
184
- WCF_CA_ZAPIER_SETTINGS_SECTION,
185
- array( __( 'Allows you to trigger webhook automatically upon cart abandonment and recovery.', 'woo-cart-abandonment-recovery' ) )
186
- );
187
-
188
- add_settings_field(
189
- 'wcf_ca_zapier_cart_abandoned_webhook',
190
- __( 'Webhook URL', 'woo-cart-abandonment-recovery' ),
191
- array( $this, 'wcf_ca_zapier_cart_abandoned_webhook_callback' ),
192
- WCF_CA_PAGE_NAME,
193
- WCF_CA_ZAPIER_SETTINGS_SECTION,
194
- array( '', 'woo-cart-abandonment-recovery' )
195
- );
196
-
197
- register_setting(
198
- WCF_CA_SETTINGS_OPTION_GROUP,
199
- 'wcf_ca_zapier_tracking_status'
200
- );
201
-
202
- register_setting(
203
- WCF_CA_SETTINGS_OPTION_GROUP,
204
- 'wcf_ca_zapier_cart_abandoned_webhook'
205
- );
206
-
207
- add_settings_section(
208
- WCF_CA_ZAPIER_SETTINGS_SECTION,
209
- __( 'Coupon Code Settings', 'woo-cart-abandonment-recovery' ),
210
- array( $this, 'wcf_cart_abandonment_options_callback' ),
211
- WCF_CA_PAGE_NAME
212
- );
213
-
214
- add_settings_field(
215
- 'wcf_ca_coupon_code_status',
216
- __( 'Create Coupon Code', 'woo-cart-abandonment-recovery' ),
217
- array( $this, 'wcf_ca_coupon_code_status_callback' ),
218
- WCF_CA_PAGE_NAME,
219
- WCF_CA_ZAPIER_SETTINGS_SECTION,
220
- array( __( 'Auto-create the special coupon for the abandoned cart to send over the emails.', 'woo-cart-abandonment-recovery' ) )
221
- );
222
-
223
- add_settings_field(
224
- 'wcf_ca_discount_type',
225
- __( 'Discount Type', 'woo-cart-abandonment-recovery' ),
226
- array( $this, 'wcf_ca_discount_type_callback' ),
227
- WCF_CA_PAGE_NAME,
228
- WCF_CA_ZAPIER_SETTINGS_SECTION,
229
- array( '', 'woo-cart-abandonment-recovery' )
230
- );
231
-
232
- add_settings_field(
233
- 'wcf_ca_coupon_amount',
234
- __( 'Coupon Amount', 'woo-cart-abandonment-recovery' ),
235
- array( $this, 'wcf_ca_coupon_amount_callback' ),
236
- WCF_CA_PAGE_NAME,
237
- WCF_CA_ZAPIER_SETTINGS_SECTION,
238
- array( '', 'woo-cart-abandonment-recovery' )
239
- );
240
-
241
- add_settings_field(
242
- 'wcf_ca_coupon_expiry',
243
- __( 'Coupon Expires After', 'woo-cart-abandonment-recovery' ),
244
- array( $this, 'wcf_ca_coupon_expiry_callback' ),
245
- WCF_CA_PAGE_NAME,
246
- WCF_CA_ZAPIER_SETTINGS_SECTION,
247
- array( __( '<br/><br/> <span class="description"><strong>Note: </strong>. Enter zero (0) to restrict coupon from expiring.</span>', 'woo-cart-abandonment-recovery' ) )
248
- );
249
-
250
- register_setting(
251
- WCF_CA_SETTINGS_OPTION_GROUP,
252
- 'wcf_ca_coupon_expiry'
253
- );
254
- register_setting(
255
- WCF_CA_SETTINGS_OPTION_GROUP,
256
- 'wcf_ca_coupon_expiry_unit'
257
- );
258
-
259
- register_setting(
260
- WCF_CA_SETTINGS_OPTION_GROUP,
261
- 'wcf_ca_coupon_code_status'
262
- );
263
-
264
- register_setting(
265
- WCF_CA_SETTINGS_OPTION_GROUP,
266
- 'wcf_ca_discount_type'
267
- );
268
-
269
- register_setting(
270
- WCF_CA_SETTINGS_OPTION_GROUP,
271
- 'wcf_ca_coupon_amount',
272
- array( $this, 'wcf_ca_coupon_amount_validation' )
273
- );
274
- // End: Settings for coupon code.
275
- // Start: Settings for Zapier.
276
- add_settings_section(
277
- WCF_CA_ZAPIER_SETTINGS_SECTION,
278
- __( 'Webhook Settings', 'woo-cart-abandonment-recovery' ),
279
- array( $this, 'wcf_cart_abandonment_options_callback' ),
280
- WCF_CA_PAGE_NAME
281
- );
282
-
283
- // End: Settings for webhook.
284
- // Start: GDPR Settings.
285
- add_settings_section(
286
- WCF_CA_GDPR_SETTINGS_SECTION,
287
- __( 'GDPR Settings', 'woo-cart-abandonment-recovery' ),
288
- array( $this, 'wcf_cart_abandonment_options_callback' ),
289
- WCF_CA_PAGE_NAME
290
- );
291
-
292
- add_settings_field(
293
- 'wcf_ca_gdpr_status',
294
- __( 'Enable GDPR Integration', 'woo-cart-abandonment-recovery' ),
295
- array( $this, 'wcf_ca_gdpr_status_callback' ),
296
- WCF_CA_PAGE_NAME,
297
- WCF_CA_GDPR_SETTINGS_SECTION,
298
- 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>', 'woo-cart-abandonment-recovery' ) )
299
- );
300
-
301
- add_settings_field(
302
- 'wcf_ca_gdpr_message',
303
- __( 'GDPR Message', 'woo-cart-abandonment-recovery' ),
304
- array( $this, 'wcf_ca_gdpr_message_callback' ),
305
- WCF_CA_PAGE_NAME,
306
- WCF_CA_GDPR_SETTINGS_SECTION,
307
- array( '', 'woo-cart-abandonment-recovery' )
308
- );
309
-
310
- register_setting(
311
- WCF_CA_SETTINGS_OPTION_GROUP,
312
- 'wcf_ca_gdpr_status'
313
- );
314
- register_setting(
315
- WCF_CA_SETTINGS_OPTION_GROUP,
316
- 'wcf_ca_gdpr_message'
317
- );
318
-
319
- }
320
-
321
- /**
322
- * Callback for cart abandonment status.
323
- *
324
- * @param array $args args.
325
- * @since 1.1.5
326
- */
327
- public function wcf_ca_coupon_code_status_callback( $args ) {
328
- $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
329
- $html = '';
330
- printf(
331
- '<input type="checkbox" id="wcf_ca_coupon_code_status" name="wcf_ca_coupon_code_status" value="on"
332
- ' . checked( 'on', $wcf_ca_coupon_code_status, false ) . ' />'
333
- );
334
- $html .= '<label for="wcf_ca_coupon_code_status"> ' . $args[0] . '</label>';
335
- echo wp_kses_post( $html );
336
- }
337
-
338
-
339
- /**
340
- * Callback for cart abandonment cut off time.
341
- *
342
- * @param array $args args.
343
- * @since 1.1.5
344
- */
345
- public function wcf_ca_zapier_cart_abandoned_webhook_callback( $args ) {
346
- $wcf_ca_zapier_cart_abandoned_webhook = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
347
- echo '<input type="text" class="wcf-ca-trigger-input" id="wcf_ca_zapier_cart_abandoned_webhook" name="wcf_ca_zapier_cart_abandoned_webhook" value="' . esc_attr( sanitize_text_field( $wcf_ca_zapier_cart_abandoned_webhook ) ) . '" />';
348
- echo '<button id="wcf_ca_trigger_web_hook_abandoned_btn" type="button" class="button"> Trigger Sample </button>';
349
- echo '<span style="margin-left: 10px;" id="wcf_ca_abandoned_btn_message"></span>';
350
- $html = '<label for="wcf_ca_zapier_cart_abandoned_webhook"> ' . $args[0] . '</label>';
351
- echo wp_kses_post( $html );
352
- }
353
-
354
-
355
- /**
356
- * Callback for cart abandonment status.
357
- *
358
- * @param array $args args.
359
- * @since 1.1.5
360
- */
361
- public function wcf_ca_zapier_tracking_status_callback( $args ) {
362
- $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
363
-
364
- $html = '';
365
- printf(
366
- '<input type="checkbox" id="wcf_ca_zapier_tracking_status" name="wcf_ca_zapier_tracking_status" value="on"
367
- ' . checked( 'on', $wcf_ca_zapier_tracking_status, false ) . ' />'
368
- );
369
- $html .= '<label for="wcf_ca_zapier_tracking_status"> ' . $args[0] . '</label>';
370
- echo wp_kses_post( $html );
371
- }
372
-
373
-
374
- /**
375
- * Callback for cart abandonment cut off time.
376
- *
377
- * @param array $args args.
378
- * @since 1.1.5
379
- */
380
- public function wcf_ca_coupon_amount_callback( $args ) {
381
- $wcf_ca_coupon_amount = get_option( 'wcf_ca_coupon_amount' );
382
- printf(
383
- '<input type="number" class="wcf-ca-trigger-input wcf-ca-email-inputs" id="wcf_ca_coupon_amount" name="wcf_ca_coupon_amount" value="%s" />',
384
- isset( $wcf_ca_coupon_amount ) ? esc_attr( $wcf_ca_coupon_amount ) : ''
385
- );
386
- $html = '<label for="wcf_ca_coupon_amount"> ' . $args[0] . '</label>';
387
- echo wp_kses_post( $html );
388
- }
389
-
390
- /**
391
- * Callback for cart abandonment cut off time.
392
- *
393
- * @param array $args args.
394
- * @since 1.1.5
395
- */
396
- public function wcf_ca_coupon_expiry_callback( $args ) {
397
- $wcf_ca_coupon_expiry = intval( get_option( 'wcf_ca_coupon_expiry' ) );
398
- printf(
399
- '<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" />',
400
- isset( $wcf_ca_coupon_expiry ) ? esc_attr( $wcf_ca_coupon_expiry ) : ''
401
- );
402
-
403
- $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
404
- $items = array(
405
- 'hours' => __( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
406
- 'days' => __( 'Day(s)', 'woo-cart-abandonment-recovery' ),
407
- );
408
- echo "<select id='wcf_ca_coupon_expiry_unit' name='wcf_ca_coupon_expiry_unit'>";
409
- foreach ( $items as $key => $item ) {
410
- $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
411
- echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
412
- }
413
- echo '</select>';
414
-
415
- $html = '<label for="wcf_ca_coupon_expiry_unit"> ' . $args[0] . '</label>';
416
- echo wp_kses_post( $html );
417
- }
418
-
419
-
420
-
421
- /**
422
- * Callback for cart abandonment cut off time.
423
- *
424
- * @param array $args args.
425
- * @since 1.1.5
426
- */
427
- public function wcf_ca_gdpr_message_callback( $args ) {
428
- $wcf_ca_gdpr_message = get_option( 'wcf_ca_gdpr_message' );
429
-
430
- printf(
431
- '<textarea rows="2" cols="60" id="wcf_ca_gdpr_message" name="wcf_ca_gdpr_message" spellcheck="false">%s</textarea>',
432
- isset( $wcf_ca_gdpr_message ) ? esc_attr( $wcf_ca_gdpr_message ) : ''
433
- );
434
- $html = '<label for="wcf_ca_gdpr_message"> ' . $args[0] . '</label>';
435
- echo wp_kses_post( $html );
436
- }
437
-
438
- /**
439
- * Callback for cart abandonment cut off time.
440
- *
441
- * @param array $args args.
442
- * @since 1.1.5
443
- */
444
- public function wcf_ca_discount_type_callback( $args ) {
445
-
446
- $discount_type = get_option( 'wcf_ca_discount_type' );
447
- $items = array(
448
- 'percent' => 'Percentage discount',
449
- 'fixed_cart' => 'Fixed cart discount',
450
- );
451
- echo "<select id='wcf_ca_discount_type' name='wcf_ca_discount_type'>";
452
- foreach ( $items as $key => $item ) {
453
- $selected = ( $discount_type === $key ) ? 'selected="selected"' : '';
454
- echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
455
- }
456
- echo '</select>';
457
- }
458
-
459
- /**
460
- * Validation for cart abandonment `cut-off` settings.
461
- *
462
- * @param array $input input.
463
- * @since 1.1.5
464
- */
465
- public function wcf_ca_coupon_amount_validation( $input ) {
466
-
467
- $output = '';
468
- if ( ( is_numeric( $input ) && $input >= 1 ) ) {
469
- $output = stripslashes( $input );
470
- } else {
471
- add_settings_error(
472
- 'wcf_ca_coupon_amount',
473
- 'error found',
474
- __( 'Coupon code should be numeric and has to be greater than or equals to 1.', 'woo-cart-abandonment-recovery' )
475
- );
476
- }
477
- return $output;
478
- }
479
-
480
- /**
481
- * Callback for cart abandonment options.
482
- *
483
- * @since 1.1.5
484
- */
485
- public function wcf_cart_abandonment_options_callback() {
486
- echo '<hr/>';
487
- }
488
-
489
-
490
- /**
491
- * Callback for cart abandonment status.
492
- *
493
- * @param array $args args.
494
- * @since 1.1.5
495
- */
496
- public function wcf_ca_status_callback( $args ) {
497
- $wcf_ca_status = get_option( 'wcf_ca_status' );
498
- $html = '';
499
- printf(
500
- '<input type="checkbox" id="wcf_ca_status" name="wcf_ca_status" value="on"
501
- ' . checked( 'on', $wcf_ca_status, false ) . ' />'
502
- );
503
- $html .= '<label for="wcf_ca_status"> ' . $args[0] . '</label>';
504
- echo wp_kses_post( $html );
505
- }
506
-
507
- /**
508
- * Callback for ignore users from tracking cart.
509
- *
510
- * @param array $args args.
511
- * @since 1.1.5
512
- */
513
- public function wcf_ca_ignore_users_callback( $args ) {
514
-
515
- $wcf_ca_ignore_users = get_option( 'wcf_ca_ignore_users' );
516
- $html = '';
517
- $roles_obj = new WP_Roles();
518
- $roles_names_array = $roles_obj->get_names();
519
- $roles_names_array = array_diff( $roles_names_array, ( is_array( 'Customer' ) ? $value : array( 'Customer' ) ) );
520
- ?>
521
- <p class="wcf_ca_ignore_users" name="wcf_ca_ignore_users" multiple="multiple">
522
- <?php
523
- foreach ( $roles_names_array as $role_name ) {
524
- ?>
525
- <input type="checkbox" name="wcf_ca_ignore_users[]"
526
- <?php
527
- if ( ! empty( $wcf_ca_ignore_users ) ) {
528
- foreach ( $wcf_ca_ignore_users as $user ) {
529
- checked( $user, $role_name );
530
- }
531
- }
532
- ?>
533
- value="<?php echo esc_attr( $role_name ); ?>">
534
- <?php
535
- echo esc_attr( $role_name );
536
- echo '<br> ';
537
- }
538
- ?>
539
- </p>
540
- <?php
541
- $html .= '<span for="wcf_ca_ignore_users"> ' . $args[0] . '</span>';
542
- echo wp_kses_post( $html );
543
- }
544
-
545
- /**
546
- * Delete coupons.
547
- *
548
- * @param array $args args.
549
- */
550
- public function wcf_ca_auto_delete_coupons_callback( $args ) {
551
- $wcf_ca_auto_delete_coupons = get_option( 'wcf_ca_auto_delete_coupons' );
552
- $html = '';
553
- printf(
554
- '<input type="checkbox" id="wcf_ca_auto_delete_coupons" name="wcf_ca_auto_delete_coupons" value="on"
555
- ' . checked( 'on', $wcf_ca_auto_delete_coupons, false ) . ' />'
556
- );
557
- $html .= '<span for="wcf_ca_auto_delete_coupons"> ' . $args[0] . '</span>';
558
- echo wp_kses_post( $html );
559
- }
560
-
561
- /**
562
- * Delete coupons.
563
- *
564
- * @param array $args args.
565
- */
566
- public function wcf_ca_delete_coupons_callback( $args ) {
567
- ?>
568
-
569
- <input type="button" class="button-secondary" id="wcf_ca_delete_coupons" value="<?php esc_html_e( 'Delete', 'woo-cart-abandonment-recovery' ); ?>" >
570
- <span class="spinner wcf-ca-spinner"></span>
571
- <span class="wcf-ca-response-msg"></span>
572
- <?php
573
- $html = '';
574
- $html .= '<span for="wcf_ca_delete_coupons"> ' . $args[0] . '</span>';
575
- echo wp_kses_post( $html );
576
- }
577
-
578
- /**
579
- * Callback for cart abandonment status.
580
- *
581
- * @param array $args args.
582
- * @since 1.1.5
583
- */
584
- public function wcf_ca_gdpr_status_callback( $args ) {
585
- $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
586
- $html = '';
587
- printf(
588
- '<input type="checkbox" id="wcf_ca_gdpr_status" name="wcf_ca_gdpr_status" value="on"
589
- ' . checked( 'on', $wcf_ca_gdpr_status, false ) . ' />'
590
- );
591
- $html .= '<label for="wcf_ca_gdpr_status"> ' . $args[0] . '</label>';
592
- echo wp_kses_post( $html );
593
- }
594
-
595
- /**
596
- * Callback for email from name.
597
- *
598
- * @param array $args Arguments.
599
- */
600
- public static function wcf_ca_from_name_callback( $args ) {
601
- $wcf_ca_from_name = get_option( 'wcf_ca_from_name' );
602
- printf(
603
- '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_name" name="wcf_ca_from_name" value="%s" />',
604
- isset( $wcf_ca_from_name ) ? esc_attr( $wcf_ca_from_name ) : ''
605
- );
606
- $html = '<label for="wcf_ca_from_name"> ' . $args[0] . '</label>';
607
- echo wp_kses_post( $html );
608
- }
609
-
610
- /**
611
- * Callback for email from.
612
- *
613
- * @param array $args Arguments.
614
- */
615
- public static function wcf_ca_from_email_callback( $args ) {
616
- $wcf_ca_from_email = get_option( 'wcf_ca_from_email' );
617
- printf(
618
- '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_email" name="wcf_ca_from_email" value="%s" />',
619
- isset( $wcf_ca_from_email ) ? esc_attr( $wcf_ca_from_email ) : ''
620
- );
621
- $html = '<label for="wcf_ca_from_email"> ' . $args[0] . '</label>';
622
- echo wp_kses_post( $html );
623
- }
624
-
625
- /**
626
- * Callback for email reply.
627
- *
628
- * @param array $args Arguments.
629
- * @since 3.5
630
- */
631
- public static function wcf_ca_reply_email_callback( $args ) {
632
- $wcf_ca_reply_email = get_option( 'wcf_ca_reply_email' );
633
- printf(
634
- '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_reply_email" name="wcf_ca_reply_email" value="%s" />',
635
- isset( $wcf_ca_reply_email ) ? esc_attr( $wcf_ca_reply_email ) : ''
636
- );
637
-
638
- $html = '<label for="wcf_ca_reply_email"> ' . $args[0] . '</label>';
639
- echo wp_kses_post( $html );
640
- }
641
-
642
-
643
- /**
644
- * Validation for email.
645
- *
646
- * @param array $input input.
647
- * @since 1.1.5
648
- */
649
- public function wcf_ca_from_email_validation( $input ) {
650
-
651
- if ( $input && ! is_email( $input ) ) {
652
- add_settings_error(
653
- 'wcf_ca_from_email',
654
- 'error found',
655
- __( 'Invalid email "From" address field', 'woo-cart-abandonment-recovery' )
656
- );
657
- }
658
- return sanitize_email( $input );
659
- }
660
-
661
- /**
662
- * Validation for reply email.
663
- *
664
- * @param array $input input.
665
- * @since 1.1.5
666
- */
667
- public function wcf_ca_reply_email_validation( $input ) {
668
-
669
- if ( $input && ! is_email( $input ) ) {
670
- add_settings_error(
671
- 'wcf_ca_reply_email',
672
- 'error found',
673
- __( 'Invalid email "Reply" address field', 'woo-cart-abandonment-recovery' )
674
- );
675
- }
676
- return sanitize_email( $input );
677
- }
678
-
679
- /**
680
- * Initiator
681
- */
682
- public static function get_instance() {
683
- if ( ! isset( self::$instance ) ) {
684
- self::$instance = new self();
685
- }
686
- return self::$instance;
687
- }
688
-
689
-
690
-
691
-
692
- }
693
- 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
+ /**
32
+ * Adding action links for plugin list page.
33
+ *
34
+ * @param array $links links.
35
+ * @return array
36
+ */
37
+ public function add_action_links( $links ) {
38
+ $mylinks = array(
39
+ '<a href="' . admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME ) . '">Settings</a>',
40
+ );
41
+
42
+ return array_merge( $mylinks, $links );
43
+ }
44
+ /**
45
+ * Add new settings for cart abandonment settings.
46
+ *
47
+ * @since 1.1.5
48
+ */
49
+ public function wcf_initialize_settings() {
50
+
51
+ // Start: Settings for cart abandonment.
52
+ add_settings_section(
53
+ WCF_CA_GENERAL_SETTINGS_SECTION,
54
+ __( 'Cart Abandonment Settings', 'woo-cart-abandonment-recovery' ),
55
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
56
+ WCF_CA_PAGE_NAME
57
+ );
58
+
59
+ add_settings_field(
60
+ 'wcf_ca_status',
61
+ __( 'Enable Tracking', 'woo-cart-abandonment-recovery' ),
62
+ array( $this, 'wcf_ca_status_callback' ),
63
+ WCF_CA_PAGE_NAME,
64
+ WCF_CA_GENERAL_SETTINGS_SECTION,
65
+ 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>', 'woo-cart-abandonment-recovery' ) )
66
+ );
67
+
68
+ register_setting(
69
+ WCF_CA_SETTINGS_OPTION_GROUP,
70
+ 'wcf_ca_status'
71
+ );
72
+
73
+ add_settings_field(
74
+ 'wcf_ca_ignore_users',
75
+ __( 'Disable Tracking For', 'woo-cart-abandonment-recovery' ),
76
+ array( $this, 'wcf_ca_ignore_users_callback' ),
77
+ WCF_CA_PAGE_NAME,
78
+ WCF_CA_GENERAL_SETTINGS_SECTION,
79
+ array( '<br><span class="description"><strong>Note:</strong>' . __( ' It will ignore selected users from abandonment process when they logged in, and hence they can not receive mail for cart abandoned by themselves.', 'woo-cart-abandonment-recovery' ) . '</span>' )
80
+ );
81
+
82
+ register_setting(
83
+ WCF_CA_SETTINGS_OPTION_GROUP,
84
+ 'wcf_ca_ignore_users'
85
+ );
86
+
87
+ // End: General Settings for cart abandonment.
88
+ // Start: Delete coupons settings for cart abandonment.
89
+
90
+ add_settings_section(
91
+ WCF_CA_COUPONS_SETTINGS_SECTION,
92
+ __( 'Coupons Settings', 'woo-cart-abandonment-recovery' ),
93
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
94
+ WCF_CA_PAGE_NAME
95
+ );
96
+
97
+ add_settings_field(
98
+ 'wcf_ca_auto_delete_coupons',
99
+ __( 'Delete Coupons Automatically', 'woo-cart-abandonment-recovery' ),
100
+ array( $this, 'wcf_ca_auto_delete_coupons_callback' ),
101
+ WCF_CA_PAGE_NAME,
102
+ WCF_CA_COUPONS_SETTINGS_SECTION,
103
+ array( __( 'Delete coupons automatically on weekly basis.<br><span class="description"><br/><strong>Note:</strong> This option will set a weekly cron to delete all <strong>expired</strong> and <strong>used</strong> coupons automatically in the background.</p>', 'woo-cart-abandonment-recovery' ) )
104
+ );
105
+
106
+ register_setting(
107
+ WCF_CA_SETTINGS_OPTION_GROUP,
108
+ 'wcf_ca_auto_delete_coupons'
109
+ );
110
+
111
+ add_settings_field(
112
+ 'wcf_ca_delete_coupons',
113
+ __( 'Delete Coupons Manually', 'woo-cart-abandonment-recovery' ),
114
+ array( $this, 'wcf_ca_delete_coupons_callback' ),
115
+ WCF_CA_PAGE_NAME,
116
+ WCF_CA_COUPONS_SETTINGS_SECTION,
117
+ array( '<br><span class="description"> ' . __( '<br><strong>Note:</strong> This will delete all <strong>expired</strong> and <strong>used</strong> coupons that were created by Woo Cart Abandonment Recovery.</p>', 'woo-cart-abandonment-recovery' ) )
118
+ );
119
+
120
+ register_setting(
121
+ WCF_CA_SETTINGS_OPTION_GROUP,
122
+ 'wcf_ca_delete_coupons'
123
+ );
124
+
125
+ // End: Delete coupons settings for cart abandonment.
126
+ // Start: Settings for email templates.
127
+ add_settings_section(
128
+ WCF_CA_EMAIL_SETTINGS_SECTION,
129
+ __( 'Email Settings', 'woo-cart-abandonment-recovery' ),
130
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
131
+ WCF_CA_PAGE_NAME
132
+ );
133
+
134
+ add_settings_field(
135
+ 'wcf_ca_from_name',
136
+ __( '"From" Name', 'woo-cart-abandonment-recovery' ),
137
+ array( $this, 'wcf_ca_from_name_callback' ),
138
+ WCF_CA_PAGE_NAME,
139
+ WCF_CA_EMAIL_SETTINGS_SECTION,
140
+ array( __( 'Name will appear in email sent.', 'woo-cart-abandonment-recovery' ) )
141
+ );
142
+
143
+ add_settings_field(
144
+ 'wcf_ca_from_email',
145
+ __( '"From" Address', 'woo-cart-abandonment-recovery' ),
146
+ array( $this, 'wcf_ca_from_email_callback' ),
147
+ WCF_CA_PAGE_NAME,
148
+ WCF_CA_EMAIL_SETTINGS_SECTION,
149
+ array( __( 'Email which send from.', 'woo-cart-abandonment-recovery' ) )
150
+ );
151
+
152
+ add_settings_field(
153
+ 'wcf_ca_reply_email',
154
+ __( '"Reply To" Address', 'woo-cart-abandonment-recovery' ),
155
+ array( $this, 'wcf_ca_reply_email_callback' ),
156
+ WCF_CA_PAGE_NAME,
157
+ WCF_CA_EMAIL_SETTINGS_SECTION,
158
+ array( __( 'When a user clicks reply, which email address should that reply be sent to?', 'woo-cart-abandonment-recovery' ) )
159
+ );
160
+
161
+ register_setting(
162
+ WCF_CA_SETTINGS_OPTION_GROUP,
163
+ 'wcf_ca_from_name'
164
+ );
165
+
166
+ register_setting(
167
+ WCF_CA_SETTINGS_OPTION_GROUP,
168
+ 'wcf_ca_from_email',
169
+ array( $this, 'wcf_ca_from_email_validation' )
170
+ );
171
+
172
+ register_setting(
173
+ WCF_CA_SETTINGS_OPTION_GROUP,
174
+ 'wcf_ca_reply_email',
175
+ array( $this, 'wcf_ca_reply_email_validation' )
176
+ );
177
+ // End: Settings for email templates.
178
+ // Start: Settings for coupon code.
179
+ add_settings_field(
180
+ 'wcf_ca_zapier_tracking_status',
181
+ __( 'Enable Webhook', 'woo-cart-abandonment-recovery' ),
182
+ array( $this, 'wcf_ca_zapier_tracking_status_callback' ),
183
+ WCF_CA_PAGE_NAME,
184
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
185
+ array( __( 'Allows you to trigger webhook automatically upon cart abandonment and recovery.', 'woo-cart-abandonment-recovery' ) )
186
+ );
187
+
188
+ add_settings_field(
189
+ 'wcf_ca_zapier_cart_abandoned_webhook',
190
+ __( 'Webhook URL', 'woo-cart-abandonment-recovery' ),
191
+ array( $this, 'wcf_ca_zapier_cart_abandoned_webhook_callback' ),
192
+ WCF_CA_PAGE_NAME,
193
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
194
+ array( '', 'woo-cart-abandonment-recovery' )
195
+ );
196
+
197
+ register_setting(
198
+ WCF_CA_SETTINGS_OPTION_GROUP,
199
+ 'wcf_ca_zapier_tracking_status'
200
+ );
201
+
202
+ register_setting(
203
+ WCF_CA_SETTINGS_OPTION_GROUP,
204
+ 'wcf_ca_zapier_cart_abandoned_webhook'
205
+ );
206
+
207
+ add_settings_section(
208
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
209
+ __( 'Coupon Code Settings', 'woo-cart-abandonment-recovery' ),
210
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
211
+ WCF_CA_PAGE_NAME
212
+ );
213
+
214
+ add_settings_field(
215
+ 'wcf_ca_coupon_code_status',
216
+ __( 'Create Coupon Code', 'woo-cart-abandonment-recovery' ),
217
+ array( $this, 'wcf_ca_coupon_code_status_callback' ),
218
+ WCF_CA_PAGE_NAME,
219
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
220
+ array( __( 'Auto-create the special coupon for the abandoned cart to send over the emails.', 'woo-cart-abandonment-recovery' ) )
221
+ );
222
+
223
+ add_settings_field(
224
+ 'wcf_ca_discount_type',
225
+ __( 'Discount Type', 'woo-cart-abandonment-recovery' ),
226
+ array( $this, 'wcf_ca_discount_type_callback' ),
227
+ WCF_CA_PAGE_NAME,
228
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
229
+ array( '', 'woo-cart-abandonment-recovery' )
230
+ );
231
+
232
+ add_settings_field(
233
+ 'wcf_ca_coupon_amount',
234
+ __( 'Coupon Amount', 'woo-cart-abandonment-recovery' ),
235
+ array( $this, 'wcf_ca_coupon_amount_callback' ),
236
+ WCF_CA_PAGE_NAME,
237
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
238
+ array( '', 'woo-cart-abandonment-recovery' )
239
+ );
240
+
241
+ add_settings_field(
242
+ 'wcf_ca_coupon_expiry',
243
+ __( 'Coupon Expires After', 'woo-cart-abandonment-recovery' ),
244
+ array( $this, 'wcf_ca_coupon_expiry_callback' ),
245
+ WCF_CA_PAGE_NAME,
246
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
247
+ array( __( '<br/><br/> <span class="description"><strong>Note: </strong>. Enter zero (0) to restrict coupon from expiring.</span>', 'woo-cart-abandonment-recovery' ) )
248
+ );
249
+
250
+ register_setting(
251
+ WCF_CA_SETTINGS_OPTION_GROUP,
252
+ 'wcf_ca_coupon_expiry'
253
+ );
254
+ register_setting(
255
+ WCF_CA_SETTINGS_OPTION_GROUP,
256
+ 'wcf_ca_coupon_expiry_unit'
257
+ );
258
+
259
+ register_setting(
260
+ WCF_CA_SETTINGS_OPTION_GROUP,
261
+ 'wcf_ca_coupon_code_status'
262
+ );
263
+
264
+ register_setting(
265
+ WCF_CA_SETTINGS_OPTION_GROUP,
266
+ 'wcf_ca_discount_type'
267
+ );
268
+
269
+ register_setting(
270
+ WCF_CA_SETTINGS_OPTION_GROUP,
271
+ 'wcf_ca_coupon_amount',
272
+ array( $this, 'wcf_ca_coupon_amount_validation' )
273
+ );
274
+ // End: Settings for coupon code.
275
+ // Start: Settings for Zapier.
276
+ add_settings_section(
277
+ WCF_CA_ZAPIER_SETTINGS_SECTION,
278
+ __( 'Webhook Settings', 'woo-cart-abandonment-recovery' ),
279
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
280
+ WCF_CA_PAGE_NAME
281
+ );
282
+
283
+ // End: Settings for webhook.
284
+ // Start: GDPR Settings.
285
+ add_settings_section(
286
+ WCF_CA_GDPR_SETTINGS_SECTION,
287
+ __( 'GDPR Settings', 'woo-cart-abandonment-recovery' ),
288
+ array( $this, 'wcf_cart_abandonment_options_callback' ),
289
+ WCF_CA_PAGE_NAME
290
+ );
291
+
292
+ add_settings_field(
293
+ 'wcf_ca_gdpr_status',
294
+ __( 'Enable GDPR Integration', 'woo-cart-abandonment-recovery' ),
295
+ array( $this, 'wcf_ca_gdpr_status_callback' ),
296
+ WCF_CA_PAGE_NAME,
297
+ WCF_CA_GDPR_SETTINGS_SECTION,
298
+ 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>', 'woo-cart-abandonment-recovery' ) )
299
+ );
300
+
301
+ add_settings_field(
302
+ 'wcf_ca_gdpr_message',
303
+ __( 'GDPR Message', 'woo-cart-abandonment-recovery' ),
304
+ array( $this, 'wcf_ca_gdpr_message_callback' ),
305
+ WCF_CA_PAGE_NAME,
306
+ WCF_CA_GDPR_SETTINGS_SECTION,
307
+ array( '', 'woo-cart-abandonment-recovery' )
308
+ );
309
+
310
+ register_setting(
311
+ WCF_CA_SETTINGS_OPTION_GROUP,
312
+ 'wcf_ca_gdpr_status'
313
+ );
314
+ register_setting(
315
+ WCF_CA_SETTINGS_OPTION_GROUP,
316
+ 'wcf_ca_gdpr_message'
317
+ );
318
+
319
+ }
320
+
321
+ /**
322
+ * Callback for cart abandonment status.
323
+ *
324
+ * @param array $args args.
325
+ * @since 1.1.5
326
+ */
327
+ public function wcf_ca_coupon_code_status_callback( $args ) {
328
+ $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
329
+ $html = '';
330
+ printf(
331
+ '<input type="checkbox" id="wcf_ca_coupon_code_status" name="wcf_ca_coupon_code_status" value="on"
332
+ ' . checked( 'on', $wcf_ca_coupon_code_status, false ) . ' />'
333
+ );
334
+ $html .= '<label for="wcf_ca_coupon_code_status"> ' . $args[0] . '</label>';
335
+ echo wp_kses_post( $html );
336
+ }
337
+
338
+
339
+ /**
340
+ * Callback for cart abandonment cut off time.
341
+ *
342
+ * @param array $args args.
343
+ * @since 1.1.5
344
+ */
345
+ public function wcf_ca_zapier_cart_abandoned_webhook_callback( $args ) {
346
+ $wcf_ca_zapier_cart_abandoned_webhook = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
347
+ echo '<input type="text" class="wcf-ca-trigger-input" id="wcf_ca_zapier_cart_abandoned_webhook" name="wcf_ca_zapier_cart_abandoned_webhook" value="' . esc_attr( sanitize_text_field( $wcf_ca_zapier_cart_abandoned_webhook ) ) . '" />';
348
+ echo '<button id="wcf_ca_trigger_web_hook_abandoned_btn" type="button" class="button"> Trigger Sample </button>';
349
+ echo '<span style="margin-left: 10px;" id="wcf_ca_abandoned_btn_message"></span>';
350
+ $html = '<label for="wcf_ca_zapier_cart_abandoned_webhook"> ' . $args[0] . '</label>';
351
+ echo wp_kses_post( $html );
352
+ }
353
+
354
+
355
+ /**
356
+ * Callback for cart abandonment status.
357
+ *
358
+ * @param array $args args.
359
+ * @since 1.1.5
360
+ */
361
+ public function wcf_ca_zapier_tracking_status_callback( $args ) {
362
+ $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
363
+
364
+ $html = '';
365
+ printf(
366
+ '<input type="checkbox" id="wcf_ca_zapier_tracking_status" name="wcf_ca_zapier_tracking_status" value="on"
367
+ ' . checked( 'on', $wcf_ca_zapier_tracking_status, false ) . ' />'
368
+ );
369
+ $html .= '<label for="wcf_ca_zapier_tracking_status"> ' . $args[0] . '</label>';
370
+ echo wp_kses_post( $html );
371
+ }
372
+
373
+
374
+ /**
375
+ * Callback for cart abandonment cut off time.
376
+ *
377
+ * @param array $args args.
378
+ * @since 1.1.5
379
+ */
380
+ public function wcf_ca_coupon_amount_callback( $args ) {
381
+ $wcf_ca_coupon_amount = get_option( 'wcf_ca_coupon_amount' );
382
+ printf(
383
+ '<input type="number" class="wcf-ca-trigger-input wcf-ca-email-inputs" id="wcf_ca_coupon_amount" name="wcf_ca_coupon_amount" value="%s" />',
384
+ isset( $wcf_ca_coupon_amount ) ? esc_attr( $wcf_ca_coupon_amount ) : ''
385
+ );
386
+ $html = '<label for="wcf_ca_coupon_amount"> ' . $args[0] . '</label>';
387
+ echo wp_kses_post( $html );
388
+ }
389
+
390
+ /**
391
+ * Callback for cart abandonment cut off time.
392
+ *
393
+ * @param array $args args.
394
+ * @since 1.1.5
395
+ */
396
+ public function wcf_ca_coupon_expiry_callback( $args ) {
397
+ $wcf_ca_coupon_expiry = intval( get_option( 'wcf_ca_coupon_expiry' ) );
398
+ printf(
399
+ '<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" />',
400
+ isset( $wcf_ca_coupon_expiry ) ? esc_attr( $wcf_ca_coupon_expiry ) : ''
401
+ );
402
+
403
+ $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
404
+ $items = array(
405
+ 'hours' => __( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
406
+ 'days' => __( 'Day(s)', 'woo-cart-abandonment-recovery' ),
407
+ );
408
+ echo "<select id='wcf_ca_coupon_expiry_unit' name='wcf_ca_coupon_expiry_unit'>";
409
+ foreach ( $items as $key => $item ) {
410
+ $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
411
+ echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
412
+ }
413
+ echo '</select>';
414
+
415
+ $html = '<label for="wcf_ca_coupon_expiry_unit"> ' . $args[0] . '</label>';
416
+ echo wp_kses_post( $html );
417
+ }
418
+
419
+
420
+
421
+ /**
422
+ * Callback for cart abandonment cut off time.
423
+ *
424
+ * @param array $args args.
425
+ * @since 1.1.5
426
+ */
427
+ public function wcf_ca_gdpr_message_callback( $args ) {
428
+ $wcf_ca_gdpr_message = get_option( 'wcf_ca_gdpr_message' );
429
+
430
+ printf(
431
+ '<textarea rows="2" cols="60" id="wcf_ca_gdpr_message" name="wcf_ca_gdpr_message" spellcheck="false">%s</textarea>',
432
+ isset( $wcf_ca_gdpr_message ) ? esc_attr( $wcf_ca_gdpr_message ) : ''
433
+ );
434
+ $html = '<label for="wcf_ca_gdpr_message"> ' . $args[0] . '</label>';
435
+ echo wp_kses_post( $html );
436
+ }
437
+
438
+ /**
439
+ * Callback for cart abandonment cut off time.
440
+ *
441
+ * @param array $args args.
442
+ * @since 1.1.5
443
+ */
444
+ public function wcf_ca_discount_type_callback( $args ) {
445
+
446
+ $discount_type = get_option( 'wcf_ca_discount_type' );
447
+ $items = array(
448
+ 'percent' => 'Percentage discount',
449
+ 'fixed_cart' => 'Fixed cart discount',
450
+ );
451
+ echo "<select id='wcf_ca_discount_type' name='wcf_ca_discount_type'>";
452
+ foreach ( $items as $key => $item ) {
453
+ $selected = ( $discount_type === $key ) ? 'selected="selected"' : '';
454
+ echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
455
+ }
456
+ echo '</select>';
457
+ }
458
+
459
+ /**
460
+ * Validation for cart abandonment `cut-off` settings.
461
+ *
462
+ * @param array $input input.
463
+ * @since 1.1.5
464
+ */
465
+ public function wcf_ca_coupon_amount_validation( $input ) {
466
+
467
+ $output = '';
468
+ if ( ( is_numeric( $input ) && $input >= 1 ) ) {
469
+ $output = stripslashes( $input );
470
+ } else {
471
+ add_settings_error(
472
+ 'wcf_ca_coupon_amount',
473
+ 'error found',
474
+ __( 'Coupon code should be numeric and has to be greater than or equals to 1.', 'woo-cart-abandonment-recovery' )
475
+ );
476
+ }
477
+ return $output;
478
+ }
479
+
480
+ /**
481
+ * Callback for cart abandonment options.
482
+ *
483
+ * @since 1.1.5
484
+ */
485
+ public function wcf_cart_abandonment_options_callback() {
486
+ echo '<hr/>';
487
+ }
488
+
489
+
490
+ /**
491
+ * Callback for cart abandonment status.
492
+ *
493
+ * @param array $args args.
494
+ * @since 1.1.5
495
+ */
496
+ public function wcf_ca_status_callback( $args ) {
497
+ $wcf_ca_status = get_option( 'wcf_ca_status' );
498
+ $html = '';
499
+ printf(
500
+ '<input type="checkbox" id="wcf_ca_status" name="wcf_ca_status" value="on"
501
+ ' . checked( 'on', $wcf_ca_status, false ) . ' />'
502
+ );
503
+ $html .= '<label for="wcf_ca_status"> ' . $args[0] . '</label>';
504
+ echo wp_kses_post( $html );
505
+ }
506
+
507
+ /**
508
+ * Callback for ignore users from tracking cart.
509
+ *
510
+ * @param array $args args.
511
+ * @since 1.1.5
512
+ */
513
+ public function wcf_ca_ignore_users_callback( $args ) {
514
+
515
+ $wcf_ca_ignore_users = get_option( 'wcf_ca_ignore_users' );
516
+ $html = '';
517
+ $roles_obj = new WP_Roles();
518
+ $roles_names_array = $roles_obj->get_names();
519
+ $roles_names_array = array_diff( $roles_names_array, ( is_array( 'Customer' ) ? $value : array( 'Customer' ) ) );
520
+ ?>
521
+ <p class="wcf_ca_ignore_users" name="wcf_ca_ignore_users" multiple="multiple">
522
+ <?php
523
+ foreach ( $roles_names_array as $role_name ) {
524
+ ?>
525
+ <input type="checkbox" name="wcf_ca_ignore_users[]"
526
+ <?php
527
+ if ( ! empty( $wcf_ca_ignore_users ) ) {
528
+ foreach ( $wcf_ca_ignore_users as $user ) {
529
+ checked( $user, $role_name );
530
+ }
531
+ }
532
+ ?>
533
+ value="<?php echo esc_attr( $role_name ); ?>">
534
+ <?php
535
+ echo esc_attr( $role_name );
536
+ echo '<br> ';
537
+ }
538
+ ?>
539
+ </p>
540
+ <?php
541
+ $html .= '<span for="wcf_ca_ignore_users"> ' . $args[0] . '</span>';
542
+ echo wp_kses_post( $html );
543
+ }
544
+
545
+ /**
546
+ * Delete coupons.
547
+ *
548
+ * @param array $args args.
549
+ */
550
+ public function wcf_ca_auto_delete_coupons_callback( $args ) {
551
+ $wcf_ca_auto_delete_coupons = get_option( 'wcf_ca_auto_delete_coupons' );
552
+ $html = '';
553
+ printf(
554
+ '<input type="checkbox" id="wcf_ca_auto_delete_coupons" name="wcf_ca_auto_delete_coupons" value="on"
555
+ ' . checked( 'on', $wcf_ca_auto_delete_coupons, false ) . ' />'
556
+ );
557
+ $html .= '<span for="wcf_ca_auto_delete_coupons"> ' . $args[0] . '</span>';
558
+ echo wp_kses_post( $html );
559
+ }
560
+
561
+ /**
562
+ * Delete coupons.
563
+ *
564
+ * @param array $args args.
565
+ */
566
+ public function wcf_ca_delete_coupons_callback( $args ) {
567
+ ?>
568
+
569
+ <input type="button" class="button-secondary" id="wcf_ca_delete_coupons" value="<?php esc_html_e( 'Delete', 'woo-cart-abandonment-recovery' ); ?>" >
570
+ <span class="spinner wcf-ca-spinner"></span>
571
+ <span class="wcf-ca-response-msg"></span>
572
+ <?php
573
+ $html = '';
574
+ $html .= '<span for="wcf_ca_delete_coupons"> ' . $args[0] . '</span>';
575
+ echo wp_kses_post( $html );
576
+ }
577
+
578
+ /**
579
+ * Callback for cart abandonment status.
580
+ *
581
+ * @param array $args args.
582
+ * @since 1.1.5
583
+ */
584
+ public function wcf_ca_gdpr_status_callback( $args ) {
585
+ $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
586
+ $html = '';
587
+ printf(
588
+ '<input type="checkbox" id="wcf_ca_gdpr_status" name="wcf_ca_gdpr_status" value="on"
589
+ ' . checked( 'on', $wcf_ca_gdpr_status, false ) . ' />'
590
+ );
591
+ $html .= '<label for="wcf_ca_gdpr_status"> ' . $args[0] . '</label>';
592
+ echo wp_kses_post( $html );
593
+ }
594
+
595
+ /**
596
+ * Callback for email from name.
597
+ *
598
+ * @param array $args Arguments.
599
+ */
600
+ public static function wcf_ca_from_name_callback( $args ) {
601
+ $wcf_ca_from_name = get_option( 'wcf_ca_from_name' );
602
+ printf(
603
+ '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_name" name="wcf_ca_from_name" value="%s" />',
604
+ isset( $wcf_ca_from_name ) ? esc_attr( $wcf_ca_from_name ) : ''
605
+ );
606
+ $html = '<label for="wcf_ca_from_name"> ' . $args[0] . '</label>';
607
+ echo wp_kses_post( $html );
608
+ }
609
+
610
+ /**
611
+ * Callback for email from.
612
+ *
613
+ * @param array $args Arguments.
614
+ */
615
+ public static function wcf_ca_from_email_callback( $args ) {
616
+ $wcf_ca_from_email = get_option( 'wcf_ca_from_email' );
617
+ printf(
618
+ '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_from_email" name="wcf_ca_from_email" value="%s" />',
619
+ isset( $wcf_ca_from_email ) ? esc_attr( $wcf_ca_from_email ) : ''
620
+ );
621
+ $html = '<label for="wcf_ca_from_email"> ' . $args[0] . '</label>';
622
+ echo wp_kses_post( $html );
623
+ }
624
+
625
+ /**
626
+ * Callback for email reply.
627
+ *
628
+ * @param array $args Arguments.
629
+ * @since 3.5
630
+ */
631
+ public static function wcf_ca_reply_email_callback( $args ) {
632
+ $wcf_ca_reply_email = get_option( 'wcf_ca_reply_email' );
633
+ printf(
634
+ '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="text" id="wcf_ca_reply_email" name="wcf_ca_reply_email" value="%s" />',
635
+ isset( $wcf_ca_reply_email ) ? esc_attr( $wcf_ca_reply_email ) : ''
636
+ );
637
+
638
+ $html = '<label for="wcf_ca_reply_email"> ' . $args[0] . '</label>';
639
+ echo wp_kses_post( $html );
640
+ }
641
+
642
+
643
+ /**
644
+ * Validation for email.
645
+ *
646
+ * @param array $input input.
647
+ * @since 1.1.5
648
+ */
649
+ public function wcf_ca_from_email_validation( $input ) {
650
+
651
+ if ( $input && ! is_email( $input ) ) {
652
+ add_settings_error(
653
+ 'wcf_ca_from_email',
654
+ 'error found',
655
+ __( 'Invalid email "From" address field', 'woo-cart-abandonment-recovery' )
656
+ );
657
+ }
658
+ return sanitize_email( $input );
659
+ }
660
+
661
+ /**
662
+ * Validation for reply email.
663
+ *
664
+ * @param array $input input.
665
+ * @since 1.1.5
666
+ */
667
+ public function wcf_ca_reply_email_validation( $input ) {
668
+
669
+ if ( $input && ! is_email( $input ) ) {
670
+ add_settings_error(
671
+ 'wcf_ca_reply_email',
672
+ 'error found',
673
+ __( 'Invalid email "Reply" address field', 'woo-cart-abandonment-recovery' )
674
+ );
675
+ }
676
+ return sanitize_email( $input );
677
+ }
678
+
679
+ /**
680
+ * Initiator
681
+ */
682
+ public static function get_instance() {
683
+ if ( ! isset( self::$instance ) ) {
684
+ self::$instance = new self();
685
+ }
686
+ return self::$instance;
687
+ }
688
+
689
+
690
+
691
+
692
+ }
693
+ Cartflows_Ca_Settings::get_instance();
classes/class-cartflows-ca-update.php CHANGED
@@ -1,92 +1,92 @@
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
- * Create tables if not exists and seed default settings.
44
- */
45
- public static function update_table_with_default_settings() {
46
-
47
- $cartflows_loader = CARTFLOWS_CA_Loader::get_instance();
48
- $cartflows_loader->initialize_cart_abandonment_tables();
49
- $cartflows_loader->update_default_settings();
50
- }
51
-
52
-
53
- /**
54
- * Init
55
- *
56
- * @since 1.0.0
57
- * @return void
58
- */
59
- public static function init() {
60
-
61
- do_action( 'cartflows_ca_update_before' );
62
-
63
- // Get auto saved version number.
64
- $saved_version = get_option( 'wcf_ca_version', false );
65
-
66
- // Update auto saved version number.
67
- if ( ! $saved_version ) {
68
- self::update_table_with_default_settings();
69
- update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
70
- return;
71
- }
72
-
73
- // If equals then return.
74
- if ( version_compare( $saved_version, CARTFLOWS_CA_VER, '=' ) ) {
75
- return;
76
- }
77
-
78
- // Update auto saved version number.
79
- update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
80
-
81
- self::update_table_with_default_settings();
82
-
83
- do_action( 'cartflows_ca_update_after' );
84
- }
85
- }
86
-
87
- /**
88
- * Kicking this off by calling 'get_instance()' method
89
- */
90
- Cartflows_Ca_Update::get_instance();
91
-
92
- 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
+ * Create tables if not exists and seed default settings.
44
+ */
45
+ public static function update_table_with_default_settings() {
46
+
47
+ $cartflows_loader = CARTFLOWS_CA_Loader::get_instance();
48
+ $cartflows_loader->initialize_cart_abandonment_tables();
49
+ $cartflows_loader->update_default_settings();
50
+ }
51
+
52
+
53
+ /**
54
+ * Init
55
+ *
56
+ * @since 1.0.0
57
+ * @return void
58
+ */
59
+ public static function init() {
60
+
61
+ do_action( 'cartflows_ca_update_before' );
62
+
63
+ // Get auto saved version number.
64
+ $saved_version = get_option( 'wcf_ca_version', false );
65
+
66
+ // Update auto saved version number.
67
+ if ( ! $saved_version ) {
68
+ self::update_table_with_default_settings();
69
+ update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
70
+ return;
71
+ }
72
+
73
+ // If equals then return.
74
+ if ( version_compare( $saved_version, CARTFLOWS_CA_VER, '=' ) ) {
75
+ return;
76
+ }
77
+
78
+ // Update auto saved version number.
79
+ update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
80
+
81
+ self::update_table_with_default_settings();
82
+
83
+ do_action( 'cartflows_ca_update_after' );
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Kicking this off by calling 'get_instance()' method
89
+ */
90
+ Cartflows_Ca_Update::get_instance();
91
+
92
+ 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
- public 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
- public 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
- public 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
- public 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
+ public 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
+ public 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
+ public 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
+ public 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/woo-cart-abandonment-recovery.pot CHANGED
@@ -2,10 +2,10 @@
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.2.4\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/woo-cart-abandonment-recovery\n"
8
- "POT-Creation-Date: 2020-02-06 11:49:03+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -229,31 +229,31 @@ msgstr ""
229
 
230
  #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:86
231
  #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:138
232
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1706
233
  msgid "Unsubscribe"
234
  msgstr ""
235
 
236
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:218
237
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1846
238
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1897
239
  #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:173
240
  msgid "Name"
241
  msgstr ""
242
 
243
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:219
244
  msgid "Email"
245
  msgstr ""
246
 
247
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:220
248
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1919
249
  msgid "Cart Total"
250
  msgstr ""
251
 
252
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:221
253
  msgid "Order Status"
254
  msgstr ""
255
 
256
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:222
257
  msgid "Time"
258
  msgstr ""
259
 
@@ -297,90 +297,90 @@ msgstr ""
297
  msgid "You won't receive further emails from us, thank you!"
298
  msgstr ""
299
 
300
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1107
301
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1108
302
  msgid "Cart Abandonment"
303
  msgstr ""
304
 
305
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1133
306
  msgid "Items deleted: %d"
307
  msgstr ""
308
 
309
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1150
310
  msgid "User(s) unsubscribed successfully!"
311
  msgstr ""
312
 
313
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1211
314
  msgid ""
315
  "Do you really want to delete the used and expired coupons created by Cart "
316
  "Abandonment Plugin?"
317
  msgstr ""
318
 
319
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1212
320
  msgid "Do you really want to export orders?"
321
  msgstr ""
322
 
323
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1216
324
  msgid "No such order is found."
325
  msgstr ""
326
 
327
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1235
328
  msgid "View Report"
329
  msgstr ""
330
 
331
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1373
332
  msgid "Report"
333
  msgstr ""
334
 
335
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1389
336
  msgid "Follow-Up Emails"
337
  msgstr ""
338
 
339
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1405
340
  msgid "Settings"
341
  msgstr ""
342
 
343
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1667
344
  msgid "there"
345
  msgstr ""
346
 
347
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1838
348
  msgid "Cart Total ( Cart Total + Shipping + Tax )"
349
  msgstr ""
350
 
351
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1845
352
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1896
353
  msgid "Item"
354
  msgstr ""
355
 
356
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1847
357
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1898
358
  msgid "Quantity"
359
  msgstr ""
360
 
361
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1848
362
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1899
363
  msgid "Price"
364
  msgstr ""
365
 
366
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1849
367
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1900
368
  msgid "Line Subtotal"
369
  msgstr ""
370
 
371
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1906
372
  msgid "Discount"
373
  msgstr ""
374
 
375
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1910
376
  msgid "Other"
377
  msgstr ""
378
 
379
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1915
380
  msgid "Shipping"
381
  msgstr ""
382
 
383
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:2063
384
  #. translators: %1$s: Coupons Deleted, %2$s: Deleted coupons count'.
385
  msgid "%1$s: %2$d"
386
  msgstr ""
@@ -598,7 +598,7 @@ msgstr ""
598
  #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:48
599
  msgid ""
600
  "All new activated emails will be reschedule for this abandoned order.New "
601
- "emails will\n"
602
  "\t\t\t\t\t\t\t\t\t\t\tbe sent to user according to schedule time."
603
  msgstr ""
604
 
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.2.5\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://wordpress.org/support/plugin/woo-cart-abandonment-recovery\n"
8
+ "POT-Creation-Date: 2020-03-11 05:30:02+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
229
 
230
  #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:86
231
  #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:138
232
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1708
233
  msgid "Unsubscribe"
234
  msgstr ""
235
 
236
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:234
237
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1848
238
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1898
239
  #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:173
240
  msgid "Name"
241
  msgstr ""
242
 
243
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:235
244
  msgid "Email"
245
  msgstr ""
246
 
247
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:236
248
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1920
249
  msgid "Cart Total"
250
  msgstr ""
251
 
252
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:237
253
  msgid "Order Status"
254
  msgstr ""
255
 
256
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:238
257
  msgid "Time"
258
  msgstr ""
259
 
297
  msgid "You won't receive further emails from us, thank you!"
298
  msgstr ""
299
 
300
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1109
301
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1110
302
  msgid "Cart Abandonment"
303
  msgstr ""
304
 
305
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1135
306
  msgid "Items deleted: %d"
307
  msgstr ""
308
 
309
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1152
310
  msgid "User(s) unsubscribed successfully!"
311
  msgstr ""
312
 
313
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1213
314
  msgid ""
315
  "Do you really want to delete the used and expired coupons created by Cart "
316
  "Abandonment Plugin?"
317
  msgstr ""
318
 
319
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1214
320
  msgid "Do you really want to export orders?"
321
  msgstr ""
322
 
323
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1218
324
  msgid "No such order is found."
325
  msgstr ""
326
 
327
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1237
328
  msgid "View Report"
329
  msgstr ""
330
 
331
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1375
332
  msgid "Report"
333
  msgstr ""
334
 
335
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1391
336
  msgid "Follow-Up Emails"
337
  msgstr ""
338
 
339
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1407
340
  msgid "Settings"
341
  msgstr ""
342
 
343
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1669
344
  msgid "there"
345
  msgstr ""
346
 
347
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1840
348
  msgid "Cart Total ( Cart Total + Shipping + Tax )"
349
  msgstr ""
350
 
351
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1847
352
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1897
353
  msgid "Item"
354
  msgstr ""
355
 
356
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1849
357
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1899
358
  msgid "Quantity"
359
  msgstr ""
360
 
361
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1850
362
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1900
363
  msgid "Price"
364
  msgstr ""
365
 
366
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1851
367
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1901
368
  msgid "Line Subtotal"
369
  msgstr ""
370
 
371
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1907
372
  msgid "Discount"
373
  msgstr ""
374
 
375
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1911
376
  msgid "Other"
377
  msgstr ""
378
 
379
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1916
380
  msgid "Shipping"
381
  msgstr ""
382
 
383
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:2064
384
  #. translators: %1$s: Coupons Deleted, %2$s: Deleted coupons count'.
385
  msgid "%1$s: %2$d"
386
  msgstr ""
598
  #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:48
599
  msgid ""
600
  "All new activated emails will be reschedule for this abandoned order.New "
601
+ "emails will\r\n"
602
  "\t\t\t\t\t\t\t\t\t\t\tbe sent to user according to schedule time."
603
  msgstr ""
604
 
modules/cart-abandonment/assets/js/cart-abandonment-tracking.js CHANGED
@@ -1,167 +1,167 @@
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
-
80
- if( typeof wcf_email === 'undefined' ){
81
- return ;
82
- }
83
-
84
- var atposition = wcf_email.indexOf("@");
85
- var dotposition = wcf_email.lastIndexOf(".");
86
-
87
-
88
- if (typeof wcf_phone === 'undefined' || wcf_phone === null) { //If phone number field does not exist on the Checkout form
89
- wcf_phone = '';
90
- }
91
-
92
- clearTimeout(timer);
93
-
94
- 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
95
- //If Email or Phone valid
96
- var wcf_name = jQuery("#billing_first_name").val();
97
- var wcf_surname = jQuery("#billing_last_name").val();
98
- var wcf_phone = jQuery("#billing_phone").val();
99
- var wcf_country = jQuery("#billing_country").val();
100
- var wcf_city = jQuery("#billing_city").val();
101
-
102
- //Other fields used for "Remember user input" function
103
- var wcf_billing_company = jQuery("#billing_company").val();
104
- var wcf_billing_address_1 = jQuery("#billing_address_1").val();
105
- var wcf_billing_address_2 = jQuery("#billing_address_2").val();
106
- var wcf_billing_state = jQuery("#billing_state").val();
107
- var wcf_billing_postcode = jQuery("#billing_postcode").val();
108
- var wcf_shipping_first_name = jQuery("#shipping_first_name").val();
109
- var wcf_shipping_last_name = jQuery("#shipping_last_name").val();
110
- var wcf_shipping_company = jQuery("#shipping_company").val();
111
- var wcf_shipping_country = jQuery("#shipping_country").val();
112
- var wcf_shipping_address_1 = jQuery("#shipping_address_1").val();
113
- var wcf_shipping_address_2 = jQuery("#shipping_address_2").val();
114
- var wcf_shipping_city = jQuery("#shipping_city").val();
115
- var wcf_shipping_state = jQuery("#shipping_state").val();
116
- var wcf_shipping_postcode = jQuery("#shipping_postcode").val();
117
- var wcf_order_comments = jQuery("#order_comments").val();
118
-
119
- var data = {
120
- action: "cartflows_save_cart_abandonment_data",
121
- wcf_email: wcf_email,
122
- wcf_name: wcf_name,
123
- wcf_surname: wcf_surname,
124
- wcf_phone: wcf_phone,
125
- wcf_country: wcf_country,
126
- wcf_city: wcf_city,
127
- wcf_billing_company: wcf_billing_company,
128
- wcf_billing_address_1: wcf_billing_address_1,
129
- wcf_billing_address_2: wcf_billing_address_2,
130
- wcf_billing_state: wcf_billing_state,
131
- wcf_billing_postcode: wcf_billing_postcode,
132
- wcf_shipping_first_name: wcf_shipping_first_name,
133
- wcf_shipping_last_name: wcf_shipping_last_name,
134
- wcf_shipping_company: wcf_shipping_company,
135
- wcf_shipping_country: wcf_shipping_country,
136
- wcf_shipping_address_1: wcf_shipping_address_1,
137
- wcf_shipping_address_2: wcf_shipping_address_2,
138
- wcf_shipping_city: wcf_shipping_city,
139
- wcf_shipping_state: wcf_shipping_state,
140
- wcf_shipping_postcode: wcf_shipping_postcode,
141
- wcf_order_comments: wcf_order_comments,
142
- security: CartFlowsProCAVars._nonce,
143
- wcf_post_id: CartFlowsProCAVars._post_id,
144
- }
145
-
146
- timer = setTimeout(
147
- function () {
148
- if (wcf_cart_abandonment._validate_email(data.wcf_email)) {
149
- jQuery.post(
150
- 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
151
- function (response) {
152
- // success response
153
- }
154
- );
155
- }
156
- }, 500
157
- );
158
- } else {
159
- //console.log("Not a valid e-mail or phone address");
160
- }
161
- }
162
-
163
- }
164
-
165
- wcf_cart_abandonment.init();
166
-
167
  })(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
+
80
+ if( typeof wcf_email === 'undefined' ){
81
+ return ;
82
+ }
83
+
84
+ var atposition = wcf_email.indexOf("@");
85
+ var dotposition = wcf_email.lastIndexOf(".");
86
+
87
+
88
+ if (typeof wcf_phone === 'undefined' || wcf_phone === null) { //If phone number field does not exist on the Checkout form
89
+ wcf_phone = '';
90
+ }
91
+
92
+ clearTimeout(timer);
93
+
94
+ 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
95
+ //If Email or Phone valid
96
+ var wcf_name = jQuery("#billing_first_name").val();
97
+ var wcf_surname = jQuery("#billing_last_name").val();
98
+ var wcf_phone = jQuery("#billing_phone").val();
99
+ var wcf_country = jQuery("#billing_country").val();
100
+ var wcf_city = jQuery("#billing_city").val();
101
+
102
+ //Other fields used for "Remember user input" function
103
+ var wcf_billing_company = jQuery("#billing_company").val();
104
+ var wcf_billing_address_1 = jQuery("#billing_address_1").val();
105
+ var wcf_billing_address_2 = jQuery("#billing_address_2").val();
106
+ var wcf_billing_state = jQuery("#billing_state").val();
107
+ var wcf_billing_postcode = jQuery("#billing_postcode").val();
108
+ var wcf_shipping_first_name = jQuery("#shipping_first_name").val();
109
+ var wcf_shipping_last_name = jQuery("#shipping_last_name").val();
110
+ var wcf_shipping_company = jQuery("#shipping_company").val();
111
+ var wcf_shipping_country = jQuery("#shipping_country").val();
112
+ var wcf_shipping_address_1 = jQuery("#shipping_address_1").val();
113
+ var wcf_shipping_address_2 = jQuery("#shipping_address_2").val();
114
+ var wcf_shipping_city = jQuery("#shipping_city").val();
115
+ var wcf_shipping_state = jQuery("#shipping_state").val();
116
+ var wcf_shipping_postcode = jQuery("#shipping_postcode").val();
117
+ var wcf_order_comments = jQuery("#order_comments").val();
118
+
119
+ var data = {
120
+ action: "cartflows_save_cart_abandonment_data",
121
+ wcf_email: wcf_email,
122
+ wcf_name: wcf_name,
123
+ wcf_surname: wcf_surname,
124
+ wcf_phone: wcf_phone,
125
+ wcf_country: wcf_country,
126
+ wcf_city: wcf_city,
127
+ wcf_billing_company: wcf_billing_company,
128
+ wcf_billing_address_1: wcf_billing_address_1,
129
+ wcf_billing_address_2: wcf_billing_address_2,
130
+ wcf_billing_state: wcf_billing_state,
131
+ wcf_billing_postcode: wcf_billing_postcode,
132
+ wcf_shipping_first_name: wcf_shipping_first_name,
133
+ wcf_shipping_last_name: wcf_shipping_last_name,
134
+ wcf_shipping_company: wcf_shipping_company,
135
+ wcf_shipping_country: wcf_shipping_country,
136
+ wcf_shipping_address_1: wcf_shipping_address_1,
137
+ wcf_shipping_address_2: wcf_shipping_address_2,
138
+ wcf_shipping_city: wcf_shipping_city,
139
+ wcf_shipping_state: wcf_shipping_state,
140
+ wcf_shipping_postcode: wcf_shipping_postcode,
141
+ wcf_order_comments: wcf_order_comments,
142
+ security: CartFlowsProCAVars._nonce,
143
+ wcf_post_id: CartFlowsProCAVars._post_id,
144
+ }
145
+
146
+ timer = setTimeout(
147
+ function () {
148
+ if (wcf_cart_abandonment._validate_email(data.wcf_email)) {
149
+ jQuery.post(
150
+ 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
151
+ function (response) {
152
+ // success response
153
+ }
154
+ );
155
+ }
156
+ }, 500
157
+ );
158
+ } else {
159
+ //console.log("Not a valid e-mail or phone address");
160
+ }
161
+ }
162
+
163
+ }
164
+
165
+ wcf_cart_abandonment.init();
166
+
167
  })(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,275 +1,291 @@
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
- * Member Variable
19
- *
20
- * @var object instance
21
- */
22
- private static $instance;
23
-
24
- /**
25
- * Initiator
26
- */
27
- public static function get_instance() {
28
- if ( ! isset( self::$instance ) ) {
29
- self::$instance = new self();
30
- }
31
- return self::$instance;
32
- }
33
-
34
- /**
35
- * Constructor function.
36
- */
37
- public function __construct() {
38
- global $status, $page;
39
-
40
- parent::__construct(
41
- array(
42
- 'singular' => 'id',
43
- 'plural' => 'ids',
44
- )
45
- );
46
- }
47
-
48
- /**
49
- * Default columns.
50
- *
51
- * @param object $item item.
52
- * @param string $column_name column name.
53
- */
54
- public function column_default( $item, $column_name ) {
55
- return $item[ $column_name ];
56
- }
57
-
58
- /**
59
- * Column name surname.
60
- *
61
- * @param object $item item.
62
- * @return string
63
- */
64
- public function column_nameSurname( $item ) {
65
-
66
- $item_details = unserialize( $item['other_fields'] );
67
-
68
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
69
-
70
- $view_url = add_query_arg(
71
- array(
72
- 'page' => WCF_CA_PAGE_NAME,
73
- 'action' => WCF_ACTION_REPORTS,
74
- 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
75
- 'session_id' => sanitize_text_field( $item['session_id'] ),
76
- ),
77
- admin_url( '/admin.php' )
78
- );
79
-
80
- $actions = array(
81
- 'view' => sprintf( '<a href="%s">%s</a>', esc_url( $view_url ), __( 'View', 'woo-cart-abandonment-recovery' ) ),
82
- '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', 'woo-cart-abandonment-recovery' ) ),
83
- );
84
-
85
- if ( WCF_CART_ABANDONED_ORDER === $item['order_status'] && ! $item['unsubscribed'] ) {
86
- $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', 'woo-cart-abandonment-recovery' ) );
87
-
88
- }
89
-
90
- return sprintf(
91
- '<a href="%s"><span class="dashicons dashicons-admin-users"></span> %s %s %s </a>',
92
- esc_url( $view_url ),
93
- esc_html( $item_details['wcf_first_name'] ),
94
- esc_html( $item_details['wcf_last_name'] ),
95
- $this->row_actions( $actions )
96
- );
97
- }
98
-
99
- /**
100
- * Render date column
101
- *
102
- * @param object $item - row (key, value array).
103
- * @return HTML
104
- */
105
- public function column_time( $item ) {
106
- $database_time = $item['time'];
107
- $date_time = new DateTime( $database_time );
108
- $date_time_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
109
- $date_time = $date_time->format( $date_time_format );
110
-
111
- return sprintf( '<span class="dashicons dashicons-clock"></span> %s', esc_html( $date_time ) );
112
- }
113
-
114
- /**
115
- * This is how checkbox column renders.
116
- *
117
- * @param object $item item.
118
- * @return HTML
119
- */
120
- public function column_cb( $item ) {
121
- return sprintf(
122
- '<input type="checkbox" name="id[]" value="%s" />',
123
- esc_html( $item['id'] )
124
- );
125
- }
126
-
127
- /**
128
- * [OPTIONAL] Return array of bult actions if has any
129
- *
130
- * @return array
131
- */
132
- public function get_bulk_actions() {
133
- $actions = array(
134
- 'delete' => __( 'Delete', 'woo-cart-abandonment-recovery' ),
135
- );
136
- $filter_table = isset( $_GET['filter_table'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_table'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
137
- if ( ! isset( $filter_table ) || ( isset( $filter_table ) && WCF_CART_ABANDONED_ORDER === $filter_table ) ) {
138
- $actions['unsubscribe'] = __( 'Unsubscribe', 'woo-cart-abandonment-recovery' );
139
- }
140
-
141
- return $actions;
142
- }
143
-
144
- /**
145
- * Whether the table has items to display or not
146
- *
147
- * @return bool
148
- */
149
- public function has_items() {
150
- return ! empty( $this->items );
151
- }
152
-
153
- /**
154
- * Fetch data from the database to render on view.
155
- *
156
- * @param string $cart_type abandoned|completed.
157
- * @param string $from_date from date.
158
- * @param string $to_date to date.
159
- */
160
- public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER, $from_date = '', $to_date = '' ) {
161
- global $wpdb;
162
- $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
163
-
164
- $per_page = 10;
165
-
166
- $columns = $this->get_columns();
167
- $hidden = array();
168
- $sortable = $this->get_sortable_columns();
169
-
170
- $this->_column_headers = array( $columns, $hidden, $sortable );
171
-
172
- $this->process_bulk_action();
173
-
174
- $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
175
- $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
176
- $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
177
- $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
178
-
179
- $paged = $paged ? max( 0, $paged - 1 ) : 0;
180
- $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
181
- $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
182
-
183
- $this->items = $wpdb->get_results(
184
- $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s LIMIT %d OFFSET %d", //phpcs:ignore
185
- $cart_type,
186
- $from_date,
187
- $to_date,
188
- $wpdb->esc_like( $search_term ),
189
- $orderby,
190
- $order,
191
- $per_page,
192
- $paged * $per_page
193
- ),
194
- ARRAY_A
195
- );
196
- $total_items = count( array( $this->items ) );
197
-
198
- // [REQUIRED] configure pagination
199
- $this->set_pagination_args(
200
- array(
201
- 'total_items' => $total_items,
202
- 'per_page' => $per_page,
203
- 'total_pages' => ceil( $total_items / $per_page ),
204
- )
205
- );
206
-
207
- return $this->items;
208
- }
209
-
210
- /**
211
- * Table columns.
212
- *
213
- * @return array
214
- */
215
- public function get_columns() {
216
- $columns = array(
217
- 'cb' => '<input type="checkbox" />',
218
- 'nameSurname' => __( 'Name', 'woo-cart-abandonment-recovery' ),
219
- 'email' => __( 'Email', 'woo-cart-abandonment-recovery' ),
220
- 'cart_total' => __( 'Cart Total', 'woo-cart-abandonment-recovery' ),
221
- 'order_status' => __( 'Order Status', 'woo-cart-abandonment-recovery' ),
222
- 'time' => __( 'Time', 'woo-cart-abandonment-recovery' ),
223
- );
224
- return $columns;
225
- }
226
-
227
- /**
228
- * Table sortable columns.
229
- *
230
- * @return array
231
- */
232
- public function get_sortable_columns() {
233
- $sortable = array(
234
- 'nameSurname' => array( 'name', true ),
235
- 'cart_total' => array( 'cart_total', true ),
236
- 'cart_total' => array( 'Cart Total', true ),
237
- 'order_status' => array( 'Order Status', true ),
238
- 'time' => array( 'time', true ),
239
- );
240
- return $sortable;
241
- }
242
-
243
- /**
244
- * Processes bulk actions
245
- */
246
- public function process_bulk_action() {
247
- global $wpdb;
248
- $table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
249
-
250
- $ids = array();
251
- $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
252
- if ( is_array( $request_id ) ) {
253
- $ids = array_map( 'intval', $request_id );
254
- } elseif ( isset( $request_id ) ) {
255
- $ids = array( intval( $request_id ) );
256
- }
257
- $ids = implode( ',', $ids );
258
- if ( ! empty( $ids ) ) {
259
-
260
- switch ( $this->current_action() ) {
261
-
262
- case 'delete':
263
- $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
264
- break;
265
- case 'unsubscribe':
266
- $wpdb->query( "UPDATE {$table_name} SET unsubscribed = 1 WHERE id IN($ids)" ); // phpcs:ignore
267
- break;
268
-
269
- }
270
- }
271
-
272
- }
273
-
274
-
275
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ * Member Variable
19
+ *
20
+ * @var object instance
21
+ */
22
+ private static $instance;
23
+
24
+ /**
25
+ * Initiator
26
+ */
27
+ public static function get_instance() {
28
+ if ( ! isset( self::$instance ) ) {
29
+ self::$instance = new self();
30
+ }
31
+ return self::$instance;
32
+ }
33
+
34
+ /**
35
+ * Constructor function.
36
+ */
37
+ public function __construct() {
38
+ global $status, $page;
39
+
40
+ parent::__construct(
41
+ array(
42
+ 'singular' => 'id',
43
+ 'plural' => 'ids',
44
+ )
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Default columns.
50
+ *
51
+ * @param object $item item.
52
+ * @param string $column_name column name.
53
+ */
54
+ public function column_default( $item, $column_name ) {
55
+ return $item[ $column_name ];
56
+ }
57
+
58
+ /**
59
+ * Column name surname.
60
+ *
61
+ * @param object $item item.
62
+ * @return string
63
+ */
64
+ public function column_nameSurname( $item ) {
65
+
66
+ $item_details = unserialize( $item['other_fields'] );
67
+
68
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
69
+
70
+ $view_url = add_query_arg(
71
+ array(
72
+ 'page' => WCF_CA_PAGE_NAME,
73
+ 'action' => WCF_ACTION_REPORTS,
74
+ 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
75
+ 'session_id' => sanitize_text_field( $item['session_id'] ),
76
+ ),
77
+ admin_url( '/admin.php' )
78
+ );
79
+
80
+ $actions = array(
81
+ 'view' => sprintf( '<a href="%s">%s</a>', esc_url( $view_url ), __( 'View', 'woo-cart-abandonment-recovery' ) ),
82
+ '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', 'woo-cart-abandonment-recovery' ) ),
83
+ );
84
+
85
+ if ( WCF_CART_ABANDONED_ORDER === $item['order_status'] && ! $item['unsubscribed'] ) {
86
+ $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', 'woo-cart-abandonment-recovery' ) );
87
+
88
+ }
89
+
90
+ return sprintf(
91
+ '<a href="%s"><span class="dashicons dashicons-admin-users"></span> %s %s %s </a>',
92
+ esc_url( $view_url ),
93
+ esc_html( $item_details['wcf_first_name'] ),
94
+ esc_html( $item_details['wcf_last_name'] ),
95
+ $this->row_actions( $actions )
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Render date column
101
+ *
102
+ * @param object $item - row (key, value array).
103
+ * @return HTML
104
+ */
105
+ public function column_time( $item ) {
106
+ $database_time = $item['time'];
107
+ $date_time = new DateTime( $database_time );
108
+ $date_time_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
109
+ $date_time = $date_time->format( $date_time_format );
110
+
111
+ return sprintf( '<span class="dashicons dashicons-clock"></span> %s', esc_html( $date_time ) );
112
+ }
113
+
114
+ /**
115
+ * This is how checkbox column renders.
116
+ *
117
+ * @param object $item item.
118
+ * @return HTML
119
+ */
120
+ public function column_cb( $item ) {
121
+ return sprintf(
122
+ '<input type="checkbox" name="id[]" value="%s" />',
123
+ esc_html( $item['id'] )
124
+ );
125
+ }
126
+
127
+ /**
128
+ * [OPTIONAL] Return array of bult actions if has any
129
+ *
130
+ * @return array
131
+ */
132
+ public function get_bulk_actions() {
133
+ $actions = array(
134
+ 'delete' => __( 'Delete', 'woo-cart-abandonment-recovery' ),
135
+ );
136
+ $filter_table = isset( $_GET['filter_table'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_table'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
137
+ if ( ! isset( $filter_table ) || ( isset( $filter_table ) && WCF_CART_ABANDONED_ORDER === $filter_table ) ) {
138
+ $actions['unsubscribe'] = __( 'Unsubscribe', 'woo-cart-abandonment-recovery' );
139
+ }
140
+
141
+ return $actions;
142
+ }
143
+
144
+ /**
145
+ * Whether the table has items to display or not
146
+ *
147
+ * @return bool
148
+ */
149
+ public function has_items() {
150
+ return ! empty( $this->items );
151
+ }
152
+
153
+ /**
154
+ * Fetch data from the database to render on view.
155
+ *
156
+ * @param string $cart_type abandoned|completed.
157
+ * @param string $from_date from date.
158
+ * @param string $to_date to date.
159
+ */
160
+ public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER, $from_date = '', $to_date = '' ) {
161
+ global $wpdb;
162
+ $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
163
+
164
+ $per_page = 10;
165
+
166
+ $columns = $this->get_columns();
167
+ $hidden = array();
168
+ $sortable = $this->get_sortable_columns();
169
+
170
+ $this->_column_headers = array( $columns, $hidden, $sortable );
171
+
172
+ $this->process_bulk_action();
173
+
174
+ $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
175
+ $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
176
+ $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
177
+ $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
178
+
179
+ $paged = $paged ? max( 0, $paged - 1 ) : 0;
180
+ $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
181
+ $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
182
+
183
+ $this->items = $wpdb->get_results(
184
+ $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s LIMIT %d OFFSET %d", //phpcs:ignore
185
+ $cart_type,
186
+ $from_date,
187
+ $to_date,
188
+ $wpdb->esc_like( $search_term ),
189
+ $orderby,
190
+ $order,
191
+ $per_page,
192
+ $paged * $per_page
193
+ ),
194
+ ARRAY_A
195
+ );
196
+
197
+ $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
198
+
199
+ // [REQUIRED] configure pagination
200
+ $this->set_pagination_args(
201
+ array(
202
+ 'total_items' => $total_items,
203
+ 'per_page' => $per_page,
204
+ 'total_pages' => ceil( $total_items / $per_page ),
205
+ )
206
+ );
207
+
208
+ $export_data = filter_input( INPUT_GET, 'export_data', FILTER_VALIDATE_BOOLEAN );
209
+ if ( $export_data ) {
210
+
211
+ $this->items = $wpdb->get_results(
212
+ $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s", //phpcs:ignore
213
+ $cart_type,
214
+ $from_date,
215
+ $to_date,
216
+ $wpdb->esc_like( $search_term ),
217
+ $orderby,
218
+ $order
219
+ ),
220
+ ARRAY_A
221
+ );
222
+ return $this->items;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Table columns.
228
+ *
229
+ * @return array
230
+ */
231
+ public function get_columns() {
232
+ $columns = array(
233
+ 'cb' => '<input type="checkbox" />',
234
+ 'nameSurname' => __( 'Name', 'woo-cart-abandonment-recovery' ),
235
+ 'email' => __( 'Email', 'woo-cart-abandonment-recovery' ),
236
+ 'cart_total' => __( 'Cart Total', 'woo-cart-abandonment-recovery' ),
237
+ 'order_status' => __( 'Order Status', 'woo-cart-abandonment-recovery' ),
238
+ 'time' => __( 'Time', 'woo-cart-abandonment-recovery' ),
239
+ );
240
+ return $columns;
241
+ }
242
+
243
+ /**
244
+ * Table sortable columns.
245
+ *
246
+ * @return array
247
+ */
248
+ public function get_sortable_columns() {
249
+ $sortable = array(
250
+ 'nameSurname' => array( 'name', true ),
251
+ 'cart_total' => array( 'cart_total', true ),
252
+ 'cart_total' => array( 'Cart Total', true ),
253
+ 'order_status' => array( 'Order Status', true ),
254
+ 'time' => array( 'time', true ),
255
+ );
256
+ return $sortable;
257
+ }
258
+
259
+ /**
260
+ * Processes bulk actions
261
+ */
262
+ public function process_bulk_action() {
263
+ global $wpdb;
264
+ $table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
265
+
266
+ $ids = array();
267
+ $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
268
+ if ( is_array( $request_id ) ) {
269
+ $ids = array_map( 'intval', $request_id );
270
+ } elseif ( isset( $request_id ) ) {
271
+ $ids = array( intval( $request_id ) );
272
+ }
273
+ $ids = implode( ',', $ids );
274
+ if ( ! empty( $ids ) ) {
275
+
276
+ switch ( $this->current_action() ) {
277
+
278
+ case 'delete':
279
+ $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
280
+ break;
281
+ case 'unsubscribe':
282
+ $wpdb->query( "UPDATE {$table_name} SET unsubscribed = 1 WHERE id IN($ids)" ); // phpcs:ignore
283
+ break;
284
+
285
+ }
286
+ }
287
+
288
+ }
289
+
290
+
291
+ }
modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php CHANGED
@@ -1,2172 +1,2173 @@
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 script to track the cart abandonment.
48
- add_action( 'woocommerce_after_checkout_form', array( $this, 'cart_abandonment_tracking_script' ) );
49
-
50
- // Store user details from the current checkout page.
51
- add_action( 'wp_ajax_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
52
- add_action( 'wp_ajax_nopriv_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
53
-
54
- // GDPR actions.
55
- add_action( 'wp_ajax_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
56
- add_action( 'wp_ajax_nopriv_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
57
-
58
- // Delete the stored cart abandonment data once order gets created.
59
- add_action( 'woocommerce_new_order', array( $this, 'delete_cart_abandonment_data' ) );
60
- add_action( 'woocommerce_thankyou', array( $this, 'delete_cart_abandonment_data' ) );
61
- add_action( 'woocommerce_order_status_changed', array( $this, 'wcf_ca_update_order_status' ), 999, 3 );
62
-
63
- // Adding filter to restore the data if recreating abandonment order.
64
- add_filter( 'wp', array( $this, 'restore_cart_abandonment_data' ), 10 );
65
- add_filter( 'wp', array( $this, 'unsubscribe_cart_abandonment_emails' ), 10 );
66
-
67
- add_action( 'wp_ajax_wcf_ca_preview_email_send', array( $this, 'send_preview_email' ) );
68
-
69
- // Delete coupons.
70
- add_action( 'wp_ajax_wcf_ca_delete_garbage_coupons', array( $this, 'delete_used_and_expired_coupons' ) );
71
-
72
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
73
- $action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
74
- if ( WCF_CA_PAGE_NAME === $page ) {
75
- // Adding filter to add new button to add custom fields.
76
- add_filter( 'mce_buttons', array( $this, 'wcf_filter_mce_button' ) );
77
- add_filter( 'mce_external_plugins', array( $this, 'wcf_filter_mce_plugin' ), 9 );
78
- }
79
-
80
- add_filter( 'cron_schedules', array( $this, 'cartflows_ca_update_order_status_action' ) ); //phpcs:ignore WordPress.WP.CronInterval.ChangeDetected
81
-
82
- // Schedule an action if it's not already scheduled.
83
- if ( ! wp_next_scheduled( 'cartflows_ca_update_order_status_action' ) ) {
84
- wp_schedule_event( time(), 'every_fifteen_minutes', 'cartflows_ca_update_order_status_action' );
85
- }
86
-
87
- // Adding notice to checkout page to inform about test email checkout page.
88
- add_action( 'woocommerce_before_checkout_form', array( $this, 'test_email_checkout_page' ), 9 );
89
-
90
- add_action( 'cartflows_ca_update_order_status_action', array( $this, 'update_order_status' ) );
91
- }
92
-
93
- }
94
-
95
-
96
- /**
97
- * Update the Order status.
98
- *
99
- * @param integer $order_id order id.
100
- * @param string $old_order_status old order status.
101
- * @param string $new_order_status new order status.
102
- */
103
- public function wcf_ca_update_order_status( $order_id, $old_order_status, $new_order_status ) {
104
-
105
- $acceptable_order_statuses = array( 'completed', 'processing', 'failed' );
106
-
107
- $exclude_on_hold_order = apply_filters( 'woo_ca_exclude_on_hold_order_from_tracking', false );
108
-
109
- if ( $exclude_on_hold_order ) {
110
- array_push( $acceptable_order_statuses, 'on-hold' );
111
- }
112
- if ( ( WCF_CART_FAILED_ORDER === $new_order_status ) ) {
113
- return;
114
- }
115
-
116
- if ( $order_id && in_array( $new_order_status, $acceptable_order_statuses, true ) ) {
117
-
118
- $order = wc_get_order( $order_id );
119
-
120
- $order_email = $order->get_billing_email();
121
- $captured_data = ( WCF_CART_FAILED_ORDER === $new_order_status ) ? $this->get_tracked_data_without_status( $order_email ) : $this->get_captured_data_by_email( $order_email );
122
-
123
- if ( $captured_data && is_object( $captured_data ) ) {
124
- $capture_status = $captured_data->order_status;
125
- global $wpdb;
126
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
127
-
128
- if ( ( WCF_CART_NORMAL_ORDER === $capture_status ) ) {
129
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $captured_data->session_id ) ) );
130
- }
131
-
132
- if ( ( WCF_CART_ABANDONED_ORDER === $capture_status || WCF_CART_LOST_ORDER === $capture_status ) ) {
133
- $this->skip_future_emails_when_order_is_completed( sanitize_key( $captured_data->session_id ) );
134
- $this->trigger_zapier_webhook( $captured_data->session_id, WCF_CART_COMPLETED_ORDER );
135
- $note = __( 'This order was abandoned & subsequently recovered.', 'woo-cart-abandonment-recovery' );
136
- $order->add_order_note( $note );
137
- $order->save();
138
- if ( WC()->session ) {
139
- WC()->session->__unset( 'wcf_session_id' );
140
- }
141
- }
142
- }
143
- }
144
-
145
- }
146
-
147
-
148
- /**
149
- * Send preview emails.
150
- */
151
- public function send_preview_email() {
152
-
153
- check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, 'security' );
154
- $mail_result = $this->send_email_templates( null, true );
155
- if ( $mail_result ) {
156
- wp_send_json_success( __( 'Mail has been sent successfully!', 'woo-cart-abandonment-recovery' ) );
157
- } else {
158
- wp_send_json_error( __( 'Mail sending failed!', 'woo-cart-abandonment-recovery' ) );
159
- }
160
- }
161
-
162
-
163
- /**
164
- * Delete tracked data and set cookie for the user.
165
- */
166
- public function skip_cart_tracking_by_gdpr() {
167
- check_ajax_referer( 'cartflows_skip_cart_tracking_gdpr', 'security' );
168
-
169
- global $wpdb;
170
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
171
-
172
- $session_id = WC()->session->get( 'wcf_session_id' );
173
- if ( $session_id ) {
174
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
175
- }
176
-
177
- setcookie( 'wcf_ca_skip_track_data', 'true', 0, '/' );
178
- wp_send_json_success();
179
-
180
- }
181
-
182
-
183
- /**
184
- * Create custom schedule.
185
- *
186
- * @param array $schedules schedules.
187
- * @return mixed
188
- */
189
- public function cartflows_ca_update_order_status_action( $schedules ) {
190
-
191
- /**
192
- * Add filter to change the cron interval time to uodate order status.
193
- */
194
- $cron_time = apply_filters( 'woo_ca_update_order_cron_interval', 15 );
195
-
196
- $schedules['every_fifteen_minutes'] = array(
197
- 'interval' => $cron_time * MINUTE_IN_SECONDS,
198
- 'display' => __( 'Every Fifteen Minutes', 'woo-cart-abandonment-recovery' ),
199
- );
200
-
201
- return $schedules;
202
- }
203
-
204
- /**
205
- * Generate new coupon code for abandoned cart.
206
- *
207
- * @param string $discount_type discount type.
208
- * @param float $amount amount.
209
- * @param string $expiry expiry.
210
- * @param string $free_shipping is free shipping.
211
- * @param string $individual_use use coupon individual.
212
- */
213
- public function generate_coupon_code( $discount_type, $amount, $expiry = '', $free_shipping = 'no', $individual_use = 'no' ) {
214
-
215
- $coupon_code = '';
216
-
217
- $coupon_code = wp_generate_password( 8, false, false );
218
-
219
- $new_coupon_id = wp_insert_post(
220
- array(
221
- 'post_title' => $coupon_code,
222
- 'post_content' => '',
223
- 'post_status' => 'publish',
224
- 'post_author' => 1,
225
- 'post_type' => 'shop_coupon',
226
- )
227
- );
228
-
229
- $coupon_post_data = array(
230
- 'discount_type' => $discount_type,
231
- 'description' => WCF_CA_COUPON_DESCRIPTION,
232
- 'coupon_amount' => $amount,
233
- 'individual_use' => $individual_use,
234
- 'product_ids' => '',
235
- 'exclude_product_ids' => '',
236
- 'usage_limit' => '1',
237
- 'usage_count' => '0',
238
- 'date_expires' => $expiry,
239
- 'apply_before_tax' => 'yes',
240
- 'free_shipping' => $free_shipping,
241
- 'coupon_generated_by' => WCF_CA_COUPON_GENERATED_BY,
242
- );
243
-
244
- foreach ( $coupon_post_data as $key => $value ) {
245
- update_post_meta( $new_coupon_id, $key, $value );
246
- }
247
-
248
- return $coupon_code;
249
- }
250
-
251
- /**
252
- * Unsubscribe the user from the mailing list.
253
- */
254
- public function unsubscribe_cart_abandonment_emails() {
255
-
256
- $unsubscribe = filter_input( INPUT_GET, 'unsubscribe', FILTER_VALIDATE_BOOLEAN );
257
- $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
258
- if ( $unsubscribe && $this->is_valid_token( $wcf_ac_token ) ) {
259
- $token_data = $this->wcf_decode_token( $wcf_ac_token );
260
- if ( isset( $token_data['wcf_session_id'] ) ) {
261
- $session_id = $token_data['wcf_session_id'];
262
-
263
- global $wpdb;
264
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
265
- $wpdb->update(
266
- $cart_abandonment_table,
267
- array( 'unsubscribed' => true ),
268
- array( 'session_id' => $session_id )
269
- );
270
- wp_die( esc_html__( 'You have successfully unsubscribed from our email list.', 'woo-cart-abandonment-recovery' ), esc_html__( 'Unsubscribed', 'woo-cart-abandonment-recovery' ) );
271
-
272
- }
273
- }
274
-
275
- }
276
-
277
-
278
- /**
279
- * Link JS to mce button.
280
- *
281
- * @param array $plugins mce pluggins.
282
- * @return mixed
283
- */
284
- public function wcf_filter_mce_plugin( $plugins ) {
285
- $plugins['cartflows_ac'] = CARTFLOWS_CA_URL . 'admin/assets/js/admin-mce.js';
286
- return $plugins;
287
- }
288
-
289
- /**
290
- * Register button.
291
- *
292
- * @param array $buttons mce buttons.
293
- * @return mixed
294
- */
295
- public function wcf_filter_mce_button( $buttons ) {
296
- array_push( $buttons, 'cartflows_ac' );
297
- return $buttons;
298
- }
299
-
300
- /**
301
- * Initialise all the constants
302
- */
303
- public function define_cart_abandonment_constants() {
304
- define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
305
- define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
306
- define( 'WCF_CART_ABANDONED_ORDER', 'abandoned' );
307
- define( 'WCF_CART_COMPLETED_ORDER', 'completed' );
308
- define( 'WCF_CART_LOST_ORDER', 'lost' );
309
- define( 'WCF_CART_NORMAL_ORDER', 'normal' );
310
- define( 'WCF_CART_FAILED_ORDER', 'failed' );
311
- define( 'CARTFLOWS_ZAPIER_ACTION_AFTER_TIME', 1800 );
312
-
313
- define( 'WCF_ACTION_ABANDONED_CARTS', 'abandoned_carts' );
314
- define( 'WCF_ACTION_RECOVERED_CARTS', 'recovered_carts' );
315
- define( 'WCF_ACTION_LOST_CARTS', 'lost_carts' );
316
- define( 'WCF_ACTION_SETTINGS', 'settings' );
317
- define( 'WCF_ACTION_REPORTS', 'reports' );
318
-
319
- define( 'WCF_SUB_ACTION_REPORTS_VIEW', 'view' );
320
- define( 'WCF_SUB_ACTION_REPORTS_RESCHEDULE', 'reschedule' );
321
-
322
- define( 'WCF_DEFAULT_CUT_OFF_TIME', 15 );
323
- define( 'WCF_DEFAULT_COUPON_AMOUNT', 10 );
324
-
325
- define( 'WCF_CA_DATETIME_FORMAT', 'Y-m-d H:i:s' );
326
-
327
- define( 'WCF_CA_COUPON_DESCRIPTION', 'This coupon is for abandoned cart email templates.' );
328
- define( 'WCF_CA_COUPON_GENERATED_BY', 'woo-cart-abandonment-recovery' );
329
- }
330
-
331
- /**
332
- * Restore cart abandonemnt data on checkout page.
333
- *
334
- * @param array $fields checkout fields values.
335
- * @return array field values
336
- */
337
- public function restore_cart_abandonment_data( $fields = array() ) {
338
- global $woocommerce;
339
- $result = array();
340
- // Restore only of user is not logged in.
341
- $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
342
- if ( $this->is_valid_token( $wcf_ac_token ) ) {
343
-
344
- // Check if `wcf_restore_token` exists to restore cart data.
345
- $token_data = $this->wcf_decode_token( $wcf_ac_token );
346
- if ( is_array( $token_data ) && isset( $token_data['wcf_session_id'] ) ) {
347
- $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
348
- if ( isset( $result ) && WCF_CART_ABANDONED_ORDER === $result->order_status || WCF_CART_LOST_ORDER === $result->order_status ) {
349
- WC()->session->set( 'wcf_session_id', $token_data['wcf_session_id'] );
350
- }
351
- }
352
-
353
- if ( $result ) {
354
- $cart_content = unserialize( $result->cart_contents );
355
-
356
- if ( $cart_content ) {
357
- $woocommerce->cart->empty_cart();
358
- wc_clear_notices();
359
- foreach ( $cart_content as $cart_item ) {
360
-
361
- $cart_item_data = array();
362
- $id = $cart_item['product_id'];
363
- $qty = $cart_item['quantity'];
364
-
365
- // Skip bundled products when added main product.
366
- if ( isset( $cart_item['bundled_by'] ) ) {
367
- continue;
368
- }
369
-
370
- if ( isset( $cart_item['ppom'] ) ) {
371
- $cart_item_data['ppom'] = $cart_item ['ppom'];
372
- }
373
-
374
- if ( isset( $cart_item['cartflows_bump'] ) ) {
375
- $cart_item_data['cartflows_bump'] = $cart_item['cartflows_bump'];
376
- }
377
-
378
- if ( isset( $cart_item['custom_price'] ) ) {
379
- $cart_item_data['custom_price'] = $cart_item['custom_price'];
380
- }
381
-
382
- $woocommerce->cart->add_to_cart( $id, $qty, $cart_item['variation_id'], array(), $cart_item_data );
383
- }
384
-
385
- if ( isset( $token_data['wcf_coupon_code'] ) && ! $woocommerce->cart->applied_coupons ) {
386
- $woocommerce->cart->add_discount( $token_data['wcf_coupon_code'] );
387
- }
388
- }
389
- $other_fields = unserialize( $result->other_fields );
390
-
391
- $parts = explode( ',', $other_fields['wcf_location'] );
392
- if ( count( $parts ) > 1 ) {
393
- $country = $parts[0];
394
- $city = trim( $parts[1] );
395
- } else {
396
- $country = $parts[0];
397
- $city = '';
398
- }
399
-
400
- foreach ( $other_fields as $key => $value ) {
401
- $key = str_replace( 'wcf_', '', $key );
402
- $_POST[ $key ] = sanitize_text_field( $value );
403
- }
404
- $_POST['billing_first_name'] = sanitize_text_field( $other_fields['wcf_first_name'] );
405
- $_POST['billing_last_name'] = sanitize_text_field( $other_fields['wcf_last_name'] );
406
- $_POST['billing_phone'] = sanitize_text_field( $other_fields['wcf_phone_number'] );
407
- $_POST['billing_email'] = sanitize_email( $result->email );
408
- $_POST['billing_city'] = sanitize_text_field( $city );
409
- $_POST['billing_country'] = sanitize_text_field( $country );
410
-
411
- }
412
- }
413
- return $fields;
414
- }
415
-
416
- /**
417
- * Add notice to inform user about test email checkout page.
418
- */
419
- public function test_email_checkout_page() {
420
-
421
- $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
422
- $token_data = $this->wcf_decode_token( $wcf_ac_token );
423
- if ( is_checkout() && ! is_wc_endpoint_url() && isset( $token_data['wcf_preview_email'] ) && $token_data['wcf_preview_email'] ) {
424
- wc_print_notice( __( 'This checkout page is generated by WooCommerce Cart Abandonment Recovery plugin from test mail.', 'woo-cart-abandonment-recovery' ), 'notice' );
425
- }
426
- }
427
-
428
-
429
- /**
430
- * Load cart abandonemnt tracking script.
431
- *
432
- * @return void
433
- */
434
- public function cart_abandonment_tracking_script() {
435
-
436
- $wcf_ca_ignore_users = get_option( 'wcf_ca_ignore_users' );
437
- $current_user = wp_get_current_user();
438
- $roles = $current_user->roles;
439
- $role = array_shift( $roles );
440
- if ( ! empty( $wcf_ca_ignore_users ) ) {
441
- foreach ( $wcf_ca_ignore_users as $user ) {
442
- $user = strtolower( $user );
443
- $role = preg_replace( '/_/', ' ', $role );
444
- if ( $role === $user ) {
445
- return;
446
- }
447
- }
448
- }
449
-
450
- global $post;
451
- wp_enqueue_script(
452
- 'cartflows-cart-abandonment-tracking',
453
- CARTFLOWS_CART_ABANDONMENT_TRACKING_URL . 'assets/js/cart-abandonment-tracking.js',
454
- array( 'jquery' ),
455
- CARTFLOWS_CA_VER,
456
- true
457
- );
458
-
459
- $vars = array(
460
- 'ajaxurl' => admin_url( 'admin-ajax.php' ),
461
- '_nonce' => wp_create_nonce( 'cartflows_save_cart_abandonment_data' ),
462
- '_gdpr_nonce' => wp_create_nonce( 'cartflows_skip_cart_tracking_gdpr' ),
463
- '_post_id' => get_the_ID(),
464
- '_show_gdpr_message' => ( wcf_ca()->utils->is_gdpr_enabled() && ! isset( $_COOKIE['wcf_ca_skip_track_data'] ) ),
465
- '_gdpr_message' => get_option( 'wcf_ca_gdpr_message' ),
466
- '_gdpr_nothanks_msg' => __( 'No Thanks', 'woo-cart-abandonment-recovery' ),
467
- '_gdpr_after_no_thanks_msg' => __( 'You won\'t receive further emails from us, thank you!', 'woo-cart-abandonment-recovery' ),
468
- 'enable_ca_tracking' => true,
469
- );
470
-
471
- wp_localize_script( 'cartflows-cart-abandonment-tracking', 'CartFlowsProCAVars', $vars );
472
-
473
- }
474
-
475
- /**
476
- * Validate the token before use.
477
- *
478
- * @param string $token token form the url.
479
- * @return bool
480
- */
481
- public function is_valid_token( $token ) {
482
- $is_valid = false;
483
- $token_data = $this->wcf_decode_token( $token );
484
- if ( is_array( $token_data ) && array_key_exists( 'wcf_session_id', $token_data ) ) {
485
- $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
486
- if ( isset( $result ) ) {
487
- $is_valid = true;
488
- }
489
- }
490
- return $is_valid;
491
- }
492
-
493
- /**
494
- * Check before emails actually send to user.
495
- *
496
- * @param array $email_data email_data.
497
- * @param array $current_cart_data cart data.
498
- * @return bool
499
- */
500
- public function check_if_already_purchased_by_email_product_ids( $email_data, $current_cart_data ) {
501
-
502
- global $wpdb;
503
- $current_cart_data = unserialize( $current_cart_data );
504
-
505
- // Fetch products & variations.
506
- $products = array_values( wp_list_pluck( $current_cart_data, 'product_id' ) );
507
- $variations = array_values( wp_list_pluck( $current_cart_data, 'variation_id' ) );
508
- $current_products = array_unique( array_merge( $products, $variations ) );
509
-
510
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
511
-
512
- $orders = wc_get_orders(
513
- array(
514
- 'billing_email' => $email_data->email,
515
- 'status' => array( 'processing', 'completed' ),
516
- 'date_after' => gmdate(
517
- 'Y-m-d h:i:s',
518
- strtotime( '-30 days' )
519
- ),
520
- )
521
- );
522
- $need_to_send_email = true;
523
-
524
- foreach ( $orders as $order ) {
525
- $order = wc_get_order( $order->get_id() );
526
- $items = $order->get_items();
527
- foreach ( $items as $item ) {
528
- $product_id = $item->get_product_id();
529
- if ( in_array( $product_id, $current_products, true ) ) {
530
- /**
531
- * Remove duplicate captured order for tracking.
532
- */
533
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $email_data->session_id ) ) );
534
- $need_to_send_email = false;
535
- break;
536
- }
537
- }
538
- }
539
- return $need_to_send_email;
540
- }
541
-
542
- /**
543
- * Execute Zapier webhook for further action inside Zapier.
544
- *
545
- * @since 1.0.0
546
- */
547
- public function update_order_status() {
548
-
549
- global $wpdb;
550
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
551
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
552
- $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
553
-
554
- /**
555
- * Delete abandoned cart orders if empty.
556
- */
557
- $this->delete_empty_abandoned_order();
558
-
559
- $wp_current_datetime = current_time( WCF_CA_DATETIME_FORMAT );
560
- $abandoned_ids = $wpdb->get_results(
561
- $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
562
- );
563
-
564
- foreach ( $abandoned_ids as $session_id ) {
565
-
566
- if ( isset( $session_id['session_id'] ) ) {
567
-
568
- $current_session_id = $session_id['session_id'];
569
- $this->schedule_emails( $current_session_id );
570
-
571
- $coupon_code = '';
572
- $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
573
-
574
- if ( 'on' === $wcf_ca_coupon_code_status ) {
575
- $discount_type = get_option( 'wcf_ca_discount_type' );
576
- $discount_type = $discount_type ? $discount_type : 'percent';
577
- $amount = get_option( 'wcf_ca_coupon_amount' );
578
- $amount = $amount ? $amount : WCF_DEFAULT_COUPON_AMOUNT;
579
- $coupon_expiry_date = get_option( 'wcf_ca_coupon_expiry' );
580
- $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
581
- $coupon_expiry_date = $coupon_expiry_date ? strtotime( $wp_current_datetime . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
582
- $free_shipping_coupon = get_option( 'wcf_ca_free_shipping_coupon' );
583
- $free_shipping = ( isset( $free_shipping_coupon ) && ( $free_shipping_coupon->meta_value ) ) ? 'yes' : 'no';
584
-
585
- $individual_use_only = get_option( 'wcf_ca_individual_use_only' );
586
- $individual_use = ( isset( $individual_use_only ) && ( $individual_use_only->meta_value ) ) ? 'yes' : 'no';
587
-
588
- $coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date, $free_shipping, $individual_use );
589
- }
590
-
591
- $wpdb->update(
592
- $cart_abandonment_table,
593
- array(
594
- 'order_status' => WCF_CART_ABANDONED_ORDER,
595
- 'coupon_code' => $coupon_code,
596
- ),
597
- array( 'session_id' => $current_session_id )
598
- );
599
-
600
- $this->trigger_zapier_webhook( $current_session_id, WCF_CART_ABANDONED_ORDER );
601
- }
602
- }
603
-
604
- /**
605
- * Send scheduled emails.
606
- */
607
- $this->send_emails_to_callback();
608
-
609
- // Update order status to lost after campaign complete.
610
- // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
611
- $wpdb->query(
612
- $wpdb->prepare(
613
- "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)
614
- AND ( (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id ) =
615
- (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id AND email_sent = 1) )",
616
- WCF_CART_ABANDONED_ORDER,
617
- $wp_current_datetime
618
- )
619
- );
620
- // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
621
-
622
- /**
623
- * Delete garbage coupons.
624
- */
625
- $wcf_ca_auto_delete_coupons = get_option( 'wcf_ca_auto_delete_coupons' );
626
-
627
- if ( isset( $wcf_ca_auto_delete_coupons ) && 'on' === $wcf_ca_auto_delete_coupons ) {
628
- $this->delete_used_and_expired_coupons();
629
- }
630
-
631
- }
632
-
633
- /**
634
- * Send zapier webhook.
635
- *
636
- * @param string $session_id session id.
637
- * @param string $order_status order status.
638
- */
639
- public function trigger_zapier_webhook( $session_id, $order_status ) {
640
-
641
- $checkout_details = $this->get_checkout_details( $session_id );
642
-
643
- if ( $checkout_details && wcf_ca()->utils->is_zapier_trigger_enabled() ) {
644
- $trigger_details = array();
645
- $url = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
646
-
647
- $other_details = unserialize( $checkout_details->other_fields );
648
- $trigger_details['first_name'] = $other_details['wcf_first_name'];
649
- $trigger_details['last_name'] = $other_details['wcf_last_name'];
650
- $trigger_details['phone_number'] = $other_details['wcf_phone_number'];
651
- $trigger_details['billing_address'] = $other_details['wcf_billing_company'] . ' ' . $other_details['wcf_billing_address_1'] . ', ' . $other_details['wcf_billing_state'] . ', ' . $other_details['wcf_location'] . ', ' . $other_details['wcf_billing_postcode'];
652
- $trigger_details['billing_address'] = trim( $trigger_details['billing_address'], ', ' );
653
- $trigger_details['shipping_address'] = $other_details['wcf_shipping_company'] . ' ' . $other_details['wcf_shipping_address_1'] . ', ' . $other_details['wcf_shipping_city'] . ', ' . $other_details['wcf_shipping_state'] . ', ' . $other_details['wcf_shipping_postcode'];
654
- $trigger_details['shipping_address'] = trim( $trigger_details['shipping_address'], ', ' );
655
- $trigger_details['email'] = $checkout_details->email;
656
- $token_data = array( 'wcf_session_id' => $checkout_details->session_id );
657
- $trigger_details['checkout_url'] = $this->get_checkout_url( $checkout_details->checkout_id, $token_data );
658
- $trigger_details['product_names'] = $this->get_comma_separated_products( $checkout_details->cart_contents );
659
- $trigger_details['coupon_code'] = $checkout_details->coupon_code;
660
- $trigger_details['order_status'] = $order_status;
661
- $trigger_details['cart_total'] = $checkout_details->cart_total;
662
- $trigger_details['product_table'] = $this->get_email_product_block( $checkout_details->cart_contents, $checkout_details->cart_total );
663
-
664
- $parameters = http_build_query( $trigger_details );
665
-
666
- wp_remote_post(
667
- $url,
668
- array(
669
- 'body' => $parameters,
670
- 'timeout' => '5',
671
- 'redirection' => '5',
672
- 'httpversion' => '1.0',
673
- 'blocking' => true,
674
- 'headers' => array(),
675
- 'cookies' => array(),
676
- )
677
- );
678
-
679
- }
680
- }
681
-
682
-
683
- /**
684
- * Sanitize post array.
685
- *
686
- * @return array
687
- */
688
- public function sanitize_post_data() {
689
-
690
- $input_post_values = array(
691
- 'wcf_billing_company' => array(
692
- 'default' => '',
693
- 'sanitize' => FILTER_SANITIZE_STRING,
694
- ),
695
- 'wcf_email' => array(
696
- 'default' => '',
697
- 'sanitize' => FILTER_SANITIZE_EMAIL,
698
- ),
699
- 'wcf_billing_address_1' => array(
700
- 'default' => '',
701
- 'sanitize' => FILTER_SANITIZE_STRING,
702
- ),
703
- 'wcf_billing_address_2' => array(
704
- 'default' => '',
705
- 'sanitize' => FILTER_SANITIZE_STRING,
706
- ),
707
- 'wcf_billing_state' => array(
708
- 'default' => '',
709
- 'sanitize' => FILTER_SANITIZE_STRING,
710
- ),
711
- 'wcf_billing_postcode' => array(
712
- 'default' => '',
713
- 'sanitize' => FILTER_SANITIZE_STRING,
714
- ),
715
- 'wcf_shipping_first_name' => array(
716
- 'default' => '',
717
- 'sanitize' => FILTER_SANITIZE_STRING,
718
- ),
719
- 'wcf_shipping_last_name' => array(
720
- 'default' => '',
721
- 'sanitize' => FILTER_SANITIZE_STRING,
722
- ),
723
- 'wcf_shipping_company' => array(
724
- 'default' => '',
725
- 'sanitize' => FILTER_SANITIZE_STRING,
726
- ),
727
- 'wcf_shipping_country' => array(
728
- 'default' => '',
729
- 'sanitize' => FILTER_SANITIZE_STRING,
730
- ),
731
- 'wcf_shipping_address_1' => array(
732
- 'default' => '',
733
- 'sanitize' => FILTER_SANITIZE_STRING,
734
- ),
735
- 'wcf_shipping_address_2' => array(
736
- 'default' => '',
737
- 'sanitize' => FILTER_SANITIZE_STRING,
738
- ),
739
- 'wcf_shipping_city' => array(
740
- 'default' => '',
741
- 'sanitize' => FILTER_SANITIZE_STRING,
742
- ),
743
- 'wcf_shipping_state' => array(
744
- 'default' => '',
745
- 'sanitize' => FILTER_SANITIZE_STRING,
746
- ),
747
- 'wcf_shipping_postcode' => array(
748
- 'default' => '',
749
- 'sanitize' => FILTER_SANITIZE_STRING,
750
- ),
751
- 'wcf_order_comments' => array(
752
- 'default' => '',
753
- 'sanitize' => FILTER_SANITIZE_STRING,
754
- ),
755
- 'wcf_name' => array(
756
- 'default' => '',
757
- 'sanitize' => FILTER_SANITIZE_STRING,
758
- ),
759
- 'wcf_surname' => array(
760
- 'default' => '',
761
- 'sanitize' => FILTER_SANITIZE_STRING,
762
- ),
763
- 'wcf_phone' => array(
764
- 'default' => '',
765
- 'sanitize' => FILTER_SANITIZE_STRING,
766
- ),
767
- 'wcf_country' => array(
768
- 'default' => '',
769
- 'sanitize' => FILTER_SANITIZE_STRING,
770
- ),
771
- 'wcf_city' => array(
772
- 'default' => '',
773
- 'sanitize' => FILTER_SANITIZE_STRING,
774
- ),
775
- 'wcf_post_id' => array(
776
- 'default' => 0,
777
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
778
- ),
779
- );
780
-
781
- $sanitized_post = array();
782
- foreach ( $input_post_values as $key => $input_post_value ) {
783
-
784
- if ( isset( $_POST[ $key ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Missing
785
- $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
786
- } else {
787
- $sanitized_post[ $key ] = $input_post_value['default'];
788
- }
789
- }
790
- return $sanitized_post;
791
-
792
- }
793
-
794
-
795
- /**
796
- * Save cart abandonment tracking and schedule new event.
797
- *
798
- * @since 1.0.0
799
- */
800
- public function save_cart_abandonment_data() {
801
- check_ajax_referer( 'cartflows_save_cart_abandonment_data', 'security' );
802
- $post_data = $this->sanitize_post_data();
803
- if ( isset( $post_data['wcf_email'] ) ) {
804
- $user_email = sanitize_email( $post_data['wcf_email'] );
805
- global $wpdb;
806
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
807
-
808
- // Verify if email is already exists.
809
- $session_id = WC()->session->get( 'wcf_session_id' );
810
- $session_checkout_details = null;
811
- if ( isset( $session_id ) ) {
812
- $session_checkout_details = $this->get_checkout_details( $session_id );
813
- } else {
814
- $session_checkout_details = $this->get_checkout_details_by_email( $user_email );
815
- if ( $session_checkout_details ) {
816
- $session_id = $session_checkout_details->session_id;
817
- WC()->session->set( 'wcf_session_id', $session_id );
818
- } else {
819
- $session_id = md5( uniqid( wp_rand(), true ) );
820
- }
821
- }
822
-
823
- $checkout_details = $this->prepare_abandonment_data( $post_data );
824
-
825
- if ( isset( $session_checkout_details ) && WCF_CART_COMPLETED_ORDER === $session_checkout_details->order_status ) {
826
- WC()->session->__unset( 'wcf_session_id' );
827
- $session_id = md5( uniqid( wp_rand(), true ) );
828
- }
829
-
830
- if ( isset( $checkout_details['cart_total'] ) && $checkout_details['cart_total'] > 0 ) {
831
-
832
- if ( ( ! is_null( $session_id ) ) && ! is_null( $session_checkout_details ) ) {
833
-
834
- // Updating row in the Database where users Session id = same as prevously saved in Session.
835
- $wpdb->update(
836
- $cart_abandonment_table,
837
- $checkout_details,
838
- array( 'session_id' => $session_id )
839
- );
840
-
841
- } else {
842
-
843
- $checkout_details['session_id'] = sanitize_text_field( $session_id );
844
- // Inserting row into Database.
845
- $wpdb->insert(
846
- $cart_abandonment_table,
847
- $checkout_details
848
- );
849
-
850
- // Storing session_id in WooCommerce session.
851
- WC()->session->set( 'wcf_session_id', $session_id );
852
-
853
- }
854
- } else {
855
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
856
- }
857
-
858
- wp_send_json_success();
859
- }
860
- }
861
-
862
-
863
- /**
864
- * Prepare cart data to save for abandonment.
865
- *
866
- * @param array $post_data post data.
867
- * @return array
868
- */
869
- public function prepare_abandonment_data( $post_data = array() ) {
870
-
871
- if ( function_exists( 'WC' ) ) {
872
-
873
- // Retrieving cart total value and currency.
874
- $cart_total = WC()->cart->total;
875
-
876
- // Retrieving cart products and their quantities.
877
- $products = WC()->cart->get_cart();
878
- $current_time = current_time( WCF_CA_DATETIME_FORMAT );
879
- $other_fields = array(
880
- 'wcf_billing_company' => $post_data['wcf_billing_company'],
881
- 'wcf_billing_address_1' => $post_data['wcf_billing_address_1'],
882
- 'wcf_billing_address_2' => $post_data['wcf_billing_address_2'],
883
- 'wcf_billing_state' => $post_data['wcf_billing_state'],
884
- 'wcf_billing_postcode' => $post_data['wcf_billing_postcode'],
885
- 'wcf_shipping_first_name' => $post_data['wcf_shipping_first_name'],
886
- 'wcf_shipping_last_name' => $post_data['wcf_shipping_last_name'],
887
- 'wcf_shipping_company' => $post_data['wcf_shipping_company'],
888
- 'wcf_shipping_country' => $post_data['wcf_shipping_country'],
889
- 'wcf_shipping_address_1' => $post_data['wcf_shipping_address_1'],
890
- 'wcf_shipping_address_2' => $post_data['wcf_shipping_address_2'],
891
- 'wcf_shipping_city' => $post_data['wcf_shipping_city'],
892
- 'wcf_shipping_state' => $post_data['wcf_shipping_state'],
893
- 'wcf_shipping_postcode' => $post_data['wcf_shipping_postcode'],
894
- 'wcf_order_comments' => $post_data['wcf_order_comments'],
895
- 'wcf_first_name' => $post_data['wcf_name'],
896
- 'wcf_last_name' => $post_data['wcf_surname'],
897
- 'wcf_phone_number' => $post_data['wcf_phone'],
898
- 'wcf_location' => $post_data['wcf_country'] . ', ' . $post_data['wcf_city'],
899
- );
900
-
901
- $checkout_details = array(
902
- 'email' => $post_data['wcf_email'],
903
- 'cart_contents' => serialize( $products ),
904
- 'cart_total' => sanitize_text_field( $cart_total ),
905
- 'time' => sanitize_text_field( $current_time ),
906
- 'other_fields' => serialize( $other_fields ),
907
- 'checkout_id' => $post_data['wcf_post_id'],
908
- );
909
- }
910
- return $checkout_details;
911
- }
912
-
913
- /**
914
- * Deletes cart abandonment tracking and scheduled event.
915
- *
916
- * @param int $order_id Order ID.
917
- * @since 1.0.0
918
- */
919
- public function delete_cart_abandonment_data( $order_id ) {
920
-
921
- $acceptable_order_statuses = array( 'completed', 'processing' );
922
- $order = wc_get_order( $order_id );
923
- $order_status = $order->get_status();
924
- if ( ! in_array( $order_status, $acceptable_order_statuses, true ) ) {
925
- // Proceed if order status in completed or processing.
926
- return;
927
- }
928
-
929
- global $wpdb;
930
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
931
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
932
-
933
- if ( isset( WC()->session ) ) {
934
- $session_id = WC()->session->get( 'wcf_session_id' );
935
-
936
- if ( isset( $session_id ) ) {
937
- $checkout_details = $this->get_checkout_details( $session_id );
938
-
939
- $has_mail_sent = count( $this->fetch_scheduled_emails( $session_id, true ) );
940
-
941
- if ( ! $has_mail_sent ) {
942
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
943
- } else {
944
- if ( $checkout_details && ( WCF_CART_ABANDONED_ORDER === $checkout_details->order_status || WCF_CART_LOST_ORDER === $checkout_details->order_status ) ) {
945
-
946
- $this->skip_future_emails_when_order_is_completed( $session_id );
947
-
948
- $this->trigger_zapier_webhook( $session_id, WCF_CART_COMPLETED_ORDER );
949
-
950
- $order = wc_get_order( $order_id );
951
- $note = __( 'This order was abandoned & subsequently recovered.', 'woo-cart-abandonment-recovery' );
952
- $order->add_order_note( $note );
953
- $order->save();
954
-
955
- } elseif ( WCF_CART_COMPLETED_ORDER !== $checkout_details->order_status ) {
956
- // Normal checkout.
957
-
958
- $billing_email = filter_input( INPUT_POST, 'billing_email', FILTER_SANITIZE_EMAIL );
959
-
960
- if ( $billing_email ) {
961
- $order_data = $this->get_captured_data_by_email( $billing_email );
962
-
963
- if ( ! is_null( $order_data ) ) {
964
- $existing_cart_contents = unserialize( $order_data->cart_contents );
965
- $order_cart_contents = unserialize( $checkout_details->cart_contents );
966
- $existing_cart_products = array_keys( (array) $existing_cart_contents );
967
- $order_cart_products = array_keys( (array) $order_cart_contents );
968
- if ( $this->check_if_similar_cart( $existing_cart_products, $order_cart_products ) ) {
969
- $this->skip_future_emails_when_order_is_completed( $order_data->session_id );
970
- }
971
- }
972
- }
973
- $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
974
- }
975
- }
976
- }
977
- if ( WC()->session ) {
978
- WC()->session->__unset( 'wcf_session_id' );
979
- }
980
- }
981
- }
982
-
983
- /**
984
- * Unschedule future emails for completed orders.
985
- *
986
- * @param string $session_id session id.
987
- * @param bool $skip_complete skip update query.
988
- */
989
- public function skip_future_emails_when_order_is_completed( $session_id, $skip_complete = false ) {
990
-
991
- global $wpdb;
992
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
993
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
994
-
995
- if ( ! $skip_complete ) {
996
- $wpdb->update(
997
- $cart_abandonment_table,
998
- array(
999
- 'order_status' => WCF_CART_COMPLETED_ORDER,
1000
- ),
1001
- array(
1002
- 'session_id' => sanitize_key( $session_id ),
1003
- )
1004
- );
1005
- }
1006
-
1007
- $wpdb->update(
1008
- $email_history_table,
1009
- array( 'email_sent' => -1 ),
1010
- array(
1011
- 'ca_session_id' => $session_id,
1012
- 'email_sent' => 0,
1013
- )
1014
- );
1015
- }
1016
-
1017
- /**
1018
- * Compare cart if similar products.
1019
- *
1020
- * @param array $cart_a cart_a.
1021
- * @param array $cart_b cart_b.
1022
- * @return bool
1023
- */
1024
- public function check_if_similar_cart( $cart_a, $cart_b ) {
1025
- return (
1026
- is_array( $cart_a )
1027
- && is_array( $cart_b )
1028
- && count( $cart_a ) === count( $cart_b )
1029
- && array_diff( $cart_a, $cart_b ) === array_diff( $cart_b, $cart_a )
1030
- );
1031
- }
1032
-
1033
-
1034
- /**
1035
- * Get the checkout details for the user.
1036
- *
1037
- * @param string $wcf_session_id checkout page session id.
1038
- * @since 1.0.0
1039
- */
1040
- public function get_checkout_details( $wcf_session_id ) {
1041
- global $wpdb;
1042
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1043
- $result = $wpdb->get_row(
1044
- $wpdb->prepare('SELECT * FROM `' . $cart_abandonment_table . '` WHERE session_id = %s', $wcf_session_id ) // phpcs:ignore
1045
- );
1046
- return $result;
1047
- }
1048
-
1049
- /**
1050
- * Get the checkout details for the user.
1051
- *
1052
- * @param string $email user email.
1053
- * @since 1.0.0
1054
- */
1055
- public function get_checkout_details_by_email( $email ) {
1056
- global $wpdb;
1057
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1058
- $result = $wpdb->get_row(
1059
- $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
1060
- );
1061
- return $result;
1062
- }
1063
-
1064
-
1065
- /**
1066
- * Get the checkout details for the user.
1067
- *
1068
- * @param string $value value.
1069
- * @since 1.0.0
1070
- */
1071
- public function get_captured_data_by_email( $value ) {
1072
- global $wpdb;
1073
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1074
- $result = $wpdb->get_row(
1075
- $wpdb->prepare(
1076
- '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
1077
- );
1078
- return $result;
1079
- }
1080
-
1081
-
1082
- /**
1083
- * Get the checkout details for the user.
1084
- *
1085
- * @param string $value value.
1086
- * @since 1.0.0
1087
- */
1088
- public function get_tracked_data_without_status( $value ) {
1089
- global $wpdb;
1090
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1091
- $result = $wpdb->get_row(
1092
- $wpdb->prepare(
1093
- 'SELECT * FROM `' . $cart_abandonment_table . '` WHERE email = %s LIMIT 1', $value ) // phpcs:ignore
1094
- );
1095
- return $result;
1096
- }
1097
-
1098
- /**
1099
- * Add submenu to admin menu.
1100
- *
1101
- * @since 1.1.5
1102
- */
1103
- public function abandoned_cart_tracking_menu() {
1104
-
1105
- add_submenu_page(
1106
- 'woocommerce',
1107
- __( 'Cart Abandonment', 'woo-cart-abandonment-recovery' ),
1108
- __( 'Cart Abandonment', 'woo-cart-abandonment-recovery' ),
1109
- 'manage_options',
1110
- WCF_CA_PAGE_NAME,
1111
- array( $this, 'render_abandoned_cart_tracking' )
1112
- );
1113
- }
1114
-
1115
- /**
1116
- * Render table view for cart abandonment tracking.
1117
- *
1118
- * @since 1.1.5
1119
- */
1120
- public function render_abandoned_cart_tracking() {
1121
-
1122
- $wcf_list_table = Cartflows_Ca_Cart_Abandonment_Table::get_instance();
1123
-
1124
- if ( 'delete' === $wcf_list_table->current_action() ) {
1125
-
1126
- $ids = array();
1127
- if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1128
- $ids = array_map( 'intval', $_REQUEST['id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1129
- }
1130
- $deleted_row_count = empty( $ids ) ? 1 : count( $ids );
1131
-
1132
- $wcf_list_table->process_bulk_action();
1133
- $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'Items deleted: %d', 'woo-cart-abandonment-recovery' ), $deleted_row_count ) . '</p></div>'; // phpcs:ignore
1134
- set_transient( 'wcf_ca_show_message', $message, 5 );
1135
- if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
1136
- wp_safe_redirect( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) );
1137
- }
1138
- } elseif ( 'unsubscribe' === $wcf_list_table->current_action() ) {
1139
-
1140
- global $wpdb;
1141
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1142
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
1143
-
1144
- $wpdb->update(
1145
- $cart_abandonment_table,
1146
- array( 'unsubscribed' => true ),
1147
- array( 'id' => $id )
1148
- );
1149
- $wcf_list_table->process_bulk_action();
1150
- $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'User(s) unsubscribed successfully!', 'woo-cart-abandonment-recovery' ) ) . '</p></div>'; // phpcs:ignore
1151
- set_transient( 'wcf_ca_show_message', $message, 5 );
1152
- if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
1153
- wp_safe_redirect( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) );
1154
- }
1155
- }
1156
- ?>
1157
-
1158
- <?php
1159
- include_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-tabs.php';
1160
- ?>
1161
- <?php
1162
- }
1163
-
1164
- /**
1165
- * Count abandoned carts
1166
- *
1167
- * @since 1.1.5
1168
- */
1169
- public function abandoned_cart_count() {
1170
- global $wpdb;
1171
- $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1172
-
1173
- $query = $wpdb->prepare( "SELECT COUNT(`id`) FROM {$cart_abandonment_table_name} WHERE `order_status` = %s", WCF_CART_ABANDONED_ORDER ); // phpcs:ignore
1174
- $total_items = $wpdb->get_var( $query ); // phpcs:ignore
1175
- return $total_items;
1176
- }
1177
-
1178
- /**
1179
- * Load analytics scripts.
1180
- */
1181
- public function load_admin_cart_abandonment_script() {
1182
-
1183
- $wcar_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
1184
-
1185
- if ( ! ( WCF_CA_PAGE_NAME === $wcar_page ) ) {
1186
- return;
1187
- }
1188
-
1189
- // Styles.
1190
- wp_enqueue_style( 'cartflows-cart-abandonment-admin', CARTFLOWS_CA_URL . 'admin/assets/css/admin-cart-abandonment.css', array(), CARTFLOWS_CA_VER );
1191
-
1192
- wp_enqueue_script(
1193
- 'cartflows-ca-email-tmpl-settings',
1194
- CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
1195
- array( 'jquery' ),
1196
- CARTFLOWS_CA_VER,
1197
- false
1198
- );
1199
-
1200
- if ( WCF_CA_PAGE_NAME === $wcar_page ) {
1201
- $filter_table = filter_input( INPUT_GET, 'filter_table', FILTER_SANITIZE_STRING );
1202
- $from_date = filter_input( INPUT_GET, 'from_date', FILTER_SANITIZE_STRING );
1203
- $to_date = filter_input( INPUT_GET, 'to_date', FILTER_SANITIZE_STRING );
1204
- }
1205
-
1206
- $vars = array(
1207
- 'url' => 'admin-ajax.php',
1208
-
1209
- // For delete coupons.
1210
- '_delete_coupon_nonce' => wp_create_nonce( 'wcf_ca_delete_garbage_coupons' ),
1211
- '_confirm_msg' => __( 'Do you really want to delete the used and expired coupons created by Cart Abandonment Plugin?', 'woo-cart-abandonment-recovery' ),
1212
- '_confirm_msg_export' => __( 'Do you really want to export orders?', 'woo-cart-abandonment-recovery' ),
1213
-
1214
- // For Search orders.
1215
- '_search_button_nonce' => wp_create_nonce( 'wcf_ca_search_orders' ),
1216
- '_result_msg' => __( 'No such order is found.', 'woo-cart-abandonment-recovery' ),
1217
-
1218
- );
1219
- wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'wcf_ca_localized_vars', $vars );
1220
- }
1221
-
1222
-
1223
- /**
1224
- * Render Cart abandonment display button beside title.
1225
- */
1226
- public function setup_cart_abandonment_button() {
1227
-
1228
- if ( ! Cartflows_Admin::is_flow_edit_admin() ) {
1229
- return;
1230
- }
1231
-
1232
- $reports_btn_markup = '<style>.wrap{ position:relative;}</style>';
1233
- $reports_btn_markup .= "<div class='wcf-reports-button-wrap'>";
1234
- $reports_btn_markup .= "<button class='wcf-cart-abandonment-reports-popup button button-secondary'>";
1235
- $reports_btn_markup .= esc_html__( 'View Report', 'woo-cart-abandonment-recovery' );
1236
- $reports_btn_markup .= '</button>';
1237
- $reports_btn_markup .= '</div>';
1238
-
1239
- echo wp_kses_post( $reports_btn_markup );
1240
-
1241
- }
1242
-
1243
- /**
1244
- * Get start and end date for given interval.
1245
- *
1246
- * @param string $interval interval .
1247
- * @return array
1248
- */
1249
- public function get_start_end_by_interval( $interval ) {
1250
-
1251
- if ( 'today' === $interval ) {
1252
- $start_date = gmdate( 'Y-m-d' );
1253
- $end_date = gmdate( 'Y-m-d' );
1254
- } else {
1255
-
1256
- $days = $interval;
1257
-
1258
- $start_date = gmdate( 'Y-m-d', strtotime( '-' . $days . ' days' ) );
1259
- $end_date = gmdate( 'Y-m-d' );
1260
- }
1261
-
1262
- return array(
1263
- 'start' => $start_date,
1264
- 'end' => $end_date,
1265
- );
1266
- }
1267
-
1268
-
1269
- /**
1270
- * Get Attributable revenue.
1271
- * Represents the revenue generated by this campaign.
1272
- *
1273
- * @param string $type abondened|completed.
1274
- * @param string $from_date from date.
1275
- * @param string $to_date to date.
1276
- */
1277
- public function get_report_by_type( $type = WCF_CART_ABANDONED_ORDER, $from_date, $to_date ) {
1278
- global $wpdb;
1279
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1280
- $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
1281
- $attributable_revenue = $wpdb->get_row(
1282
- $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
1283
- ARRAY_A
1284
- );
1285
- return $attributable_revenue;
1286
- }
1287
-
1288
-
1289
- /**
1290
- * Get checkout url.
1291
- *
1292
- * @param integer $post_id post id.
1293
- * @param string $token_data token data.
1294
- * @return string
1295
- */
1296
- public function get_checkout_url( $post_id, $token_data ) {
1297
-
1298
- $token = $this->wcf_generate_token( (array) $token_data );
1299
- $checkout_url = get_permalink( $post_id ) . '?wcf_ac_token=' . $token;
1300
- return esc_url( $checkout_url );
1301
- }
1302
-
1303
- /**
1304
- * Geberate the token for the given data.
1305
- *
1306
- * @param array $data data.
1307
- */
1308
- public function wcf_generate_token( $data ) {
1309
- return urlencode( base64_encode( http_build_query( $data ) ) );
1310
- }
1311
-
1312
- /**
1313
- * Decode and get the original contents.
1314
- *
1315
- * @param string $token token.
1316
- */
1317
- public function wcf_decode_token( $token ) {
1318
- $token = sanitize_text_field( $token );
1319
- parse_str( base64_decode( urldecode( $token ) ), $token );
1320
- return $token;
1321
- }
1322
-
1323
- /**
1324
- * Render Cart abandonment tabs.
1325
- *
1326
- * @since 1.1.5
1327
- */
1328
- public function wcf_display_tabs() {
1329
-
1330
- $wcar_action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
1331
- $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
1332
-
1333
- if ( ! $wcar_action ) {
1334
- $wcar_action = WCF_ACTION_REPORTS;
1335
- $active_settings = '';
1336
- $active_reports = '';
1337
- $active_email_templates = '';
1338
- }
1339
-
1340
- switch ( $wcar_action ) {
1341
- case WCF_ACTION_SETTINGS:
1342
- $active_settings = 'nav-tab-active';
1343
- break;
1344
- case WCF_ACTION_REPORTS:
1345
- $active_reports = 'nav-tab-active';
1346
- break;
1347
- case WCF_ACTION_EMAIL_TEMPLATES:
1348
- $active_email_templates = 'nav-tab-active';
1349
- break;
1350
- default:
1351
- $active_reports = 'nav-tab-active';
1352
- break;
1353
- }
1354
- // phpcs:disable
1355
- ?>
1356
-
1357
-
1358
- <div class="nav-tab-wrapper woo-nav-tab-wrapper">
1359
-
1360
- <?php
1361
- $url = add_query_arg( array(
1362
- 'page' => WCF_CA_PAGE_NAME,
1363
- 'action' => WCF_ACTION_REPORTS
1364
- ), admin_url( '/admin.php' ) )
1365
- ?>
1366
- <a href="<?php echo $url; ?>"
1367
- class="nav-tab
1368
- <?php
1369
- if ( isset( $active_reports ) ) {
1370
- echo $active_reports;}
1371
- ?>
1372
- ">
1373
- <?php _e( 'Report', 'woo-cart-abandonment-recovery' ); ?>
1374
- </a>
1375
-
1376
- <?php
1377
- $url = add_query_arg( array(
1378
- 'page' => WCF_CA_PAGE_NAME,
1379
- 'action' => WCF_ACTION_EMAIL_TEMPLATES
1380
- ), admin_url( '/admin.php' ) )
1381
- ?>
1382
- <a href="<?php echo $url; ?>"
1383
- class="nav-tab
1384
- <?php
1385
- if ( isset( $active_email_templates ) ) {
1386
- echo $active_email_templates;}
1387
- ?>
1388
- ">
1389
- <?php _e( 'Follow-Up Emails', 'woo-cart-abandonment-recovery' ); ?>
1390
- </a>
1391
-
1392
- <?php
1393
- $url = add_query_arg( array(
1394
- 'page' => WCF_CA_PAGE_NAME,
1395
- 'action' => WCF_ACTION_SETTINGS
1396
- ), admin_url( '/admin.php' ) )
1397
- ?>
1398
- <a href="<?php echo $url; ?>"
1399
- class="nav-tab
1400
- <?php
1401
- if ( isset( $active_settings ) ) {
1402
- echo $active_settings;}
1403
- ?>
1404
- ">
1405
- <?php _e( 'Settings', 'woo-cart-abandonment-recovery' ); ?>
1406
- </a>
1407
-
1408
- </div>
1409
- <?php
1410
- // phpcs:enable
1411
- }
1412
-
1413
- /**
1414
- * Render Cart abandonment settings.
1415
- *
1416
- * @since 1.1.5
1417
- */
1418
- public function wcf_display_settings() {
1419
- ?>
1420
-
1421
- <form method="post" action="options.php">
1422
- <?php settings_fields( WCF_CA_SETTINGS_OPTION_GROUP ); ?>
1423
- <?php do_settings_sections( WCF_CA_PAGE_NAME ); ?>
1424
- <?php submit_button(); ?>
1425
- </form>
1426
-
1427
- <?php
1428
- }
1429
-
1430
- /**
1431
- * Render Cart abandonment reports.
1432
- *
1433
- * @since 1.1.5
1434
- */
1435
- public function wcf_display_reports() {
1436
-
1437
- $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
1438
- $filter_table = filter_input( INPUT_GET, 'filter_table', FILTER_SANITIZE_STRING );
1439
-
1440
- if ( ! $filter ) {
1441
- $filter = 'last_month';
1442
- }
1443
- if ( ! $filter_table ) {
1444
- $filter_table = WCF_CART_ABANDONED_ORDER;
1445
- }
1446
-
1447
- $from_date = filter_input( INPUT_GET, 'from_date', FILTER_SANITIZE_STRING );
1448
- $to_date = filter_input( INPUT_GET, 'to_date', FILTER_SANITIZE_STRING );
1449
- $export_data = filter_input( INPUT_GET, 'export_data', FILTER_VALIDATE_BOOLEAN );
1450
-
1451
- switch ( $filter ) {
1452
-
1453
- case 'yesterday':
1454
- $to_date = gmdate( 'Y-m-d', strtotime( '-1 days' ) );
1455
- $from_date = $to_date;
1456
- break;
1457
- case 'today':
1458
- $to_date = gmdate( 'Y-m-d' );
1459
- $from_date = $to_date;
1460
- break;
1461
- case 'last_week':
1462
- $from_date = gmdate( 'Y-m-d', strtotime( '-7 days' ) );
1463
- $to_date = gmdate( 'Y-m-d' );
1464
- break;
1465
- case 'last_month':
1466
- $from_date = gmdate( 'Y-m-d', strtotime( '-1 months' ) );
1467
- $to_date = gmdate( 'Y-m-d' );
1468
- break;
1469
- case 'custom':
1470
- $to_date = $to_date ? $to_date : gmdate( 'Y-m-d' );
1471
- $from_date = $from_date ? $from_date : $to_date;
1472
- break;
1473
-
1474
- }
1475
-
1476
- $abandoned_report = $this->get_report_by_type( WCF_CART_ABANDONED_ORDER, $from_date, $to_date );
1477
- $recovered_report = $this->get_report_by_type( WCF_CART_COMPLETED_ORDER, $from_date, $to_date );
1478
- $lost_report = $this->get_report_by_type( WCF_CART_LOST_ORDER, $from_date, $to_date );
1479
-
1480
- $wcf_list_table = Cartflows_Ca_Cart_Abandonment_Table::get_instance();
1481
- $wcf_list_table->prepare_items( $filter_table, $from_date, $to_date );
1482
-
1483
- if ( $export_data ) {
1484
-
1485
- $this->download_send_headers();
1486
- echo $this->array2csv( $wcf_list_table->items ); //phpcs:ignore
1487
- die;
1488
-
1489
- }
1490
-
1491
- $conversion_rate = 0;
1492
- $total_orders = ( $recovered_report['no_of_orders'] + $abandoned_report['no_of_orders'] + $lost_report['no_of_orders'] );
1493
- if ( $total_orders ) {
1494
- $conversion_rate = ( $recovered_report['no_of_orders'] / $total_orders ) * 100;
1495
- }
1496
-
1497
- global $woocommerce;
1498
- $conversion_rate = number_format_i18n( $conversion_rate, 2 );
1499
- $currency_symbol = get_woocommerce_currency_symbol();
1500
- require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-reports.php';
1501
-
1502
- }
1503
-
1504
-
1505
- /**
1506
- * Show report details for specific order.
1507
- */
1508
- public function wcf_display_report_details() {
1509
-
1510
- $sesson_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
1511
-
1512
- if ( $sesson_id ) {
1513
- $details = $this->get_checkout_details( $sesson_id );
1514
- $user_details = (object) unserialize( $details->other_fields );
1515
- $scheduled_emails = $this->fetch_scheduled_emails( $sesson_id );
1516
-
1517
- require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-ca-single-report-details.php';
1518
- }
1519
-
1520
- }
1521
-
1522
- /**
1523
- * Check and show warning message if cart abandonment is disabled.
1524
- */
1525
- public function wcf_show_warning_ca() {
1526
- $settings_url = add_query_arg(
1527
- array(
1528
- 'page' => WCF_CA_PAGE_NAME,
1529
- 'action' => WCF_ACTION_SETTINGS,
1530
- ),
1531
- admin_url( '/admin.php' )
1532
- );
1533
-
1534
- if ( ! wcf_ca()->utils->is_cart_abandonment_tracking_enabled() ) {
1535
- ?>
1536
- <div class="notice notice-warning is-dismissible">
1537
- <p>
1538
- <?php echo __('Looks like abandonment tracking is disabled! Please enable it from <a href=' . esc_url($settings_url) . '> <strong>settings</strong></a>.', 'woo-cart-abandonment-recovery'); // phpcs:ignore
1539
- ?>
1540
- </p>
1541
- </div>
1542
- <?php
1543
- }
1544
- }
1545
-
1546
- /**
1547
- * Callback trigger event to send the emails.
1548
- */
1549
- public function send_emails_to_callback() {
1550
-
1551
- global $wpdb;
1552
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1553
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1554
- $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
1555
-
1556
- $current_time = current_time( WCF_CA_DATETIME_FORMAT );
1557
- // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1558
- $emails_send_to = $wpdb->get_results(
1559
- $wpdb->prepare(
1560
- 'SELECT *, EHT.id as email_history_id, ETT.id as email_template_id FROM ' . $email_history_table . ' as EHT
1561
- INNER JOIN ' . $cart_abandonment_table . ' as CAT ON EHT.`ca_session_id` = CAT.`session_id`
1562
- INNER JOIN ' . $email_template_table . ' as ETT ON ETT.`id` = EHT.`template_id`
1563
- WHERE CAT.`order_status` = %s AND CAT.unsubscribed = 0 AND EHT.`email_sent` = 0 AND EHT.`scheduled_time` <= %s',
1564
- WCF_CART_ABANDONED_ORDER,
1565
- $current_time
1566
- )
1567
- );
1568
- // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1569
- foreach ( $emails_send_to as $email_send_to ) {
1570
- $email_result = $this->send_email_templates( $email_send_to );
1571
- if ( $email_result ) {
1572
- $wpdb->update(
1573
- $email_history_table,
1574
- array( 'email_sent' => true ),
1575
- array( 'id' => $email_send_to->email_history_id )
1576
- );
1577
- }
1578
- }
1579
- }
1580
-
1581
-
1582
- /**
1583
- * Create a dummy object for the preview email.
1584
- *
1585
- * @return stdClass
1586
- */
1587
- public function create_dummy_session_for_preview_email() {
1588
-
1589
- $email_data = new stdClass();
1590
- $current_user = wp_get_current_user();
1591
- $email_data->email_template_id = null;
1592
- $email_data->checkout_id = wc_get_page_id( 'checkout' );
1593
- $email_data->session_id = 'dummy-session-id';
1594
- $email_send_to = filter_input( INPUT_POST, 'email_send_to', FILTER_SANITIZE_EMAIL );
1595
- $email_data->email = $email_send_to ? $email_send_to : $current_user->user_email;
1596
- $email_data->email_body = filter_input( INPUT_POST, 'email_body', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1597
- $email_data->email_subject = filter_input( INPUT_POST, 'email_subject', FILTER_SANITIZE_STRING );
1598
- $email_data->email_body = html_entity_decode( $email_data->email_body, ENT_COMPAT, 'UTF-8' );
1599
- $email_data->other_fields = serialize(
1600
- array(
1601
- 'wcf_first_name' => $current_user->user_firstname,
1602
- 'wcf_last_name' => $current_user->user_lastname,
1603
- )
1604
- );
1605
- if ( ! WC()->cart->get_cart_contents_count() ) {
1606
- $args = array(
1607
- 'posts_per_page' => 1,
1608
- 'orderby' => 'rand',
1609
- 'post_type' => 'product',
1610
- 'meta_query' => array( //phpcs:ignore
1611
- // Exclude out of stock products.
1612
- array(
1613
- 'key' => '_stock_status',
1614
- 'value' => 'outofstock',
1615
- 'compare' => 'NOT IN',
1616
- ),
1617
- ),
1618
- 'tax_query' => array( //phpcs:ignore
1619
- array(
1620
- 'taxonomy' => 'product_type',
1621
- 'field' => 'slug',
1622
- 'terms' => 'simple',
1623
- ),
1624
- ),
1625
- );
1626
-
1627
- $random_products = get_posts( $args );
1628
- if ( ! empty( $random_products ) ) {
1629
- $random_product = reset( $random_products );
1630
- WC()->cart->add_to_cart( $random_product->ID );
1631
- }
1632
- }
1633
-
1634
- $email_data->cart_total = WC()->cart->total + floatval( WC()->cart->get_cart_shipping_total() );
1635
- $email_data->cart_contents = serialize( WC()->cart->get_cart() );
1636
- $email_data->time = current_time( WCF_CA_DATETIME_FORMAT );
1637
- return $email_data;
1638
- }
1639
-
1640
- /**
1641
- * Callback function to send email templates.
1642
- *
1643
- * @param array $email_data email data .
1644
- * @param boolean $preview_email preview email.
1645
- * @since 1.0.0
1646
- */
1647
- public function send_email_templates( $email_data, $preview_email = false ) {
1648
-
1649
- if ( $preview_email ) {
1650
- $email_data = $this->create_dummy_session_for_preview_email();
1651
- }
1652
-
1653
- if ( filter_var( $email_data->email, FILTER_VALIDATE_EMAIL ) ) {
1654
- if ( ! $preview_email ) {
1655
- if ( ! $this->check_if_already_purchased_by_email_product_ids( $email_data, $email_data->cart_contents ) ) {
1656
- return false;
1657
- }
1658
- }
1659
-
1660
- $other_fields = unserialize( $email_data->other_fields );
1661
-
1662
- $from_email_name = get_option( 'wcf_ca_from_name' );
1663
- $reply_name_preview = get_option( 'wcf_ca_reply_email' );
1664
- $from_email_preview = get_option( 'wcf_ca_from_email' );
1665
-
1666
- $user_first_name = ucfirst( $other_fields['wcf_first_name'] );
1667
- $user_first_name = $user_first_name ? $user_first_name : __( 'there', 'woo-cart-abandonment-recovery' );
1668
- $user_last_name = ucfirst( $other_fields['wcf_last_name'] );
1669
- $user_full_name = trim( $user_first_name . ' ' . $user_last_name );
1670
-
1671
- $subject_email_preview = stripslashes( html_entity_decode( $email_data->email_subject, ENT_QUOTES, 'UTF-8' ) );
1672
- $subject_email_preview = convert_smilies( $subject_email_preview );
1673
- $subject_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $subject_email_preview );
1674
- $body_email_preview = convert_smilies( $email_data->email_body );
1675
- $body_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $body_email_preview );
1676
- $body_email_preview = str_replace( '{{customer.lastname}}', $user_last_name, $body_email_preview );
1677
- $body_email_preview = str_replace( '{{customer.fullname}}', $user_full_name, $body_email_preview );
1678
-
1679
- $email_instance = Cartflows_Ca_Email_Templates::get_instance();
1680
- if ( $preview_email ) {
1681
- $coupon_code = 'DUMMY-COUPON';
1682
- } else {
1683
- $override_global_coupon = $email_instance->get_email_template_meta_by_key( $email_data->email_template_id, 'override_global_coupon' );
1684
- if ( $override_global_coupon->meta_value ) {
1685
- $email_history = $email_instance->get_email_history_by_id( $email_data->email_history_id );
1686
- $coupon_code = $email_history->coupon_code;
1687
- } else {
1688
- $coupon_code = $email_data->coupon_code;
1689
- }
1690
- }
1691
-
1692
- $auto_apply_coupon = $email_instance->get_email_template_meta_by_key( $email_data->email_template_id, 'auto_coupon' );
1693
-
1694
- $token_data = array(
1695
- 'wcf_session_id' => $email_data->session_id,
1696
- 'wcf_coupon_code' => isset( $auto_apply_coupon ) && $auto_apply_coupon->meta_value ? $coupon_code : null,
1697
- 'wcf_preview_email' => $preview_email ? true : false,
1698
- );
1699
-
1700
- $checkout_url = $this->get_checkout_url( $email_data->checkout_id, $token_data );
1701
-
1702
- $body_email_preview = str_replace( '{{cart.coupon_code}}', $coupon_code, $body_email_preview );
1703
-
1704
- $current_time_stamp = $email_data->time;
1705
- $body_email_preview = str_replace( '{{cart.abandoned_date}}', $current_time_stamp, $body_email_preview );
1706
- $unsubscribe_element = '<a target="_blank" style="color: lightgray" href="' . $checkout_url . '&unsubscribe=true ">' . __( 'Unsubscribe', 'woo-cart-abandonment-recovery' ) . '</a>';
1707
- $body_email_preview = str_replace( '{{cart.unsubscribe}}', $unsubscribe_element, $body_email_preview );
1708
- $body_email_preview = str_replace( 'http://{{cart.checkout_url}}', '{{cart.checkout_url}}', $body_email_preview );
1709
- $body_email_preview = str_replace( 'https://{{cart.checkout_url}}', '{{cart.checkout_url}}', $body_email_preview );
1710
- $body_email_preview = str_replace( '{{cart.checkout_url}}', $checkout_url, $body_email_preview );
1711
- $host = wp_parse_url( get_site_url() );
1712
- $body_email_preview = str_replace( '{{site.url}}', $host['host'], $body_email_preview );
1713
-
1714
- if ( false !== strpos( $body_email_preview, '{{cart.product.names}}' ) ) {
1715
- $body_email_preview = str_replace( '{{cart.product.names}}', $this->get_comma_separated_products( $email_data->cart_contents ), $body_email_preview );
1716
- }
1717
-
1718
- $admin_user = get_users(
1719
- array(
1720
- 'role' => 'Administrator',
1721
- 'number' => 1,
1722
- )
1723
- );
1724
- $admin_user = reset( $admin_user );
1725
- $admin_first_name = $admin_user->user_firstname ? $admin_user->user_firstname : 'Admin';
1726
- $body_email_preview = str_replace( '{{admin.firstname}}', $admin_first_name, $body_email_preview );
1727
- $body_email_preview = str_replace( '{{admin.company}}', get_bloginfo( 'name' ), $body_email_preview );
1728
-
1729
- $headers = 'From: ' . $from_email_name . ' <' . $from_email_preview . '>' . "\r\n";
1730
- $headers .= 'Content-Type: text/html' . "\r\n";
1731
- $headers .= 'Reply-To: ' . $reply_name_preview . ' ' . "\r\n";
1732
- $var = $this->get_email_product_block( $email_data->cart_contents, $email_data->cart_total );
1733
-
1734
- $body_email_preview = str_replace( '{{cart.product.table}}', $var, $body_email_preview );
1735
- $body_email_preview = wpautop( $body_email_preview );
1736
- $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1737
- if ( $mail_result ) {
1738
- return true;
1739
- } else {
1740
- // Retry sending mail.
1741
- $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1742
- if ( ! $preview_email ) {
1743
- return true;
1744
- }
1745
- return false;
1746
- }
1747
- } else {
1748
- return false;
1749
- }
1750
-
1751
- }
1752
-
1753
- /**
1754
- * Generate comma separated products.
1755
- *
1756
- * @param object $cart_contents user cart details.
1757
- */
1758
- public function get_comma_separated_products( $cart_contents ) {
1759
- $cart_comma_string = '';
1760
- if ( ! $cart_contents ) {
1761
- return $cart_comma_string;
1762
- }
1763
- $cart_data = unserialize( $cart_contents );
1764
-
1765
- $cart_length = count( $cart_data );
1766
- $index = 0;
1767
- foreach ( $cart_data as $key => $product ) {
1768
-
1769
- if ( ! isset( $product['product_id'] ) ) {
1770
- continue;
1771
- }
1772
-
1773
- $cart_product = wc_get_product( $product['product_id'] );
1774
-
1775
- $cart_comma_string = $cart_comma_string . $cart_product->get_title();
1776
- if ( ( $cart_length - 2 ) === $index ) {
1777
- $cart_comma_string = $cart_comma_string . ' & ';
1778
- } elseif ( ( $cart_length - 1 ) !== $index ) {
1779
- $cart_comma_string = $cart_comma_string . ', ';
1780
- }
1781
- $index++;
1782
- }
1783
- return $cart_comma_string;
1784
-
1785
- }
1786
-
1787
- /**
1788
- * Generate the view for email product cart block.
1789
- *
1790
- * @param object $cart_contents user cart contents details.
1791
- * @param float $cart_total user cart total.
1792
- * @return string
1793
- */
1794
- public function get_email_product_block( $cart_contents, $cart_total ) {
1795
-
1796
- $cart_items = unserialize( $cart_contents );
1797
-
1798
- if ( ! is_array( $cart_items ) || ! count( $cart_items ) ) {
1799
- return;
1800
- }
1801
-
1802
- $currency_symbol = get_woocommerce_currency_symbol();
1803
- $tr = '';
1804
- $style = array(
1805
- 'product_image' => array(
1806
- 'style' => 'height: 42px; width: 42px;',
1807
- ),
1808
- 'table' => array(
1809
- 'style' => 'color: #636363; border: 1px solid #e5e5e5;',
1810
- 'attribute' => 'align= left;',
1811
- ),
1812
- );
1813
-
1814
- $style_filter = apply_filters( 'woo_ca_email_template_table_style', $style );
1815
- $product_image_style = isset( $style_filter['product_image']['style'] ) ? $style_filter['product_image']['style'] : '';
1816
- $style = isset( $style_filter['table']['style'] ) ? $style_filter['table']['style'] : '';
1817
-
1818
- foreach ( $cart_items as $cart_item ) {
1819
-
1820
- if ( isset( $cart_item['product_id'] ) && isset( $cart_item['quantity'] ) && isset( $cart_item['line_total'] ) ) {
1821
-
1822
- $tr = $tr . '<tr style=' . $style . ' align="center">
1823
- <td style="' . $style . '"><img class="demo_img" style="' . $product_image_style . '" src="' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . '"></td>
1824
- <td style="' . $style . '">' . get_the_title( $cart_item['product_id'] ) . '</td>
1825
- <td style="' . $style . '"> ' . $cart_item['quantity'] . ' </td>
1826
- <td style="' . $style . '">' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1827
- <td style="' . $style . '" >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1828
- </tr> ';
1829
- }
1830
- }
1831
-
1832
- /**
1833
- * Add filter to toggle the Cart Total row.
1834
- */
1835
- $enable_cart_total = apply_filters( 'woo_ca_recovery_enable_cart_total', false );
1836
- if ( $enable_cart_total ) {
1837
- $tr = $tr . '<tr style="' . $style . '" align="center">
1838
- <td colspan="4" style="' . $style . '"> ' . __( 'Cart Total ( Cart Total + Shipping + Tax )', 'woo-cart-abandonment-recovery' ) . ' </td>
1839
- <td style="' . $style . '" >' . $currency_symbol . number_format_i18n( $cart_total, 2 ) . '</td>
1840
- </tr> ';
1841
- }
1842
-
1843
- return '<table ' . $style_filter['table']['attribute'] . ' cellpadding="10" cellspacing="0" style="float: none; border: 1px solid #e5e5e5;">
1844
- <tr align="center">
1845
- <th style="' . $style . '">' . __( 'Item', 'woo-cart-abandonment-recovery' ) . '</th>
1846
- <th style="' . $style . '">' . __( 'Name', 'woo-cart-abandonment-recovery' ) . '</th>
1847
- <th style="' . $style . '">' . __( 'Quantity', 'woo-cart-abandonment-recovery' ) . '</th>
1848
- <th style="' . $style . '">' . __( 'Price', 'woo-cart-abandonment-recovery' ) . '</th>
1849
- <th style="' . $style . '">' . __( 'Line Subtotal', 'woo-cart-abandonment-recovery' ) . '</th>
1850
- </tr> ' . $tr . '
1851
- </table>';
1852
- }
1853
-
1854
- /**
1855
- * Generate the view for admin product cart block.
1856
- *
1857
- * @param object $cart_contents user cart contents details.
1858
- * @param float $cart_total user cart total.
1859
- * @return string
1860
- */
1861
- public function get_admin_product_block( $cart_contents, $cart_total ) {
1862
-
1863
- $cart_items = unserialize( $cart_contents );
1864
-
1865
- if ( ! is_array( $cart_items ) || ! count( $cart_items ) ) {
1866
- return;
1867
- }
1868
-
1869
- $currency_symbol = get_woocommerce_currency_symbol();
1870
- $tr = '';
1871
- $total = 0;
1872
- $discount = 0;
1873
- $tax = 0;
1874
-
1875
- foreach ( $cart_items as $cart_item ) {
1876
-
1877
- if ( isset( $cart_item['product_id'] ) && isset( $cart_item['quantity'] ) && isset( $cart_item['line_total'] ) && isset( $cart_item['line_subtotal'] ) ) {
1878
-
1879
- $discount = number_format_i18n( $discount + ( $cart_item['line_subtotal'] - $cart_item['line_total'] ), 2 );
1880
- $total = number_format_i18n( $total + $cart_item['line_subtotal'], 2 );
1881
- $tax = number_format_i18n( $tax + $cart_item['line_tax'], 2 );
1882
-
1883
- $tr = $tr . '<tr align="center">
1884
- <td ><img class="demo_img" width="42" height="42" src=" ' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . ' "/></td>
1885
- <td >' . get_the_title( $cart_item['product_id'] ) . '</td>
1886
- <td > ' . $cart_item['quantity'] . ' </td>
1887
- <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1888
- <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1889
- </tr> ';
1890
- }
1891
- }
1892
-
1893
- return '<table align="left" cellspacing="0" class="widefat fixed striped posts">
1894
- <thead>
1895
- <tr align="center">
1896
- <th >' . __( 'Item', 'woo-cart-abandonment-recovery' ) . '</th>
1897
- <th >' . __( 'Name', 'woo-cart-abandonment-recovery' ) . '</th>
1898
- <th >' . __( 'Quantity', 'woo-cart-abandonment-recovery' ) . '</th>
1899
- <th >' . __( 'Price', 'woo-cart-abandonment-recovery' ) . '</th>
1900
- <th >' . __( 'Line Subtotal', 'woo-cart-abandonment-recovery' ) . '</th>
1901
- </tr>
1902
- </thead>
1903
- <tbody>
1904
- ' . $tr . '
1905
- <tr align="center" id="wcf-ca-discount">
1906
- <td colspan="4" >' . __( 'Discount', 'woo-cart-abandonment-recovery' ) . '</td>
1907
- <td>' . $currency_symbol . ( $discount ) . '</td>
1908
- </tr>
1909
- <tr align="center" id="wcf-ca-other">
1910
- <td colspan="4" >' . __( 'Other', 'woo-cart-abandonment-recovery' ) . '</td>
1911
- <td>' . $currency_symbol . ( $tax ) . '</td>
1912
- </tr>
1913
-
1914
- <tr align="center" id="wcf-ca-shipping">
1915
- <td colspan="4" >' . __( 'Shipping', 'woo-cart-abandonment-recovery' ) . '</td>
1916
- <td>' . $currency_symbol . number_format_i18n( $discount + ( $cart_total - $total ) - $tax, 2 ) . '</td>
1917
- </tr>
1918
- <tr align="center" id="wcf-ca-cart-total">
1919
- <td colspan="4" >' . __( 'Cart Total', 'woo-cart-abandonment-recovery' ) . '</td>
1920
- <td>' . $currency_symbol . $cart_total . '</td>
1921
- </tr>
1922
- </tbody>
1923
- </table>';
1924
- }
1925
-
1926
- /**
1927
- * Schedule events for the abadoned carts to send emails.
1928
- *
1929
- * @param integer $session_id user session id.
1930
- * @param boolean $force_reschedule force reschedule.
1931
- */
1932
- public function schedule_emails( $session_id, $force_reschedule = false ) {
1933
-
1934
- $checkout_details = $this->get_checkout_details( $session_id );
1935
-
1936
- if ( ( $checkout_details->unsubscribed ) || ( WCF_CART_COMPLETED_ORDER === $checkout_details->order_status ) ) {
1937
- return;
1938
- }
1939
- $scheduled_time_from = current_time( WCF_CA_DATETIME_FORMAT );
1940
- $scheduled_emails = $this->fetch_scheduled_emails( $session_id );
1941
- $scheduled_templates = array_column( $scheduled_emails, 'template_id' ); //phpcs:ignore
1942
- $scheduled_time_from = $checkout_details->time;
1943
-
1944
- $email_tmpl = Cartflows_Ca_Email_Templates::get_instance();
1945
- $templates = $email_tmpl->fetch_all_active_templates();
1946
-
1947
- global $wpdb;
1948
-
1949
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1950
-
1951
- foreach ( $templates as $template ) {
1952
-
1953
- if ( false !== array_search( $template->id, $scheduled_templates, true ) ) {
1954
- continue;
1955
- }
1956
-
1957
- $timestamp_str = '+' . $template->frequency . ' ' . $template->frequency_unit . 'S';
1958
- $scheduled_time = gmdate( WCF_CA_DATETIME_FORMAT, strtotime( $scheduled_time_from . $timestamp_str ) );
1959
- $discount_type = $email_tmpl->get_email_template_meta_by_key( $template->id, 'discount_type' );
1960
- $discount_type = isset( $discount_type->meta_value ) ? $discount_type->meta_value : '';
1961
- $amount = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_amount' );
1962
- $amount = isset( $amount->meta_value ) ? $amount->meta_value : '';
1963
-
1964
- $coupon_expiry_date = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_date' );
1965
- $coupon_expiry_unit = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_unit' );
1966
- $coupon_expiry_date = isset( $coupon_expiry_date->meta_value ) ? $coupon_expiry_date->meta_value : '';
1967
- $coupon_expiry_unit = isset( $coupon_expiry_unit->meta_value ) ? $coupon_expiry_unit->meta_value : 'hours';
1968
-
1969
- $coupon_expiry_date = $coupon_expiry_date ? strtotime( $scheduled_time . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
1970
-
1971
- $free_shipping_coupon = $email_tmpl->get_email_template_meta_by_key( $template->id, 'free_shipping_coupon' );
1972
- $free_shipping = ( isset( $free_shipping_coupon ) && ( $free_shipping_coupon->meta_value ) ) ? 'yes' : 'no';
1973
-
1974
- $individual_use_only = $email_tmpl->get_email_template_meta_by_key( $template->id, 'individual_use_only' );
1975
- $individual_use = ( isset( $individual_use_only ) && ( $individual_use_only->meta_value ) ) ? 'yes' : 'no';
1976
-
1977
- $override_global_coupon = $email_tmpl->get_email_template_meta_by_key( $template->id, 'override_global_coupon' );
1978
-
1979
- $new_coupon_code = '';
1980
- if ( $override_global_coupon->meta_value ) {
1981
- $new_coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date, $free_shipping, $individual_use );
1982
- }
1983
-
1984
- $wpdb->replace(
1985
- $email_history_table,
1986
- array(
1987
- 'template_id' => $template->id,
1988
- 'ca_session_id' => $checkout_details->session_id,
1989
- 'coupon_code' => $new_coupon_code,
1990
- 'scheduled_time' => $scheduled_time,
1991
- )
1992
- );
1993
- }
1994
- }
1995
-
1996
- /**
1997
- * Fetch all the scheduled emails with templates for the specific session.
1998
- *
1999
- * @param string $session_id session id.
2000
- * @param boolean $fetch_sent sfetch sent emails.
2001
- * @return array|object|null
2002
- */
2003
- public function fetch_scheduled_emails( $session_id, $fetch_sent = false ) {
2004
- global $wpdb;
2005
- $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
2006
- $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
2007
-
2008
- $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
2009
-
2010
- if ( $fetch_sent ) {
2011
- $query .= ' AND email_sent = 1';
2012
- }
2013
-
2014
- $result = $wpdb->get_results( $query ); // phpcs:ignore
2015
- return $result;
2016
- }
2017
-
2018
- /**
2019
- * Delete orders from cart abandonment table whose cart total is zero and order status is abandoned.
2020
- */
2021
- public function delete_empty_abandoned_order() {
2022
- global $wpdb;
2023
-
2024
- $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
2025
-
2026
- $where = array(
2027
- 'cart_total' => 0,
2028
- );
2029
-
2030
- $wpdb->delete( $cart_abandonment_table, $where );
2031
- }
2032
-
2033
-
2034
- /**
2035
- * Check if transient is set for delete garbage coupons.
2036
- */
2037
- public function delete_used_and_expired_coupons() {
2038
- $is_ajax_request = wp_doing_ajax();
2039
- $is_transient_set = false;
2040
- global $wpdb;
2041
- if ( $is_ajax_request ) {
2042
- check_ajax_referer( 'wcf_ca_delete_garbage_coupons', 'security' );
2043
- } else {
2044
- $is_transient_set = get_transient( 'woocommerce_ca_delete_garbage_coupons' );
2045
- }
2046
-
2047
- if ( false === $is_transient_set || $is_ajax_request ) {
2048
- $coupons = $this->delete_garbage_coupons();
2049
- $coupon_count = count( $coupons );
2050
-
2051
- if ( $coupon_count ) {
2052
- $coupons_post_ids = implode( ',', wp_list_pluck( $coupons, 'ID' ) );
2053
- $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN(" . $coupons_post_ids . ')' );//phpcs:ignore
2054
- $wpdb->query( "DELETE FROM {$wpdb->posts} WHERE ID IN(" . $coupons_post_ids . ')' );//phpcs:ignore
2055
- }
2056
-
2057
- if ( ! $is_ajax_request ) {
2058
- set_transient( 'woocommerce_ca_delete_garbage_coupons', $coupons, WEEK_IN_SECONDS );
2059
- return;
2060
- }
2061
-
2062
- // translators: %1$s: Coupons Deleted, %2$s: Deleted coupons count'.
2063
- wp_send_json_success( sprintf( __( '%1$s: %2$d', 'woo-cart-abandonment-recovery' ), 'Coupons Deleted', $coupon_count ) );
2064
-
2065
- }
2066
- }
2067
-
2068
-
2069
- /**
2070
- * Set transient and delete garbage coupons.
2071
- */
2072
- public function delete_garbage_coupons() {
2073
-
2074
- global $wpdb;
2075
-
2076
- $coupon_generated_by = WCF_CA_COUPON_GENERATED_BY;
2077
- $timestamp = time();
2078
- $post_type = 'shop_coupon';
2079
- $coupons = $wpdb->get_results(
2080
- $wpdb->prepare(
2081
- "SELECT ID, coupon_code, usage_limit, total_usaged, expiry_date FROM (
2082
- SELECT p.ID,
2083
- p.post_title AS coupon_code,
2084
- Max(CASE WHEN pm.meta_key = 'date_expires' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS expiry_date,
2085
- Max(CASE WHEN pm.meta_key = 'usage_limit' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS usage_limit,
2086
- Max(CASE WHEN pm.meta_key = 'usage_count' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS total_usaged,
2087
-
2088
- Max(CASE WHEN pm.meta_key = 'coupon_generated_by' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS coupon_generated_by
2089
- FROM wp_posts AS p
2090
- INNER JOIN wp_postmeta AS pm ON p.ID = pm.post_id
2091
- WHERE p.`post_type` = %s
2092
-
2093
- GROUP BY p.ID
2094
- ) AS final_res WHERE coupon_generated_by IS NOT NULL AND coupon_generated_by = %s AND ( ( usage_limit = total_usaged ) OR ( expiry_date <= %d AND expiry_date != '') )",
2095
- $post_type,
2096
- $coupon_generated_by,
2097
- $timestamp
2098
- )
2099
- );
2100
- return $coupons;
2101
- }
2102
-
2103
- /**
2104
- * Send headers to export orders to csv format.
2105
- */
2106
- private function download_send_headers() {
2107
- $now = gmdate( 'Y-m-d-H-i-s' );
2108
- $filename = 'woo-cart-abandonment-recovery-export-' . $now . '.csv';
2109
-
2110
- header( 'Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate' );
2111
- header( "Last-Modified: {$now} GMT" );
2112
-
2113
- // force download.
2114
- header( 'Content-Type: application/force-download' );
2115
- header( 'Content-Type: application/octet-stream' );
2116
- header( 'Content-Type: application/download' );
2117
-
2118
- // disposition / encoding on response body.
2119
- header( "Content-Disposition: attachment;filename={$filename}" );
2120
- header( 'Content-Transfer-Encoding: binary' );
2121
- }
2122
-
2123
- /**
2124
- * Convert users data to csv format.
2125
- *
2126
- * @param array $user_data users data.
2127
- */
2128
- private function array2csv( array $user_data ) {
2129
- if ( empty( $user_data ) ) {
2130
- return;
2131
- }
2132
- ob_clean();
2133
- ob_start();
2134
- $data_file = fopen( 'php://output', 'w' );
2135
- fputcsv(
2136
- $data_file,
2137
- array(
2138
- 'First-Name',
2139
- 'Last-Name',
2140
- 'Email',
2141
- 'Products',
2142
- 'Cart-Total in ' . get_woocommerce_currency(),
2143
- 'Order-Status',
2144
- 'Unsubscribed',
2145
- 'Coupon-Code',
2146
- )
2147
- );
2148
- foreach ( $user_data as $data ) {
2149
- $name = unserialize( $data['other_fields'] );
2150
- $checkout_details = $this->get_checkout_details( $data['session_id'] );
2151
- $cart_data = $this->get_comma_separated_products( $checkout_details->cart_contents );
2152
- fputcsv(
2153
- $data_file,
2154
- array(
2155
- $name['wcf_first_name'],
2156
- $name['wcf_last_name'],
2157
- $data['email'],
2158
- $cart_data,
2159
- $data['cart_total'],
2160
- $data['order_status'],
2161
- $data['unsubscribed'] ? 'Yes' : 'No',
2162
- $data['coupon_code'],
2163
- )
2164
- );
2165
-
2166
- }
2167
- fclose( $data_file ); //phpcs:ignore
2168
- return ob_get_clean();
2169
- }
2170
- }
2171
-
2172
- 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 script to track the cart abandonment.
48
+ add_action( 'woocommerce_after_checkout_form', array( $this, 'cart_abandonment_tracking_script' ) );
49
+
50
+ // Store user details from the current checkout page.
51
+ add_action( 'wp_ajax_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
52
+ add_action( 'wp_ajax_nopriv_cartflows_save_cart_abandonment_data', array( $this, 'save_cart_abandonment_data' ) );
53
+
54
+ // GDPR actions.
55
+ add_action( 'wp_ajax_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
56
+ add_action( 'wp_ajax_nopriv_cartflows_skip_cart_tracking_gdpr', array( $this, 'skip_cart_tracking_by_gdpr' ) );
57
+
58
+ // Delete the stored cart abandonment data once order gets created.
59
+ add_action( 'woocommerce_new_order', array( $this, 'delete_cart_abandonment_data' ) );
60
+ add_action( 'woocommerce_thankyou', array( $this, 'delete_cart_abandonment_data' ) );
61
+ add_action( 'woocommerce_order_status_changed', array( $this, 'wcf_ca_update_order_status' ), 999, 3 );
62
+
63
+ // Adding filter to restore the data if recreating abandonment order.
64
+ add_filter( 'wp', array( $this, 'restore_cart_abandonment_data' ), 10 );
65
+ add_filter( 'wp', array( $this, 'unsubscribe_cart_abandonment_emails' ), 10 );
66
+
67
+ add_action( 'wp_ajax_wcf_ca_preview_email_send', array( $this, 'send_preview_email' ) );
68
+
69
+ // Delete coupons.
70
+ add_action( 'wp_ajax_wcf_ca_delete_garbage_coupons', array( $this, 'delete_used_and_expired_coupons' ) );
71
+
72
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
73
+ $action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
74
+ if ( WCF_CA_PAGE_NAME === $page ) {
75
+ // Adding filter to add new button to add custom fields.
76
+ add_filter( 'mce_buttons', array( $this, 'wcf_filter_mce_button' ) );
77
+ add_filter( 'mce_external_plugins', array( $this, 'wcf_filter_mce_plugin' ), 9 );
78
+ }
79
+
80
+ add_filter( 'cron_schedules', array( $this, 'cartflows_ca_update_order_status_action' ) ); //phpcs:ignore WordPress.WP.CronInterval.ChangeDetected
81
+
82
+ // Schedule an action if it's not already scheduled.
83
+ if ( ! wp_next_scheduled( 'cartflows_ca_update_order_status_action' ) ) {
84
+ wp_schedule_event( time(), 'every_fifteen_minutes', 'cartflows_ca_update_order_status_action' );
85
+ }
86
+
87
+ // Adding notice to checkout page to inform about test email checkout page.
88
+ add_action( 'woocommerce_before_checkout_form', array( $this, 'test_email_checkout_page' ), 9 );
89
+
90
+ add_action( 'cartflows_ca_update_order_status_action', array( $this, 'update_order_status' ) );
91
+ }
92
+
93
+ }
94
+
95
+
96
+ /**
97
+ * Update the Order status.
98
+ *
99
+ * @param integer $order_id order id.
100
+ * @param string $old_order_status old order status.
101
+ * @param string $new_order_status new order status.
102
+ */
103
+ public function wcf_ca_update_order_status( $order_id, $old_order_status, $new_order_status ) {
104
+
105
+ $acceptable_order_statuses = array( 'completed', 'processing', 'failed' );
106
+
107
+ $exclude_on_hold_order = apply_filters( 'woo_ca_exclude_on_hold_order_from_tracking', false );
108
+
109
+ if ( $exclude_on_hold_order ) {
110
+ array_push( $acceptable_order_statuses, 'on-hold' );
111
+ }
112
+ if ( ( WCF_CART_FAILED_ORDER === $new_order_status ) ) {
113
+ return;
114
+ }
115
+
116
+ if ( $order_id && in_array( $new_order_status, $acceptable_order_statuses, true ) ) {
117
+
118
+ $order = wc_get_order( $order_id );
119
+
120
+ $order_email = $order->get_billing_email();
121
+ $captured_data = ( WCF_CART_FAILED_ORDER === $new_order_status ) ? $this->get_tracked_data_without_status( $order_email ) : $this->get_captured_data_by_email( $order_email );
122
+
123
+ if ( $captured_data && is_object( $captured_data ) ) {
124
+ $capture_status = $captured_data->order_status;
125
+ global $wpdb;
126
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
127
+
128
+ if ( ( WCF_CART_NORMAL_ORDER === $capture_status ) ) {
129
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $captured_data->session_id ) ) );
130
+ }
131
+
132
+ if ( ( WCF_CART_ABANDONED_ORDER === $capture_status || WCF_CART_LOST_ORDER === $capture_status ) ) {
133
+ $this->skip_future_emails_when_order_is_completed( sanitize_key( $captured_data->session_id ) );
134
+ $this->trigger_zapier_webhook( $captured_data->session_id, WCF_CART_COMPLETED_ORDER );
135
+ $note = __( 'This order was abandoned & subsequently recovered.', 'woo-cart-abandonment-recovery' );
136
+ $order->add_order_note( $note );
137
+ $order->save();
138
+ if ( WC()->session ) {
139
+ WC()->session->__unset( 'wcf_session_id' );
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ }
146
+
147
+
148
+ /**
149
+ * Send preview emails.
150
+ */
151
+ public function send_preview_email() {
152
+
153
+ check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, 'security' );
154
+ $mail_result = $this->send_email_templates( null, true );
155
+ if ( $mail_result ) {
156
+ wp_send_json_success( __( 'Mail has been sent successfully!', 'woo-cart-abandonment-recovery' ) );
157
+ } else {
158
+ wp_send_json_error( __( 'Mail sending failed!', 'woo-cart-abandonment-recovery' ) );
159
+ }
160
+ }
161
+
162
+
163
+ /**
164
+ * Delete tracked data and set cookie for the user.
165
+ */
166
+ public function skip_cart_tracking_by_gdpr() {
167
+ check_ajax_referer( 'cartflows_skip_cart_tracking_gdpr', 'security' );
168
+
169
+ global $wpdb;
170
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
171
+
172
+ $session_id = WC()->session->get( 'wcf_session_id' );
173
+ if ( $session_id ) {
174
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
175
+ }
176
+
177
+ setcookie( 'wcf_ca_skip_track_data', 'true', 0, '/' );
178
+ wp_send_json_success();
179
+
180
+ }
181
+
182
+
183
+ /**
184
+ * Create custom schedule.
185
+ *
186
+ * @param array $schedules schedules.
187
+ * @return mixed
188
+ */
189
+ public function cartflows_ca_update_order_status_action( $schedules ) {
190
+
191
+ /**
192
+ * Add filter to change the cron interval time to uodate order status.
193
+ */
194
+ $cron_time = apply_filters( 'woo_ca_update_order_cron_interval', 15 );
195
+
196
+ $schedules['every_fifteen_minutes'] = array(
197
+ 'interval' => $cron_time * MINUTE_IN_SECONDS,
198
+ 'display' => __( 'Every Fifteen Minutes', 'woo-cart-abandonment-recovery' ),
199
+ );
200
+
201
+ return $schedules;
202
+ }
203
+
204
+ /**
205
+ * Generate new coupon code for abandoned cart.
206
+ *
207
+ * @param string $discount_type discount type.
208
+ * @param float $amount amount.
209
+ * @param string $expiry expiry.
210
+ * @param string $free_shipping is free shipping.
211
+ * @param string $individual_use use coupon individual.
212
+ */
213
+ public function generate_coupon_code( $discount_type, $amount, $expiry = '', $free_shipping = 'no', $individual_use = 'no' ) {
214
+
215
+ $coupon_code = '';
216
+
217
+ $coupon_code = wp_generate_password( 8, false, false );
218
+
219
+ $new_coupon_id = wp_insert_post(
220
+ array(
221
+ 'post_title' => $coupon_code,
222
+ 'post_content' => '',
223
+ 'post_status' => 'publish',
224
+ 'post_author' => 1,
225
+ 'post_type' => 'shop_coupon',
226
+ )
227
+ );
228
+
229
+ $coupon_post_data = array(
230
+ 'discount_type' => $discount_type,
231
+ 'description' => WCF_CA_COUPON_DESCRIPTION,
232
+ 'coupon_amount' => $amount,
233
+ 'individual_use' => $individual_use,
234
+ 'product_ids' => '',
235
+ 'exclude_product_ids' => '',
236
+ 'usage_limit' => '1',
237
+ 'usage_count' => '0',
238
+ 'date_expires' => $expiry,
239
+ 'apply_before_tax' => 'yes',
240
+ 'free_shipping' => $free_shipping,
241
+ 'coupon_generated_by' => WCF_CA_COUPON_GENERATED_BY,
242
+ );
243
+
244
+ foreach ( $coupon_post_data as $key => $value ) {
245
+ update_post_meta( $new_coupon_id, $key, $value );
246
+ }
247
+
248
+ return $coupon_code;
249
+ }
250
+
251
+ /**
252
+ * Unsubscribe the user from the mailing list.
253
+ */
254
+ public function unsubscribe_cart_abandonment_emails() {
255
+
256
+ $unsubscribe = filter_input( INPUT_GET, 'unsubscribe', FILTER_VALIDATE_BOOLEAN );
257
+ $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
258
+ if ( $unsubscribe && $this->is_valid_token( $wcf_ac_token ) ) {
259
+ $token_data = $this->wcf_decode_token( $wcf_ac_token );
260
+ if ( isset( $token_data['wcf_session_id'] ) ) {
261
+ $session_id = $token_data['wcf_session_id'];
262
+
263
+ global $wpdb;
264
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
265
+ $wpdb->update(
266
+ $cart_abandonment_table,
267
+ array( 'unsubscribed' => true ),
268
+ array( 'session_id' => $session_id )
269
+ );
270
+ wp_die( esc_html__( 'You have successfully unsubscribed from our email list.', 'woo-cart-abandonment-recovery' ), esc_html__( 'Unsubscribed', 'woo-cart-abandonment-recovery' ) );
271
+
272
+ }
273
+ }
274
+
275
+ }
276
+
277
+
278
+ /**
279
+ * Link JS to mce button.
280
+ *
281
+ * @param array $plugins mce pluggins.
282
+ * @return mixed
283
+ */
284
+ public function wcf_filter_mce_plugin( $plugins ) {
285
+ $plugins['cartflows_ac'] = CARTFLOWS_CA_URL . 'admin/assets/js/admin-mce.js';
286
+ return $plugins;
287
+ }
288
+
289
+ /**
290
+ * Register button.
291
+ *
292
+ * @param array $buttons mce buttons.
293
+ * @return mixed
294
+ */
295
+ public function wcf_filter_mce_button( $buttons ) {
296
+ array_push( $buttons, 'cartflows_ac' );
297
+ return $buttons;
298
+ }
299
+
300
+ /**
301
+ * Initialise all the constants
302
+ */
303
+ public function define_cart_abandonment_constants() {
304
+ define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
305
+ define( 'CARTFLOWS_CART_ABANDONMENT_TRACKING_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
306
+ define( 'WCF_CART_ABANDONED_ORDER', 'abandoned' );
307
+ define( 'WCF_CART_COMPLETED_ORDER', 'completed' );
308
+ define( 'WCF_CART_LOST_ORDER', 'lost' );
309
+ define( 'WCF_CART_NORMAL_ORDER', 'normal' );
310
+ define( 'WCF_CART_FAILED_ORDER', 'failed' );
311
+ define( 'CARTFLOWS_ZAPIER_ACTION_AFTER_TIME', 1800 );
312
+
313
+ define( 'WCF_ACTION_ABANDONED_CARTS', 'abandoned_carts' );
314
+ define( 'WCF_ACTION_RECOVERED_CARTS', 'recovered_carts' );
315
+ define( 'WCF_ACTION_LOST_CARTS', 'lost_carts' );
316
+ define( 'WCF_ACTION_SETTINGS', 'settings' );
317
+ define( 'WCF_ACTION_REPORTS', 'reports' );
318
+
319
+ define( 'WCF_SUB_ACTION_REPORTS_VIEW', 'view' );
320
+ define( 'WCF_SUB_ACTION_REPORTS_RESCHEDULE', 'reschedule' );
321
+
322
+ define( 'WCF_DEFAULT_CUT_OFF_TIME', 15 );
323
+ define( 'WCF_DEFAULT_COUPON_AMOUNT', 10 );
324
+
325
+ define( 'WCF_CA_DATETIME_FORMAT', 'Y-m-d H:i:s' );
326
+
327
+ define( 'WCF_CA_COUPON_DESCRIPTION', 'This coupon is for abandoned cart email templates.' );
328
+ define( 'WCF_CA_COUPON_GENERATED_BY', 'woo-cart-abandonment-recovery' );
329
+ }
330
+
331
+ /**
332
+ * Restore cart abandonemnt data on checkout page.
333
+ *
334
+ * @param array $fields checkout fields values.
335
+ * @return array field values
336
+ */
337
+ public function restore_cart_abandonment_data( $fields = array() ) {
338
+ global $woocommerce;
339
+ $result = array();
340
+ // Restore only of user is not logged in.
341
+ $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
342
+ if ( $this->is_valid_token( $wcf_ac_token ) ) {
343
+
344
+ // Check if `wcf_restore_token` exists to restore cart data.
345
+ $token_data = $this->wcf_decode_token( $wcf_ac_token );
346
+ if ( is_array( $token_data ) && isset( $token_data['wcf_session_id'] ) ) {
347
+ $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
348
+ if ( isset( $result ) && WCF_CART_ABANDONED_ORDER === $result->order_status || WCF_CART_LOST_ORDER === $result->order_status ) {
349
+ WC()->session->set( 'wcf_session_id', $token_data['wcf_session_id'] );
350
+ }
351
+ }
352
+
353
+ if ( $result ) {
354
+ $cart_content = unserialize( $result->cart_contents );
355
+
356
+ if ( $cart_content ) {
357
+ $woocommerce->cart->empty_cart();
358
+ wc_clear_notices();
359
+ foreach ( $cart_content as $cart_item ) {
360
+
361
+ $cart_item_data = array();
362
+ $id = $cart_item['product_id'];
363
+ $qty = $cart_item['quantity'];
364
+
365
+ // Skip bundled products when added main product.
366
+ if ( isset( $cart_item['bundled_by'] ) ) {
367
+ continue;
368
+ }
369
+
370
+ if ( isset( $cart_item['ppom'] ) ) {
371
+ $cart_item_data['ppom'] = $cart_item ['ppom'];
372
+ }
373
+
374
+ if ( isset( $cart_item['cartflows_bump'] ) ) {
375
+ $cart_item_data['cartflows_bump'] = $cart_item['cartflows_bump'];
376
+ }
377
+
378
+ if ( isset( $cart_item['custom_price'] ) ) {
379
+ $cart_item_data['custom_price'] = $cart_item['custom_price'];
380
+ }
381
+
382
+ $woocommerce->cart->add_to_cart( $id, $qty, $cart_item['variation_id'], array(), $cart_item_data );
383
+ }
384
+
385
+ if ( isset( $token_data['wcf_coupon_code'] ) && ! $woocommerce->cart->applied_coupons ) {
386
+ $woocommerce->cart->add_discount( $token_data['wcf_coupon_code'] );
387
+ }
388
+ }
389
+ $other_fields = unserialize( $result->other_fields );
390
+
391
+ $parts = explode( ',', $other_fields['wcf_location'] );
392
+ if ( count( $parts ) > 1 ) {
393
+ $country = $parts[0];
394
+ $city = trim( $parts[1] );
395
+ } else {
396
+ $country = $parts[0];
397
+ $city = '';
398
+ }
399
+
400
+ foreach ( $other_fields as $key => $value ) {
401
+ $key = str_replace( 'wcf_', '', $key );
402
+ $_POST[ $key ] = sanitize_text_field( $value );
403
+ }
404
+ $_POST['billing_first_name'] = sanitize_text_field( $other_fields['wcf_first_name'] );
405
+ $_POST['billing_last_name'] = sanitize_text_field( $other_fields['wcf_last_name'] );
406
+ $_POST['billing_phone'] = sanitize_text_field( $other_fields['wcf_phone_number'] );
407
+ $_POST['billing_email'] = sanitize_email( $result->email );
408
+ $_POST['billing_city'] = sanitize_text_field( $city );
409
+ $_POST['billing_country'] = sanitize_text_field( $country );
410
+
411
+ }
412
+ }
413
+ return $fields;
414
+ }
415
+
416
+ /**
417
+ * Add notice to inform user about test email checkout page.
418
+ */
419
+ public function test_email_checkout_page() {
420
+
421
+ $wcf_ac_token = filter_input( INPUT_GET, 'wcf_ac_token', FILTER_SANITIZE_STRING );
422
+ $token_data = $this->wcf_decode_token( $wcf_ac_token );
423
+ if ( is_checkout() && ! is_wc_endpoint_url() && isset( $token_data['wcf_preview_email'] ) && $token_data['wcf_preview_email'] ) {
424
+ wc_print_notice( __( 'This checkout page is generated by WooCommerce Cart Abandonment Recovery plugin from test mail.', 'woo-cart-abandonment-recovery' ), 'notice' );
425
+ }
426
+ }
427
+
428
+
429
+ /**
430
+ * Load cart abandonemnt tracking script.
431
+ *
432
+ * @return void
433
+ */
434
+ public function cart_abandonment_tracking_script() {
435
+
436
+ $wcf_ca_ignore_users = get_option( 'wcf_ca_ignore_users' );
437
+ $current_user = wp_get_current_user();
438
+ $roles = $current_user->roles;
439
+ $role = array_shift( $roles );
440
+ if ( ! empty( $wcf_ca_ignore_users ) ) {
441
+ foreach ( $wcf_ca_ignore_users as $user ) {
442
+ $user = strtolower( $user );
443
+ $role = preg_replace( '/_/', ' ', $role );
444
+ if ( $role === $user ) {
445
+ return;
446
+ }
447
+ }
448
+ }
449
+
450
+ global $post;
451
+ wp_enqueue_script(
452
+ 'cartflows-cart-abandonment-tracking',
453
+ CARTFLOWS_CART_ABANDONMENT_TRACKING_URL . 'assets/js/cart-abandonment-tracking.js',
454
+ array( 'jquery' ),
455
+ CARTFLOWS_CA_VER,
456
+ true
457
+ );
458
+
459
+ $vars = array(
460
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
461
+ '_nonce' => wp_create_nonce( 'cartflows_save_cart_abandonment_data' ),
462
+ '_gdpr_nonce' => wp_create_nonce( 'cartflows_skip_cart_tracking_gdpr' ),
463
+ '_post_id' => get_the_ID(),
464
+ '_show_gdpr_message' => ( wcf_ca()->utils->is_gdpr_enabled() && ! isset( $_COOKIE['wcf_ca_skip_track_data'] ) ),
465
+ '_gdpr_message' => get_option( 'wcf_ca_gdpr_message' ),
466
+ '_gdpr_nothanks_msg' => __( 'No Thanks', 'woo-cart-abandonment-recovery' ),
467
+ '_gdpr_after_no_thanks_msg' => __( 'You won\'t receive further emails from us, thank you!', 'woo-cart-abandonment-recovery' ),
468
+ 'enable_ca_tracking' => true,
469
+ );
470
+
471
+ wp_localize_script( 'cartflows-cart-abandonment-tracking', 'CartFlowsProCAVars', $vars );
472
+
473
+ }
474
+
475
+ /**
476
+ * Validate the token before use.
477
+ *
478
+ * @param string $token token form the url.
479
+ * @return bool
480
+ */
481
+ public function is_valid_token( $token ) {
482
+ $is_valid = false;
483
+ $token_data = $this->wcf_decode_token( $token );
484
+ if ( is_array( $token_data ) && array_key_exists( 'wcf_session_id', $token_data ) ) {
485
+ $result = $this->get_checkout_details( $token_data['wcf_session_id'] );
486
+ if ( isset( $result ) ) {
487
+ $is_valid = true;
488
+ }
489
+ }
490
+ return $is_valid;
491
+ }
492
+
493
+ /**
494
+ * Check before emails actually send to user.
495
+ *
496
+ * @param array $email_data email_data.
497
+ * @param array $current_cart_data cart data.
498
+ * @return bool
499
+ */
500
+ public function check_if_already_purchased_by_email_product_ids( $email_data, $current_cart_data ) {
501
+
502
+ global $wpdb;
503
+ $current_cart_data = unserialize( $current_cart_data );
504
+
505
+ // Fetch products & variations.
506
+ $products = array_values( wp_list_pluck( $current_cart_data, 'product_id' ) );
507
+ $variations = array_values( wp_list_pluck( $current_cart_data, 'variation_id' ) );
508
+ $current_products = array_unique( array_merge( $products, $variations ) );
509
+
510
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
511
+
512
+ $orders = wc_get_orders(
513
+ array(
514
+ 'billing_email' => $email_data->email,
515
+ 'status' => array( 'processing', 'completed' ),
516
+ 'date_after' => gmdate(
517
+ 'Y-m-d h:i:s',
518
+ strtotime( '-30 days' )
519
+ ),
520
+ )
521
+ );
522
+ $need_to_send_email = true;
523
+
524
+ foreach ( $orders as $order ) {
525
+ $order = wc_get_order( $order->get_id() );
526
+ $items = $order->get_items();
527
+ foreach ( $items as $item ) {
528
+ $product_id = $item->get_product_id();
529
+ if ( in_array( $product_id, $current_products, true ) ) {
530
+ /**
531
+ * Remove duplicate captured order for tracking.
532
+ */
533
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $email_data->session_id ) ) );
534
+ $need_to_send_email = false;
535
+ break;
536
+ }
537
+ }
538
+ }
539
+ return $need_to_send_email;
540
+ }
541
+
542
+ /**
543
+ * Execute Zapier webhook for further action inside Zapier.
544
+ *
545
+ * @since 1.0.0
546
+ */
547
+ public function update_order_status() {
548
+
549
+ global $wpdb;
550
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
551
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
552
+ $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
553
+
554
+ /**
555
+ * Delete abandoned cart orders if empty.
556
+ */
557
+ $this->delete_empty_abandoned_order();
558
+
559
+ $wp_current_datetime = current_time( WCF_CA_DATETIME_FORMAT );
560
+ $abandoned_ids = $wpdb->get_results(
561
+ $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
562
+ );
563
+
564
+ foreach ( $abandoned_ids as $session_id ) {
565
+
566
+ if ( isset( $session_id['session_id'] ) ) {
567
+
568
+ $current_session_id = $session_id['session_id'];
569
+ $this->schedule_emails( $current_session_id );
570
+
571
+ $coupon_code = '';
572
+ $wcf_ca_coupon_code_status = get_option( 'wcf_ca_coupon_code_status' );
573
+
574
+ if ( 'on' === $wcf_ca_coupon_code_status ) {
575
+ $discount_type = get_option( 'wcf_ca_discount_type' );
576
+ $discount_type = $discount_type ? $discount_type : 'percent';
577
+ $amount = get_option( 'wcf_ca_coupon_amount' );
578
+ $amount = $amount ? $amount : WCF_DEFAULT_COUPON_AMOUNT;
579
+ $coupon_expiry_date = get_option( 'wcf_ca_coupon_expiry' );
580
+ $coupon_expiry_unit = get_option( 'wcf_ca_coupon_expiry_unit' );
581
+ $coupon_expiry_date = $coupon_expiry_date ? strtotime( $wp_current_datetime . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
582
+ $free_shipping_coupon = get_option( 'wcf_ca_free_shipping_coupon' );
583
+ $free_shipping = ( isset( $free_shipping_coupon ) && ( $free_shipping_coupon->meta_value ) ) ? 'yes' : 'no';
584
+
585
+ $individual_use_only = get_option( 'wcf_ca_individual_use_only' );
586
+ $individual_use = ( isset( $individual_use_only ) && ( $individual_use_only->meta_value ) ) ? 'yes' : 'no';
587
+
588
+ $coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date, $free_shipping, $individual_use );
589
+ }
590
+
591
+ $wpdb->update(
592
+ $cart_abandonment_table,
593
+ array(
594
+ 'order_status' => WCF_CART_ABANDONED_ORDER,
595
+ 'coupon_code' => $coupon_code,
596
+ ),
597
+ array( 'session_id' => $current_session_id )
598
+ );
599
+
600
+ $this->trigger_zapier_webhook( $current_session_id, WCF_CART_ABANDONED_ORDER );
601
+ }
602
+ }
603
+
604
+ /**
605
+ * Send scheduled emails.
606
+ */
607
+ $this->send_emails_to_callback();
608
+
609
+ // Update order status to lost after campaign complete.
610
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
611
+ $wpdb->query(
612
+ $wpdb->prepare(
613
+ "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)
614
+ AND ( (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id ) =
615
+ (SELECT count(*) FROM $email_history_table WHERE ca_session_id = ca.session_id AND email_sent = 1) )",
616
+ WCF_CART_ABANDONED_ORDER,
617
+ $wp_current_datetime
618
+ )
619
+ );
620
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
621
+
622
+ /**
623
+ * Delete garbage coupons.
624
+ */
625
+ $wcf_ca_auto_delete_coupons = get_option( 'wcf_ca_auto_delete_coupons' );
626
+
627
+ if ( isset( $wcf_ca_auto_delete_coupons ) && 'on' === $wcf_ca_auto_delete_coupons ) {
628
+ $this->delete_used_and_expired_coupons();
629
+ }
630
+
631
+ }
632
+
633
+ /**
634
+ * Send zapier webhook.
635
+ *
636
+ * @param string $session_id session id.
637
+ * @param string $order_status order status.
638
+ */
639
+ public function trigger_zapier_webhook( $session_id, $order_status ) {
640
+
641
+ $checkout_details = $this->get_checkout_details( $session_id );
642
+
643
+ if ( $checkout_details && wcf_ca()->utils->is_zapier_trigger_enabled() ) {
644
+ $trigger_details = array();
645
+ $url = get_option( 'wcf_ca_zapier_cart_abandoned_webhook' );
646
+
647
+ $other_details = unserialize( $checkout_details->other_fields );
648
+ $trigger_details['first_name'] = $other_details['wcf_first_name'];
649
+ $trigger_details['last_name'] = $other_details['wcf_last_name'];
650
+ $trigger_details['phone_number'] = $other_details['wcf_phone_number'];
651
+ $trigger_details['billing_address'] = $other_details['wcf_billing_company'] . ' ' . $other_details['wcf_billing_address_1'] . ', ' . $other_details['wcf_billing_state'] . ', ' . $other_details['wcf_location'] . ', ' . $other_details['wcf_billing_postcode'];
652
+ $trigger_details['billing_address'] = trim( $trigger_details['billing_address'], ', ' );
653
+ $trigger_details['shipping_address'] = $other_details['wcf_shipping_company'] . ' ' . $other_details['wcf_shipping_address_1'] . ', ' . $other_details['wcf_shipping_city'] . ', ' . $other_details['wcf_shipping_state'] . ', ' . $other_details['wcf_shipping_postcode'];
654
+ $trigger_details['shipping_address'] = trim( $trigger_details['shipping_address'], ', ' );
655
+ $trigger_details['email'] = $checkout_details->email;
656
+ $token_data = array( 'wcf_session_id' => $checkout_details->session_id );
657
+ $trigger_details['checkout_url'] = $this->get_checkout_url( $checkout_details->checkout_id, $token_data );
658
+ $trigger_details['product_names'] = $this->get_comma_separated_products( $checkout_details->cart_contents );
659
+ $trigger_details['coupon_code'] = $checkout_details->coupon_code;
660
+ $trigger_details['order_status'] = $order_status;
661
+ $trigger_details['cart_total'] = $checkout_details->cart_total;
662
+ $trigger_details['product_table'] = $this->get_email_product_block( $checkout_details->cart_contents, $checkout_details->cart_total );
663
+
664
+ $parameters = http_build_query( $trigger_details );
665
+
666
+ wp_remote_post(
667
+ $url,
668
+ array(
669
+ 'body' => $parameters,
670
+ 'timeout' => '5',
671
+ 'redirection' => '5',
672
+ 'httpversion' => '1.0',
673
+ 'blocking' => true,
674
+ 'headers' => array(),
675
+ 'cookies' => array(),
676
+ )
677
+ );
678
+
679
+ }
680
+ }
681
+
682
+
683
+ /**
684
+ * Sanitize post array.
685
+ *
686
+ * @return array
687
+ */
688
+ public function sanitize_post_data() {
689
+
690
+ $input_post_values = array(
691
+ 'wcf_billing_company' => array(
692
+ 'default' => '',
693
+ 'sanitize' => FILTER_SANITIZE_STRING,
694
+ ),
695
+ 'wcf_email' => array(
696
+ 'default' => '',
697
+ 'sanitize' => FILTER_SANITIZE_EMAIL,
698
+ ),
699
+ 'wcf_billing_address_1' => array(
700
+ 'default' => '',
701
+ 'sanitize' => FILTER_SANITIZE_STRING,
702
+ ),
703
+ 'wcf_billing_address_2' => array(
704
+ 'default' => '',
705
+ 'sanitize' => FILTER_SANITIZE_STRING,
706
+ ),
707
+ 'wcf_billing_state' => array(
708
+ 'default' => '',
709
+ 'sanitize' => FILTER_SANITIZE_STRING,
710
+ ),
711
+ 'wcf_billing_postcode' => array(
712
+ 'default' => '',
713
+ 'sanitize' => FILTER_SANITIZE_STRING,
714
+ ),
715
+ 'wcf_shipping_first_name' => array(
716
+ 'default' => '',
717
+ 'sanitize' => FILTER_SANITIZE_STRING,
718
+ ),
719
+ 'wcf_shipping_last_name' => array(
720
+ 'default' => '',
721
+ 'sanitize' => FILTER_SANITIZE_STRING,
722
+ ),
723
+ 'wcf_shipping_company' => array(
724
+ 'default' => '',
725
+ 'sanitize' => FILTER_SANITIZE_STRING,
726
+ ),
727
+ 'wcf_shipping_country' => array(
728
+ 'default' => '',
729
+ 'sanitize' => FILTER_SANITIZE_STRING,
730
+ ),
731
+ 'wcf_shipping_address_1' => array(
732
+ 'default' => '',
733
+ 'sanitize' => FILTER_SANITIZE_STRING,
734
+ ),
735
+ 'wcf_shipping_address_2' => array(
736
+ 'default' => '',
737
+ 'sanitize' => FILTER_SANITIZE_STRING,
738
+ ),
739
+ 'wcf_shipping_city' => array(
740
+ 'default' => '',
741
+ 'sanitize' => FILTER_SANITIZE_STRING,
742
+ ),
743
+ 'wcf_shipping_state' => array(
744
+ 'default' => '',
745
+ 'sanitize' => FILTER_SANITIZE_STRING,
746
+ ),
747
+ 'wcf_shipping_postcode' => array(
748
+ 'default' => '',
749
+ 'sanitize' => FILTER_SANITIZE_STRING,
750
+ ),
751
+ 'wcf_order_comments' => array(
752
+ 'default' => '',
753
+ 'sanitize' => FILTER_SANITIZE_STRING,
754
+ ),
755
+ 'wcf_name' => array(
756
+ 'default' => '',
757
+ 'sanitize' => FILTER_SANITIZE_STRING,
758
+ ),
759
+ 'wcf_surname' => array(
760
+ 'default' => '',
761
+ 'sanitize' => FILTER_SANITIZE_STRING,
762
+ ),
763
+ 'wcf_phone' => array(
764
+ 'default' => '',
765
+ 'sanitize' => FILTER_SANITIZE_STRING,
766
+ ),
767
+ 'wcf_country' => array(
768
+ 'default' => '',
769
+ 'sanitize' => FILTER_SANITIZE_STRING,
770
+ ),
771
+ 'wcf_city' => array(
772
+ 'default' => '',
773
+ 'sanitize' => FILTER_SANITIZE_STRING,
774
+ ),
775
+ 'wcf_post_id' => array(
776
+ 'default' => 0,
777
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
778
+ ),
779
+ );
780
+
781
+ $sanitized_post = array();
782
+ foreach ( $input_post_values as $key => $input_post_value ) {
783
+
784
+ if ( isset( $_POST[ $key ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Missing
785
+ $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
786
+ } else {
787
+ $sanitized_post[ $key ] = $input_post_value['default'];
788
+ }
789
+ }
790
+ return $sanitized_post;
791
+
792
+ }
793
+
794
+
795
+ /**
796
+ * Save cart abandonment tracking and schedule new event.
797
+ *
798
+ * @since 1.0.0
799
+ */
800
+ public function save_cart_abandonment_data() {
801
+ check_ajax_referer( 'cartflows_save_cart_abandonment_data', 'security' );
802
+ $post_data = $this->sanitize_post_data();
803
+ if ( isset( $post_data['wcf_email'] ) ) {
804
+ $user_email = sanitize_email( $post_data['wcf_email'] );
805
+ global $wpdb;
806
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
807
+
808
+ // Verify if email is already exists.
809
+ $session_id = WC()->session->get( 'wcf_session_id' );
810
+ $session_checkout_details = null;
811
+ if ( isset( $session_id ) ) {
812
+ $session_checkout_details = $this->get_checkout_details( $session_id );
813
+ } else {
814
+ $session_checkout_details = $this->get_checkout_details_by_email( $user_email );
815
+ if ( $session_checkout_details ) {
816
+ $session_id = $session_checkout_details->session_id;
817
+ WC()->session->set( 'wcf_session_id', $session_id );
818
+ } else {
819
+ $session_id = md5( uniqid( wp_rand(), true ) );
820
+ }
821
+ }
822
+
823
+ $checkout_details = $this->prepare_abandonment_data( $post_data );
824
+
825
+ if ( isset( $session_checkout_details ) && WCF_CART_COMPLETED_ORDER === $session_checkout_details->order_status ) {
826
+ WC()->session->__unset( 'wcf_session_id' );
827
+ $session_id = md5( uniqid( wp_rand(), true ) );
828
+ }
829
+
830
+ if ( isset( $checkout_details['cart_total'] ) && $checkout_details['cart_total'] > 0 ) {
831
+
832
+ if ( ( ! is_null( $session_id ) ) && ! is_null( $session_checkout_details ) ) {
833
+
834
+ // Updating row in the Database where users Session id = same as prevously saved in Session.
835
+ $wpdb->update(
836
+ $cart_abandonment_table,
837
+ $checkout_details,
838
+ array( 'session_id' => $session_id )
839
+ );
840
+
841
+ } else {
842
+
843
+ $checkout_details['session_id'] = sanitize_text_field( $session_id );
844
+ // Inserting row into Database.
845
+ $wpdb->insert(
846
+ $cart_abandonment_table,
847
+ $checkout_details
848
+ );
849
+
850
+ // Storing session_id in WooCommerce session.
851
+ WC()->session->set( 'wcf_session_id', $session_id );
852
+
853
+ }
854
+ } else {
855
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
856
+ }
857
+
858
+ wp_send_json_success();
859
+ }
860
+ }
861
+
862
+
863
+ /**
864
+ * Prepare cart data to save for abandonment.
865
+ *
866
+ * @param array $post_data post data.
867
+ * @return array
868
+ */
869
+ public function prepare_abandonment_data( $post_data = array() ) {
870
+
871
+ if ( function_exists( 'WC' ) ) {
872
+
873
+ // Retrieving cart total value and currency.
874
+ $cart_total = WC()->cart->total;
875
+
876
+ // Retrieving cart products and their quantities.
877
+ $products = WC()->cart->get_cart();
878
+ $current_time = current_time( WCF_CA_DATETIME_FORMAT );
879
+ $other_fields = array(
880
+ 'wcf_billing_company' => $post_data['wcf_billing_company'],
881
+ 'wcf_billing_address_1' => $post_data['wcf_billing_address_1'],
882
+ 'wcf_billing_address_2' => $post_data['wcf_billing_address_2'],
883
+ 'wcf_billing_state' => $post_data['wcf_billing_state'],
884
+ 'wcf_billing_postcode' => $post_data['wcf_billing_postcode'],
885
+ 'wcf_shipping_first_name' => $post_data['wcf_shipping_first_name'],
886
+ 'wcf_shipping_last_name' => $post_data['wcf_shipping_last_name'],
887
+ 'wcf_shipping_company' => $post_data['wcf_shipping_company'],
888
+ 'wcf_shipping_country' => $post_data['wcf_shipping_country'],
889
+ 'wcf_shipping_address_1' => $post_data['wcf_shipping_address_1'],
890
+ 'wcf_shipping_address_2' => $post_data['wcf_shipping_address_2'],
891
+ 'wcf_shipping_city' => $post_data['wcf_shipping_city'],
892
+ 'wcf_shipping_state' => $post_data['wcf_shipping_state'],
893
+ 'wcf_shipping_postcode' => $post_data['wcf_shipping_postcode'],
894
+ 'wcf_order_comments' => $post_data['wcf_order_comments'],
895
+ 'wcf_first_name' => $post_data['wcf_name'],
896
+ 'wcf_last_name' => $post_data['wcf_surname'],
897
+ 'wcf_phone_number' => $post_data['wcf_phone'],
898
+ 'wcf_location' => $post_data['wcf_country'] . ', ' . $post_data['wcf_city'],
899
+ );
900
+
901
+ $checkout_details = array(
902
+ 'email' => $post_data['wcf_email'],
903
+ 'cart_contents' => serialize( $products ),
904
+ 'cart_total' => sanitize_text_field( $cart_total ),
905
+ 'time' => sanitize_text_field( $current_time ),
906
+ 'other_fields' => serialize( $other_fields ),
907
+ 'checkout_id' => $post_data['wcf_post_id'],
908
+ );
909
+ }
910
+ return $checkout_details;
911
+ }
912
+
913
+ /**
914
+ * Deletes cart abandonment tracking and scheduled event.
915
+ *
916
+ * @param int $order_id Order ID.
917
+ * @since 1.0.0
918
+ */
919
+ public function delete_cart_abandonment_data( $order_id ) {
920
+
921
+ $acceptable_order_statuses = array( 'completed', 'processing' );
922
+ $order = wc_get_order( $order_id );
923
+ $order_status = $order->get_status();
924
+ if ( ! in_array( $order_status, $acceptable_order_statuses, true ) ) {
925
+ // Proceed if order status in completed or processing.
926
+ return;
927
+ }
928
+
929
+ global $wpdb;
930
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
931
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
932
+
933
+ if ( isset( WC()->session ) ) {
934
+ $session_id = WC()->session->get( 'wcf_session_id' );
935
+
936
+ if ( isset( $session_id ) ) {
937
+ $checkout_details = $this->get_checkout_details( $session_id );
938
+
939
+ $has_mail_sent = count( $this->fetch_scheduled_emails( $session_id, true ) );
940
+
941
+ if ( ! $has_mail_sent ) {
942
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
943
+ } else {
944
+ if ( $checkout_details && ( WCF_CART_ABANDONED_ORDER === $checkout_details->order_status || WCF_CART_LOST_ORDER === $checkout_details->order_status ) ) {
945
+
946
+ $this->skip_future_emails_when_order_is_completed( $session_id );
947
+
948
+ $this->trigger_zapier_webhook( $session_id, WCF_CART_COMPLETED_ORDER );
949
+
950
+ $order = wc_get_order( $order_id );
951
+ $note = __( 'This order was abandoned & subsequently recovered.', 'woo-cart-abandonment-recovery' );
952
+ $order->add_order_note( $note );
953
+ $order->save();
954
+
955
+ } elseif ( WCF_CART_COMPLETED_ORDER !== $checkout_details->order_status ) {
956
+ // Normal checkout.
957
+
958
+ $billing_email = filter_input( INPUT_POST, 'billing_email', FILTER_SANITIZE_EMAIL );
959
+
960
+ if ( $billing_email ) {
961
+ $order_data = $this->get_captured_data_by_email( $billing_email );
962
+
963
+ if ( ! is_null( $order_data ) ) {
964
+ $existing_cart_contents = unserialize( $order_data->cart_contents );
965
+ $order_cart_contents = unserialize( $checkout_details->cart_contents );
966
+ $existing_cart_products = array_keys( (array) $existing_cart_contents );
967
+ $order_cart_products = array_keys( (array) $order_cart_contents );
968
+ if ( $this->check_if_similar_cart( $existing_cart_products, $order_cart_products ) ) {
969
+ $this->skip_future_emails_when_order_is_completed( $order_data->session_id );
970
+ }
971
+ }
972
+ }
973
+ $wpdb->delete( $cart_abandonment_table, array( 'session_id' => sanitize_key( $session_id ) ) );
974
+ }
975
+ }
976
+ }
977
+ if ( WC()->session ) {
978
+ WC()->session->__unset( 'wcf_session_id' );
979
+ }
980
+ }
981
+ }
982
+
983
+ /**
984
+ * Unschedule future emails for completed orders.
985
+ *
986
+ * @param string $session_id session id.
987
+ * @param bool $skip_complete skip update query.
988
+ */
989
+ public function skip_future_emails_when_order_is_completed( $session_id, $skip_complete = false ) {
990
+
991
+ global $wpdb;
992
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
993
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
994
+
995
+ if ( ! $skip_complete ) {
996
+ $wpdb->update(
997
+ $cart_abandonment_table,
998
+ array(
999
+ 'order_status' => WCF_CART_COMPLETED_ORDER,
1000
+ ),
1001
+ array(
1002
+ 'session_id' => sanitize_key( $session_id ),
1003
+ )
1004
+ );
1005
+ }
1006
+
1007
+ $wpdb->update(
1008
+ $email_history_table,
1009
+ array( 'email_sent' => -1 ),
1010
+ array(
1011
+ 'ca_session_id' => $session_id,
1012
+ 'email_sent' => 0,
1013
+ )
1014
+ );
1015
+ }
1016
+
1017
+ /**
1018
+ * Compare cart if similar products.
1019
+ *
1020
+ * @param array $cart_a cart_a.
1021
+ * @param array $cart_b cart_b.
1022
+ * @return bool
1023
+ */
1024
+ public function check_if_similar_cart( $cart_a, $cart_b ) {
1025
+ return (
1026
+ is_array( $cart_a )
1027
+ && is_array( $cart_b )
1028
+ && count( $cart_a ) === count( $cart_b )
1029
+ && array_diff( $cart_a, $cart_b ) === array_diff( $cart_b, $cart_a )
1030
+ );
1031
+ }
1032
+
1033
+
1034
+ /**
1035
+ * Get the checkout details for the user.
1036
+ *
1037
+ * @param string $wcf_session_id checkout page session id.
1038
+ * @since 1.0.0
1039
+ */
1040
+ public function get_checkout_details( $wcf_session_id ) {
1041
+ global $wpdb;
1042
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1043
+ $result = $wpdb->get_row(
1044
+ $wpdb->prepare('SELECT * FROM `' . $cart_abandonment_table . '` WHERE session_id = %s', $wcf_session_id ) // phpcs:ignore
1045
+ );
1046
+ return $result;
1047
+ }
1048
+
1049
+ /**
1050
+ * Get the checkout details for the user.
1051
+ *
1052
+ * @param string $email user email.
1053
+ * @since 1.0.0
1054
+ */
1055
+ public function get_checkout_details_by_email( $email ) {
1056
+ global $wpdb;
1057
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1058
+ $result = $wpdb->get_row(
1059
+ $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
1060
+ );
1061
+ return $result;
1062
+ }
1063
+
1064
+
1065
+ /**
1066
+ * Get the checkout details for the user.
1067
+ *
1068
+ * @param string $value value.
1069
+ * @since 1.0.0
1070
+ */
1071
+ public function get_captured_data_by_email( $value ) {
1072
+ global $wpdb;
1073
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1074
+ $result = $wpdb->get_row(
1075
+ $wpdb->prepare(
1076
+ '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
1077
+ );
1078
+ return $result;
1079
+ }
1080
+
1081
+
1082
+ /**
1083
+ * Get the checkout details for the user.
1084
+ *
1085
+ * @param string $value value.
1086
+ * @since 1.0.0
1087
+ */
1088
+ public function get_tracked_data_without_status( $value ) {
1089
+ global $wpdb;
1090
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1091
+ $result = $wpdb->get_row(
1092
+ $wpdb->prepare(
1093
+ 'SELECT * FROM `' . $cart_abandonment_table . '` WHERE email = %s LIMIT 1', $value ) // phpcs:ignore
1094
+ );
1095
+ return $result;
1096
+ }
1097
+
1098
+ /**
1099
+ * Add submenu to admin menu.
1100
+ *
1101
+ * @since 1.1.5
1102
+ */
1103
+ public function abandoned_cart_tracking_menu() {
1104
+
1105
+ $capability = current_user_can( 'manage_woocommerce' ) ? 'manage_woocommerce' : 'manage_options';
1106
+
1107
+ add_submenu_page(
1108
+ 'woocommerce',
1109
+ __( 'Cart Abandonment', 'woo-cart-abandonment-recovery' ),
1110
+ __( 'Cart Abandonment', 'woo-cart-abandonment-recovery' ),
1111
+ $capability,
1112
+ WCF_CA_PAGE_NAME,
1113
+ array( $this, 'render_abandoned_cart_tracking' )
1114
+ );
1115
+ }
1116
+
1117
+ /**
1118
+ * Render table view for cart abandonment tracking.
1119
+ *
1120
+ * @since 1.1.5
1121
+ */
1122
+ public function render_abandoned_cart_tracking() {
1123
+
1124
+ $wcf_list_table = Cartflows_Ca_Cart_Abandonment_Table::get_instance();
1125
+
1126
+ if ( 'delete' === $wcf_list_table->current_action() ) {
1127
+
1128
+ $ids = array();
1129
+ if ( isset( $_REQUEST['id'] ) && is_array( $_REQUEST['id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1130
+ $ids = array_map( 'intval', $_REQUEST['id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1131
+ }
1132
+ $deleted_row_count = empty( $ids ) ? 1 : count( $ids );
1133
+
1134
+ $wcf_list_table->process_bulk_action();
1135
+ $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'Items deleted: %d', 'woo-cart-abandonment-recovery' ), $deleted_row_count ) . '</p></div>'; // phpcs:ignore
1136
+ set_transient( 'wcf_ca_show_message', $message, 5 );
1137
+ if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
1138
+ wp_safe_redirect( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) );
1139
+ }
1140
+ } elseif ( 'unsubscribe' === $wcf_list_table->current_action() ) {
1141
+
1142
+ global $wpdb;
1143
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1144
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
1145
+
1146
+ $wpdb->update(
1147
+ $cart_abandonment_table,
1148
+ array( 'unsubscribed' => true ),
1149
+ array( 'id' => $id )
1150
+ );
1151
+ $wcf_list_table->process_bulk_action();
1152
+ $message = '<div class="notice notice-success is-dismissible" id="message"><p>' . sprintf( __( 'User(s) unsubscribed successfully!', 'woo-cart-abandonment-recovery' ) ) . '</p></div>'; // phpcs:ignore
1153
+ set_transient( 'wcf_ca_show_message', $message, 5 );
1154
+ if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
1155
+ wp_safe_redirect( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) );
1156
+ }
1157
+ }
1158
+ ?>
1159
+
1160
+ <?php
1161
+ include_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-tabs.php';
1162
+ ?>
1163
+ <?php
1164
+ }
1165
+
1166
+ /**
1167
+ * Count abandoned carts
1168
+ *
1169
+ * @since 1.1.5
1170
+ */
1171
+ public function abandoned_cart_count() {
1172
+ global $wpdb;
1173
+ $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1174
+
1175
+ $query = $wpdb->prepare( "SELECT COUNT(`id`) FROM {$cart_abandonment_table_name} WHERE `order_status` = %s", WCF_CART_ABANDONED_ORDER ); // phpcs:ignore
1176
+ $total_items = $wpdb->get_var( $query ); // phpcs:ignore
1177
+ return $total_items;
1178
+ }
1179
+
1180
+ /**
1181
+ * Load analytics scripts.
1182
+ */
1183
+ public function load_admin_cart_abandonment_script() {
1184
+
1185
+ $wcar_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
1186
+
1187
+ if ( ! ( WCF_CA_PAGE_NAME === $wcar_page ) ) {
1188
+ return;
1189
+ }
1190
+
1191
+ // Styles.
1192
+ wp_enqueue_style( 'cartflows-cart-abandonment-admin', CARTFLOWS_CA_URL . 'admin/assets/css/admin-cart-abandonment.css', array(), CARTFLOWS_CA_VER );
1193
+
1194
+ wp_enqueue_script(
1195
+ 'cartflows-ca-email-tmpl-settings',
1196
+ CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
1197
+ array( 'jquery' ),
1198
+ CARTFLOWS_CA_VER,
1199
+ false
1200
+ );
1201
+
1202
+ if ( WCF_CA_PAGE_NAME === $wcar_page ) {
1203
+ $filter_table = filter_input( INPUT_GET, 'filter_table', FILTER_SANITIZE_STRING );
1204
+ $from_date = filter_input( INPUT_GET, 'from_date', FILTER_SANITIZE_STRING );
1205
+ $to_date = filter_input( INPUT_GET, 'to_date', FILTER_SANITIZE_STRING );
1206
+ }
1207
+
1208
+ $vars = array(
1209
+ 'url' => 'admin-ajax.php',
1210
+
1211
+ // For delete coupons.
1212
+ '_delete_coupon_nonce' => wp_create_nonce( 'wcf_ca_delete_garbage_coupons' ),
1213
+ '_confirm_msg' => __( 'Do you really want to delete the used and expired coupons created by Cart Abandonment Plugin?', 'woo-cart-abandonment-recovery' ),
1214
+ '_confirm_msg_export' => __( 'Do you really want to export orders?', 'woo-cart-abandonment-recovery' ),
1215
+
1216
+ // For Search orders.
1217
+ '_search_button_nonce' => wp_create_nonce( 'wcf_ca_search_orders' ),
1218
+ '_result_msg' => __( 'No such order is found.', 'woo-cart-abandonment-recovery' ),
1219
+
1220
+ );
1221
+ wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'wcf_ca_localized_vars', $vars );
1222
+ }
1223
+
1224
+
1225
+ /**
1226
+ * Render Cart abandonment display button beside title.
1227
+ */
1228
+ public function setup_cart_abandonment_button() {
1229
+
1230
+ if ( ! Cartflows_Admin::is_flow_edit_admin() ) {
1231
+ return;
1232
+ }
1233
+
1234
+ $reports_btn_markup = '<style>.wrap{ position:relative;}</style>';
1235
+ $reports_btn_markup .= "<div class='wcf-reports-button-wrap'>";
1236
+ $reports_btn_markup .= "<button class='wcf-cart-abandonment-reports-popup button button-secondary'>";
1237
+ $reports_btn_markup .= esc_html__( 'View Report', 'woo-cart-abandonment-recovery' );
1238
+ $reports_btn_markup .= '</button>';
1239
+ $reports_btn_markup .= '</div>';
1240
+
1241
+ echo wp_kses_post( $reports_btn_markup );
1242
+
1243
+ }
1244
+
1245
+ /**
1246
+ * Get start and end date for given interval.
1247
+ *
1248
+ * @param string $interval interval .
1249
+ * @return array
1250
+ */
1251
+ public function get_start_end_by_interval( $interval ) {
1252
+
1253
+ if ( 'today' === $interval ) {
1254
+ $start_date = gmdate( 'Y-m-d' );
1255
+ $end_date = gmdate( 'Y-m-d' );
1256
+ } else {
1257
+
1258
+ $days = $interval;
1259
+
1260
+ $start_date = gmdate( 'Y-m-d', strtotime( '-' . $days . ' days' ) );
1261
+ $end_date = gmdate( 'Y-m-d' );
1262
+ }
1263
+
1264
+ return array(
1265
+ 'start' => $start_date,
1266
+ 'end' => $end_date,
1267
+ );
1268
+ }
1269
+
1270
+
1271
+ /**
1272
+ * Get Attributable revenue.
1273
+ * Represents the revenue generated by this campaign.
1274
+ *
1275
+ * @param string $type abondened|completed.
1276
+ * @param string $from_date from date.
1277
+ * @param string $to_date to date.
1278
+ */
1279
+ public function get_report_by_type( $type = WCF_CART_ABANDONED_ORDER, $from_date, $to_date ) {
1280
+ global $wpdb;
1281
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1282
+ $minutes = wcf_ca()->utils->get_cart_abandonment_tracking_cut_off_time();
1283
+ $attributable_revenue = $wpdb->get_row(
1284
+ $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
1285
+ ARRAY_A
1286
+ );
1287
+ return $attributable_revenue;
1288
+ }
1289
+
1290
+
1291
+ /**
1292
+ * Get checkout url.
1293
+ *
1294
+ * @param integer $post_id post id.
1295
+ * @param string $token_data token data.
1296
+ * @return string
1297
+ */
1298
+ public function get_checkout_url( $post_id, $token_data ) {
1299
+
1300
+ $token = $this->wcf_generate_token( (array) $token_data );
1301
+ $checkout_url = get_permalink( $post_id ) . '?wcf_ac_token=' . $token;
1302
+ return esc_url( $checkout_url );
1303
+ }
1304
+
1305
+ /**
1306
+ * Geberate the token for the given data.
1307
+ *
1308
+ * @param array $data data.
1309
+ */
1310
+ public function wcf_generate_token( $data ) {
1311
+ return urlencode( base64_encode( http_build_query( $data ) ) );
1312
+ }
1313
+
1314
+ /**
1315
+ * Decode and get the original contents.
1316
+ *
1317
+ * @param string $token token.
1318
+ */
1319
+ public function wcf_decode_token( $token ) {
1320
+ $token = sanitize_text_field( $token );
1321
+ parse_str( base64_decode( urldecode( $token ) ), $token );
1322
+ return $token;
1323
+ }
1324
+
1325
+ /**
1326
+ * Render Cart abandonment tabs.
1327
+ *
1328
+ * @since 1.1.5
1329
+ */
1330
+ public function wcf_display_tabs() {
1331
+
1332
+ $wcar_action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
1333
+ $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
1334
+
1335
+ if ( ! $wcar_action ) {
1336
+ $wcar_action = WCF_ACTION_REPORTS;
1337
+ $active_settings = '';
1338
+ $active_reports = '';
1339
+ $active_email_templates = '';
1340
+ }
1341
+
1342
+ switch ( $wcar_action ) {
1343
+ case WCF_ACTION_SETTINGS:
1344
+ $active_settings = 'nav-tab-active';
1345
+ break;
1346
+ case WCF_ACTION_REPORTS:
1347
+ $active_reports = 'nav-tab-active';
1348
+ break;
1349
+ case WCF_ACTION_EMAIL_TEMPLATES:
1350
+ $active_email_templates = 'nav-tab-active';
1351
+ break;
1352
+ default:
1353
+ $active_reports = 'nav-tab-active';
1354
+ break;
1355
+ }
1356
+ // phpcs:disable
1357
+ ?>
1358
+
1359
+
1360
+ <div class="nav-tab-wrapper woo-nav-tab-wrapper">
1361
+
1362
+ <?php
1363
+ $url = add_query_arg( array(
1364
+ 'page' => WCF_CA_PAGE_NAME,
1365
+ 'action' => WCF_ACTION_REPORTS
1366
+ ), admin_url( '/admin.php' ) )
1367
+ ?>
1368
+ <a href="<?php echo $url; ?>"
1369
+ class="nav-tab
1370
+ <?php
1371
+ if ( isset( $active_reports ) ) {
1372
+ echo $active_reports;}
1373
+ ?>
1374
+ ">
1375
+ <?php _e( 'Report', 'woo-cart-abandonment-recovery' ); ?>
1376
+ </a>
1377
+
1378
+ <?php
1379
+ $url = add_query_arg( array(
1380
+ 'page' => WCF_CA_PAGE_NAME,
1381
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES
1382
+ ), admin_url( '/admin.php' ) )
1383
+ ?>
1384
+ <a href="<?php echo $url; ?>"
1385
+ class="nav-tab
1386
+ <?php
1387
+ if ( isset( $active_email_templates ) ) {
1388
+ echo $active_email_templates;}
1389
+ ?>
1390
+ ">
1391
+ <?php _e( 'Follow-Up Emails', 'woo-cart-abandonment-recovery' ); ?>
1392
+ </a>
1393
+
1394
+ <?php
1395
+ $url = add_query_arg( array(
1396
+ 'page' => WCF_CA_PAGE_NAME,
1397
+ 'action' => WCF_ACTION_SETTINGS
1398
+ ), admin_url( '/admin.php' ) )
1399
+ ?>
1400
+ <a href="<?php echo $url; ?>"
1401
+ class="nav-tab
1402
+ <?php
1403
+ if ( isset( $active_settings ) ) {
1404
+ echo $active_settings;}
1405
+ ?>
1406
+ ">
1407
+ <?php _e( 'Settings', 'woo-cart-abandonment-recovery' ); ?>
1408
+ </a>
1409
+
1410
+ </div>
1411
+ <?php
1412
+ // phpcs:enable
1413
+ }
1414
+
1415
+ /**
1416
+ * Render Cart abandonment settings.
1417
+ *
1418
+ * @since 1.1.5
1419
+ */
1420
+ public function wcf_display_settings() {
1421
+ ?>
1422
+
1423
+ <form method="post" action="options.php">
1424
+ <?php settings_fields( WCF_CA_SETTINGS_OPTION_GROUP ); ?>
1425
+ <?php do_settings_sections( WCF_CA_PAGE_NAME ); ?>
1426
+ <?php submit_button(); ?>
1427
+ </form>
1428
+
1429
+ <?php
1430
+ }
1431
+
1432
+ /**
1433
+ * Render Cart abandonment reports.
1434
+ *
1435
+ * @since 1.1.5
1436
+ */
1437
+ public function wcf_display_reports() {
1438
+
1439
+ $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
1440
+ $filter_table = filter_input( INPUT_GET, 'filter_table', FILTER_SANITIZE_STRING );
1441
+
1442
+ if ( ! $filter ) {
1443
+ $filter = 'last_month';
1444
+ }
1445
+ if ( ! $filter_table ) {
1446
+ $filter_table = WCF_CART_ABANDONED_ORDER;
1447
+ }
1448
+
1449
+ $from_date = filter_input( INPUT_GET, 'from_date', FILTER_SANITIZE_STRING );
1450
+ $to_date = filter_input( INPUT_GET, 'to_date', FILTER_SANITIZE_STRING );
1451
+ $export_data = filter_input( INPUT_GET, 'export_data', FILTER_VALIDATE_BOOLEAN );
1452
+
1453
+ switch ( $filter ) {
1454
+
1455
+ case 'yesterday':
1456
+ $to_date = gmdate( 'Y-m-d', strtotime( '-1 days' ) );
1457
+ $from_date = $to_date;
1458
+ break;
1459
+ case 'today':
1460
+ $to_date = gmdate( 'Y-m-d' );
1461
+ $from_date = $to_date;
1462
+ break;
1463
+ case 'last_week':
1464
+ $from_date = gmdate( 'Y-m-d', strtotime( '-7 days' ) );
1465
+ $to_date = gmdate( 'Y-m-d' );
1466
+ break;
1467
+ case 'last_month':
1468
+ $from_date = gmdate( 'Y-m-d', strtotime( '-1 months' ) );
1469
+ $to_date = gmdate( 'Y-m-d' );
1470
+ break;
1471
+ case 'custom':
1472
+ $to_date = $to_date ? $to_date : gmdate( 'Y-m-d' );
1473
+ $from_date = $from_date ? $from_date : $to_date;
1474
+ break;
1475
+
1476
+ }
1477
+
1478
+ $abandoned_report = $this->get_report_by_type( WCF_CART_ABANDONED_ORDER, $from_date, $to_date );
1479
+ $recovered_report = $this->get_report_by_type( WCF_CART_COMPLETED_ORDER, $from_date, $to_date );
1480
+ $lost_report = $this->get_report_by_type( WCF_CART_LOST_ORDER, $from_date, $to_date );
1481
+
1482
+ $wcf_list_table = Cartflows_Ca_Cart_Abandonment_Table::get_instance();
1483
+ $wcf_list_table->prepare_items( $filter_table, $from_date, $to_date );
1484
+
1485
+ if ( $export_data ) {
1486
+
1487
+ $this->download_send_headers();
1488
+ echo $this->array2csv( $wcf_list_table->items ); //phpcs:ignore
1489
+ die;
1490
+
1491
+ }
1492
+
1493
+ $conversion_rate = 0;
1494
+ $total_orders = ( $recovered_report['no_of_orders'] + $abandoned_report['no_of_orders'] + $lost_report['no_of_orders'] );
1495
+ if ( $total_orders ) {
1496
+ $conversion_rate = ( $recovered_report['no_of_orders'] / $total_orders ) * 100;
1497
+ }
1498
+
1499
+ global $woocommerce;
1500
+ $conversion_rate = number_format_i18n( $conversion_rate, 2 );
1501
+ $currency_symbol = get_woocommerce_currency_symbol();
1502
+ require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-cart-abandonment-reports.php';
1503
+
1504
+ }
1505
+
1506
+
1507
+ /**
1508
+ * Show report details for specific order.
1509
+ */
1510
+ public function wcf_display_report_details() {
1511
+
1512
+ $sesson_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
1513
+
1514
+ if ( $sesson_id ) {
1515
+ $details = $this->get_checkout_details( $sesson_id );
1516
+ $user_details = (object) unserialize( $details->other_fields );
1517
+ $scheduled_emails = $this->fetch_scheduled_emails( $sesson_id );
1518
+
1519
+ require_once CARTFLOWS_CART_ABANDONMENT_TRACKING_DIR . 'includes/admin/cartflows-ca-single-report-details.php';
1520
+ }
1521
+
1522
+ }
1523
+
1524
+ /**
1525
+ * Check and show warning message if cart abandonment is disabled.
1526
+ */
1527
+ public function wcf_show_warning_ca() {
1528
+ $settings_url = add_query_arg(
1529
+ array(
1530
+ 'page' => WCF_CA_PAGE_NAME,
1531
+ 'action' => WCF_ACTION_SETTINGS,
1532
+ ),
1533
+ admin_url( '/admin.php' )
1534
+ );
1535
+
1536
+ if ( ! wcf_ca()->utils->is_cart_abandonment_tracking_enabled() ) {
1537
+ ?>
1538
+ <div class="notice notice-warning is-dismissible">
1539
+ <p>
1540
+ <?php echo __('Looks like abandonment tracking is disabled! Please enable it from <a href=' . esc_url($settings_url) . '> <strong>settings</strong></a>.', 'woo-cart-abandonment-recovery'); // phpcs:ignore
1541
+ ?>
1542
+ </p>
1543
+ </div>
1544
+ <?php
1545
+ }
1546
+ }
1547
+
1548
+ /**
1549
+ * Callback trigger event to send the emails.
1550
+ */
1551
+ public function send_emails_to_callback() {
1552
+
1553
+ global $wpdb;
1554
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1555
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
1556
+ $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
1557
+
1558
+ $current_time = current_time( WCF_CA_DATETIME_FORMAT );
1559
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1560
+ $emails_send_to = $wpdb->get_results(
1561
+ $wpdb->prepare(
1562
+ 'SELECT *, EHT.id as email_history_id, ETT.id as email_template_id FROM ' . $email_history_table . ' as EHT
1563
+ INNER JOIN ' . $cart_abandonment_table . ' as CAT ON EHT.`ca_session_id` = CAT.`session_id`
1564
+ INNER JOIN ' . $email_template_table . ' as ETT ON ETT.`id` = EHT.`template_id`
1565
+ WHERE CAT.`order_status` = %s AND CAT.unsubscribed = 0 AND EHT.`email_sent` = 0 AND EHT.`scheduled_time` <= %s',
1566
+ WCF_CART_ABANDONED_ORDER,
1567
+ $current_time
1568
+ )
1569
+ );
1570
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1571
+ foreach ( $emails_send_to as $email_send_to ) {
1572
+ $email_result = $this->send_email_templates( $email_send_to );
1573
+ if ( $email_result ) {
1574
+ $wpdb->update(
1575
+ $email_history_table,
1576
+ array( 'email_sent' => true ),
1577
+ array( 'id' => $email_send_to->email_history_id )
1578
+ );
1579
+ }
1580
+ }
1581
+ }
1582
+
1583
+
1584
+ /**
1585
+ * Create a dummy object for the preview email.
1586
+ *
1587
+ * @return stdClass
1588
+ */
1589
+ public function create_dummy_session_for_preview_email() {
1590
+
1591
+ $email_data = new stdClass();
1592
+ $current_user = wp_get_current_user();
1593
+ $email_data->email_template_id = null;
1594
+ $email_data->checkout_id = wc_get_page_id( 'checkout' );
1595
+ $email_data->session_id = 'dummy-session-id';
1596
+ $email_send_to = filter_input( INPUT_POST, 'email_send_to', FILTER_SANITIZE_EMAIL );
1597
+ $email_data->email = $email_send_to ? $email_send_to : $current_user->user_email;
1598
+ $email_data->email_body = filter_input( INPUT_POST, 'email_body', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1599
+ $email_data->email_subject = filter_input( INPUT_POST, 'email_subject', FILTER_SANITIZE_STRING );
1600
+ $email_data->email_body = html_entity_decode( $email_data->email_body, ENT_COMPAT, 'UTF-8' );
1601
+ $email_data->other_fields = serialize(
1602
+ array(
1603
+ 'wcf_first_name' => $current_user->user_firstname,
1604
+ 'wcf_last_name' => $current_user->user_lastname,
1605
+ )
1606
+ );
1607
+ if ( ! WC()->cart->get_cart_contents_count() ) {
1608
+ $args = array(
1609
+ 'posts_per_page' => 1,
1610
+ 'orderby' => 'rand',
1611
+ 'post_type' => 'product',
1612
+ 'meta_query' => array( //phpcs:ignore
1613
+ // Exclude out of stock products.
1614
+ array(
1615
+ 'key' => '_stock_status',
1616
+ 'value' => 'outofstock',
1617
+ 'compare' => 'NOT IN',
1618
+ ),
1619
+ ),
1620
+ 'tax_query' => array( //phpcs:ignore
1621
+ array(
1622
+ 'taxonomy' => 'product_type',
1623
+ 'field' => 'slug',
1624
+ 'terms' => 'simple',
1625
+ ),
1626
+ ),
1627
+ );
1628
+
1629
+ $random_products = get_posts( $args );
1630
+ if ( ! empty( $random_products ) ) {
1631
+ $random_product = reset( $random_products );
1632
+ WC()->cart->add_to_cart( $random_product->ID );
1633
+ }
1634
+ }
1635
+
1636
+ $email_data->cart_total = WC()->cart->total + floatval( WC()->cart->get_cart_shipping_total() );
1637
+ $email_data->cart_contents = serialize( WC()->cart->get_cart() );
1638
+ $email_data->time = current_time( WCF_CA_DATETIME_FORMAT );
1639
+ return $email_data;
1640
+ }
1641
+
1642
+ /**
1643
+ * Callback function to send email templates.
1644
+ *
1645
+ * @param array $email_data email data .
1646
+ * @param boolean $preview_email preview email.
1647
+ * @since 1.0.0
1648
+ */
1649
+ public function send_email_templates( $email_data, $preview_email = false ) {
1650
+
1651
+ if ( $preview_email ) {
1652
+ $email_data = $this->create_dummy_session_for_preview_email();
1653
+ }
1654
+
1655
+ if ( filter_var( $email_data->email, FILTER_VALIDATE_EMAIL ) ) {
1656
+ if ( ! $preview_email ) {
1657
+ if ( ! $this->check_if_already_purchased_by_email_product_ids( $email_data, $email_data->cart_contents ) ) {
1658
+ return false;
1659
+ }
1660
+ }
1661
+
1662
+ $other_fields = unserialize( $email_data->other_fields );
1663
+
1664
+ $from_email_name = get_option( 'wcf_ca_from_name' );
1665
+ $reply_name_preview = get_option( 'wcf_ca_reply_email' );
1666
+ $from_email_preview = get_option( 'wcf_ca_from_email' );
1667
+
1668
+ $user_first_name = ucfirst( $other_fields['wcf_first_name'] );
1669
+ $user_first_name = $user_first_name ? $user_first_name : __( 'there', 'woo-cart-abandonment-recovery' );
1670
+ $user_last_name = ucfirst( $other_fields['wcf_last_name'] );
1671
+ $user_full_name = trim( $user_first_name . ' ' . $user_last_name );
1672
+
1673
+ $subject_email_preview = stripslashes( html_entity_decode( $email_data->email_subject, ENT_QUOTES, 'UTF-8' ) );
1674
+ $subject_email_preview = convert_smilies( $subject_email_preview );
1675
+ $subject_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $subject_email_preview );
1676
+ $body_email_preview = convert_smilies( $email_data->email_body );
1677
+ $body_email_preview = str_replace( '{{customer.firstname}}', $user_first_name, $body_email_preview );
1678
+ $body_email_preview = str_replace( '{{customer.lastname}}', $user_last_name, $body_email_preview );
1679
+ $body_email_preview = str_replace( '{{customer.fullname}}', $user_full_name, $body_email_preview );
1680
+
1681
+ $email_instance = Cartflows_Ca_Email_Templates::get_instance();
1682
+ if ( $preview_email ) {
1683
+ $coupon_code = 'DUMMY-COUPON';
1684
+ } else {
1685
+ $override_global_coupon = $email_instance->get_email_template_meta_by_key( $email_data->email_template_id, 'override_global_coupon' );
1686
+ if ( $override_global_coupon->meta_value ) {
1687
+ $email_history = $email_instance->get_email_history_by_id( $email_data->email_history_id );
1688
+ $coupon_code = $email_history->coupon_code;
1689
+ } else {
1690
+ $coupon_code = $email_data->coupon_code;
1691
+ }
1692
+ }
1693
+
1694
+ $auto_apply_coupon = $email_instance->get_email_template_meta_by_key( $email_data->email_template_id, 'auto_coupon' );
1695
+
1696
+ $token_data = array(
1697
+ 'wcf_session_id' => $email_data->session_id,
1698
+ 'wcf_coupon_code' => isset( $auto_apply_coupon ) && $auto_apply_coupon->meta_value ? $coupon_code : null,
1699
+ 'wcf_preview_email' => $preview_email ? true : false,
1700
+ );
1701
+
1702
+ $checkout_url = $this->get_checkout_url( $email_data->checkout_id, $token_data );
1703
+
1704
+ $body_email_preview = str_replace( '{{cart.coupon_code}}', $coupon_code, $body_email_preview );
1705
+
1706
+ $current_time_stamp = $email_data->time;
1707
+ $body_email_preview = str_replace( '{{cart.abandoned_date}}', $current_time_stamp, $body_email_preview );
1708
+ $unsubscribe_element = '<a target="_blank" style="color: lightgray" href="' . $checkout_url . '&unsubscribe=true ">' . __( 'Unsubscribe', 'woo-cart-abandonment-recovery' ) . '</a>';
1709
+ $body_email_preview = str_replace( '{{cart.unsubscribe}}', $unsubscribe_element, $body_email_preview );
1710
+ $body_email_preview = str_replace( 'http://{{cart.checkout_url}}', '{{cart.checkout_url}}', $body_email_preview );
1711
+ $body_email_preview = str_replace( 'https://{{cart.checkout_url}}', '{{cart.checkout_url}}', $body_email_preview );
1712
+ $body_email_preview = str_replace( '{{cart.checkout_url}}', $checkout_url, $body_email_preview );
1713
+ $host = wp_parse_url( get_site_url() );
1714
+ $body_email_preview = str_replace( '{{site.url}}', $host['host'], $body_email_preview );
1715
+
1716
+ if ( false !== strpos( $body_email_preview, '{{cart.product.names}}' ) ) {
1717
+ $body_email_preview = str_replace( '{{cart.product.names}}', $this->get_comma_separated_products( $email_data->cart_contents ), $body_email_preview );
1718
+ }
1719
+
1720
+ $admin_user = get_users(
1721
+ array(
1722
+ 'role' => 'Administrator',
1723
+ 'number' => 1,
1724
+ )
1725
+ );
1726
+ $admin_user = reset( $admin_user );
1727
+ $admin_first_name = $admin_user->user_firstname ? $admin_user->user_firstname : 'Admin';
1728
+ $body_email_preview = str_replace( '{{admin.firstname}}', $admin_first_name, $body_email_preview );
1729
+ $body_email_preview = str_replace( '{{admin.company}}', get_bloginfo( 'name' ), $body_email_preview );
1730
+
1731
+ $headers = 'From: ' . $from_email_name . ' <' . $from_email_preview . '>' . "\r\n";
1732
+ $headers .= 'Content-Type: text/html' . "\r\n";
1733
+ $headers .= 'Reply-To: ' . $reply_name_preview . ' ' . "\r\n";
1734
+ $var = $this->get_email_product_block( $email_data->cart_contents, $email_data->cart_total );
1735
+
1736
+ $body_email_preview = str_replace( '{{cart.product.table}}', $var, $body_email_preview );
1737
+ $body_email_preview = wpautop( $body_email_preview );
1738
+ $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1739
+ if ( $mail_result ) {
1740
+ return true;
1741
+ } else {
1742
+ // Retry sending mail.
1743
+ $mail_result = wp_mail( $email_data->email, $subject_email_preview, stripslashes( $body_email_preview ), $headers );
1744
+ if ( ! $preview_email ) {
1745
+ return true;
1746
+ }
1747
+ return false;
1748
+ }
1749
+ } else {
1750
+ return false;
1751
+ }
1752
+
1753
+ }
1754
+
1755
+ /**
1756
+ * Generate comma separated products.
1757
+ *
1758
+ * @param object $cart_contents user cart details.
1759
+ */
1760
+ public function get_comma_separated_products( $cart_contents ) {
1761
+ $cart_comma_string = '';
1762
+ if ( ! $cart_contents ) {
1763
+ return $cart_comma_string;
1764
+ }
1765
+ $cart_data = unserialize( $cart_contents );
1766
+
1767
+ $cart_length = count( $cart_data );
1768
+ $index = 0;
1769
+ foreach ( $cart_data as $key => $product ) {
1770
+
1771
+ if ( ! isset( $product['product_id'] ) ) {
1772
+ continue;
1773
+ }
1774
+
1775
+ $cart_product = wc_get_product( $product['product_id'] );
1776
+
1777
+ $cart_comma_string = $cart_comma_string . $cart_product->get_title();
1778
+ if ( ( $cart_length - 2 ) === $index ) {
1779
+ $cart_comma_string = $cart_comma_string . ' & ';
1780
+ } elseif ( ( $cart_length - 1 ) !== $index ) {
1781
+ $cart_comma_string = $cart_comma_string . ', ';
1782
+ }
1783
+ $index++;
1784
+ }
1785
+ return $cart_comma_string;
1786
+
1787
+ }
1788
+
1789
+ /**
1790
+ * Generate the view for email product cart block.
1791
+ *
1792
+ * @param object $cart_contents user cart contents details.
1793
+ * @param float $cart_total user cart total.
1794
+ * @return string
1795
+ */
1796
+ public function get_email_product_block( $cart_contents, $cart_total ) {
1797
+
1798
+ $cart_items = unserialize( $cart_contents );
1799
+
1800
+ if ( ! is_array( $cart_items ) || ! count( $cart_items ) ) {
1801
+ return;
1802
+ }
1803
+
1804
+ $currency_symbol = get_woocommerce_currency_symbol();
1805
+ $tr = '';
1806
+ $style = array(
1807
+ 'product_image' => array(
1808
+ 'style' => 'height: 42px; width: 42px;',
1809
+ ),
1810
+ 'table' => array(
1811
+ 'style' => 'color: #636363; border: 1px solid #e5e5e5;',
1812
+ 'attribute' => 'align= left;',
1813
+ ),
1814
+ );
1815
+
1816
+ $style_filter = apply_filters( 'woo_ca_email_template_table_style', $style );
1817
+ $product_image_style = isset( $style_filter['product_image']['style'] ) ? $style_filter['product_image']['style'] : '';
1818
+ $style = isset( $style_filter['table']['style'] ) ? $style_filter['table']['style'] : '';
1819
+
1820
+ foreach ( $cart_items as $cart_item ) {
1821
+
1822
+ if ( isset( $cart_item['product_id'] ) && isset( $cart_item['quantity'] ) && isset( $cart_item['line_total'] ) ) {
1823
+ $id = 0 !== $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'];
1824
+ $tr = $tr . '<tr style=' . $style . ' align="center">
1825
+ <td style="' . $style . '"><img class="demo_img" style="' . $product_image_style . '" src="' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . '"></td>
1826
+ <td style="' . $style . '">' . get_the_title( $id ) . '</td>
1827
+ <td style="' . $style . '"> ' . $cart_item['quantity'] . ' </td>
1828
+ <td style="' . $style . '">' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1829
+ <td style="' . $style . '" >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1830
+ </tr> ';
1831
+ }
1832
+ }
1833
+
1834
+ /**
1835
+ * Add filter to toggle the Cart Total row.
1836
+ */
1837
+ $enable_cart_total = apply_filters( 'woo_ca_recovery_enable_cart_total', false );
1838
+ if ( $enable_cart_total ) {
1839
+ $tr = $tr . '<tr style="' . $style . '" align="center">
1840
+ <td colspan="4" style="' . $style . '"> ' . __( 'Cart Total ( Cart Total + Shipping + Tax )', 'woo-cart-abandonment-recovery' ) . ' </td>
1841
+ <td style="' . $style . '" >' . $currency_symbol . number_format_i18n( $cart_total, 2 ) . '</td>
1842
+ </tr> ';
1843
+ }
1844
+
1845
+ return '<table ' . $style_filter['table']['attribute'] . ' cellpadding="10" cellspacing="0" style="float: none; border: 1px solid #e5e5e5;">
1846
+ <tr align="center">
1847
+ <th style="' . $style . '">' . __( 'Item', 'woo-cart-abandonment-recovery' ) . '</th>
1848
+ <th style="' . $style . '">' . __( 'Name', 'woo-cart-abandonment-recovery' ) . '</th>
1849
+ <th style="' . $style . '">' . __( 'Quantity', 'woo-cart-abandonment-recovery' ) . '</th>
1850
+ <th style="' . $style . '">' . __( 'Price', 'woo-cart-abandonment-recovery' ) . '</th>
1851
+ <th style="' . $style . '">' . __( 'Line Subtotal', 'woo-cart-abandonment-recovery' ) . '</th>
1852
+ </tr> ' . $tr . '
1853
+ </table>';
1854
+ }
1855
+
1856
+ /**
1857
+ * Generate the view for admin product cart block.
1858
+ *
1859
+ * @param object $cart_contents user cart contents details.
1860
+ * @param float $cart_total user cart total.
1861
+ * @return string
1862
+ */
1863
+ public function get_admin_product_block( $cart_contents, $cart_total ) {
1864
+
1865
+ $cart_items = unserialize( $cart_contents );
1866
+
1867
+ if ( ! is_array( $cart_items ) || ! count( $cart_items ) ) {
1868
+ return;
1869
+ }
1870
+
1871
+ $currency_symbol = get_woocommerce_currency_symbol();
1872
+ $tr = '';
1873
+ $total = 0;
1874
+ $discount = 0;
1875
+ $tax = 0;
1876
+
1877
+ foreach ( $cart_items as $cart_item ) {
1878
+
1879
+ if ( isset( $cart_item['product_id'] ) && isset( $cart_item['quantity'] ) && isset( $cart_item['line_total'] ) && isset( $cart_item['line_subtotal'] ) ) {
1880
+ $id = 0 !== $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'];
1881
+ $discount = number_format_i18n( $discount + ( $cart_item['line_subtotal'] - $cart_item['line_total'] ), 2 );
1882
+ $total = number_format_i18n( $total + $cart_item['line_subtotal'], 2 );
1883
+ $tax = number_format_i18n( $tax + $cart_item['line_tax'], 2 );
1884
+ $tr = $tr . '<tr align="center">
1885
+ <td ><img class="demo_img" width="42" height="42" src=" ' . esc_url( get_the_post_thumbnail_url( $cart_item['product_id'] ) ) . ' "/></td>
1886
+ <td >' . get_the_title( $id ) . '</td>
1887
+ <td > ' . $cart_item['quantity'] . ' </td>
1888
+ <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1889
+ <td >' . $currency_symbol . number_format_i18n( $cart_item['line_total'], 2 ) . '</td>
1890
+ </tr> ';
1891
+ }
1892
+ }
1893
+
1894
+ return '<table align="left" cellspacing="0" class="widefat fixed striped posts">
1895
+ <thead>
1896
+ <tr align="center">
1897
+ <th >' . __( 'Item', 'woo-cart-abandonment-recovery' ) . '</th>
1898
+ <th >' . __( 'Name', 'woo-cart-abandonment-recovery' ) . '</th>
1899
+ <th >' . __( 'Quantity', 'woo-cart-abandonment-recovery' ) . '</th>
1900
+ <th >' . __( 'Price', 'woo-cart-abandonment-recovery' ) . '</th>
1901
+ <th >' . __( 'Line Subtotal', 'woo-cart-abandonment-recovery' ) . '</th>
1902
+ </tr>
1903
+ </thead>
1904
+ <tbody>
1905
+ ' . $tr . '
1906
+ <tr align="center" id="wcf-ca-discount">
1907
+ <td colspan="4" >' . __( 'Discount', 'woo-cart-abandonment-recovery' ) . '</td>
1908
+ <td>' . $currency_symbol . ( $discount ) . '</td>
1909
+ </tr>
1910
+ <tr align="center" id="wcf-ca-other">
1911
+ <td colspan="4" >' . __( 'Other', 'woo-cart-abandonment-recovery' ) . '</td>
1912
+ <td>' . $currency_symbol . ( $tax ) . '</td>
1913
+ </tr>
1914
+
1915
+ <tr align="center" id="wcf-ca-shipping">
1916
+ <td colspan="4" >' . __( 'Shipping', 'woo-cart-abandonment-recovery' ) . '</td>
1917
+ <td>' . $currency_symbol . number_format_i18n( $discount + ( $cart_total - $total ) - $tax, 2 ) . '</td>
1918
+ </tr>
1919
+ <tr align="center" id="wcf-ca-cart-total">
1920
+ <td colspan="4" >' . __( 'Cart Total', 'woo-cart-abandonment-recovery' ) . '</td>
1921
+ <td>' . $currency_symbol . $cart_total . '</td>
1922
+ </tr>
1923
+ </tbody>
1924
+ </table>';
1925
+ }
1926
+
1927
+ /**
1928
+ * Schedule events for the abadoned carts to send emails.
1929
+ *
1930
+ * @param integer $session_id user session id.
1931
+ * @param boolean $force_reschedule force reschedule.
1932
+ */
1933
+ public function schedule_emails( $session_id, $force_reschedule = false ) {
1934
+
1935
+ $checkout_details = $this->get_checkout_details( $session_id );
1936
+
1937
+ if ( ( $checkout_details->unsubscribed ) || ( WCF_CART_COMPLETED_ORDER === $checkout_details->order_status ) ) {
1938
+ return;
1939
+ }
1940
+ $scheduled_time_from = current_time( WCF_CA_DATETIME_FORMAT );
1941
+ $scheduled_emails = $this->fetch_scheduled_emails( $session_id );
1942
+ $scheduled_templates = array_column( $scheduled_emails, 'template_id' ); //phpcs:ignore
1943
+ $scheduled_time_from = $checkout_details->time;
1944
+
1945
+ $email_tmpl = Cartflows_Ca_Email_Templates::get_instance();
1946
+ $templates = $email_tmpl->fetch_all_active_templates();
1947
+
1948
+ global $wpdb;
1949
+
1950
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
1951
+
1952
+ foreach ( $templates as $template ) {
1953
+
1954
+ if ( false !== array_search( $template->id, $scheduled_templates, true ) ) {
1955
+ continue;
1956
+ }
1957
+
1958
+ $timestamp_str = '+' . $template->frequency . ' ' . $template->frequency_unit . 'S';
1959
+ $scheduled_time = gmdate( WCF_CA_DATETIME_FORMAT, strtotime( $scheduled_time_from . $timestamp_str ) );
1960
+ $discount_type = $email_tmpl->get_email_template_meta_by_key( $template->id, 'discount_type' );
1961
+ $discount_type = isset( $discount_type->meta_value ) ? $discount_type->meta_value : '';
1962
+ $amount = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_amount' );
1963
+ $amount = isset( $amount->meta_value ) ? $amount->meta_value : '';
1964
+
1965
+ $coupon_expiry_date = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_date' );
1966
+ $coupon_expiry_unit = $email_tmpl->get_email_template_meta_by_key( $template->id, 'coupon_expiry_unit' );
1967
+ $coupon_expiry_date = isset( $coupon_expiry_date->meta_value ) ? $coupon_expiry_date->meta_value : '';
1968
+ $coupon_expiry_unit = isset( $coupon_expiry_unit->meta_value ) ? $coupon_expiry_unit->meta_value : 'hours';
1969
+
1970
+ $coupon_expiry_date = $coupon_expiry_date ? strtotime( $scheduled_time . ' +' . $coupon_expiry_date . ' ' . $coupon_expiry_unit ) : '';
1971
+
1972
+ $free_shipping_coupon = $email_tmpl->get_email_template_meta_by_key( $template->id, 'free_shipping_coupon' );
1973
+ $free_shipping = ( isset( $free_shipping_coupon ) && ( $free_shipping_coupon->meta_value ) ) ? 'yes' : 'no';
1974
+
1975
+ $individual_use_only = $email_tmpl->get_email_template_meta_by_key( $template->id, 'individual_use_only' );
1976
+ $individual_use = ( isset( $individual_use_only ) && ( $individual_use_only->meta_value ) ) ? 'yes' : 'no';
1977
+
1978
+ $override_global_coupon = $email_tmpl->get_email_template_meta_by_key( $template->id, 'override_global_coupon' );
1979
+
1980
+ $new_coupon_code = '';
1981
+ if ( $override_global_coupon->meta_value ) {
1982
+ $new_coupon_code = $this->generate_coupon_code( $discount_type, $amount, $coupon_expiry_date, $free_shipping, $individual_use );
1983
+ }
1984
+
1985
+ $wpdb->replace(
1986
+ $email_history_table,
1987
+ array(
1988
+ 'template_id' => $template->id,
1989
+ 'ca_session_id' => $checkout_details->session_id,
1990
+ 'coupon_code' => $new_coupon_code,
1991
+ 'scheduled_time' => $scheduled_time,
1992
+ )
1993
+ );
1994
+ }
1995
+ }
1996
+
1997
+ /**
1998
+ * Fetch all the scheduled emails with templates for the specific session.
1999
+ *
2000
+ * @param string $session_id session id.
2001
+ * @param boolean $fetch_sent sfetch sent emails.
2002
+ * @return array|object|null
2003
+ */
2004
+ public function fetch_scheduled_emails( $session_id, $fetch_sent = false ) {
2005
+ global $wpdb;
2006
+ $email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
2007
+ $email_template_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
2008
+
2009
+ $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
2010
+
2011
+ if ( $fetch_sent ) {
2012
+ $query .= ' AND email_sent = 1';
2013
+ }
2014
+
2015
+ $result = $wpdb->get_results( $query ); // phpcs:ignore
2016
+ return $result;
2017
+ }
2018
+
2019
+ /**
2020
+ * Delete orders from cart abandonment table whose cart total is zero and order status is abandoned.
2021
+ */
2022
+ public function delete_empty_abandoned_order() {
2023
+ global $wpdb;
2024
+
2025
+ $cart_abandonment_table = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
2026
+
2027
+ $where = array(
2028
+ 'cart_total' => 0,
2029
+ );
2030
+
2031
+ $wpdb->delete( $cart_abandonment_table, $where );
2032
+ }
2033
+
2034
+
2035
+ /**
2036
+ * Check if transient is set for delete garbage coupons.
2037
+ */
2038
+ public function delete_used_and_expired_coupons() {
2039
+ $is_ajax_request = wp_doing_ajax();
2040
+ $is_transient_set = false;
2041
+ global $wpdb;
2042
+ if ( $is_ajax_request ) {
2043
+ check_ajax_referer( 'wcf_ca_delete_garbage_coupons', 'security' );
2044
+ } else {
2045
+ $is_transient_set = get_transient( 'woocommerce_ca_delete_garbage_coupons' );
2046
+ }
2047
+
2048
+ if ( false === $is_transient_set || $is_ajax_request ) {
2049
+ $coupons = $this->delete_garbage_coupons();
2050
+ $coupon_count = count( $coupons );
2051
+
2052
+ if ( $coupon_count ) {
2053
+ $coupons_post_ids = implode( ',', wp_list_pluck( $coupons, 'ID' ) );
2054
+ $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN(" . $coupons_post_ids . ')' );//phpcs:ignore
2055
+ $wpdb->query( "DELETE FROM {$wpdb->posts} WHERE ID IN(" . $coupons_post_ids . ')' );//phpcs:ignore
2056
+ }
2057
+
2058
+ if ( ! $is_ajax_request ) {
2059
+ set_transient( 'woocommerce_ca_delete_garbage_coupons', $coupons, WEEK_IN_SECONDS );
2060
+ return;
2061
+ }
2062
+
2063
+ // translators: %1$s: Coupons Deleted, %2$s: Deleted coupons count'.
2064
+ wp_send_json_success( sprintf( __( '%1$s: %2$d', 'woo-cart-abandonment-recovery' ), 'Coupons Deleted', $coupon_count ) );
2065
+
2066
+ }
2067
+ }
2068
+
2069
+
2070
+ /**
2071
+ * Set transient and delete garbage coupons.
2072
+ */
2073
+ public function delete_garbage_coupons() {
2074
+
2075
+ global $wpdb;
2076
+
2077
+ $coupon_generated_by = WCF_CA_COUPON_GENERATED_BY;
2078
+ $timestamp = time();
2079
+ $post_type = 'shop_coupon';
2080
+ $coupons = $wpdb->get_results(
2081
+ $wpdb->prepare(
2082
+ "SELECT ID, coupon_code, usage_limit, total_usaged, expiry_date FROM (
2083
+ SELECT p.ID,
2084
+ p.post_title AS coupon_code,
2085
+ Max(CASE WHEN pm.meta_key = 'date_expires' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS expiry_date,
2086
+ Max(CASE WHEN pm.meta_key = 'usage_limit' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS usage_limit,
2087
+ Max(CASE WHEN pm.meta_key = 'usage_count' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS total_usaged,
2088
+
2089
+ Max(CASE WHEN pm.meta_key = 'coupon_generated_by' AND p.`ID` = pm.`post_id` THEN pm.meta_value END) AS coupon_generated_by
2090
+ FROM wp_posts AS p
2091
+ INNER JOIN wp_postmeta AS pm ON p.ID = pm.post_id
2092
+ WHERE p.`post_type` = %s
2093
+
2094
+ GROUP BY p.ID
2095
+ ) AS final_res WHERE coupon_generated_by IS NOT NULL AND coupon_generated_by = %s AND ( ( usage_limit = total_usaged ) OR ( expiry_date <= %d AND expiry_date != '') )",
2096
+ $post_type,
2097
+ $coupon_generated_by,
2098
+ $timestamp
2099
+ )
2100
+ );
2101
+ return $coupons;
2102
+ }
2103
+
2104
+ /**
2105
+ * Send headers to export orders to csv format.
2106
+ */
2107
+ private function download_send_headers() {
2108
+ $now = gmdate( 'Y-m-d-H-i-s' );
2109
+ $filename = 'woo-cart-abandonment-recovery-export-' . $now . '.csv';
2110
+
2111
+ header( 'Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate' );
2112
+ header( "Last-Modified: {$now} GMT" );
2113
+
2114
+ // force download.
2115
+ header( 'Content-Type: application/force-download' );
2116
+ header( 'Content-Type: application/octet-stream' );
2117
+ header( 'Content-Type: application/download' );
2118
+
2119
+ // disposition / encoding on response body.
2120
+ header( "Content-Disposition: attachment;filename={$filename}" );
2121
+ header( 'Content-Transfer-Encoding: binary' );
2122
+ }
2123
+
2124
+ /**
2125
+ * Convert users data to csv format.
2126
+ *
2127
+ * @param array $user_data users data.
2128
+ */
2129
+ private function array2csv( array $user_data ) {
2130
+ if ( empty( $user_data ) ) {
2131
+ return;
2132
+ }
2133
+ ob_clean();
2134
+ ob_start();
2135
+ $data_file = fopen( 'php://output', 'w' );
2136
+ fputcsv(
2137
+ $data_file,
2138
+ array(
2139
+ 'First-Name',
2140
+ 'Last-Name',
2141
+ 'Email',
2142
+ 'Products',
2143
+ 'Cart-Total in ' . get_woocommerce_currency(),
2144
+ 'Order-Status',
2145
+ 'Unsubscribed',
2146
+ 'Coupon-Code',
2147
+ )
2148
+ );
2149
+ foreach ( $user_data as $data ) {
2150
+ $name = unserialize( $data['other_fields'] );
2151
+ $checkout_details = $this->get_checkout_details( $data['session_id'] );
2152
+ $cart_data = $this->get_comma_separated_products( $checkout_details->cart_contents );
2153
+ fputcsv(
2154
+ $data_file,
2155
+ array(
2156
+ $name['wcf_first_name'],
2157
+ $name['wcf_last_name'],
2158
+ $data['email'],
2159
+ $cart_data,
2160
+ $data['cart_total'],
2161
+ $data['order_status'],
2162
+ $data['unsubscribed'] ? 'Yes' : 'No',
2163
+ $data['coupon_code'],
2164
+ )
2165
+ );
2166
+
2167
+ }
2168
+ fclose( $data_file ); //phpcs:ignore
2169
+ return ob_get_clean();
2170
+ }
2171
+ }
2172
+
2173
+ Cartflows_Ca_Cart_Abandonment::get_instance();
modules/cart-abandonment/class-cartflows-ca-email-templates-table.php CHANGED
@@ -1,268 +1,268 @@
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
- public 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
- * Default columns.
46
- *
47
- * @param object $item item.
48
- * @param string $column_name column name.
49
- */
50
- public function column_default( $item, $column_name ) {
51
- return $item[ $column_name ];
52
- }
53
-
54
- /**
55
- * This is how id column renders.
56
- *
57
- * @param object $item item.
58
- * @return HTML
59
- */
60
- public function column_template_name( $item ) {
61
-
62
- $row_actions['edit'] = '<a href="' . wp_nonce_url(
63
- add_query_arg(
64
- array(
65
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
66
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
67
- 'id' => $item['id'],
68
- ),
69
- $this->base_url
70
- ),
71
- WCF_EMAIL_TEMPLATES_NONCE
72
- ) . '">' . __( 'Edit', 'woo-cart-abandonment-recovery' ) . '</a>';
73
-
74
- $row_actions['delete'] = '<a onclick="return confirm(\'Are you sure to delete this email template?\');" href="' . wp_nonce_url(
75
- add_query_arg(
76
- array(
77
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
78
- 'sub_action' => WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES,
79
- 'id' => $item['id'],
80
- ),
81
- $this->base_url
82
- ),
83
- WCF_EMAIL_TEMPLATES_NONCE
84
- ) . '">' . __( 'Delete', 'woo-cart-abandonment-recovery' ) . '</a>';
85
-
86
- $row_actions['clone'] = '<a href="' . wp_nonce_url(
87
- add_query_arg(
88
- array(
89
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
90
- 'sub_action' => WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES,
91
- 'id' => $item['id'],
92
- ),
93
- $this->base_url
94
- ),
95
- WCF_EMAIL_TEMPLATES_NONCE
96
- ) . '">' . __( 'Clone', 'woo-cart-abandonment-recovery' ) . '</a>';
97
-
98
- return sprintf( '%s %s', esc_html( $item['template_name'] ), $this->row_actions( $row_actions ) );
99
- }
100
-
101
- /**
102
- * This is how checkbox column renders.
103
- *
104
- * @param object $item item.
105
- * @return HTML
106
- */
107
- public function column_cb( $item ) {
108
- return sprintf( '<input type="checkbox" name="id[]" value="%s" />', esc_html( $item['id'] ) );
109
- }
110
-
111
- /**
112
- * [OPTIONAL] Return array of bult actions if has any
113
- *
114
- * @return array
115
- */
116
- public function get_bulk_actions() {
117
- $actions = array(
118
- WCF_ACTION_EMAIL_TEMPLATES => __( 'Delete', 'woo-cart-abandonment-recovery' ),
119
- );
120
- return $actions;
121
- }
122
-
123
- /**
124
- * Whether the table has items to display or not
125
- *
126
- * @return bool
127
- */
128
- public function has_items() {
129
- return ! empty( $this->items );
130
- }
131
-
132
- /**
133
- * Fetch data from the database to render on view.
134
- *
135
- * @param string $cart_type abandoned|completed.
136
- */
137
- public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER ) {
138
- global $wpdb;
139
- $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
140
-
141
- $per_page = 10;
142
-
143
- $columns = $this->get_columns();
144
- $hidden = array();
145
- $sortable = $this->get_sortable_columns();
146
-
147
- $this->_column_headers = array( $columns, $hidden, $sortable );
148
-
149
- $this->process_bulk_action();
150
-
151
- $total_items = $wpdb->get_var( "SELECT COUNT(id) FROM $cart_abandonment_template_table_name" ); // phpcs:ignore
152
-
153
- $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
154
- $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
155
- $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
156
-
157
- $paged = $paged ? max( 0, $paged - 1 ) : 0;
158
- $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
159
- $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
160
-
161
- // [REQUIRED] configure pagination
162
- $this->set_pagination_args(
163
- array(
164
- 'total_items' => $total_items,
165
- 'per_page' => $per_page,
166
- 'total_pages' => ceil( $total_items / $per_page ),
167
- )
168
- );
169
- $this->items = $wpdb->get_results(
170
- $wpdb->prepare( "SELECT * FROM {$cart_abandonment_template_table_name} ORDER BY $orderby $order LIMIT %d OFFSET %d", $per_page, $paged * $per_page ), // phpcs:ignore
171
- ARRAY_A
172
- );
173
- }
174
-
175
- /**
176
- * Table columns.
177
- *
178
- * @return array
179
- */
180
- public function get_columns() {
181
- $columns = array(
182
- 'cb' => '<input type="checkbox" />',
183
- 'template_name' => __( 'Template Name', 'woo-cart-abandonment-recovery' ),
184
- 'email_subject' => __( 'Email Subject', 'woo-cart-abandonment-recovery' ),
185
- 'trigger_time' => __( 'Trigger After', 'woo-cart-abandonment-recovery' ),
186
- 'is_activated' => __( 'Activate Template', 'woo-cart-abandonment-recovery' ),
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
- protected 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
- */
213
- protected function column_is_activated( $item ) {
214
- global $wpdb;
215
- if ( isset( $item['id'] ) ) {
216
- $id = $item['id'];
217
- }
218
- $is_activated = '';
219
- $active_status = 0;
220
- if ( $item && isset( $item['is_activated'] ) ) {
221
- $active_status = stripslashes( $item['is_activated'] );
222
- $is_activated = $active_status ? 'on' : 'off';
223
-
224
- }
225
- print '<button type="button" id="' . esc_attr( $id ) . '" class="wcf-ca-switch wcf-toggle-template-status wcar-switch-grid" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
226
- print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
227
- }
228
-
229
- /**
230
- * Table sortable columns.
231
- *
232
- * @return array
233
- */
234
- public function get_sortable_columns() {
235
- $sortable = array(
236
- 'id' => array( 'id', true ),
237
- 'template_name' => array( 'Template Name', true ),
238
- 'email_subject' => array( 'Email Subject', true ),
239
- );
240
- return $sortable;
241
- }
242
-
243
- /**
244
- * Processes bulk actions
245
- */
246
- public function process_bulk_action() {
247
-
248
- global $wpdb;
249
- $table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
250
- $action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
251
-
252
- if ( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES === $action ) {
253
- $ids = array();
254
- $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
255
- if ( is_array( $request_id ) ) {
256
- $ids = array_map( 'intval', $request_id );
257
- } else {
258
- $ids = array( intval( $request_id ) );
259
- }
260
- $ids = implode( ',', $ids );
261
-
262
- if ( ! empty( $ids ) ) {
263
- $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
264
- }
265
- }
266
-
267
- }
268
- }
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
+ public 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
+ * Default columns.
46
+ *
47
+ * @param object $item item.
48
+ * @param string $column_name column name.
49
+ */
50
+ public function column_default( $item, $column_name ) {
51
+ return $item[ $column_name ];
52
+ }
53
+
54
+ /**
55
+ * This is how id column renders.
56
+ *
57
+ * @param object $item item.
58
+ * @return HTML
59
+ */
60
+ public function column_template_name( $item ) {
61
+
62
+ $row_actions['edit'] = '<a href="' . wp_nonce_url(
63
+ add_query_arg(
64
+ array(
65
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
66
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
67
+ 'id' => $item['id'],
68
+ ),
69
+ $this->base_url
70
+ ),
71
+ WCF_EMAIL_TEMPLATES_NONCE
72
+ ) . '">' . __( 'Edit', 'woo-cart-abandonment-recovery' ) . '</a>';
73
+
74
+ $row_actions['delete'] = '<a onclick="return confirm(\'Are you sure to delete this email template?\');" href="' . wp_nonce_url(
75
+ add_query_arg(
76
+ array(
77
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
78
+ 'sub_action' => WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES,
79
+ 'id' => $item['id'],
80
+ ),
81
+ $this->base_url
82
+ ),
83
+ WCF_EMAIL_TEMPLATES_NONCE
84
+ ) . '">' . __( 'Delete', 'woo-cart-abandonment-recovery' ) . '</a>';
85
+
86
+ $row_actions['clone'] = '<a href="' . wp_nonce_url(
87
+ add_query_arg(
88
+ array(
89
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
90
+ 'sub_action' => WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES,
91
+ 'id' => $item['id'],
92
+ ),
93
+ $this->base_url
94
+ ),
95
+ WCF_EMAIL_TEMPLATES_NONCE
96
+ ) . '">' . __( 'Clone', 'woo-cart-abandonment-recovery' ) . '</a>';
97
+
98
+ return sprintf( '%s %s', esc_html( $item['template_name'] ), $this->row_actions( $row_actions ) );
99
+ }
100
+
101
+ /**
102
+ * This is how checkbox column renders.
103
+ *
104
+ * @param object $item item.
105
+ * @return HTML
106
+ */
107
+ public function column_cb( $item ) {
108
+ return sprintf( '<input type="checkbox" name="id[]" value="%s" />', esc_html( $item['id'] ) );
109
+ }
110
+
111
+ /**
112
+ * [OPTIONAL] Return array of bult actions if has any
113
+ *
114
+ * @return array
115
+ */
116
+ public function get_bulk_actions() {
117
+ $actions = array(
118
+ WCF_ACTION_EMAIL_TEMPLATES => __( 'Delete', 'woo-cart-abandonment-recovery' ),
119
+ );
120
+ return $actions;
121
+ }
122
+
123
+ /**
124
+ * Whether the table has items to display or not
125
+ *
126
+ * @return bool
127
+ */
128
+ public function has_items() {
129
+ return ! empty( $this->items );
130
+ }
131
+
132
+ /**
133
+ * Fetch data from the database to render on view.
134
+ *
135
+ * @param string $cart_type abandoned|completed.
136
+ */
137
+ public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER ) {
138
+ global $wpdb;
139
+ $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
140
+
141
+ $per_page = 10;
142
+
143
+ $columns = $this->get_columns();
144
+ $hidden = array();
145
+ $sortable = $this->get_sortable_columns();
146
+
147
+ $this->_column_headers = array( $columns, $hidden, $sortable );
148
+
149
+ $this->process_bulk_action();
150
+
151
+ $total_items = $wpdb->get_var( "SELECT COUNT(id) FROM $cart_abandonment_template_table_name" ); // phpcs:ignore
152
+
153
+ $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
154
+ $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
155
+ $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
156
+
157
+ $paged = $paged ? max( 0, $paged - 1 ) : 0;
158
+ $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
159
+ $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
160
+
161
+ // [REQUIRED] configure pagination
162
+ $this->set_pagination_args(
163
+ array(
164
+ 'total_items' => $total_items,
165
+ 'per_page' => $per_page,
166
+ 'total_pages' => ceil( $total_items / $per_page ),
167
+ )
168
+ );
169
+ $this->items = $wpdb->get_results(
170
+ $wpdb->prepare( "SELECT * FROM {$cart_abandonment_template_table_name} ORDER BY $orderby $order LIMIT %d OFFSET %d", $per_page, $paged * $per_page ), // phpcs:ignore
171
+ ARRAY_A
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Table columns.
177
+ *
178
+ * @return array
179
+ */
180
+ public function get_columns() {
181
+ $columns = array(
182
+ 'cb' => '<input type="checkbox" />',
183
+ 'template_name' => __( 'Template Name', 'woo-cart-abandonment-recovery' ),
184
+ 'email_subject' => __( 'Email Subject', 'woo-cart-abandonment-recovery' ),
185
+ 'trigger_time' => __( 'Trigger After', 'woo-cart-abandonment-recovery' ),
186
+ 'is_activated' => __( 'Activate Template', 'woo-cart-abandonment-recovery' ),
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
+ protected 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
+ */
213
+ protected function column_is_activated( $item ) {
214
+ global $wpdb;
215
+ if ( isset( $item['id'] ) ) {
216
+ $id = $item['id'];
217
+ }
218
+ $is_activated = '';
219
+ $active_status = 0;
220
+ if ( $item && isset( $item['is_activated'] ) ) {
221
+ $active_status = stripslashes( $item['is_activated'] );
222
+ $is_activated = $active_status ? 'on' : 'off';
223
+
224
+ }
225
+ print '<button type="button" id="' . esc_attr( $id ) . '" class="wcf-ca-switch wcf-toggle-template-status wcar-switch-grid" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
226
+ print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
227
+ }
228
+
229
+ /**
230
+ * Table sortable columns.
231
+ *
232
+ * @return array
233
+ */
234
+ public function get_sortable_columns() {
235
+ $sortable = array(
236
+ 'id' => array( 'id', true ),
237
+ 'template_name' => array( 'Template Name', true ),
238
+ 'email_subject' => array( 'Email Subject', true ),
239
+ );
240
+ return $sortable;
241
+ }
242
+
243
+ /**
244
+ * Processes bulk actions
245
+ */
246
+ public function process_bulk_action() {
247
+
248
+ global $wpdb;
249
+ $table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
250
+ $action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
251
+
252
+ if ( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES === $action ) {
253
+ $ids = array();
254
+ $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
255
+ if ( is_array( $request_id ) ) {
256
+ $ids = array_map( 'intval', $request_id );
257
+ } else {
258
+ $ids = array( intval( $request_id ) );
259
+ }
260
+ $ids = implode( ',', $ids );
261
+
262
+ if ( ! empty( $ids ) ) {
263
+ $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
264
+ }
265
+ }
266
+
267
+ }
268
+ }
modules/cart-abandonment/class-cartflows-ca-email-templates.php CHANGED
@@ -1,1096 +1,1096 @@
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
-
65
-
66
-
67
- /**
68
- * Constructor function that initializes required actions and hooks
69
- */
70
- public function __construct() {
71
- $this->define_template_constants();
72
- global $wpdb;
73
- $this->cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
74
- $this->email_templates_meta_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
75
- $this->email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
76
- $this->wpdb = $wpdb;
77
-
78
- add_action( 'admin_enqueue_scripts', __class__ . '::load_email_templates_script', 15 );
79
- add_action( 'wp_ajax_activate_email_templates', array( $this, 'update_email_toggle_button' ) );
80
- }
81
-
82
-
83
-
84
-
85
- /**
86
- * Add email template JS script.
87
- */
88
- public static function load_email_templates_script() {
89
-
90
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
91
-
92
- if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
93
- return;
94
- }
95
-
96
- wp_enqueue_script( 'jquery-ui-datepicker' );
97
- wp_enqueue_style( 'jquery-ui-style' );
98
-
99
- wp_enqueue_script(
100
- 'cartflows-ca-email-tmpl-settings',
101
- CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
102
- array( 'jquery' ),
103
- CARTFLOWS_CA_VER,
104
- false
105
- );
106
-
107
- $current_user = wp_get_current_user();
108
- $vars = array(
109
- 'email' => $current_user->user_email,
110
- 'name' => $current_user->user_firstname,
111
- 'surname' => $current_user->user_lastname,
112
- 'phone' => get_user_meta( $current_user->ID, 'billing_phone', true ),
113
- 'billing_company' => get_user_meta( $current_user->ID, 'billing_company', true ),
114
- 'billing_address_1' => get_user_meta( $current_user->ID, 'billing_address_1', true ),
115
- 'billing_address_2' => get_user_meta( $current_user->ID, 'billing_address_2', true ),
116
- 'billing_state' => get_user_meta( $current_user->ID, 'billing_state', true ),
117
- 'billing_postcode' => get_user_meta( $current_user->ID, 'billing_postcode', true ),
118
- 'shipping_first_name' => $current_user->user_firstname,
119
- 'shipping_last_name' => $current_user->user_lastname,
120
- 'shipping_company' => get_user_meta( $current_user->ID, 'shipping_company', true ),
121
- 'shipping_address_1' => get_user_meta( $current_user->ID, 'shipping_address_1', true ),
122
- 'shipping_address_2' => get_user_meta( $current_user->ID, 'shipping_address_2', true ),
123
- 'shipping_city' => get_user_meta( $current_user->ID, 'shipping_city', true ),
124
- 'shipping_state' => get_user_meta( $current_user->ID, 'shipping_state', true ),
125
- 'shipping_postcode' => get_user_meta( $current_user->ID, 'shipping_postcode', true ),
126
- 'woo_currency_symbol' => get_woocommerce_currency_symbol(),
127
- 'email_toggle_button_nonce' => wp_create_nonce( 'activate_email_templates' ),
128
- 'admin_firstname' => __( 'Admin Firstname', 'woo-cart-abandonment-recovery' ),
129
- 'admin_company' => __( 'Admin Company', 'woo-cart-abandonment-recovery' ),
130
- 'abandoned_product_details_table' => __( 'Abandoned Product Details Table', 'woo-cart-abandonment-recovery' ),
131
- 'abandoned_product_names' => __( 'Abandoned Product Names', 'woo-cart-abandonment-recovery' ),
132
- 'cart_checkout_url' => __( 'Cart Checkout URL', 'woo-cart-abandonment-recovery' ),
133
- 'coupon_code' => __( 'Coupon Code', 'woo-cart-abandonment-recovery' ),
134
- 'customer_firstname' => __( 'Customer First Name', 'woo-cart-abandonment-recovery' ),
135
- 'customer_lastname' => __( 'Customer Last Name', 'woo-cart-abandonment-recovery' ),
136
- 'customer_full_name' => __( 'Customer Full Name', 'woo-cart-abandonment-recovery' ),
137
- 'cart_abandonment_date' => __( 'Cart Abandonment Date', 'woo-cart-abandonment-recovery' ),
138
- 'site_url' => __( 'Site URL', 'woo-cart-abandonment-recovery' ),
139
- 'unsubscribe_link' => __( 'Unsubscribe Link', 'woo-cart-abandonment-recovery' ),
140
- );
141
- wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'wcf_ca_details', $vars );
142
-
143
- }
144
-
145
-
146
- /**
147
- * Update the activate email template toggle button.
148
- */
149
- public function update_email_toggle_button() {
150
-
151
- check_ajax_referer( 'activate_email_templates', 'security' );
152
- global $wpdb;
153
- $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
154
-
155
- $id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
156
-
157
- $is_activated = filter_input( INPUT_POST, 'state', FILTER_SANITIZE_STRING );
158
-
159
- $response = __( 'Something went wrong', 'woo-cart-abandonment-recovery' );
160
- if ( ! isset( $is_activated ) || ! isset( $id ) ) {
161
- wp_send_json_error( $response );
162
- }
163
-
164
- if ( $is_activated && 'on' === $is_activated ) {
165
- $is_activated = 1;
166
- $response = __( 'Activated', 'woo-cart-abandonment-recovery' );
167
- } else {
168
- $is_activated = 0;
169
- $response = __( 'Deactivated', 'woo-cart-abandonment-recovery' );
170
- }
171
-
172
- $wpdb->query( $wpdb->prepare( "UPDATE {$cart_abandonment_template_table_name} SET is_activated = %d WHERE id = %d ", $is_activated, $id ), ARRAY_A ); // phpcs:ignore
173
- wp_send_json_success( $response );
174
-
175
- }
176
-
177
- /**
178
- * Initialise all the constants
179
- */
180
- public function define_template_constants() {
181
- define( 'WCF_CA_PAGE_NAME', 'woo-cart-abandonment-recovery' );
182
-
183
- define( 'WCF_CA_GENERAL_SETTINGS_SECTION', 'cartflows_cart_abandonment_settings_section' );
184
- define( 'WCF_CA_COUPONS_SETTINGS_SECTION', 'cartflows_cart_abandonment_coupons_settings_section' );
185
- define( 'WCF_CA_EMAIL_SETTINGS_SECTION', 'cartflows_email_template_settings_section' );
186
- define( 'WCF_CA_COUPON_CODE_SECTION', 'cartflows_coupon_code_settings_section' );
187
- define( 'WCF_CA_ZAPIER_SETTINGS_SECTION', 'cartflows_zapier_settings_section' );
188
- define( 'WCF_CA_GDPR_SETTINGS_SECTION', 'cartflows_gdpr_settings_section' );
189
-
190
- define( 'WCF_CA_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-settings' );
191
- define( 'WCF_CA_EMAIL_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-email-settings' );
192
-
193
- define( 'WCF_ACTION_EMAIL_TEMPLATES', 'email_tmpl' );
194
-
195
- define( 'WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES', 'add_email_tmpl' );
196
- define( 'WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES', 'edit_email_tmpl' );
197
- define( 'WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES', 'delete_email_tmpl' );
198
- define( 'WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES', 'clone_email_tmpl' );
199
- define( 'WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES', 'delete_bulk_email_tmpl' );
200
- define( 'WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES', 'save_email_template' );
201
- define( 'WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES', 'restore_default_email_tmpl' );
202
-
203
- define( 'WCF_SUB_ACTION_CART_ABANDONMENT_SETTINGS', 'cart_abandonment_settings' );
204
- define( 'WCF_SUB_ACTION_EMAIL_SETTINGS', 'email_settings' );
205
- define( 'WCF_SUB_ACTION_COUPON_CODE_SETTINGS', 'coupon_code_settings' );
206
- define( 'WCF_SUB_ACTION_ZAPIER_SETTINGS', 'zapier_settings' );
207
-
208
- define( 'WCF_EMAIL_TEMPLATES_NONCE', 'email_template_nonce' );
209
-
210
- }
211
-
212
- /**
213
- * Show success messages for email templates.
214
- */
215
- public function show_messages() {
216
-
217
- $wcf_ca_template_created = filter_input( INPUT_GET, 'wcf_ca_template_created', FILTER_SANITIZE_STRING );
218
- $wcf_ca_template_cloned = filter_input( INPUT_GET, 'wcf_ca_template_cloned', FILTER_SANITIZE_STRING );
219
- $wcf_ca_template_deleted = filter_input( INPUT_GET, 'wcf_ca_template_deleted', FILTER_SANITIZE_STRING );
220
- $wcf_ca_template_updated = filter_input( INPUT_GET, 'wcf_ca_template_updated', FILTER_SANITIZE_STRING );
221
- $wcf_ca_template_restored = filter_input( INPUT_GET, 'wcf_ca_template_restored', FILTER_SANITIZE_STRING );
222
-
223
- ?>
224
- <?php if ( 'YES' === $wcf_ca_template_created ) { ?>
225
- <div id="message" class="notice notice-success is-dismissible">
226
- <p>
227
- <strong>
228
- <?php esc_html_e( 'The Email Template has been successfully added.', 'woo-cart-abandonment-recovery' ); ?>
229
- </strong>
230
- </p>
231
- </div>
232
- <?php } ?>
233
-
234
- <?php if ( 'YES' === $wcf_ca_template_cloned ) { ?>
235
- <div id="message" class="notice notice-success is-dismissible">
236
- <p>
237
- <strong>
238
- <?php esc_html_e( 'The Email Template has been cloned successfully.', 'woo-cart-abandonment-recovery' ); ?>
239
- </strong>
240
- </p>
241
- </div>
242
- <?php } ?>
243
-
244
- <?php if ( 'YES' === $wcf_ca_template_deleted ) { ?>
245
- <div id="message" class="notice notice-success is-dismissible">
246
- <p>
247
- <strong>
248
- <?php esc_html_e( 'The Email Template has been successfully deleted.', 'woo-cart-abandonment-recovery' ); ?>
249
- </strong>
250
- </p>
251
- </div>
252
- <?php } ?>
253
- <?php if ( 'YES' === $wcf_ca_template_updated ) { ?>
254
- <div id="message" class="notice notice-success is-dismissible">
255
- <p>
256
- <strong>
257
- <?php esc_html_e( 'The Email Template has been successfully updated.', 'woo-cart-abandonment-recovery' ); ?>
258
- </strong>
259
- </p>
260
- </div>
261
- <?php } ?>
262
-
263
- <?php if ( 'YES' === $wcf_ca_template_restored ) { ?>
264
- <div id="message" class="notice notice-success is-dismissible">
265
- <p>
266
- <strong>
267
- <?php esc_html_e( 'Default Email Templates has been restored successfully.', 'woo-cart-abandonment-recovery' ); ?>
268
- </strong>
269
- </p>
270
- </div>
271
- <?php } ?>
272
- <?php
273
-
274
- }
275
-
276
- /**
277
- * Delete bulk email templates.
278
- */
279
- public function delete_bulk_templates() {
280
- $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
281
- $wcf_template_list->process_bulk_action();
282
- $param = array(
283
- 'page' => WCF_CA_PAGE_NAME,
284
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
285
- 'wcf_ca_template_deleted' => 'YES',
286
- );
287
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
288
- wp_safe_redirect( $redirect_url );
289
- }
290
-
291
-
292
- /**
293
- * Delete email templates.
294
- */
295
- public function delete_single_template() {
296
-
297
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
298
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
299
-
300
- if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
301
-
302
- $this->wpdb->delete(
303
- $this->cart_abandonment_template_table_name,
304
- array( 'id' => $id ),
305
- '%d'
306
- );
307
- $param = array(
308
- 'page' => WCF_CA_PAGE_NAME,
309
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
310
- 'wcf_ca_template_deleted' => 'YES',
311
- );
312
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
313
- wp_safe_redirect( $redirect_url );
314
-
315
- }
316
- }
317
-
318
- /**
319
- * Delete email templates.
320
- */
321
- public function clone_email_template() {
322
-
323
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
324
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
325
-
326
- if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
327
-
328
- $email_template = $this->get_template_by_id( $id );
329
-
330
- $this->wpdb->insert(
331
- $this->cart_abandonment_template_table_name,
332
- array(
333
- 'template_name' => sanitize_text_field( $email_template->template_name ),
334
- 'email_subject' => sanitize_text_field( $email_template->email_subject ),
335
- 'email_body' => $email_template->email_body,
336
- 'frequency' => intval( sanitize_text_field( $email_template->frequency ) ),
337
- 'frequency_unit' => sanitize_text_field( $email_template->frequency_unit ),
338
-
339
- ),
340
- array( '%s', '%s', '%s', '%d', '%s' )
341
- );
342
-
343
- $email_template_id = $this->wpdb->insert_id;
344
- $meta_data = array(
345
- 'override_global_coupon' => false,
346
- 'discount_type' => 'percent',
347
- 'coupon_amount' => 10,
348
- 'coupon_expiry_date' => '',
349
- 'coupon_expiry_unit' => 'hours',
350
-
351
- );
352
-
353
- foreach ( $meta_data as $mera_key => $meta_value ) {
354
- $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
355
- }
356
-
357
- $param = array(
358
- 'page' => WCF_CA_PAGE_NAME,
359
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
360
- 'wcf_ca_template_cloned' => 'YES',
361
- );
362
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
363
- wp_safe_redirect( $redirect_url );
364
-
365
- }
366
- }
367
-
368
- /**
369
- * Get email template by id.
370
- *
371
- * @param int $email_tmpl_id template id.
372
- */
373
- public function get_email_template_by_id( $email_tmpl_id ) {
374
-
375
- $query = 'SELECT * FROM ' . $this->cart_abandonment_template_table_name . ' WHERE id = %d ';
376
- return $this->wpdb->get_row($this->wpdb->prepare($query, $email_tmpl_id)); // phpcs:ignore
377
-
378
- }
379
-
380
- /**
381
- * Render email template add/edit form.
382
- *
383
- * @param string $sub_action sub_action.
384
- */
385
- public function render_email_template_form( $sub_action = WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES ) {
386
-
387
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
388
-
389
- if ( $id ) {
390
- $results = $this->get_email_template_by_id( $id );
391
- }
392
-
393
- ?>
394
-
395
- <div id="content">
396
-
397
- <?php
398
- $param = array(
399
- 'page' => WCF_CA_PAGE_NAME,
400
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
401
- 'sub_action' => WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES,
402
- );
403
- $save_template_url = esc_url( add_query_arg( $param, admin_url( '/admin.php' ) ) );
404
- ?>
405
-
406
- <form method="post" action="<?php echo esc_attr( $save_template_url ); ?>" id="wcf_settings">
407
- <input type="hidden" name="sub_action" value="<?php echo esc_attr( $sub_action ); ?>"/>
408
- <?php
409
- $id_by = '';
410
- if ( isset( $id ) ) {
411
- $id_by = $id;
412
- }
413
- ?>
414
- <input type="hidden" name="id" value="<?php echo esc_attr( $id_by ); ?>"/>
415
- <?php
416
-
417
- $button_sub_action = 'save';
418
- $display_message = 'Add New Email Template:';
419
-
420
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
421
- $button_sub_action = 'update';
422
- $display_message = 'Edit Email Template:';
423
- }
424
- print '<input type="hidden" name="wcf_settings_frm" value="' . esc_attr( $button_sub_action ) . '">';
425
- ?>
426
- <div id="poststuff">
427
- <div> <!-- <div class="postbox" > -->
428
- <h3><?php esc_html_e($display_message, 'woo-cart-abandonment-recovery'); // phpcs:ignore ?></h3>
429
- <hr/>
430
- <div>
431
- <table class="form-table" id="addedit_template">
432
- <tr>
433
- <th>
434
- <label for="wcf_email_subject"><b><?php esc_html_e( 'Activate Template now?', 'woo-cart-abandonment-recovery' ); ?></b></label>
435
- </th>
436
- <td>
437
- <?php
438
- $is_activated = '';
439
- $active_status = 0;
440
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->is_activated ) ) {
441
- $active_status = stripslashes( $results->is_activated );
442
- $is_activated = $active_status ? 'on' : 'off';
443
-
444
- }
445
- print '<button type="button" class="wcf-ca-switch wcf-toggle-template-status" wcf-template-id="1" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
446
- print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
447
- ?>
448
-
449
- </td>
450
- </tr>
451
-
452
- <tr>
453
- <th>
454
- <label for="wcf_template_name"><b><?php esc_html_e( 'Template Name:', 'woo-cart-abandonment-recovery' ); ?></b></label>
455
- </th>
456
- <td>
457
- <?php
458
- $template_name = '';
459
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->template_name ) ) {
460
- $template_name = $results->template_name;
461
- }
462
- print '<input type="text" name="wcf_template_name" id="wcf_template_name" class="wcf-ca-trigger-input" value="' . esc_attr( $template_name ) . '">';
463
- ?>
464
- </td>
465
- </tr>
466
-
467
- <tr>
468
- <th>
469
- <label for="wcf_email_subject"><b><?php esc_html_e( 'Email Subject:', 'woo-cart-abandonment-recovery' ); ?></b></label>
470
- </th>
471
- <td>
472
- <?php
473
- $subject_edit = '';
474
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_subject ) ) {
475
- $subject_edit = stripslashes( $results->email_subject );
476
- }
477
- print '<input type="text" name="wcf_email_subject" id="wcf_email_subject" class="wcf-ca-trigger-input" value="' . esc_attr( $subject_edit ) . '">';
478
- ?>
479
- </td>
480
- </tr>
481
-
482
- <tr>
483
- <th>
484
- <label for="wcf_email_body"><b><?php esc_html_e( 'Email Body:', 'woo-cart-abandonment-recovery' ); ?></b></label>
485
- </th>
486
- <td>
487
- <?php
488
- $initial_data = '';
489
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_body ) ) {
490
- $initial_data = stripslashes( $results->email_body );
491
- }
492
-
493
- wp_editor(
494
- $initial_data,
495
- 'wcf_email_body',
496
- array(
497
- 'media_buttons' => true,
498
- 'textarea_rows' => 15,
499
- 'tabindex' => 4,
500
- 'tinymce' => array(
501
- 'theme_advanced_buttons1' => 'bold,italic,underline,|,bullist,numlist,blockquote,|,link,unlink,|,spellchecker,fullscreen,|,formatselect,styleselect',
502
- ),
503
- )
504
- );
505
-
506
- ?>
507
- <?php echo stripslashes( get_option( 'wcf_email_body' ) ); //phpcs:ignore ?>
508
- </td>
509
- </tr>
510
-
511
- <tr>
512
- <th>
513
- <label for="wcf_override_global_coupon"><b><?php esc_html_e( 'Create Coupon', 'woo-cart-abandonment-recovery' ); ?></b></label>
514
- </th>
515
- <td>
516
- <?php
517
-
518
- $wcf_override_global_coupon = '';
519
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
520
- $wcf_override_global_coupon = $this->get_email_template_meta_by_key( $results->id, 'override_global_coupon' );
521
- if ( isset( $wcf_override_global_coupon->meta_value ) ) {
522
- $wcf_override_global_coupon = $wcf_override_global_coupon->meta_value ? 'checked' : '';
523
- }
524
- }
525
-
526
- print '<input ' . esc_attr( $wcf_override_global_coupon ) . ' id="wcf_override_global_coupon" name="wcf_override_global_coupon" type="checkbox" value="" /><span class="description">' . esc_html__( 'Allows you to send new coupon only for this template.', 'woo-cart-abandonment-recovery' ) . '</span>';
527
- ?>
528
- </td>
529
- </tr>
530
-
531
- <tr>
532
- <th>
533
- <label class="wcf-sub-heading" for="wcf_email_discount_type"> <?php esc_html_e( 'Discount Type', 'woo-cart-abandonment-recovery' ); ?> </label>
534
- </th>
535
- <td>
536
- <?php
537
-
538
- $wcf_email_discount_type = 'percent';
539
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
540
- $wcf_email_discount_type = $this->get_email_template_meta_by_key( $results->id, 'discount_type' );
541
- if ( isset( $wcf_email_discount_type->meta_value ) ) {
542
- $wcf_email_discount_type = $wcf_email_discount_type->meta_value;
543
- }
544
- }
545
-
546
- $dropdown_options = array(
547
- 'percent' => 'Percentage discount',
548
- 'fixed_cart' => 'Fixed cart discount',
549
- );
550
-
551
- echo '<select id="wcf_email_discount_type" name="wcf_email_discount_type">';
552
- foreach ( $dropdown_options as $key => $value ) {
553
- $is_selected = $key === $wcf_email_discount_type ? 'selected' : '';
554
- echo '<option ' . esc_attr( $is_selected ) . ' value=' . esc_attr( $key ) . '>' . esc_attr( $value ) . '</option>';
555
-
556
- }
557
- echo '</select>';
558
-
559
- ?>
560
- </td>
561
- </tr>
562
-
563
- <tr>
564
- <th>
565
- <label class="wcf-sub-heading" for="wcf_email_discount_amount"> <?php esc_html_e( 'Coupon Amount', 'woo-cart-abandonment-recovery' ); ?> </label>
566
- </th>
567
- <td>
568
- <?php
569
- $wcf_email_discount_amount = 10;
570
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
571
- $wcf_email_discount_amount = $this->get_email_template_meta_by_key( $results->id, 'coupon_amount' );
572
- if ( isset( $wcf_email_discount_amount->meta_value ) ) {
573
- $wcf_email_discount_amount = $wcf_email_discount_amount->meta_value;
574
- }
575
- }
576
- print '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="number" id="wcf_email_discount_amount" name="wcf_email_discount_amount" value="' . esc_attr( $wcf_email_discount_amount ) . '">';
577
- ?>
578
- </td>
579
- </tr>
580
-
581
- <tr>
582
- <th>
583
- <label class="wcf-sub-heading" for="wcf_email_coupon_expiry_date"> <?php esc_html_e( 'Coupon expiry date', 'woo-cart-abandonment-recovery' ); ?> </label>
584
- </th>
585
- <td>
586
- <?php
587
- $wcf_email_coupon_expiry_date = 0;
588
- $coupon_expiry_unit = 'hours';
589
-
590
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
591
- $wcf_email_coupon_expiry_date = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_date' );
592
- $wcf_email_coupon_expiry_unit = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_unit' );
593
-
594
- if ( isset( $wcf_email_coupon_expiry_date->meta_value ) ) {
595
- $wcf_email_coupon_expiry_date = $wcf_email_coupon_expiry_date->meta_value;
596
- }
597
- if ( isset( $wcf_email_coupon_expiry_unit->meta_value ) ) {
598
- $coupon_expiry_unit = $wcf_email_coupon_expiry_unit->meta_value;
599
- }
600
- }
601
- 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" />';
602
- $items = array(
603
- 'hours' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
604
- 'days' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
605
- );
606
- echo "<select id='wcf_coupon_expiry_unit' name='wcf_coupon_expiry_unit'>";
607
- foreach ( $items as $key => $item ) {
608
- $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
609
- echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
610
- }
611
- echo '</select>';
612
-
613
- echo " <span class='description'>" . esc_html__( 'Enter zero (0) to restrict coupon from expiring', 'woo-cart-abandonment-recovery' ) . ' </span>'
614
- ?>
615
- </td>
616
- </tr>
617
- <tr>
618
- <th>
619
- <label class="wcf-sub-heading" for="wcf_free_shipping_coupon"> <?php esc_html_e( 'Free Shipping', 'woo-cart-abandonment-recovery' ); ?> </label>
620
- </th>
621
- <td>
622
- <?php
623
-
624
- $wcf_free_shipping_coupon = '';
625
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
626
- $wcf_free_shipping_coupon = $this->get_email_template_meta_by_key( $results->id, 'free_shipping_coupon' );
627
- if ( isset( $wcf_free_shipping_coupon->meta_value ) ) {
628
- $wcf_free_shipping_coupon = $wcf_free_shipping_coupon->meta_value ? 'checked' : '';
629
- }
630
- }
631
-
632
- print '<input ' . esc_attr( $wcf_free_shipping_coupon ) . ' id="wcf_free_shipping_coupon" name="wcf_free_shipping_coupon" type="checkbox" value="" /><span class="description"> ' . esc_html__( 'Allows you to grant free shipping. A free shipping method must be enabled in your shipping zone and be set to require "a valid free shipping coupon". ', 'woo-cart-abandonment-recovery' ) . '</span>';
633
-
634
- ?>
635
- </td>
636
- </tr>
637
- <tr>
638
- <th>
639
- <label class="wcf-sub-heading" for="wcf_individual_use_only"><?php esc_html_e( 'Individual use only', 'woo-cart-abandonment-recovery' ); ?></label>
640
- </th>
641
- <td>
642
- <?php
643
-
644
- $wcf_individual_use_only = '';
645
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
646
- $wcf_individual_use_only = $this->get_email_template_meta_by_key( $results->id, 'individual_use_only' );
647
- if ( isset( $wcf_individual_use_only->meta_value ) ) {
648
- $wcf_individual_use_only = $wcf_individual_use_only->meta_value ? 'checked' : '';
649
- }
650
- }
651
-
652
- print '<input ' . esc_attr( $wcf_individual_use_only ) . ' id="wcf_individual_use_only" name="wcf_individual_use_only" type="checkbox" value="" />
653
- <span class="description">' . esc_html__( 'Check this box if the coupon cannot be used in conjunction with other coupons.', 'woo-cart-abandonment-recovery' ) . ' </span>';
654
-
655
- ?>
656
- </td>
657
- </tr>
658
- <tr>
659
- <th>
660
- <label class="wcf-sub-heading" for="wcf_apply_coupon_auto"> <?php esc_html_e( 'Auto Apply Coupon', 'woo-cart-abandonment-recovery' ); ?> </label>
661
- </th>
662
- <td>
663
- <?php
664
-
665
- $wcf_apply_coupon_auto = '';
666
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
667
- $wcf_apply_coupon_auto = $this->get_email_template_meta_by_key( $results->id, 'auto_coupon' );
668
-
669
- if ( isset( $wcf_apply_coupon_auto->meta_value ) ) {
670
- $wcf_apply_coupon_auto = $wcf_apply_coupon_auto->meta_value ? 'checked' : '';
671
- }
672
- }
673
-
674
- print '<input ' . esc_attr( $wcf_apply_coupon_auto ) . ' id="wcf_auto_coupon_apply" name="wcf_auto_coupon_apply" type="checkbox" value="" /><span class="description" > ' . esc_html__( ' Automatically add the coupon to the cart at the checkout.', 'woo-cart-abandonment-recovery' ) . ' </span>';
675
- ?>
676
- </td>
677
- </tr>
678
- <tr>
679
- <th>
680
- <label for="wcf_email_subject"><b><?php esc_html_e( 'Send This Email', 'woo-cart-abandonment-recovery' ); ?></b></label>
681
- </th>
682
- <td>
683
- <?php
684
- $frequency_edit = '';
685
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency ) ) {
686
- $frequency_edit = $results->frequency;
687
- }
688
- print '<input style="width:15%" type="number" name="wcf_email_frequency" id="wcf_email_frequency" class="wcf-ca-trigger-input" value="' . esc_attr( $frequency_edit ) . '">';
689
- ?>
690
-
691
- <select name="wcf_email_frequency_unit" id="wcf_email_frequency_unit">
692
- <?php
693
- $frequency_unit = '';
694
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency_unit ) ) {
695
- $frequency_unit = $results->frequency_unit;
696
- }
697
- $days_or_hours = array(
698
- 'MINUTE' => esc_html__( 'Minute(s)', 'woo-cart-abandonment-recovery' ),
699
- 'HOUR' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
700
- 'DAY' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
701
- );
702
- foreach ( $days_or_hours as $key => $value ) {
703
- printf(
704
- "<option %s value='%s'>%s</option>\n",
705
- selected( $key, $frequency_unit, false ),
706
- esc_attr( $key ),
707
- esc_attr( $value )
708
- );
709
- }
710
- ?>
711
- </select>
712
- <span class="description">
713
- <?php esc_html_e( 'after cart is abandoned.', 'woo-cart-abandonment-recovery' ); ?>
714
- </span>
715
-
716
-
717
- </td>
718
- </tr>
719
-
720
- <tr>
721
- <?php $current_user = wp_get_current_user(); ?>
722
- <th>
723
- <label for="wcf_email_preview"><b><?php esc_html_e( 'Send Test Email To:', 'woo-cart-abandonment-recovery' ); ?></b></label>
724
- </th>
725
- <td>
726
- <input class="wcf-ca-trigger-input" type="text" id="wcf_send_test_email" name="send_test_email" value="<?php echo esc_attr( $current_user->user_email ); ?>" class="wcf-ca-trigger-input">
727
- <input class="button" type="button" value=" <?php esc_html_e( 'Send a test email', 'woo-cart-abandonment-recovery' ); ?>" id="wcf_preview_email"/> <br/>
728
-
729
- <label id="mail_response_msg"> </label>
730
- </td>
731
- </tr>
732
-
733
- </table>
734
- </div>
735
- </div>
736
- </div>
737
- <?php wp_nonce_field( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' ); ?>
738
- <p class="submit">
739
- <?php
740
- $button_value = esc_html__( 'Save Changes', 'woo-cart-abandonment-recovery' );
741
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
742
- $button_value = esc_html__( 'Update Changes', 'woo-cart-abandonment-recovery' );
743
- }
744
- ?>
745
- <input type="submit" name="Submit" class="button-primary" value="<?php echo esc_attr( $button_value ); ?>"/>
746
- </p>
747
- </form>
748
- </div>
749
- <?php
750
-
751
- }
752
-
753
-
754
- /**
755
- * Sanitize email post data.
756
- *
757
- * @return array
758
- */
759
- public function sanitize_email_post_data() {
760
-
761
- $input_post_values = array(
762
- 'wcf_email_subject' => array(
763
- 'default' => '',
764
- 'sanitize' => FILTER_SANITIZE_STRING,
765
- ),
766
- 'wcf_email_body' => array(
767
- 'default' => '',
768
- 'sanitize' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
769
- ),
770
- 'wcf_template_name' => array(
771
- 'default' => '',
772
- 'sanitize' => FILTER_SANITIZE_STRING,
773
- ),
774
- 'wcf_email_frequency' => array(
775
- 'default' => 30,
776
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
777
- ),
778
- 'wcf_email_frequency_unit' => array(
779
- 'default' => 'MINUTE',
780
- 'sanitize' => FILTER_SANITIZE_STRING,
781
- ),
782
- 'wcf_activate_email_template' => array(
783
- 'default' => 0,
784
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
785
- ),
786
-
787
- 'wcf_email_discount_type' => array(
788
- 'default' => 'percent',
789
- 'sanitize' => FILTER_SANITIZE_STRING,
790
- ),
791
- 'wcf_email_discount_amount' => array(
792
- 'default' => 10,
793
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
794
- ),
795
- 'wcf_email_coupon_expiry_date' => array(
796
- 'default' => '',
797
- 'sanitize' => FILTER_SANITIZE_STRING,
798
- ),
799
- 'wcf_coupon_expiry_unit' => array(
800
- 'default' => 'hours',
801
- 'sanitize' => FILTER_SANITIZE_STRING,
802
- ),
803
- 'id' => array(
804
- 'default' => null,
805
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
806
- ),
807
- );
808
-
809
- $sanitized_post = array();
810
- foreach ( $input_post_values as $key => $input_post_value ) {
811
-
812
- if ( isset( $_POST[ $key ] ) ) { //phpcs:ignore
813
- $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
814
- } else {
815
- $sanitized_post[ $key ] = $input_post_value['default'];
816
- }
817
- }
818
-
819
- $sanitized_post['wcf_override_global_coupon'] = isset( $_POST['wcf_override_global_coupon'] ) ? true : false; //phpcs:ignore
820
- $sanitized_post['wcf_auto_coupon_apply'] = isset( $_POST['wcf_auto_coupon_apply'] ) ? true : false; //phpcs:ignore
821
- $sanitized_post['wcf_free_shipping_coupon'] = isset( $_POST['wcf_free_shipping_coupon'] ) ? true : false; //phpcs:ignore
822
- $sanitized_post['wcf_individual_use_only'] = isset( $_POST['wcf_individual_use_only'] ) ? true : false; //phpcs:ignore
823
- $sanitized_post['wcf_email_body'] = html_entity_decode( $sanitized_post['wcf_email_body'], ENT_COMPAT, 'UTF-8' );
824
-
825
- return $sanitized_post;
826
-
827
- }
828
-
829
-
830
- /**
831
- * Add email template callback ajax.
832
- */
833
- public function add_email_template() {
834
-
835
- $sanitized_post = $this->sanitize_email_post_data();
836
- $this->wpdb->insert(
837
- $this->cart_abandonment_template_table_name,
838
- array(
839
- 'template_name' => $sanitized_post['wcf_template_name'],
840
- 'email_subject' => $sanitized_post['wcf_email_subject'],
841
- 'email_body' => $sanitized_post['wcf_email_body'],
842
- 'frequency' => $sanitized_post['wcf_email_frequency'],
843
- 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
844
- 'is_activated' => $sanitized_post['wcf_activate_email_template'],
845
- ),
846
- array( '%s', '%s', '%s', '%d', '%s', '%d' )
847
- );
848
-
849
- $email_template_id = $this->wpdb->insert_id;
850
- $meta_data = array(
851
- 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
852
- 'discount_type' => $sanitized_post['wcf_email_discount_type'],
853
- 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
854
- 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
855
- 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
856
- 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
857
- 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
858
- 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
859
-
860
- );
861
-
862
- foreach ( $meta_data as $mera_key => $meta_value ) {
863
- $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
864
- }
865
-
866
- $param = array(
867
- 'page' => WCF_CA_PAGE_NAME,
868
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
869
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
870
- 'id' => $email_template_id,
871
- 'wcf_ca_template_created' => 'YES',
872
- );
873
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
874
- wp_safe_redirect( $redirect_url );
875
-
876
- }
877
-
878
- /**
879
- * Edit email template callback ajax.
880
- */
881
- public function edit_email_template() {
882
- $sanitized_post = $this->sanitize_email_post_data();
883
- $email_template_id = $sanitized_post['id'];
884
-
885
- $this->wpdb->update(
886
- $this->cart_abandonment_template_table_name,
887
- array(
888
- 'template_name' => $sanitized_post['wcf_template_name'],
889
- 'email_subject' => $sanitized_post['wcf_email_subject'],
890
- 'email_body' => $sanitized_post['wcf_email_body'],
891
- 'frequency' => $sanitized_post['wcf_email_frequency'],
892
- 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
893
- 'is_activated' => $sanitized_post['wcf_activate_email_template'],
894
- ),
895
- array( 'id' => $email_template_id ),
896
- array( '%s', '%s', '%s', '%d', '%s', '%d' ),
897
- array( '%d' )
898
- );
899
-
900
- $meta_data = array(
901
- 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
902
- 'discount_type' => $sanitized_post['wcf_email_discount_type'],
903
- 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
904
- 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
905
- 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
906
- 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
907
- 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
908
- 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
909
-
910
- );
911
- foreach ( $meta_data as $mera_key => $meta_value ) {
912
- $this->update_email_template_meta( $email_template_id, $mera_key, $meta_value );
913
- }
914
-
915
- $param = array(
916
- 'page' => WCF_CA_PAGE_NAME,
917
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
918
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
919
- 'id' => $email_template_id,
920
- 'wcf_ca_template_updated' => 'YES',
921
- );
922
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
923
-
924
- wp_safe_redirect( $redirect_url );
925
-
926
- }
927
-
928
- /**
929
- * Restore default email templates.
930
- */
931
- public function restore_email_templates() {
932
-
933
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
934
-
935
- if ( $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
936
-
937
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
938
- $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
939
- $db->template_table_seeder( true );
940
-
941
- $param = array(
942
- 'page' => WCF_CA_PAGE_NAME,
943
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
944
- 'wcf_ca_template_restored' => 'YES',
945
- );
946
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
947
- wp_safe_redirect( $redirect_url );
948
- }
949
-
950
- }
951
-
952
- /**
953
- * Update the meta values.
954
- *
955
- * @param integer $email_template_id email template id.
956
- * @param string $meta_key meta key.
957
- * @param string $meta_value meta value.
958
- */
959
- public function update_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
960
-
961
- $template_meta = $this->get_email_template_meta_by_key( $email_template_id, $meta_key );
962
-
963
- if ( $template_meta ) {
964
- $this->wpdb->update(
965
- $this->email_templates_meta_table,
966
- array(
967
- 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
968
- ),
969
- array(
970
- 'email_template_id' => $email_template_id,
971
- 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
972
- )
973
- );
974
- } else {
975
- $this->add_email_template_meta( $email_template_id, $meta_key, $meta_value );
976
- }
977
-
978
- }
979
-
980
-
981
- /**
982
- * Add the meta values.
983
- *
984
- * @param integer $email_template_id email template id.
985
- * @param string $meta_key meta key.
986
- * @param string $meta_value meta value.
987
- */
988
- public function add_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
989
- $this->wpdb->insert(
990
- $this->email_templates_meta_table,
991
- array(
992
- 'email_template_id' => $email_template_id,
993
- 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
994
- 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
995
- )
996
- );
997
- }
998
-
999
- /**
1000
- * Get the meta values.
1001
- *
1002
- * @param integer $email_template_id email template id.
1003
- * @param string $meta_key meta key.
1004
- */
1005
- public function get_email_template_meta_by_key( $email_template_id, $meta_key ) {
1006
- return $this->wpdb->get_row(
1007
- $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
1008
- );
1009
- }
1010
-
1011
- /**
1012
- * Render email template grid.
1013
- */
1014
- public function show_email_template_data_table() {
1015
- $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
1016
- $wcf_template_list->prepare_items();
1017
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
1018
- ?>
1019
- <div class="wrap">
1020
- <form id="wcf-cart-abandonment-template-table" method="GET">
1021
- <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
1022
- <input type="hidden" name="action" value="<?php echo esc_html( WCF_ACTION_EMAIL_TEMPLATES ); ?>"/>
1023
- <input type="hidden" name="sub_action" value="<?php echo esc_html( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES ); ?>"/>
1024
- <?php $wcf_template_list->display(); ?>
1025
- </form>
1026
- </div>
1027
- <?php
1028
- }
1029
-
1030
- /**
1031
- * Render 'Add Email Template button'.
1032
- */
1033
- public function show_add_new_template_button() {
1034
- $param = array(
1035
- 'page' => WCF_CA_PAGE_NAME,
1036
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
1037
- 'sub_action' => WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES,
1038
- );
1039
-
1040
- $add_new_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1041
-
1042
- $param['sub_action'] = WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES;
1043
- $restore_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1044
-
1045
- ?>
1046
- <div class="wcf-ca-report-btn">
1047
- <div class="wcf-ca-left-report-field-group">
1048
- <a style="cursor: pointer" href="<?php echo esc_url( $add_new_template_url ); ?>" class="button-secondary"><?php esc_html_e( 'Create New Template', 'woo-cart-abandonment-recovery' ); ?></a>
1049
- </div>
1050
- <div class="wcf-ca-right-report-field-group">
1051
- <a onclick="return confirm('Are you sure to restore email templates?');" style="cursor: pointer" href="<?php echo esc_url( $restore_template_url ); ?>" class="button-secondary"><?php esc_html_e( ' Restore Default Templates', 'woo-cart-abandonment-recovery' ); ?></a>
1052
- </div>
1053
- </div>
1054
- <?php
1055
- }
1056
-
1057
- /**
1058
- * Get all active templates.
1059
- *
1060
- * @return array|object|null
1061
- */
1062
- public function fetch_all_active_templates() {
1063
- $result = $this->wpdb->get_results(
1064
- $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE is_activated = %s', true) // phpcs:ignore
1065
- );
1066
- return $result;
1067
- }
1068
-
1069
- /**
1070
- * Get specific template by id.
1071
- *
1072
- * @param integer $tmpl_id template id.
1073
- * @return array|object|void|null
1074
- */
1075
- public function get_template_by_id( $tmpl_id ) {
1076
- $result = $this->wpdb->get_row(
1077
- $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE id = %s', $tmpl_id) // phpcs:ignore
1078
- );
1079
- return $result;
1080
- }
1081
-
1082
- /**
1083
- * Get the email history.
1084
- *
1085
- * @param integer $email_history_id email history id.
1086
- * @return array|object|void|null
1087
- */
1088
- public function get_email_history_by_id( $email_history_id ) {
1089
- $result = $this->wpdb->get_row(
1090
- $this->wpdb->prepare('SELECT * FROM `' . $this->email_history_table . '` WHERE id = %s', $email_history_id) // phpcs:ignore
1091
- );
1092
- return $result;
1093
- }
1094
- }
1095
-
1096
- 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
+
65
+
66
+
67
+ /**
68
+ * Constructor function that initializes required actions and hooks
69
+ */
70
+ public function __construct() {
71
+ $this->define_template_constants();
72
+ global $wpdb;
73
+ $this->cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
74
+ $this->email_templates_meta_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
75
+ $this->email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
76
+ $this->wpdb = $wpdb;
77
+
78
+ add_action( 'admin_enqueue_scripts', __class__ . '::load_email_templates_script', 15 );
79
+ add_action( 'wp_ajax_activate_email_templates', array( $this, 'update_email_toggle_button' ) );
80
+ }
81
+
82
+
83
+
84
+
85
+ /**
86
+ * Add email template JS script.
87
+ */
88
+ public static function load_email_templates_script() {
89
+
90
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
91
+
92
+ if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
93
+ return;
94
+ }
95
+
96
+ wp_enqueue_script( 'jquery-ui-datepicker' );
97
+ wp_enqueue_style( 'jquery-ui-style' );
98
+
99
+ wp_enqueue_script(
100
+ 'cartflows-ca-email-tmpl-settings',
101
+ CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
102
+ array( 'jquery' ),
103
+ CARTFLOWS_CA_VER,
104
+ false
105
+ );
106
+
107
+ $current_user = wp_get_current_user();
108
+ $vars = array(
109
+ 'email' => $current_user->user_email,
110
+ 'name' => $current_user->user_firstname,
111
+ 'surname' => $current_user->user_lastname,
112
+ 'phone' => get_user_meta( $current_user->ID, 'billing_phone', true ),
113
+ 'billing_company' => get_user_meta( $current_user->ID, 'billing_company', true ),
114
+ 'billing_address_1' => get_user_meta( $current_user->ID, 'billing_address_1', true ),
115
+ 'billing_address_2' => get_user_meta( $current_user->ID, 'billing_address_2', true ),
116
+ 'billing_state' => get_user_meta( $current_user->ID, 'billing_state', true ),
117
+ 'billing_postcode' => get_user_meta( $current_user->ID, 'billing_postcode', true ),
118
+ 'shipping_first_name' => $current_user->user_firstname,
119
+ 'shipping_last_name' => $current_user->user_lastname,
120
+ 'shipping_company' => get_user_meta( $current_user->ID, 'shipping_company', true ),
121
+ 'shipping_address_1' => get_user_meta( $current_user->ID, 'shipping_address_1', true ),
122
+ 'shipping_address_2' => get_user_meta( $current_user->ID, 'shipping_address_2', true ),
123
+ 'shipping_city' => get_user_meta( $current_user->ID, 'shipping_city', true ),
124
+ 'shipping_state' => get_user_meta( $current_user->ID, 'shipping_state', true ),
125
+ 'shipping_postcode' => get_user_meta( $current_user->ID, 'shipping_postcode', true ),
126
+ 'woo_currency_symbol' => get_woocommerce_currency_symbol(),
127
+ 'email_toggle_button_nonce' => wp_create_nonce( 'activate_email_templates' ),
128
+ 'admin_firstname' => __( 'Admin Firstname', 'woo-cart-abandonment-recovery' ),
129
+ 'admin_company' => __( 'Admin Company', 'woo-cart-abandonment-recovery' ),
130
+ 'abandoned_product_details_table' => __( 'Abandoned Product Details Table', 'woo-cart-abandonment-recovery' ),
131
+ 'abandoned_product_names' => __( 'Abandoned Product Names', 'woo-cart-abandonment-recovery' ),
132
+ 'cart_checkout_url' => __( 'Cart Checkout URL', 'woo-cart-abandonment-recovery' ),
133
+ 'coupon_code' => __( 'Coupon Code', 'woo-cart-abandonment-recovery' ),
134
+ 'customer_firstname' => __( 'Customer First Name', 'woo-cart-abandonment-recovery' ),
135
+ 'customer_lastname' => __( 'Customer Last Name', 'woo-cart-abandonment-recovery' ),
136
+ 'customer_full_name' => __( 'Customer Full Name', 'woo-cart-abandonment-recovery' ),
137
+ 'cart_abandonment_date' => __( 'Cart Abandonment Date', 'woo-cart-abandonment-recovery' ),
138
+ 'site_url' => __( 'Site URL', 'woo-cart-abandonment-recovery' ),
139
+ 'unsubscribe_link' => __( 'Unsubscribe Link', 'woo-cart-abandonment-recovery' ),
140
+ );
141
+ wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'wcf_ca_details', $vars );
142
+
143
+ }
144
+
145
+
146
+ /**
147
+ * Update the activate email template toggle button.
148
+ */
149
+ public function update_email_toggle_button() {
150
+
151
+ check_ajax_referer( 'activate_email_templates', 'security' );
152
+ global $wpdb;
153
+ $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
154
+
155
+ $id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
156
+
157
+ $is_activated = filter_input( INPUT_POST, 'state', FILTER_SANITIZE_STRING );
158
+
159
+ $response = __( 'Something went wrong', 'woo-cart-abandonment-recovery' );
160
+ if ( ! isset( $is_activated ) || ! isset( $id ) ) {
161
+ wp_send_json_error( $response );
162
+ }
163
+
164
+ if ( $is_activated && 'on' === $is_activated ) {
165
+ $is_activated = 1;
166
+ $response = __( 'Activated', 'woo-cart-abandonment-recovery' );
167
+ } else {
168
+ $is_activated = 0;
169
+ $response = __( 'Deactivated', 'woo-cart-abandonment-recovery' );
170
+ }
171
+
172
+ $wpdb->query( $wpdb->prepare( "UPDATE {$cart_abandonment_template_table_name} SET is_activated = %d WHERE id = %d ", $is_activated, $id ), ARRAY_A ); // phpcs:ignore
173
+ wp_send_json_success( $response );
174
+
175
+ }
176
+
177
+ /**
178
+ * Initialise all the constants
179
+ */
180
+ public function define_template_constants() {
181
+ define( 'WCF_CA_PAGE_NAME', 'woo-cart-abandonment-recovery' );
182
+
183
+ define( 'WCF_CA_GENERAL_SETTINGS_SECTION', 'cartflows_cart_abandonment_settings_section' );
184
+ define( 'WCF_CA_COUPONS_SETTINGS_SECTION', 'cartflows_cart_abandonment_coupons_settings_section' );
185
+ define( 'WCF_CA_EMAIL_SETTINGS_SECTION', 'cartflows_email_template_settings_section' );
186
+ define( 'WCF_CA_COUPON_CODE_SECTION', 'cartflows_coupon_code_settings_section' );
187
+ define( 'WCF_CA_ZAPIER_SETTINGS_SECTION', 'cartflows_zapier_settings_section' );
188
+ define( 'WCF_CA_GDPR_SETTINGS_SECTION', 'cartflows_gdpr_settings_section' );
189
+
190
+ define( 'WCF_CA_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-settings' );
191
+ define( 'WCF_CA_EMAIL_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-email-settings' );
192
+
193
+ define( 'WCF_ACTION_EMAIL_TEMPLATES', 'email_tmpl' );
194
+
195
+ define( 'WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES', 'add_email_tmpl' );
196
+ define( 'WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES', 'edit_email_tmpl' );
197
+ define( 'WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES', 'delete_email_tmpl' );
198
+ define( 'WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES', 'clone_email_tmpl' );
199
+ define( 'WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES', 'delete_bulk_email_tmpl' );
200
+ define( 'WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES', 'save_email_template' );
201
+ define( 'WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES', 'restore_default_email_tmpl' );
202
+
203
+ define( 'WCF_SUB_ACTION_CART_ABANDONMENT_SETTINGS', 'cart_abandonment_settings' );
204
+ define( 'WCF_SUB_ACTION_EMAIL_SETTINGS', 'email_settings' );
205
+ define( 'WCF_SUB_ACTION_COUPON_CODE_SETTINGS', 'coupon_code_settings' );
206
+ define( 'WCF_SUB_ACTION_ZAPIER_SETTINGS', 'zapier_settings' );
207
+
208
+ define( 'WCF_EMAIL_TEMPLATES_NONCE', 'email_template_nonce' );
209
+
210
+ }
211
+
212
+ /**
213
+ * Show success messages for email templates.
214
+ */
215
+ public function show_messages() {
216
+
217
+ $wcf_ca_template_created = filter_input( INPUT_GET, 'wcf_ca_template_created', FILTER_SANITIZE_STRING );
218
+ $wcf_ca_template_cloned = filter_input( INPUT_GET, 'wcf_ca_template_cloned', FILTER_SANITIZE_STRING );
219
+ $wcf_ca_template_deleted = filter_input( INPUT_GET, 'wcf_ca_template_deleted', FILTER_SANITIZE_STRING );
220
+ $wcf_ca_template_updated = filter_input( INPUT_GET, 'wcf_ca_template_updated', FILTER_SANITIZE_STRING );
221
+ $wcf_ca_template_restored = filter_input( INPUT_GET, 'wcf_ca_template_restored', FILTER_SANITIZE_STRING );
222
+
223
+ ?>
224
+ <?php if ( 'YES' === $wcf_ca_template_created ) { ?>
225
+ <div id="message" class="notice notice-success is-dismissible">
226
+ <p>
227
+ <strong>
228
+ <?php esc_html_e( 'The Email Template has been successfully added.', 'woo-cart-abandonment-recovery' ); ?>
229
+ </strong>
230
+ </p>
231
+ </div>
232
+ <?php } ?>
233
+
234
+ <?php if ( 'YES' === $wcf_ca_template_cloned ) { ?>
235
+ <div id="message" class="notice notice-success is-dismissible">
236
+ <p>
237
+ <strong>
238
+ <?php esc_html_e( 'The Email Template has been cloned successfully.', 'woo-cart-abandonment-recovery' ); ?>
239
+ </strong>
240
+ </p>
241
+ </div>
242
+ <?php } ?>
243
+
244
+ <?php if ( 'YES' === $wcf_ca_template_deleted ) { ?>
245
+ <div id="message" class="notice notice-success is-dismissible">
246
+ <p>
247
+ <strong>
248
+ <?php esc_html_e( 'The Email Template has been successfully deleted.', 'woo-cart-abandonment-recovery' ); ?>
249
+ </strong>
250
+ </p>
251
+ </div>
252
+ <?php } ?>
253
+ <?php if ( 'YES' === $wcf_ca_template_updated ) { ?>
254
+ <div id="message" class="notice notice-success is-dismissible">
255
+ <p>
256
+ <strong>
257
+ <?php esc_html_e( 'The Email Template has been successfully updated.', 'woo-cart-abandonment-recovery' ); ?>
258
+ </strong>
259
+ </p>
260
+ </div>
261
+ <?php } ?>
262
+
263
+ <?php if ( 'YES' === $wcf_ca_template_restored ) { ?>
264
+ <div id="message" class="notice notice-success is-dismissible">
265
+ <p>
266
+ <strong>
267
+ <?php esc_html_e( 'Default Email Templates has been restored successfully.', 'woo-cart-abandonment-recovery' ); ?>
268
+ </strong>
269
+ </p>
270
+ </div>
271
+ <?php } ?>
272
+ <?php
273
+
274
+ }
275
+
276
+ /**
277
+ * Delete bulk email templates.
278
+ */
279
+ public function delete_bulk_templates() {
280
+ $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
281
+ $wcf_template_list->process_bulk_action();
282
+ $param = array(
283
+ 'page' => WCF_CA_PAGE_NAME,
284
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
285
+ 'wcf_ca_template_deleted' => 'YES',
286
+ );
287
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
288
+ wp_safe_redirect( $redirect_url );
289
+ }
290
+
291
+
292
+ /**
293
+ * Delete email templates.
294
+ */
295
+ public function delete_single_template() {
296
+
297
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
298
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
299
+
300
+ if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
301
+
302
+ $this->wpdb->delete(
303
+ $this->cart_abandonment_template_table_name,
304
+ array( 'id' => $id ),
305
+ '%d'
306
+ );
307
+ $param = array(
308
+ 'page' => WCF_CA_PAGE_NAME,
309
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
310
+ 'wcf_ca_template_deleted' => 'YES',
311
+ );
312
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
313
+ wp_safe_redirect( $redirect_url );
314
+
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Delete email templates.
320
+ */
321
+ public function clone_email_template() {
322
+
323
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
324
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
325
+
326
+ if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
327
+
328
+ $email_template = $this->get_template_by_id( $id );
329
+
330
+ $this->wpdb->insert(
331
+ $this->cart_abandonment_template_table_name,
332
+ array(
333
+ 'template_name' => sanitize_text_field( $email_template->template_name ),
334
+ 'email_subject' => sanitize_text_field( $email_template->email_subject ),
335
+ 'email_body' => $email_template->email_body,
336
+ 'frequency' => intval( sanitize_text_field( $email_template->frequency ) ),
337
+ 'frequency_unit' => sanitize_text_field( $email_template->frequency_unit ),
338
+
339
+ ),
340
+ array( '%s', '%s', '%s', '%d', '%s' )
341
+ );
342
+
343
+ $email_template_id = $this->wpdb->insert_id;
344
+ $meta_data = array(
345
+ 'override_global_coupon' => false,
346
+ 'discount_type' => 'percent',
347
+ 'coupon_amount' => 10,
348
+ 'coupon_expiry_date' => '',
349
+ 'coupon_expiry_unit' => 'hours',
350
+
351
+ );
352
+
353
+ foreach ( $meta_data as $mera_key => $meta_value ) {
354
+ $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
355
+ }
356
+
357
+ $param = array(
358
+ 'page' => WCF_CA_PAGE_NAME,
359
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
360
+ 'wcf_ca_template_cloned' => 'YES',
361
+ );
362
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
363
+ wp_safe_redirect( $redirect_url );
364
+
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Get email template by id.
370
+ *
371
+ * @param int $email_tmpl_id template id.
372
+ */
373
+ public function get_email_template_by_id( $email_tmpl_id ) {
374
+
375
+ $query = 'SELECT * FROM ' . $this->cart_abandonment_template_table_name . ' WHERE id = %d ';
376
+ return $this->wpdb->get_row($this->wpdb->prepare($query, $email_tmpl_id)); // phpcs:ignore
377
+
378
+ }
379
+
380
+ /**
381
+ * Render email template add/edit form.
382
+ *
383
+ * @param string $sub_action sub_action.
384
+ */
385
+ public function render_email_template_form( $sub_action = WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES ) {
386
+
387
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
388
+
389
+ if ( $id ) {
390
+ $results = $this->get_email_template_by_id( $id );
391
+ }
392
+
393
+ ?>
394
+
395
+ <div id="content">
396
+
397
+ <?php
398
+ $param = array(
399
+ 'page' => WCF_CA_PAGE_NAME,
400
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
401
+ 'sub_action' => WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES,
402
+ );
403
+ $save_template_url = esc_url( add_query_arg( $param, admin_url( '/admin.php' ) ) );
404
+ ?>
405
+
406
+ <form method="post" action="<?php echo esc_attr( $save_template_url ); ?>" id="wcf_settings">
407
+ <input type="hidden" name="sub_action" value="<?php echo esc_attr( $sub_action ); ?>"/>
408
+ <?php
409
+ $id_by = '';
410
+ if ( isset( $id ) ) {
411
+ $id_by = $id;
412
+ }
413
+ ?>
414
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id_by ); ?>"/>
415
+ <?php
416
+
417
+ $button_sub_action = 'save';
418
+ $display_message = 'Add New Email Template:';
419
+
420
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
421
+ $button_sub_action = 'update';
422
+ $display_message = 'Edit Email Template:';
423
+ }
424
+ print '<input type="hidden" name="wcf_settings_frm" value="' . esc_attr( $button_sub_action ) . '">';
425
+ ?>
426
+ <div id="poststuff">
427
+ <div> <!-- <div class="postbox" > -->
428
+ <h3><?php esc_html_e($display_message, 'woo-cart-abandonment-recovery'); // phpcs:ignore ?></h3>
429
+ <hr/>
430
+ <div>
431
+ <table class="form-table" id="addedit_template">
432
+ <tr>
433
+ <th>
434
+ <label for="wcf_email_subject"><b><?php esc_html_e( 'Activate Template now?', 'woo-cart-abandonment-recovery' ); ?></b></label>
435
+ </th>
436
+ <td>
437
+ <?php
438
+ $is_activated = '';
439
+ $active_status = 0;
440
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->is_activated ) ) {
441
+ $active_status = stripslashes( $results->is_activated );
442
+ $is_activated = $active_status ? 'on' : 'off';
443
+
444
+ }
445
+ print '<button type="button" class="wcf-ca-switch wcf-toggle-template-status" wcf-template-id="1" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
446
+ print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
447
+ ?>
448
+
449
+ </td>
450
+ </tr>
451
+
452
+ <tr>
453
+ <th>
454
+ <label for="wcf_template_name"><b><?php esc_html_e( 'Template Name:', 'woo-cart-abandonment-recovery' ); ?></b></label>
455
+ </th>
456
+ <td>
457
+ <?php
458
+ $template_name = '';
459
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->template_name ) ) {
460
+ $template_name = $results->template_name;
461
+ }
462
+ print '<input type="text" name="wcf_template_name" id="wcf_template_name" class="wcf-ca-trigger-input" value="' . esc_attr( $template_name ) . '">';
463
+ ?>
464
+ </td>
465
+ </tr>
466
+
467
+ <tr>
468
+ <th>
469
+ <label for="wcf_email_subject"><b><?php esc_html_e( 'Email Subject:', 'woo-cart-abandonment-recovery' ); ?></b></label>
470
+ </th>
471
+ <td>
472
+ <?php
473
+ $subject_edit = '';
474
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_subject ) ) {
475
+ $subject_edit = stripslashes( $results->email_subject );
476
+ }
477
+ print '<input type="text" name="wcf_email_subject" id="wcf_email_subject" class="wcf-ca-trigger-input" value="' . esc_attr( $subject_edit ) . '">';
478
+ ?>
479
+ </td>
480
+ </tr>
481
+
482
+ <tr>
483
+ <th>
484
+ <label for="wcf_email_body"><b><?php esc_html_e( 'Email Body:', 'woo-cart-abandonment-recovery' ); ?></b></label>
485
+ </th>
486
+ <td>
487
+ <?php
488
+ $initial_data = '';
489
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_body ) ) {
490
+ $initial_data = stripslashes( $results->email_body );
491
+ }
492
+
493
+ wp_editor(
494
+ $initial_data,
495
+ 'wcf_email_body',
496
+ array(
497
+ 'media_buttons' => true,
498
+ 'textarea_rows' => 15,
499
+ 'tabindex' => 4,
500
+ 'tinymce' => array(
501
+ 'theme_advanced_buttons1' => 'bold,italic,underline,|,bullist,numlist,blockquote,|,link,unlink,|,spellchecker,fullscreen,|,formatselect,styleselect',
502
+ ),
503
+ )
504
+ );
505
+
506
+ ?>
507
+ <?php echo stripslashes( get_option( 'wcf_email_body' ) ); //phpcs:ignore ?>
508
+ </td>
509
+ </tr>
510
+
511
+ <tr>
512
+ <th>
513
+ <label for="wcf_override_global_coupon"><b><?php esc_html_e( 'Create Coupon', 'woo-cart-abandonment-recovery' ); ?></b></label>
514
+ </th>
515
+ <td>
516
+ <?php
517
+
518
+ $wcf_override_global_coupon = '';
519
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
520
+ $wcf_override_global_coupon = $this->get_email_template_meta_by_key( $results->id, 'override_global_coupon' );
521
+ if ( isset( $wcf_override_global_coupon->meta_value ) ) {
522
+ $wcf_override_global_coupon = $wcf_override_global_coupon->meta_value ? 'checked' : '';
523
+ }
524
+ }
525
+
526
+ print '<input ' . esc_attr( $wcf_override_global_coupon ) . ' id="wcf_override_global_coupon" name="wcf_override_global_coupon" type="checkbox" value="" /><span class="description">' . esc_html__( 'Allows you to send new coupon only for this template.', 'woo-cart-abandonment-recovery' ) . '</span>';
527
+ ?>
528
+ </td>
529
+ </tr>
530
+
531
+ <tr>
532
+ <th>
533
+ <label class="wcf-sub-heading" for="wcf_email_discount_type"> <?php esc_html_e( 'Discount Type', 'woo-cart-abandonment-recovery' ); ?> </label>
534
+ </th>
535
+ <td>
536
+ <?php
537
+
538
+ $wcf_email_discount_type = 'percent';
539
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
540
+ $wcf_email_discount_type = $this->get_email_template_meta_by_key( $results->id, 'discount_type' );
541
+ if ( isset( $wcf_email_discount_type->meta_value ) ) {
542
+ $wcf_email_discount_type = $wcf_email_discount_type->meta_value;
543
+ }
544
+ }
545
+
546
+ $dropdown_options = array(
547
+ 'percent' => 'Percentage discount',
548
+ 'fixed_cart' => 'Fixed cart discount',
549
+ );
550
+
551
+ echo '<select id="wcf_email_discount_type" name="wcf_email_discount_type">';
552
+ foreach ( $dropdown_options as $key => $value ) {
553
+ $is_selected = $key === $wcf_email_discount_type ? 'selected' : '';
554
+ echo '<option ' . esc_attr( $is_selected ) . ' value=' . esc_attr( $key ) . '>' . esc_attr( $value ) . '</option>';
555
+
556
+ }
557
+ echo '</select>';
558
+
559
+ ?>
560
+ </td>
561
+ </tr>
562
+
563
+ <tr>
564
+ <th>
565
+ <label class="wcf-sub-heading" for="wcf_email_discount_amount"> <?php esc_html_e( 'Coupon Amount', 'woo-cart-abandonment-recovery' ); ?> </label>
566
+ </th>
567
+ <td>
568
+ <?php
569
+ $wcf_email_discount_amount = 10;
570
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
571
+ $wcf_email_discount_amount = $this->get_email_template_meta_by_key( $results->id, 'coupon_amount' );
572
+ if ( isset( $wcf_email_discount_amount->meta_value ) ) {
573
+ $wcf_email_discount_amount = $wcf_email_discount_amount->meta_value;
574
+ }
575
+ }
576
+ print '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="number" id="wcf_email_discount_amount" name="wcf_email_discount_amount" value="' . esc_attr( $wcf_email_discount_amount ) . '">';
577
+ ?>
578
+ </td>
579
+ </tr>
580
+
581
+ <tr>
582
+ <th>
583
+ <label class="wcf-sub-heading" for="wcf_email_coupon_expiry_date"> <?php esc_html_e( 'Coupon expiry date', 'woo-cart-abandonment-recovery' ); ?> </label>
584
+ </th>
585
+ <td>
586
+ <?php
587
+ $wcf_email_coupon_expiry_date = 0;
588
+ $coupon_expiry_unit = 'hours';
589
+
590
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
591
+ $wcf_email_coupon_expiry_date = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_date' );
592
+ $wcf_email_coupon_expiry_unit = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_unit' );
593
+
594
+ if ( isset( $wcf_email_coupon_expiry_date->meta_value ) ) {
595
+ $wcf_email_coupon_expiry_date = $wcf_email_coupon_expiry_date->meta_value;
596
+ }
597
+ if ( isset( $wcf_email_coupon_expiry_unit->meta_value ) ) {
598
+ $coupon_expiry_unit = $wcf_email_coupon_expiry_unit->meta_value;
599
+ }
600
+ }
601
+ 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" />';
602
+ $items = array(
603
+ 'hours' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
604
+ 'days' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
605
+ );
606
+ echo "<select id='wcf_coupon_expiry_unit' name='wcf_coupon_expiry_unit'>";
607
+ foreach ( $items as $key => $item ) {
608
+ $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
609
+ echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
610
+ }
611
+ echo '</select>';
612
+
613
+ echo " <span class='description'>" . esc_html__( 'Enter zero (0) to restrict coupon from expiring', 'woo-cart-abandonment-recovery' ) . ' </span>'
614
+ ?>
615
+ </td>
616
+ </tr>
617
+ <tr>
618
+ <th>
619
+ <label class="wcf-sub-heading" for="wcf_free_shipping_coupon"> <?php esc_html_e( 'Free Shipping', 'woo-cart-abandonment-recovery' ); ?> </label>
620
+ </th>
621
+ <td>
622
+ <?php
623
+
624
+ $wcf_free_shipping_coupon = '';
625
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
626
+ $wcf_free_shipping_coupon = $this->get_email_template_meta_by_key( $results->id, 'free_shipping_coupon' );
627
+ if ( isset( $wcf_free_shipping_coupon->meta_value ) ) {
628
+ $wcf_free_shipping_coupon = $wcf_free_shipping_coupon->meta_value ? 'checked' : '';
629
+ }
630
+ }
631
+
632
+ print '<input ' . esc_attr( $wcf_free_shipping_coupon ) . ' id="wcf_free_shipping_coupon" name="wcf_free_shipping_coupon" type="checkbox" value="" /><span class="description"> ' . esc_html__( 'Allows you to grant free shipping. A free shipping method must be enabled in your shipping zone and be set to require "a valid free shipping coupon". ', 'woo-cart-abandonment-recovery' ) . '</span>';
633
+
634
+ ?>
635
+ </td>
636
+ </tr>
637
+ <tr>
638
+ <th>
639
+ <label class="wcf-sub-heading" for="wcf_individual_use_only"><?php esc_html_e( 'Individual use only', 'woo-cart-abandonment-recovery' ); ?></label>
640
+ </th>
641
+ <td>
642
+ <?php
643
+
644
+ $wcf_individual_use_only = '';
645
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
646
+ $wcf_individual_use_only = $this->get_email_template_meta_by_key( $results->id, 'individual_use_only' );
647
+ if ( isset( $wcf_individual_use_only->meta_value ) ) {
648
+ $wcf_individual_use_only = $wcf_individual_use_only->meta_value ? 'checked' : '';
649
+ }
650
+ }
651
+
652
+ print '<input ' . esc_attr( $wcf_individual_use_only ) . ' id="wcf_individual_use_only" name="wcf_individual_use_only" type="checkbox" value="" />
653
+ <span class="description">' . esc_html__( 'Check this box if the coupon cannot be used in conjunction with other coupons.', 'woo-cart-abandonment-recovery' ) . ' </span>';
654
+
655
+ ?>
656
+ </td>
657
+ </tr>
658
+ <tr>
659
+ <th>
660
+ <label class="wcf-sub-heading" for="wcf_apply_coupon_auto"> <?php esc_html_e( 'Auto Apply Coupon', 'woo-cart-abandonment-recovery' ); ?> </label>
661
+ </th>
662
+ <td>
663
+ <?php
664
+
665
+ $wcf_apply_coupon_auto = '';
666
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
667
+ $wcf_apply_coupon_auto = $this->get_email_template_meta_by_key( $results->id, 'auto_coupon' );
668
+
669
+ if ( isset( $wcf_apply_coupon_auto->meta_value ) ) {
670
+ $wcf_apply_coupon_auto = $wcf_apply_coupon_auto->meta_value ? 'checked' : '';
671
+ }
672
+ }
673
+
674
+ print '<input ' . esc_attr( $wcf_apply_coupon_auto ) . ' id="wcf_auto_coupon_apply" name="wcf_auto_coupon_apply" type="checkbox" value="" /><span class="description" > ' . esc_html__( ' Automatically add the coupon to the cart at the checkout.', 'woo-cart-abandonment-recovery' ) . ' </span>';
675
+ ?>
676
+ </td>
677
+ </tr>
678
+ <tr>
679
+ <th>
680
+ <label for="wcf_email_subject"><b><?php esc_html_e( 'Send This Email', 'woo-cart-abandonment-recovery' ); ?></b></label>
681
+ </th>
682
+ <td>
683
+ <?php
684
+ $frequency_edit = '';
685
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency ) ) {
686
+ $frequency_edit = $results->frequency;
687
+ }
688
+ print '<input style="width:15%" type="number" name="wcf_email_frequency" id="wcf_email_frequency" class="wcf-ca-trigger-input" value="' . esc_attr( $frequency_edit ) . '">';
689
+ ?>
690
+
691
+ <select name="wcf_email_frequency_unit" id="wcf_email_frequency_unit">
692
+ <?php
693
+ $frequency_unit = '';
694
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency_unit ) ) {
695
+ $frequency_unit = $results->frequency_unit;
696
+ }
697
+ $days_or_hours = array(
698
+ 'MINUTE' => esc_html__( 'Minute(s)', 'woo-cart-abandonment-recovery' ),
699
+ 'HOUR' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
700
+ 'DAY' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
701
+ );
702
+ foreach ( $days_or_hours as $key => $value ) {
703
+ printf(
704
+ "<option %s value='%s'>%s</option>\n",
705
+ selected( $key, $frequency_unit, false ),
706
+ esc_attr( $key ),
707
+ esc_attr( $value )
708
+ );
709
+ }
710
+ ?>
711
+ </select>
712
+ <span class="description">
713
+ <?php esc_html_e( 'after cart is abandoned.', 'woo-cart-abandonment-recovery' ); ?>
714
+ </span>
715
+
716
+
717
+ </td>
718
+ </tr>
719
+
720
+ <tr>
721
+ <?php $current_user = wp_get_current_user(); ?>
722
+ <th>
723
+ <label for="wcf_email_preview"><b><?php esc_html_e( 'Send Test Email To:', 'woo-cart-abandonment-recovery' ); ?></b></label>
724
+ </th>
725
+ <td>
726
+ <input class="wcf-ca-trigger-input" type="text" id="wcf_send_test_email" name="send_test_email" value="<?php echo esc_attr( $current_user->user_email ); ?>" class="wcf-ca-trigger-input">
727
+ <input class="button" type="button" value=" <?php esc_html_e( 'Send a test email', 'woo-cart-abandonment-recovery' ); ?>" id="wcf_preview_email"/> <br/>
728
+
729
+ <label id="mail_response_msg"> </label>
730
+ </td>
731
+ </tr>
732
+
733
+ </table>
734
+ </div>
735
+ </div>
736
+ </div>
737
+ <?php wp_nonce_field( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' ); ?>
738
+ <p class="submit">
739
+ <?php
740
+ $button_value = esc_html__( 'Save Changes', 'woo-cart-abandonment-recovery' );
741
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
742
+ $button_value = esc_html__( 'Update Changes', 'woo-cart-abandonment-recovery' );
743
+ }
744
+ ?>
745
+ <input type="submit" name="Submit" class="button-primary" value="<?php echo esc_attr( $button_value ); ?>"/>
746
+ </p>
747
+ </form>
748
+ </div>
749
+ <?php
750
+
751
+ }
752
+
753
+
754
+ /**
755
+ * Sanitize email post data.
756
+ *
757
+ * @return array
758
+ */
759
+ public function sanitize_email_post_data() {
760
+
761
+ $input_post_values = array(
762
+ 'wcf_email_subject' => array(
763
+ 'default' => '',
764
+ 'sanitize' => FILTER_SANITIZE_STRING,
765
+ ),
766
+ 'wcf_email_body' => array(
767
+ 'default' => '',
768
+ 'sanitize' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
769
+ ),
770
+ 'wcf_template_name' => array(
771
+ 'default' => '',
772
+ 'sanitize' => FILTER_SANITIZE_STRING,
773
+ ),
774
+ 'wcf_email_frequency' => array(
775
+ 'default' => 30,
776
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
777
+ ),
778
+ 'wcf_email_frequency_unit' => array(
779
+ 'default' => 'MINUTE',
780
+ 'sanitize' => FILTER_SANITIZE_STRING,
781
+ ),
782
+ 'wcf_activate_email_template' => array(
783
+ 'default' => 0,
784
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
785
+ ),
786
+
787
+ 'wcf_email_discount_type' => array(
788
+ 'default' => 'percent',
789
+ 'sanitize' => FILTER_SANITIZE_STRING,
790
+ ),
791
+ 'wcf_email_discount_amount' => array(
792
+ 'default' => 10,
793
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
794
+ ),
795
+ 'wcf_email_coupon_expiry_date' => array(
796
+ 'default' => '',
797
+ 'sanitize' => FILTER_SANITIZE_STRING,
798
+ ),
799
+ 'wcf_coupon_expiry_unit' => array(
800
+ 'default' => 'hours',
801
+ 'sanitize' => FILTER_SANITIZE_STRING,
802
+ ),
803
+ 'id' => array(
804
+ 'default' => null,
805
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
806
+ ),
807
+ );
808
+
809
+ $sanitized_post = array();
810
+ foreach ( $input_post_values as $key => $input_post_value ) {
811
+
812
+ if ( isset( $_POST[ $key ] ) ) { //phpcs:ignore
813
+ $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
814
+ } else {
815
+ $sanitized_post[ $key ] = $input_post_value['default'];
816
+ }
817
+ }
818
+
819
+ $sanitized_post['wcf_override_global_coupon'] = isset( $_POST['wcf_override_global_coupon'] ) ? true : false; //phpcs:ignore
820
+ $sanitized_post['wcf_auto_coupon_apply'] = isset( $_POST['wcf_auto_coupon_apply'] ) ? true : false; //phpcs:ignore
821
+ $sanitized_post['wcf_free_shipping_coupon'] = isset( $_POST['wcf_free_shipping_coupon'] ) ? true : false; //phpcs:ignore
822
+ $sanitized_post['wcf_individual_use_only'] = isset( $_POST['wcf_individual_use_only'] ) ? true : false; //phpcs:ignore
823
+ $sanitized_post['wcf_email_body'] = html_entity_decode( $sanitized_post['wcf_email_body'], ENT_COMPAT, 'UTF-8' );
824
+
825
+ return $sanitized_post;
826
+
827
+ }
828
+
829
+
830
+ /**
831
+ * Add email template callback ajax.
832
+ */
833
+ public function add_email_template() {
834
+
835
+ $sanitized_post = $this->sanitize_email_post_data();
836
+ $this->wpdb->insert(
837
+ $this->cart_abandonment_template_table_name,
838
+ array(
839
+ 'template_name' => $sanitized_post['wcf_template_name'],
840
+ 'email_subject' => $sanitized_post['wcf_email_subject'],
841
+ 'email_body' => $sanitized_post['wcf_email_body'],
842
+ 'frequency' => $sanitized_post['wcf_email_frequency'],
843
+ 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
844
+ 'is_activated' => $sanitized_post['wcf_activate_email_template'],
845
+ ),
846
+ array( '%s', '%s', '%s', '%d', '%s', '%d' )
847
+ );
848
+
849
+ $email_template_id = $this->wpdb->insert_id;
850
+ $meta_data = array(
851
+ 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
852
+ 'discount_type' => $sanitized_post['wcf_email_discount_type'],
853
+ 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
854
+ 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
855
+ 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
856
+ 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
857
+ 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
858
+ 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
859
+
860
+ );
861
+
862
+ foreach ( $meta_data as $mera_key => $meta_value ) {
863
+ $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
864
+ }
865
+
866
+ $param = array(
867
+ 'page' => WCF_CA_PAGE_NAME,
868
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
869
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
870
+ 'id' => $email_template_id,
871
+ 'wcf_ca_template_created' => 'YES',
872
+ );
873
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
874
+ wp_safe_redirect( $redirect_url );
875
+
876
+ }
877
+
878
+ /**
879
+ * Edit email template callback ajax.
880
+ */
881
+ public function edit_email_template() {
882
+ $sanitized_post = $this->sanitize_email_post_data();
883
+ $email_template_id = $sanitized_post['id'];
884
+
885
+ $this->wpdb->update(
886
+ $this->cart_abandonment_template_table_name,
887
+ array(
888
+ 'template_name' => $sanitized_post['wcf_template_name'],
889
+ 'email_subject' => $sanitized_post['wcf_email_subject'],
890
+ 'email_body' => $sanitized_post['wcf_email_body'],
891
+ 'frequency' => $sanitized_post['wcf_email_frequency'],
892
+ 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
893
+ 'is_activated' => $sanitized_post['wcf_activate_email_template'],
894
+ ),
895
+ array( 'id' => $email_template_id ),
896
+ array( '%s', '%s', '%s', '%d', '%s', '%d' ),
897
+ array( '%d' )
898
+ );
899
+
900
+ $meta_data = array(
901
+ 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
902
+ 'discount_type' => $sanitized_post['wcf_email_discount_type'],
903
+ 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
904
+ 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
905
+ 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
906
+ 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
907
+ 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
908
+ 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
909
+
910
+ );
911
+ foreach ( $meta_data as $mera_key => $meta_value ) {
912
+ $this->update_email_template_meta( $email_template_id, $mera_key, $meta_value );
913
+ }
914
+
915
+ $param = array(
916
+ 'page' => WCF_CA_PAGE_NAME,
917
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
918
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
919
+ 'id' => $email_template_id,
920
+ 'wcf_ca_template_updated' => 'YES',
921
+ );
922
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
923
+
924
+ wp_safe_redirect( $redirect_url );
925
+
926
+ }
927
+
928
+ /**
929
+ * Restore default email templates.
930
+ */
931
+ public function restore_email_templates() {
932
+
933
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
934
+
935
+ if ( $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
936
+
937
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
938
+ $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
939
+ $db->template_table_seeder( true );
940
+
941
+ $param = array(
942
+ 'page' => WCF_CA_PAGE_NAME,
943
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
944
+ 'wcf_ca_template_restored' => 'YES',
945
+ );
946
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
947
+ wp_safe_redirect( $redirect_url );
948
+ }
949
+
950
+ }
951
+
952
+ /**
953
+ * Update the meta values.
954
+ *
955
+ * @param integer $email_template_id email template id.
956
+ * @param string $meta_key meta key.
957
+ * @param string $meta_value meta value.
958
+ */
959
+ public function update_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
960
+
961
+ $template_meta = $this->get_email_template_meta_by_key( $email_template_id, $meta_key );
962
+
963
+ if ( $template_meta ) {
964
+ $this->wpdb->update(
965
+ $this->email_templates_meta_table,
966
+ array(
967
+ 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
968
+ ),
969
+ array(
970
+ 'email_template_id' => $email_template_id,
971
+ 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
972
+ )
973
+ );
974
+ } else {
975
+ $this->add_email_template_meta( $email_template_id, $meta_key, $meta_value );
976
+ }
977
+
978
+ }
979
+
980
+
981
+ /**
982
+ * Add the meta values.
983
+ *
984
+ * @param integer $email_template_id email template id.
985
+ * @param string $meta_key meta key.
986
+ * @param string $meta_value meta value.
987
+ */
988
+ public function add_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
989
+ $this->wpdb->insert(
990
+ $this->email_templates_meta_table,
991
+ array(
992
+ 'email_template_id' => $email_template_id,
993
+ 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
994
+ 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
995
+ )
996
+ );
997
+ }
998
+
999
+ /**
1000
+ * Get the meta values.
1001
+ *
1002
+ * @param integer $email_template_id email template id.
1003
+ * @param string $meta_key meta key.
1004
+ */
1005
+ public function get_email_template_meta_by_key( $email_template_id, $meta_key ) {
1006
+ return $this->wpdb->get_row(
1007
+ $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
1008
+ );
1009
+ }
1010
+
1011
+ /**
1012
+ * Render email template grid.
1013
+ */
1014
+ public function show_email_template_data_table() {
1015
+ $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
1016
+ $wcf_template_list->prepare_items();
1017
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
1018
+ ?>
1019
+ <div class="wrap">
1020
+ <form id="wcf-cart-abandonment-template-table" method="GET">
1021
+ <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
1022
+ <input type="hidden" name="action" value="<?php echo esc_html( WCF_ACTION_EMAIL_TEMPLATES ); ?>"/>
1023
+ <input type="hidden" name="sub_action" value="<?php echo esc_html( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES ); ?>"/>
1024
+ <?php $wcf_template_list->display(); ?>
1025
+ </form>
1026
+ </div>
1027
+ <?php
1028
+ }
1029
+
1030
+ /**
1031
+ * Render 'Add Email Template button'.
1032
+ */
1033
+ public function show_add_new_template_button() {
1034
+ $param = array(
1035
+ 'page' => WCF_CA_PAGE_NAME,
1036
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
1037
+ 'sub_action' => WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES,
1038
+ );
1039
+
1040
+ $add_new_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1041
+
1042
+ $param['sub_action'] = WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES;
1043
+ $restore_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1044
+
1045
+ ?>
1046
+ <div class="wcf-ca-report-btn">
1047
+ <div class="wcf-ca-left-report-field-group">
1048
+ <a style="cursor: pointer" href="<?php echo esc_url( $add_new_template_url ); ?>" class="button-secondary"><?php esc_html_e( 'Create New Template', 'woo-cart-abandonment-recovery' ); ?></a>
1049
+ </div>
1050
+ <div class="wcf-ca-right-report-field-group">
1051
+ <a onclick="return confirm('Are you sure to restore email templates?');" style="cursor: pointer" href="<?php echo esc_url( $restore_template_url ); ?>" class="button-secondary"><?php esc_html_e( ' Restore Default Templates', 'woo-cart-abandonment-recovery' ); ?></a>
1052
+ </div>
1053
+ </div>
1054
+ <?php
1055
+ }
1056
+
1057
+ /**
1058
+ * Get all active templates.
1059
+ *
1060
+ * @return array|object|null
1061
+ */
1062
+ public function fetch_all_active_templates() {
1063
+ $result = $this->wpdb->get_results(
1064
+ $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE is_activated = %s', true) // phpcs:ignore
1065
+ );
1066
+ return $result;
1067
+ }
1068
+
1069
+ /**
1070
+ * Get specific template by id.
1071
+ *
1072
+ * @param integer $tmpl_id template id.
1073
+ * @return array|object|void|null
1074
+ */
1075
+ public function get_template_by_id( $tmpl_id ) {
1076
+ $result = $this->wpdb->get_row(
1077
+ $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE id = %s', $tmpl_id) // phpcs:ignore
1078
+ );
1079
+ return $result;
1080
+ }
1081
+
1082
+ /**
1083
+ * Get the email history.
1084
+ *
1085
+ * @param integer $email_history_id email history id.
1086
+ * @return array|object|void|null
1087
+ */
1088
+ public function get_email_history_by_id( $email_history_id ) {
1089
+ $result = $this->wpdb->get_row(
1090
+ $this->wpdb->prepare('SELECT * FROM `' . $this->email_history_table . '` WHERE id = %s', $email_history_id) // phpcs:ignore
1091
+ );
1092
+ return $result;
1093
+ }
1094
+ }
1095
+
1096
+ 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
- private 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
+ private 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,249 +1,249 @@
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 esc_attr( $back_link ); ?>" class="button button-secondary back-button"><span
27
- class="dashicons dashicons-arrow-left"></span> <?php esc_html_e( 'Back to Reports', 'woo-cart-abandonment-recovery' ); ?> </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 esc_html_e( 'Email Details:', 'woo-cart-abandonment-recovery' ); ?> </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
- <?php
48
- esc_html_e(
49
- 'All new activated emails will be reschedule for this abandoned order.New emails will
50
- be sent to user according to schedule time.',
51
- 'woo-cart-abandonment-recovery'
52
- );
53
- ?>
54
- </p>
55
- <p>
56
- <strong><?php esc_html_e( 'Are your sure?', 'woo-cart-abandonment-recovery' ); ?></strong>
57
- </p>
58
- <p>
59
- <button onclick="window.location.search += '&sub_action=<?php echo esc_attr( WCF_SUB_ACTION_REPORTS_RESCHEDULE ); ?>';"
60
- class="button button-secondary"> <?php esc_html_e( 'Reschedule', 'woo-cart-abandonment-recovery' ); ?>
61
- </button>
62
- <button type="button"
63
- onclick='document.getElementById("TB_closeWindowButton").click()'
64
- class="button button-secondary"> <?php esc_html_e( 'Close', 'woo-cart-abandonment-recovery' ); ?>
65
- </button>
66
- </p>
67
- </div>
68
- </div>
69
- <a name="<?php esc_html_e( 'Do you really want to reschedule emails?', 'woo-cart-abandonment-recovery' ); ?>" href="#TB_inline?&width=500&height=200&inlineId=wcf-ca-confirm-email-reschedule" class="thickbox button button-secondary"> <?php esc_html_e( 'Reschedule Emails', 'woo-cart-abandonment-recovery' ); ?> </a>
70
- <?php endif; ?>
71
- </div>
72
- </div>
73
-
74
- <?php if ( empty( $scheduled_emails ) ) : ?>
75
- <div style="text-align: center;"><strong> <?php esc_html_e( ' No Email Scheduled.', 'woo-cart-abandonment-recovery' ); ?></strong>
76
- </div>
77
- <?php else : ?>
78
- <table cellpadding="15" cellspacing="0" class="wcf-table wcf-table-striped fixed posts">
79
- <thead>
80
- <tr>
81
-
82
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Scheduled Template', 'woo-cart-abandonment-recovery' ); ?></th>
83
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Subject', 'woo-cart-abandonment-recovery' ); ?></th>
84
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Coupon', 'woo-cart-abandonment-recovery' ); ?></th>
85
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Sent', 'woo-cart-abandonment-recovery' ); ?></th>
86
- <th class="wcf-ca-report-table-row"><span class="dashicons dashicons-clock"></span> <?php esc_html_e( 'Scheduled At', 'woo-cart-abandonment-recovery' ); ?>
87
- </th>
88
-
89
- </tr>
90
- </thead>
91
-
92
- <tbody>
93
- <?php foreach ( $scheduled_emails as $scheduled_email ) : ?>
94
-
95
- <?php
96
- $email_tmpl_url = wp_nonce_url(
97
- add_query_arg(
98
- array(
99
- 'page' => WCF_CA_PAGE_NAME,
100
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
101
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
102
- 'id' => $scheduled_email->template_id,
103
- ),
104
- admin_url( '/admin.php' )
105
- ),
106
- WCF_EMAIL_TEMPLATES_NONCE
107
- );
108
-
109
-
110
-
111
- switch ( $scheduled_email->email_sent ) {
112
- case 0:
113
- if ( $details->unsubscribed ) {
114
- $icon = '<span class="dashicons dashicons-minus"></span>';
115
- $title_text = esc_html__( 'The email has been unsubscribed and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
116
- } else {
117
- $icon = '<span class="dashicons dashicons-no"></span>';
118
- $title_text = esc_html__( 'Email is in the queue and will be sent at the scheduled time.', 'woo-cart-abandonment-recovery' );
119
- }
120
- break;
121
- case 1:
122
- $icon = '<span class="dashicons dashicons-yes wp-ui-text-highlight" ></span>';
123
- $title_text = esc_html__( 'The email has been sent.', 'woo-cart-abandonment-recovery' );
124
- break;
125
- case -1:
126
- $icon = '<span class="dashicons dashicons-dismiss wp-ui-text-highlight" ></span>';
127
- $title_text = esc_html__( 'The email has been unscheduled due to the complete order and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
128
- break;
129
- }
130
-
131
-
132
- $scheduled_time = gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $scheduled_email->scheduled_time ) );
133
- ?>
134
-
135
- <tr class="wcf-ca-report-table-row">
136
- <td class="wcf-ca-report-table-row"><a
137
- href="<?php echo esc_url( $email_tmpl_url ); ?>"
138
- class="wp-ui-text-highlight"> <?php echo esc_attr( $scheduled_email->template_name ); ?> </a>
139
- </td>
140
- <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->email_subject ); ?> </td>
141
- <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->coupon_code ? $scheduled_email->coupon_code : '--' ); ?> </td>
142
- <td class="wcf-ca-report-table-row wcf-ca-icon-row"> <?php echo( $icon ); //phpcs:ignore ?>
143
- <span class="wcf-ca-tooltip-text"><?php echo esc_attr( $title_text ); ?></span>
144
- </td>
145
- <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_time ); ?> </td>
146
- </tr>
147
- <?php endforeach; ?>
148
- </tbody>
149
- </table>
150
- <?php endif; ?>
151
-
152
- </div>
153
- </div>
154
-
155
- <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-left">
156
- <div class="wcf-ca-user-detail ">
157
-
158
- <div class="wcf-ca-report-btn" style="padding: 0px">
159
- <div class="wcf-ca-left-report-field-group">
160
- <h2> <?php esc_html_e( 'User Address Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
161
- </div>
162
- <div class="wcf-ca-right-report-field-group">
163
- <?php if ( $details->unsubscribed ) : ?>
164
- <span class="wcf-ca-tag"> <?php esc_html_e( 'Unsubscribed', 'woo-cart-abandonment-recovery' ); ?> </span>
165
- <?php endif; ?>
166
-
167
- <span class="wcf-ca-tag"> <?php echo esc_attr( ucfirst( $details->order_status ) ); ?> </span>
168
- </div>
169
- </div>
170
-
171
- <div class="wcf-ca-user-address wcf-pull-left">
172
- <h3> <?php esc_html_e( 'Billing Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
173
- <p><strong> <?php esc_html_e( 'Name', 'woo-cart-abandonment-recovery' ); ?> </strong>
174
- <?php echo esc_attr( $user_details->wcf_first_name . ' ' . $user_details->wcf_last_name ); ?> </p>
175
- <p>
176
- <strong> <?php esc_html_e( 'Email address', 'woo-cart-abandonment-recovery' ); ?> </strong>
177
- <a href="mailto:<?php echo esc_attr( $details->email ); ?>"><?php echo esc_attr( $details->email ); ?></a>
178
- </p>
179
-
180
- <p>
181
- <strong> <?php esc_html_e( 'Phone', 'woo-cart-abandonment-recovery' ); ?> </strong>
182
- <a href="tel:<?php echo esc_attr( $user_details->wcf_phone_number ); ?>"><?php echo esc_attr( $user_details->wcf_phone_number ); ?></a>
183
- </p>
184
-
185
- <p>
186
- <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_1 ); ?>
187
- </p>
188
- <p>
189
- <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_2 ); ?>
190
- </p>
191
- <p>
192
- <strong> <?php esc_html_e( 'Country, City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_location ); ?>
193
- </p>
194
- <p>
195
- <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_state ); ?>
196
- </p>
197
-
198
- <p>
199
- <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_postcode ); ?>
200
- </p>
201
- </div>
202
-
203
- <div class="wcf-ca-user-address wcf-pull-left">
204
- <h3> <?php esc_html_e( 'Shipping Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
205
- <p>
206
- <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_1 ); ?>
207
- </p>
208
- <p>
209
- <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_2 ); ?>
210
- </p>
211
- <p>
212
- <strong> <?php esc_html_e( 'City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_city ); ?>
213
- </p>
214
- <p>
215
- <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_state ); ?>
216
- </p>
217
- <p>
218
- <strong> <?php esc_html_e( 'Country:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_country ); ?>
219
- </p>
220
- <p>
221
- <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_postcode ); ?>
222
- </p>
223
- <p>
224
- <?php
225
- $cart_abandonment = Cartflows_Ca_Cart_Abandonment::get_instance();
226
- $token_data = array( 'wcf_session_id' => $details->session_id );
227
- ?>
228
- <strong> <a target="_blank" href=" <?php echo $cart_abandonment->get_checkout_url( $details->checkout_id, $token_data ); //phpcs:ignore?> ">
229
- <?php esc_html_e( 'Checkout Link', 'woo-cart-abandonment-recovery' ); ?>
230
- </a>
231
- </strong>
232
- </p>
233
- </div>
234
-
235
- </div>
236
- </div>
237
- </div>
238
- <!-- First panel closed -->
239
-
240
- <!-- Second panel Start -->
241
- <div class="wcf-ca-panel">
242
- <div class="wcf-ca-column wcf-ca-column-one">
243
- <div class="wcf-ca-user-order">
244
- <h2> <?php esc_html_e( 'User Order Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
245
- <?php echo( $this->get_admin_product_block( $details->cart_contents, $details->cart_total ) ); //phpcs:ignore ?>
246
- </div>
247
- </div>
248
- </div>
249
- <!-- 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 esc_attr( $back_link ); ?>" class="button button-secondary back-button"><span
27
+ class="dashicons dashicons-arrow-left"></span> <?php esc_html_e( 'Back to Reports', 'woo-cart-abandonment-recovery' ); ?> </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 esc_html_e( 'Email Details:', 'woo-cart-abandonment-recovery' ); ?> </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
+ <?php
48
+ esc_html_e(
49
+ 'All new activated emails will be reschedule for this abandoned order.New emails will
50
+ be sent to user according to schedule time.',
51
+ 'woo-cart-abandonment-recovery'
52
+ );
53
+ ?>
54
+ </p>
55
+ <p>
56
+ <strong><?php esc_html_e( 'Are your sure?', 'woo-cart-abandonment-recovery' ); ?></strong>
57
+ </p>
58
+ <p>
59
+ <button onclick="window.location.search += '&sub_action=<?php echo esc_attr( WCF_SUB_ACTION_REPORTS_RESCHEDULE ); ?>';"
60
+ class="button button-secondary"> <?php esc_html_e( 'Reschedule', 'woo-cart-abandonment-recovery' ); ?>
61
+ </button>
62
+ <button type="button"
63
+ onclick='document.getElementById("TB_closeWindowButton").click()'
64
+ class="button button-secondary"> <?php esc_html_e( 'Close', 'woo-cart-abandonment-recovery' ); ?>
65
+ </button>
66
+ </p>
67
+ </div>
68
+ </div>
69
+ <a name="<?php esc_html_e( 'Do you really want to reschedule emails?', 'woo-cart-abandonment-recovery' ); ?>" href="#TB_inline?&width=500&height=200&inlineId=wcf-ca-confirm-email-reschedule" class="thickbox button button-secondary"> <?php esc_html_e( 'Reschedule Emails', 'woo-cart-abandonment-recovery' ); ?> </a>
70
+ <?php endif; ?>
71
+ </div>
72
+ </div>
73
+
74
+ <?php if ( empty( $scheduled_emails ) ) : ?>
75
+ <div style="text-align: center;"><strong> <?php esc_html_e( ' No Email Scheduled.', 'woo-cart-abandonment-recovery' ); ?></strong>
76
+ </div>
77
+ <?php else : ?>
78
+ <table cellpadding="15" cellspacing="0" class="wcf-table wcf-table-striped fixed posts">
79
+ <thead>
80
+ <tr>
81
+
82
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Scheduled Template', 'woo-cart-abandonment-recovery' ); ?></th>
83
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Subject', 'woo-cart-abandonment-recovery' ); ?></th>
84
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Coupon', 'woo-cart-abandonment-recovery' ); ?></th>
85
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Sent', 'woo-cart-abandonment-recovery' ); ?></th>
86
+ <th class="wcf-ca-report-table-row"><span class="dashicons dashicons-clock"></span> <?php esc_html_e( 'Scheduled At', 'woo-cart-abandonment-recovery' ); ?>
87
+ </th>
88
+
89
+ </tr>
90
+ </thead>
91
+
92
+ <tbody>
93
+ <?php foreach ( $scheduled_emails as $scheduled_email ) : ?>
94
+
95
+ <?php
96
+ $email_tmpl_url = wp_nonce_url(
97
+ add_query_arg(
98
+ array(
99
+ 'page' => WCF_CA_PAGE_NAME,
100
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
101
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
102
+ 'id' => $scheduled_email->template_id,
103
+ ),
104
+ admin_url( '/admin.php' )
105
+ ),
106
+ WCF_EMAIL_TEMPLATES_NONCE
107
+ );
108
+
109
+
110
+
111
+ switch ( $scheduled_email->email_sent ) {
112
+ case 0:
113
+ if ( $details->unsubscribed ) {
114
+ $icon = '<span class="dashicons dashicons-minus"></span>';
115
+ $title_text = esc_html__( 'The email has been unsubscribed and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
116
+ } else {
117
+ $icon = '<span class="dashicons dashicons-no"></span>';
118
+ $title_text = esc_html__( 'Email is in the queue and will be sent at the scheduled time.', 'woo-cart-abandonment-recovery' );
119
+ }
120
+ break;
121
+ case 1:
122
+ $icon = '<span class="dashicons dashicons-yes wp-ui-text-highlight" ></span>';
123
+ $title_text = esc_html__( 'The email has been sent.', 'woo-cart-abandonment-recovery' );
124
+ break;
125
+ case -1:
126
+ $icon = '<span class="dashicons dashicons-dismiss wp-ui-text-highlight" ></span>';
127
+ $title_text = esc_html__( 'The email has been unscheduled due to the complete order and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
128
+ break;
129
+ }
130
+
131
+
132
+ $scheduled_time = gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $scheduled_email->scheduled_time ) );
133
+ ?>
134
+
135
+ <tr class="wcf-ca-report-table-row">
136
+ <td class="wcf-ca-report-table-row"><a
137
+ href="<?php echo esc_url( $email_tmpl_url ); ?>"
138
+ class="wp-ui-text-highlight"> <?php echo esc_attr( $scheduled_email->template_name ); ?> </a>
139
+ </td>
140
+ <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->email_subject ); ?> </td>
141
+ <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->coupon_code ? $scheduled_email->coupon_code : '--' ); ?> </td>
142
+ <td class="wcf-ca-report-table-row wcf-ca-icon-row"> <?php echo( $icon ); //phpcs:ignore ?>
143
+ <span class="wcf-ca-tooltip-text"><?php echo esc_attr( $title_text ); ?></span>
144
+ </td>
145
+ <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_time ); ?> </td>
146
+ </tr>
147
+ <?php endforeach; ?>
148
+ </tbody>
149
+ </table>
150
+ <?php endif; ?>
151
+
152
+ </div>
153
+ </div>
154
+
155
+ <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-left">
156
+ <div class="wcf-ca-user-detail ">
157
+
158
+ <div class="wcf-ca-report-btn" style="padding: 0px">
159
+ <div class="wcf-ca-left-report-field-group">
160
+ <h2> <?php esc_html_e( 'User Address Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
161
+ </div>
162
+ <div class="wcf-ca-right-report-field-group">
163
+ <?php if ( $details->unsubscribed ) : ?>
164
+ <span class="wcf-ca-tag"> <?php esc_html_e( 'Unsubscribed', 'woo-cart-abandonment-recovery' ); ?> </span>
165
+ <?php endif; ?>
166
+
167
+ <span class="wcf-ca-tag"> <?php echo esc_attr( ucfirst( $details->order_status ) ); ?> </span>
168
+ </div>
169
+ </div>
170
+
171
+ <div class="wcf-ca-user-address wcf-pull-left">
172
+ <h3> <?php esc_html_e( 'Billing Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
173
+ <p><strong> <?php esc_html_e( 'Name', 'woo-cart-abandonment-recovery' ); ?> </strong>
174
+ <?php echo esc_attr( $user_details->wcf_first_name . ' ' . $user_details->wcf_last_name ); ?> </p>
175
+ <p>
176
+ <strong> <?php esc_html_e( 'Email address', 'woo-cart-abandonment-recovery' ); ?> </strong>
177
+ <a href="mailto:<?php echo esc_attr( $details->email ); ?>"><?php echo esc_attr( $details->email ); ?></a>
178
+ </p>
179
+
180
+ <p>
181
+ <strong> <?php esc_html_e( 'Phone', 'woo-cart-abandonment-recovery' ); ?> </strong>
182
+ <a href="tel:<?php echo esc_attr( $user_details->wcf_phone_number ); ?>"><?php echo esc_attr( $user_details->wcf_phone_number ); ?></a>
183
+ </p>
184
+
185
+ <p>
186
+ <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_1 ); ?>
187
+ </p>
188
+ <p>
189
+ <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_2 ); ?>
190
+ </p>
191
+ <p>
192
+ <strong> <?php esc_html_e( 'Country, City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_location ); ?>
193
+ </p>
194
+ <p>
195
+ <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_state ); ?>
196
+ </p>
197
+
198
+ <p>
199
+ <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_postcode ); ?>
200
+ </p>
201
+ </div>
202
+
203
+ <div class="wcf-ca-user-address wcf-pull-left">
204
+ <h3> <?php esc_html_e( 'Shipping Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
205
+ <p>
206
+ <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_1 ); ?>
207
+ </p>
208
+ <p>
209
+ <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_2 ); ?>
210
+ </p>
211
+ <p>
212
+ <strong> <?php esc_html_e( 'City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_city ); ?>
213
+ </p>
214
+ <p>
215
+ <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_state ); ?>
216
+ </p>
217
+ <p>
218
+ <strong> <?php esc_html_e( 'Country:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_country ); ?>
219
+ </p>
220
+ <p>
221
+ <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_postcode ); ?>
222
+ </p>
223
+ <p>
224
+ <?php
225
+ $cart_abandonment = Cartflows_Ca_Cart_Abandonment::get_instance();
226
+ $token_data = array( 'wcf_session_id' => $details->session_id );
227
+ ?>
228
+ <strong> <a target="_blank" href=" <?php echo $cart_abandonment->get_checkout_url( $details->checkout_id, $token_data ); //phpcs:ignore?> ">
229
+ <?php esc_html_e( 'Checkout Link', 'woo-cart-abandonment-recovery' ); ?>
230
+ </a>
231
+ </strong>
232
+ </p>
233
+ </div>
234
+
235
+ </div>
236
+ </div>
237
+ </div>
238
+ <!-- First panel closed -->
239
+
240
+ <!-- Second panel Start -->
241
+ <div class="wcf-ca-panel">
242
+ <div class="wcf-ca-column wcf-ca-column-one">
243
+ <div class="wcf-ca-user-order">
244
+ <h2> <?php esc_html_e( 'User Order Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
245
+ <?php echo( $this->get_admin_product_block( $details->cart_contents, $details->cart_total ) ); //phpcs:ignore ?>
246
+ </div>
247
+ </div>
248
+ </div>
249
+ <!-- Second panel closed -->
modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php CHANGED
@@ -1,156 +1,156 @@
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'; ?>"> <?php esc_html_e( 'Today', 'woo-cart-abandonment-recovery' ); ?>
15
- </button>
16
-
17
- <button onclick="window.location.search += '&filter=yesterday';"
18
- class="button <?php echo 'yesterday' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Yesterday', 'woo-cart-abandonment-recovery' ); ?>
19
- </button>
20
-
21
- <button onclick="window.location.search += '&filter=last_week';"
22
- class="button <?php echo 'last_week' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Last Week', 'woo-cart-abandonment-recovery' ); ?>
23
- </button>
24
-
25
- <button onclick="window.location.search += '&filter=last_month';"
26
- class="button <?php echo 'last_month' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Last Month', 'woo-cart-abandonment-recovery' ); ?>
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 esc_attr( $from_date ); ?>"/>
33
- <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_to" placeholder="YYYY-MM-DD" value="<?php echo esc_attr( $to_date ); ?>" />
34
- <button id="wcf_ca_custom_filter"
35
- class="button <?php echo 'custom' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Custom Filter', 'woo-cart-abandonment-recovery' ); ?>
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 esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?> </h3>
47
- </div>
48
- <div class="wcf-ca-ibox-content">
49
- <h1> <?php echo esc_attr( $abandoned_report['no_of_orders'] ); ?> </h1>
50
- <small> <?php esc_html_e( 'Total Recoverable Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
51
- </div>
52
- </div>
53
-
54
- <div class="wcf-ca-ibox">
55
- <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
56
- <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $recovered_report['no_of_orders'] ); ?></h1>
57
- <small> <?php esc_html_e( 'Total Recovered Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
58
- </div>
59
- </div>
60
-
61
- <div class="wcf-ca-ibox">
62
- <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
63
- <div class="wcf-ca-ibox-content"><h1
64
- ><?php echo esc_attr( $lost_report['no_of_orders'] ); ?></h1>
65
- <small> <?php esc_html_e( 'Total Lost Orders.', 'woo-cart-abandonment-recovery' ); ?> </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 esc_html_e( 'Recoverable Revenue', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
75
- <div class="wcf-ca-ibox-content">
76
- <h1>
77
- <?php echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $abandoned_report['revenue'], 2 ) ); ?>
78
- </h1>
79
- <small> <?php esc_html_e( 'Total Recoverable Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
80
- </div>
81
- </div>
82
-
83
- <div class="wcf-ca-ibox">
84
- <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Revenue', 'woo-cart-abandonment-recovery' ); ?></h3></div>
85
- <div class="wcf-ca-ibox-content"><h1>
86
- <?php
87
- echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $recovered_report['revenue'], 2 ) );
88
- ?>
89
- </h1>
90
- <small> <?php esc_html_e( 'Total Recovered Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
91
- </div>
92
- </div>
93
-
94
- <div class="wcf-ca-ibox">
95
- <div class="wcf-ca-ibox-title"><h3> <?php esc_html_e( 'Recovery Rate', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
96
- <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $conversion_rate ) . '%'; ?></h1>
97
- <small><?php esc_html_e( 'Total Percentage Of Recovered Orders After Abandonment.', 'woo-cart-abandonment-recovery' ); ?> </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 esc_attr( WCF_CART_ABANDONED_ORDER ); ?>';"
108
- class="button <?php echo WCF_CART_ABANDONED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?>
109
- </button>
110
- <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_COMPLETED_ORDER ); ?>';"
111
- class="button <?php echo WCF_CART_COMPLETED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?>
112
- </button>
113
- <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_LOST_ORDER ); ?>';"
114
- class="button <?php echo WCF_CART_LOST_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?>
115
- </button>
116
- </div>
117
-
118
- <div class="wcf-ca-right-report-field-group">
119
- <div class="wcf-search-orders" id="wcf_search_wrapper" >
120
- <div class="search-box">
121
- <?php
122
- $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
123
- ?>
124
- <input type="search" id="wcf_search_id_search_input" name="s" placeholder="<?php echo esc_html__( 'Search by email', 'woo-cart-abandonment-recovery' ); ?>" value="<?php echo esc_attr( $search_term ); ?>">
125
- <input type="submit" id="wcf_search_id_submit" class="button" value="<?php esc_html_e( 'Search Orders', 'woo-cart-abandonment-recovery' ); ?>">
126
- </div>
127
- </div>
128
- <div class="wcf_export_orders">
129
- <?php
130
- if ( count( $wcf_list_table->items ) !== 0 ) {
131
- ?>
132
- <button id="wcf_ca_export_orders"
133
- class="button-primary " > Export Orders <span class="dashicons dashicons-download wcf-ca-export-icon" ></span>
134
- </button>
135
- <?php } ?>
136
- </div>
137
- </div>
138
- </div>
139
-
140
- <?php
141
- if ( count( $wcf_list_table->items ) ) {
142
- $wcar_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
143
- ?>
144
- <form id="wcf-cart-abandonment-table" method="GET">
145
- <input type="hidden" name="page" value="<?php echo esc_html( $wcar_page ); ?>"/>
146
- <?php $wcf_list_table->display(); ?>
147
- </form>
148
-
149
- <?php
150
- } else {
151
-
152
- echo '<div> <strong> ' . esc_html__( 'No Orders Found.', 'woo-cart-abandonment-recovery' ) . '</strong> </div>';
153
-
154
- }
155
-
156
- ?>
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'; ?>"> <?php esc_html_e( 'Today', 'woo-cart-abandonment-recovery' ); ?>
15
+ </button>
16
+
17
+ <button onclick="window.location.search += '&filter=yesterday';"
18
+ class="button <?php echo 'yesterday' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Yesterday', 'woo-cart-abandonment-recovery' ); ?>
19
+ </button>
20
+
21
+ <button onclick="window.location.search += '&filter=last_week';"
22
+ class="button <?php echo 'last_week' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Last Week', 'woo-cart-abandonment-recovery' ); ?>
23
+ </button>
24
+
25
+ <button onclick="window.location.search += '&filter=last_month';"
26
+ class="button <?php echo 'last_month' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Last Month', 'woo-cart-abandonment-recovery' ); ?>
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 esc_attr( $from_date ); ?>"/>
33
+ <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_to" placeholder="YYYY-MM-DD" value="<?php echo esc_attr( $to_date ); ?>" />
34
+ <button id="wcf_ca_custom_filter"
35
+ class="button <?php echo 'custom' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Custom Filter', 'woo-cart-abandonment-recovery' ); ?>
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 esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?> </h3>
47
+ </div>
48
+ <div class="wcf-ca-ibox-content">
49
+ <h1> <?php echo esc_attr( $abandoned_report['no_of_orders'] ); ?> </h1>
50
+ <small> <?php esc_html_e( 'Total Recoverable Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="wcf-ca-ibox">
55
+ <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
56
+ <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $recovered_report['no_of_orders'] ); ?></h1>
57
+ <small> <?php esc_html_e( 'Total Recovered Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="wcf-ca-ibox">
62
+ <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
63
+ <div class="wcf-ca-ibox-content"><h1
64
+ ><?php echo esc_attr( $lost_report['no_of_orders'] ); ?></h1>
65
+ <small> <?php esc_html_e( 'Total Lost Orders.', 'woo-cart-abandonment-recovery' ); ?> </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 esc_html_e( 'Recoverable Revenue', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
75
+ <div class="wcf-ca-ibox-content">
76
+ <h1>
77
+ <?php echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $abandoned_report['revenue'], 2 ) ); ?>
78
+ </h1>
79
+ <small> <?php esc_html_e( 'Total Recoverable Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="wcf-ca-ibox">
84
+ <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Revenue', 'woo-cart-abandonment-recovery' ); ?></h3></div>
85
+ <div class="wcf-ca-ibox-content"><h1>
86
+ <?php
87
+ echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $recovered_report['revenue'], 2 ) );
88
+ ?>
89
+ </h1>
90
+ <small> <?php esc_html_e( 'Total Recovered Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="wcf-ca-ibox">
95
+ <div class="wcf-ca-ibox-title"><h3> <?php esc_html_e( 'Recovery Rate', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
96
+ <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $conversion_rate ) . '%'; ?></h1>
97
+ <small><?php esc_html_e( 'Total Percentage Of Recovered Orders After Abandonment.', 'woo-cart-abandonment-recovery' ); ?> </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 esc_attr( WCF_CART_ABANDONED_ORDER ); ?>';"
108
+ class="button <?php echo WCF_CART_ABANDONED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?>
109
+ </button>
110
+ <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_COMPLETED_ORDER ); ?>';"
111
+ class="button <?php echo WCF_CART_COMPLETED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?>
112
+ </button>
113
+ <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_LOST_ORDER ); ?>';"
114
+ class="button <?php echo WCF_CART_LOST_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?>
115
+ </button>
116
+ </div>
117
+
118
+ <div class="wcf-ca-right-report-field-group">
119
+ <div class="wcf-search-orders" id="wcf_search_wrapper" >
120
+ <div class="search-box">
121
+ <?php
122
+ $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
123
+ ?>
124
+ <input type="search" id="wcf_search_id_search_input" name="s" placeholder="<?php echo esc_html__( 'Search by email', 'woo-cart-abandonment-recovery' ); ?>" value="<?php echo esc_attr( $search_term ); ?>">
125
+ <input type="submit" id="wcf_search_id_submit" class="button" value="<?php esc_html_e( 'Search Orders', 'woo-cart-abandonment-recovery' ); ?>">
126
+ </div>
127
+ </div>
128
+ <div class="wcf_export_orders">
129
+ <?php
130
+ if ( count( $wcf_list_table->items ) !== 0 ) {
131
+ ?>
132
+ <button id="wcf_ca_export_orders"
133
+ class="button-primary " > Export Orders <span class="dashicons dashicons-download wcf-ca-export-icon" ></span>
134
+ </button>
135
+ <?php } ?>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <?php
141
+ if ( count( $wcf_list_table->items ) ) {
142
+ $wcar_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
143
+ ?>
144
+ <form id="wcf-cart-abandonment-table" method="GET">
145
+ <input type="hidden" name="page" value="<?php echo esc_html( $wcar_page ); ?>"/>
146
+ <?php $wcf_list_table->display(); ?>
147
+ </form>
148
+
149
+ <?php
150
+ } else {
151
+
152
+ echo '<div> <strong> ' . esc_html__( 'No Orders Found.', 'woo-cart-abandonment-recovery' ) . '</strong> </div>';
153
+
154
+ }
155
+
156
+ ?>
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 esc_html__( 'WooCommerce Cart Abandonment Recovery ', 'woo-cart-abandonment-recovery' ); ?></h1>
11
- <?php
12
-
13
- $wcar_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 ( ! $wcar_action ) {
18
- $wcar_action = WCF_ACTION_REPORTS;
19
- }
20
-
21
- $this->wcf_display_tabs();
22
- $this->wcf_show_warning_ca();
23
- ?>
24
- <?php
25
- echo wp_kses_post( get_transient( 'wcf_ca_show_message' ) );
26
- ?>
27
-
28
- <?php if ( WCF_ACTION_SETTINGS === $wcar_action ) : ?>
29
- <?php
30
- $this->wcf_display_settings();
31
- ?>
32
- <?php endif; ?>
33
-
34
- <?php if ( WCF_ACTION_REPORTS === $wcar_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 === $wcar_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
- $action_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 && $action_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 esc_html__( 'WooCommerce Cart Abandonment Recovery ', 'woo-cart-abandonment-recovery' ); ?></h1>
11
+ <?php
12
+
13
+ $wcar_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 ( ! $wcar_action ) {
18
+ $wcar_action = WCF_ACTION_REPORTS;
19
+ }
20
+
21
+ $this->wcf_display_tabs();
22
+ $this->wcf_show_warning_ca();
23
+ ?>
24
+ <?php
25
+ echo wp_kses_post( get_transient( 'wcf_ca_show_message' ) );
26
+ ?>
27
+
28
+ <?php if ( WCF_ACTION_SETTINGS === $wcar_action ) : ?>
29
+ <?php
30
+ $this->wcf_display_settings();
31
+ ?>
32
+ <?php endif; ?>
33
+
34
+ <?php if ( WCF_ACTION_REPORTS === $wcar_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 === $wcar_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
+ $action_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 && $action_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,216 +1,222 @@
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.3.2
7
- Stable tag: 1.2.4
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
-
16
- **It’s Time to Stop Cart Abandonments and Recover Your Lost Revenue!**
17
-
18
- Research shows about 60% to 80% of the users who go to the checkout page, do not complete their purchase. Even the best <a href="https://wpastra.com/best-checkout-experience/" target="_blank">optimized checkout process</a> has an abandonment rate of 20%
19
-
20
- Cart gets abandoned for many reasons.
21
-
22
- But we have good news for you. Install our plugin and automatically recover your lost revenue **absolutely free**.
23
-
24
- **How Does This Plugin Work?**
25
-
26
- The plugin captures the email address of users on the checkout page.
27
-
28
- If the purchase is not completed within 15 minutes, it starts sending an automated series of follow up emails that you can customize to match your brand.
29
-
30
- Through the email series, you can: remind them to complete the purchase, ask for feedback or offer a custom discount that will entice potential buyers to complete the purchase. You can send as many emails as you would like.
31
-
32
- Below is just an example of email sequence you can have:
33
-
34
- * **1st email after 1 hour**: Ask if there was any technical issue.
35
-
36
- * **2nd email after 24 hours**: Remind to complete purchase
37
-
38
- * **3rd email after 72 hours**: Offer a unique, limited time 5% discount
39
-
40
- **Some Amazing Features**
41
-
42
-
43
- WooCommerce Cart Abandonment Recovery offers everything you need to recover your abandoning carts.
44
-
45
- * **Unique Checkout Links**: Email a unique checkout link to each shopper that takes them exactly where they left off. So if a shopper had filled the checkout form, click on the unique link takes him to a prefilled checkout page. Less the friction for the shopper, and more conversions for you!
46
-
47
- * **GDPR Compliant**: You can optionally show a GDPR notice on the checkout page.
48
-
49
- * **Ready templates for follow up emails**: Writing emails from scratch can be a pain. Not everyone can frame effective follow-up emails. We provide ready conversion tested email templates.
50
-
51
- * **Webhooks**: Use a marketing automation tool like Active Campaign, Campaign Monitor, etc? This plugin integrates with all of them through webhook easily.
52
-
53
- * **Coupon Code**: This plugin can generate limited time unique discount coupons to entice your shoppers and send them automatically via email.
54
-
55
- * **Reports**: You get a full report of how the plugin is working behind the scenes, and recovering your lost revenue on autopilot.
56
-
57
- [youtube https://www.youtube.com/watch?v=VWGxjjuP2_k]
58
-
59
- **Is This Plugin Really Free? What’s the Catch?**
60
-
61
- Absolutely. There is no catch at all. This is a 100% free gift for all WooCommerce users from our team at CartFlows.
62
-
63
- <a href="https://cartflows.com" target="_blank">CartFlows</a> is a premium WooCommerce plugin that is used to create marketing and sales funnels. With CartFlows, you can design better checkout pages, add <a href="https://cartflows.com" target="_blank">order bump</a> or even <a href="https://cartflows.com" target="_blank">one-click upsell</a> functionality.
64
-
65
- **Will It Affects the Performance of My WooCommerce Shop?**
66
-
67
- No. Just as WooCommerce, this plugin stores everything locally in the database of WordPress. Emails are sent via WordPress native 'wpmail' function or SMTP. We have optimized the plugin so it leaves no performance impact.
68
-
69
-
70
- **How Can I Get Started?**
71
-
72
- Getting started is very easy.
73
-
74
- * **Step 1**: Install and activate the WooCommerce Cart Abandonment Recovery plugin.
75
-
76
- * **Step 2**: Review the default email templates. Make necessary changes if required.
77
-
78
- * **Step 3**: You’re done!
79
-
80
- The plugin will start recovering your lost sales in as quickly as 15 minutes.
81
-
82
- == Installation ==
83
-
84
- 1. Upload `woocommerce-cart-abandonment-recovery.zip` to the `/wp-content/plugins/` directory
85
- 2. Activate the plugin through the 'Plugins' menu in WordPress
86
-
87
- == Frequently Asked Questions ==
88
-
89
- = What Is Meant by Cart Abandonment? =
90
-
91
- While shopping, a user adds products to the cart. But if this user doesn't complete the purchase on the checkout page, the cart is considered abandoned.
92
-
93
- = How Often Cart Gets Abandoned? Is It Happening on My Shop? =
94
-
95
- According to research, 6 out of 10 visitors, leave the checkout page and do not complete the purchase. Even if you have motivated enough, 20% to 25% of the shoppers leave the purchase process.
96
-
97
- = Do I Need Any Technical Experience to Use This Plugin? =
98
-
99
- Any WooCommerce shop owner selling anything online can use this plugin.You will not need any technical experience to start recovering your lost revenue. Once initiated the plugin will work automatically for you.
100
-
101
- = Can I Send Coupon with Follow up Email? =
102
-
103
- Yes. You can generate and send unique, limited-time discount coupon. Though there is no compulsion of sending coupon. It's completely optional.
104
-
105
- = Can I Directly Take Users to Checkout Page, Exactly Where They Left Off? =
106
-
107
- Absolutely. A unique checkout link can be sent with follow up email. This will take the shopper to their prefilled checkout page. This will make the purchase process easier for the shopper.
108
-
109
- = Can Marketing Automation Tools Be Integrated with This? =
110
-
111
- Plugin offers Webhooks. This allows integrating Active Campaign, Mautic, Campaign Monitor, etc with the plugin.
112
-
113
- = Will This Plugin Add Any Extra Time in Website Loading? =
114
-
115
- Not at all. All the plugin data is stored in its own database table. It is completely self-hosted plugin. It works smoothly and does not leave any impact on the performance of the website. So you don't have to worry about the speed.
116
-
117
- = Why This Awesome Plugin Is Free? =
118
-
119
- Here are few thoughts behind making it available for free:
120
- - It is our way of saying thank you to the community and helping shop owners to boost their profits.
121
- - And quite honestly, we want you to try one of our products for free. And when you see how helpful it is, it should get you excited to buy other products from us in the future
122
-
123
- == Screenshots ==
124
-
125
- 1. Track recovery report for abandonment sales from the dashboard
126
- 2. Schedule the follow-up emails from one place
127
- 3. Prebuilt and easy-to-edit Email templates
128
- 4. General settings for Email, Webhook (Coupon Code), GDPR
129
-
130
- == Changelog ==
131
-
132
- = Version 1.2.4 - Thursday, 06th February 2020 =
133
- * New: Added option to export abandoned orders.
134
- * New: Added option to search abandoned orders.
135
- * Improvement: Compatibility with the latest WordPress PHP_CodeSniffer rules.
136
- * Fix: Get id error while sending emails.
137
-
138
- = Version 1.2.3 - Thursday, 12th December 2019 =
139
- * New: Added option to unsubscribe users in bulk.
140
- * New: Added filter 'woo_ca_exclude_on_hold_order_from_tracking' to exclude on hold orders from the tracking.
141
- * New: Added product table shortcode for webhook.
142
- * Improvement: Updated filter 'woo_ca_email_template_table_style' for product table alignment.
143
- * Fix: Sometimes test emails are not sending.
144
-
145
- = Version 1.2.2 - Tuesday, 12th November 2019 =
146
- * Fix: Duplicate order issue for variation products.
147
-
148
- = Version 1.2.1 - Tuesday, 5th November 2019 =
149
- * New: Added delete option for used & expired coupons which will be created now onwards.
150
- * Fix: Sometimes order status remains "abandoned" for initially failed orders.
151
- * Fix: Strings updated for translation.
152
-
153
- = Version 1.2.0 - Monday, 14th October 2019 =
154
- * New: Added support for PPOM products.
155
- * Improvement: Added email activate toggle button on grid.
156
- * Improvement: Added notice on the checkout page for test emails.
157
- * Fix: Zero-value orders getting tracked.
158
- * Fix: Disable tracking for the custom user roles.
159
-
160
- = Version 1.1.9 - Thursday, 19th September 2019 =
161
- * New: Option added to ignore users from cart abandonment process.
162
- * New: Filter added to customize the styling of email template table.
163
- * Improvement: Added compatibility with Razorpay plugin.
164
- * Fix: Email template markup was breaking after save.
165
- * Fix: Failed orders were getting marked as completed.
166
- * Fix: Empty order was getting tracked and email sending for it.
167
- * Fix: Email settings options were swapping value of from and reply-to.
168
-
169
- = Version 1.1.8 - Tuesday, 3rd September 2019 =
170
- * New: Option added to auto-apply coupon on the checkout.
171
- * New: Option added to apply coupon individually.
172
- * New: Option added to create free shipping coupons.
173
-
174
- = Version 1.1.7 - Monday, 12th August 2019 =
175
- * New: Filter added to show the cart total inside the email template.
176
- * New: Filter added to change the cart abandoned time.
177
- * Improvement: Order tracking logic updated for automated payments.
178
- * Improvement: Update report dashboard DateTime format to WordPress format.
179
- * Fix: Broken image in the email template.
180
-
181
- = Version 1.1.6 - Friday, 19th July 2019 =
182
- * New: Bundled product support for email checkout URL.
183
- * Improvement: Added phone number and address while triggering the to webhook.
184
- * Fix: Creating tables and default settings on activation.
185
-
186
- = Version 1.1.5 - Tuesday, 9th July 2019 =
187
- * Fix: Other crons disappearing issue.
188
-
189
- = Version 1.1.4 - Tuesday, 9th July 2019 =
190
- * Fix: Follow up emails were getting sent even after the completion of the order.
191
- * Fix: Email template variable 'Abandoned Product Names' warning issue.
192
-
193
- = Version 1.1.3 - Thursday, 27th June 2019 =
194
- * Improvement: Added checkout link for abandoned cart inside the admin section.
195
- * Fix: Added pagination for reports.
196
- * Fix: Recover report calculations before campaign triggers.
197
- * Fix: Empty cart notice when CartFlows checkout is set global.
198
-
199
- = Version 1.1.2 - Wednesday, 12th June 2019 =
200
- * Fix: Issue of timezone while sending mail through cron.
201
- * Fix: Delete single cart abandonment order.
202
- * Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
203
-
204
- = Version 1.1.1 - Thursday, 06th June 2019 =
205
- * New: Added feature to reschedule emails for Admin.
206
- * Fix: Coupon expiry time issue.
207
- * Fix: Email issue for a user who has an already purchased order.
208
- * Fix: Translatable strings updated.
209
-
210
- = Version 1.1.0 - Thursday, 30th May 2019 =
211
- * Added a view for admin to check email status specific to the particular abandoned user.
212
-
213
- = Version 1.0.0 - Monday, 27th May 2019 =
214
- * Initial Release
215
-
 
 
 
 
 
 
216
  == 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.4
7
+ Stable tag: 1.2.5
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
+
16
+ **It’s Time to Stop Cart Abandonments and Recover Your Lost Revenue!**
17
+
18
+ Research shows about 60% to 80% of the users who go to the checkout page, do not complete their purchase. Even the best <a href="https://wpastra.com/best-checkout-experience/" target="_blank">optimized checkout process</a> has an abandonment rate of 20%
19
+
20
+ Cart gets abandoned for many reasons.
21
+
22
+ But we have good news for you. Install our plugin and automatically recover your lost revenue **absolutely free**.
23
+
24
+ **How Does This Plugin Work?**
25
+
26
+ The plugin captures the email address of users on the checkout page.
27
+
28
+ If the purchase is not completed within 15 minutes, it starts sending an automated series of follow up emails that you can customize to match your brand.
29
+
30
+ Through the email series, you can: remind them to complete the purchase, ask for feedback or offer a custom discount that will entice potential buyers to complete the purchase. You can send as many emails as you would like.
31
+
32
+ Below is just an example of email sequence you can have:
33
+
34
+ * **1st email after 1 hour**: Ask if there was any technical issue.
35
+
36
+ * **2nd email after 24 hours**: Remind to complete purchase
37
+
38
+ * **3rd email after 72 hours**: Offer a unique, limited time 5% discount
39
+
40
+ **Some Amazing Features**
41
+
42
+
43
+ WooCommerce Cart Abandonment Recovery offers everything you need to recover your abandoning carts.
44
+
45
+ * **Unique Checkout Links**: Email a unique checkout link to each shopper that takes them exactly where they left off. So if a shopper had filled the checkout form, click on the unique link takes him to a prefilled checkout page. Less the friction for the shopper, and more conversions for you!
46
+
47
+ * **GDPR Compliant**: You can optionally show a GDPR notice on the checkout page.
48
+
49
+ * **Ready templates for follow up emails**: Writing emails from scratch can be a pain. Not everyone can frame effective follow-up emails. We provide ready conversion tested email templates.
50
+
51
+ * **Webhooks**: Use a marketing automation tool like Active Campaign, Campaign Monitor, etc? This plugin integrates with all of them through webhook easily.
52
+
53
+ * **Coupon Code**: This plugin can generate limited time unique discount coupons to entice your shoppers and send them automatically via email.
54
+
55
+ * **Reports**: You get a full report of how the plugin is working behind the scenes, and recovering your lost revenue on autopilot.
56
+
57
+ [youtube https://www.youtube.com/watch?v=VWGxjjuP2_k]
58
+
59
+ **Is This Plugin Really Free? What’s the Catch?**
60
+
61
+ Absolutely. There is no catch at all. This is a 100% free gift for all WooCommerce users from our team at CartFlows.
62
+
63
+ <a href="https://cartflows.com" target="_blank">CartFlows</a> is a premium WooCommerce plugin that is used to create marketing and sales funnels. With CartFlows, you can design better checkout pages, add <a href="https://cartflows.com" target="_blank">order bump</a> or even <a href="https://cartflows.com" target="_blank">one-click upsell</a> functionality.
64
+
65
+ **Will It Affects the Performance of My WooCommerce Shop?**
66
+
67
+ No. Just as WooCommerce, this plugin stores everything locally in the database of WordPress. Emails are sent via WordPress native 'wpmail' function or SMTP. We have optimized the plugin so it leaves no performance impact.
68
+
69
+
70
+ **How Can I Get Started?**
71
+
72
+ Getting started is very easy.
73
+
74
+ * **Step 1**: Install and activate the WooCommerce Cart Abandonment Recovery plugin.
75
+
76
+ * **Step 2**: Review the default email templates. Make necessary changes if required.
77
+
78
+ * **Step 3**: You’re done!
79
+
80
+ The plugin will start recovering your lost sales in as quickly as 15 minutes.
81
+
82
+ == Installation ==
83
+
84
+ 1. Upload `woocommerce-cart-abandonment-recovery.zip` to the `/wp-content/plugins/` directory
85
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
86
+
87
+ == Frequently Asked Questions ==
88
+
89
+ = What Is Meant by Cart Abandonment? =
90
+
91
+ While shopping, a user adds products to the cart. But if this user doesn't complete the purchase on the checkout page, the cart is considered abandoned.
92
+
93
+ = How Often Cart Gets Abandoned? Is It Happening on My Shop? =
94
+
95
+ According to research, 6 out of 10 visitors, leave the checkout page and do not complete the purchase. Even if you have motivated enough, 20% to 25% of the shoppers leave the purchase process.
96
+
97
+ = Do I Need Any Technical Experience to Use This Plugin? =
98
+
99
+ Any WooCommerce shop owner selling anything online can use this plugin.You will not need any technical experience to start recovering your lost revenue. Once initiated the plugin will work automatically for you.
100
+
101
+ = Can I Send Coupon with Follow up Email? =
102
+
103
+ Yes. You can generate and send unique, limited-time discount coupon. Though there is no compulsion of sending coupon. It's completely optional.
104
+
105
+ = Can I Directly Take Users to Checkout Page, Exactly Where They Left Off? =
106
+
107
+ Absolutely. A unique checkout link can be sent with follow up email. This will take the shopper to their prefilled checkout page. This will make the purchase process easier for the shopper.
108
+
109
+ = Can Marketing Automation Tools Be Integrated with This? =
110
+
111
+ Plugin offers Webhooks. This allows integrating Active Campaign, Mautic, Campaign Monitor, etc with the plugin.
112
+
113
+ = Will This Plugin Add Any Extra Time in Website Loading? =
114
+
115
+ Not at all. All the plugin data is stored in its own database table. It is completely self-hosted plugin. It works smoothly and does not leave any impact on the performance of the website. So you don't have to worry about the speed.
116
+
117
+ = Why This Awesome Plugin Is Free? =
118
+
119
+ Here are few thoughts behind making it available for free:
120
+ - It is our way of saying thank you to the community and helping shop owners to boost their profits.
121
+ - And quite honestly, we want you to try one of our products for free. And when you see how helpful it is, it should get you excited to buy other products from us in the future
122
+
123
+ == Screenshots ==
124
+
125
+ 1. Track recovery report for abandonment sales from the dashboard
126
+ 2. Schedule the follow-up emails from one place
127
+ 3. Prebuilt and easy-to-edit Email templates
128
+ 4. General settings for Email, Webhook (Coupon Code), GDPR
129
+
130
+ == Changelog ==
131
+
132
+ = Version 1.2.5 - Wednesday, 11th March 2020 =
133
+ * Improvement: Allowed plugin access to the shop manager.
134
+ * Fix: Variable product name not showing in the product table.
135
+ * Fix: All orders are not exporting due to the wrong pagination.
136
+ * Fix: Not showing the next page's orders.
137
+
138
+ = Version 1.2.4 - Thursday, 06th February 2020 =
139
+ * New: Added option to export abandoned orders.
140
+ * New: Added option to search abandoned orders.
141
+ * Improvement: Compatibility with the latest WordPress PHP_CodeSniffer rules.
142
+ * Fix: Get id error while sending emails.
143
+
144
+ = Version 1.2.3 - Thursday, 12th December 2019 =
145
+ * New: Added option to unsubscribe users in bulk.
146
+ * New: Added filter 'woo_ca_exclude_on_hold_order_from_tracking' to exclude on hold orders from the tracking.
147
+ * New: Added product table shortcode for webhook.
148
+ * Improvement: Updated filter 'woo_ca_email_template_table_style' for product table alignment.
149
+ * Fix: Sometimes test emails are not sending.
150
+
151
+ = Version 1.2.2 - Tuesday, 12th November 2019 =
152
+ * Fix: Duplicate order issue for variation products.
153
+
154
+ = Version 1.2.1 - Tuesday, 5th November 2019 =
155
+ * New: Added delete option for used & expired coupons which will be created now onwards.
156
+ * Fix: Sometimes order status remains "abandoned" for initially failed orders.
157
+ * Fix: Strings updated for translation.
158
+
159
+ = Version 1.2.0 - Monday, 14th October 2019 =
160
+ * New: Added support for PPOM products.
161
+ * Improvement: Added email activate toggle button on grid.
162
+ * Improvement: Added notice on the checkout page for test emails.
163
+ * Fix: Zero-value orders getting tracked.
164
+ * Fix: Disable tracking for the custom user roles.
165
+
166
+ = Version 1.1.9 - Thursday, 19th September 2019 =
167
+ * New: Option added to ignore users from cart abandonment process.
168
+ * New: Filter added to customize the styling of email template table.
169
+ * Improvement: Added compatibility with Razorpay plugin.
170
+ * Fix: Email template markup was breaking after save.
171
+ * Fix: Failed orders were getting marked as completed.
172
+ * Fix: Empty order was getting tracked and email sending for it.
173
+ * Fix: Email settings options were swapping value of from and reply-to.
174
+
175
+ = Version 1.1.8 - Tuesday, 3rd September 2019 =
176
+ * New: Option added to auto-apply coupon on the checkout.
177
+ * New: Option added to apply coupon individually.
178
+ * New: Option added to create free shipping coupons.
179
+
180
+ = Version 1.1.7 - Monday, 12th August 2019 =
181
+ * New: Filter added to show the cart total inside the email template.
182
+ * New: Filter added to change the cart abandoned time.
183
+ * Improvement: Order tracking logic updated for automated payments.
184
+ * Improvement: Update report dashboard DateTime format to WordPress format.
185
+ * Fix: Broken image in the email template.
186
+
187
+ = Version 1.1.6 - Friday, 19th July 2019 =
188
+ * New: Bundled product support for email checkout URL.
189
+ * Improvement: Added phone number and address while triggering the to webhook.
190
+ * Fix: Creating tables and default settings on activation.
191
+
192
+ = Version 1.1.5 - Tuesday, 9th July 2019 =
193
+ * Fix: Other crons disappearing issue.
194
+
195
+ = Version 1.1.4 - Tuesday, 9th July 2019 =
196
+ * Fix: Follow up emails were getting sent even after the completion of the order.
197
+ * Fix: Email template variable 'Abandoned Product Names' warning issue.
198
+
199
+ = Version 1.1.3 - Thursday, 27th June 2019 =
200
+ * Improvement: Added checkout link for abandoned cart inside the admin section.
201
+ * Fix: Added pagination for reports.
202
+ * Fix: Recover report calculations before campaign triggers.
203
+ * Fix: Empty cart notice when CartFlows checkout is set global.
204
+
205
+ = Version 1.1.2 - Wednesday, 12th June 2019 =
206
+ * Fix: Issue of timezone while sending mail through cron.
207
+ * Fix: Delete single cart abandonment order.
208
+ * Fix: MySql 5.5 support for CURRENT_TIMESTAMP.
209
+
210
+ = Version 1.1.1 - Thursday, 06th June 2019 =
211
+ * New: Added feature to reschedule emails for Admin.
212
+ * Fix: Coupon expiry time issue.
213
+ * Fix: Email issue for a user who has an already purchased order.
214
+ * Fix: Translatable strings updated.
215
+
216
+ = Version 1.1.0 - Thursday, 30th May 2019 =
217
+ * Added a view for admin to check email status specific to the particular abandoned user.
218
+
219
+ = Version 1.0.0 - Monday, 27th May 2019 =
220
+ * Initial Release
221
+
222
  == 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.2.4
7
- * Author: CartFlows Inc
8
- * Author URI: https://cartflows.com/
9
- * Text Domain: woo-cart-abandonment-recovery
10
- * WC requires at least: 3.0
11
- * WC tested up to: 3.9.1
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.2.5
7
+ * Author: CartFlows Inc
8
+ * Author URI: https://cartflows.com/
9
+ * Text Domain: woo-cart-abandonment-recovery
10
+ * WC requires at least: 3.0
11
+ * WC tested up to: 4.0.0
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';