WooCommerce PDF Invoices & Packing Slips - Version 2.3.0

Version Description

  • Feature: Setting to disable invoices globally for specific order statuses
  • Feature: Control action buttons visibility from settings wizard.
  • Feature: Allow loading of existing PDF file instead of generating on the fly via filter (wpo_wcpdf_load_pdf_file_path)
  • Fix: Check if temp folder exists before creating
  • Fix: Newlines in address from settings wizard
  • Fix: Double images issue with WooCommerce German Market
  • Fix: Only store document settings when creating one
  • Tested with WooCommerce 3.7
Download this release

Release Info

Developer pomegranate
Plugin Icon 128x128 WooCommerce PDF Invoices & Packing Slips
Version 2.3.0
Comparing to
See all releases

Code changes from version 2.2.14 to 2.3.0

assets/css/setup-wizard.css CHANGED
@@ -1,399 +1,399 @@
1
- .wpo-wizzard {
2
- background:#f9f9f9;
3
- }
4
-
5
- .wpo-wcpdf-setup {
6
- padding:0;
7
- font-family: 'Ubuntu', sans-serif;
8
- font-size: 14px;
9
- line-height: 22px;
10
- color:#444;
11
- background:none;
12
- -webkit-box-shadow: none;
13
- box-shadow: none;
14
- }
15
-
16
- .wpo-wcpdf-setup h1, .wpo-wcpdf-setup h2 {
17
- border:none;
18
- color:#444;
19
- margin:0;
20
- }
21
-
22
- #confetti {
23
- width:100%;
24
- height:100%;
25
- position:absolute;
26
- left:0;
27
- top:0;
28
- z-index:-999;
29
- }
30
-
31
- .wpo-setup {
32
- background-color:#f9f9f9;
33
- font-family: 'Ubuntu', sans-serif;
34
- font-size: 14px;
35
- line-height: 22px;
36
- color:#444;
37
- width:100%;
38
- height:100%;
39
- margin:0;
40
- padding:0;
41
- }
42
-
43
- .confetti {
44
- width:100%;
45
- height:100%;
46
- z-index:-999;
47
- position:relative;
48
- }
49
-
50
- .wpo-setup-card {
51
- display:block;
52
- background-color:#f2fafa;
53
- max-width:900px;
54
- margin:100px auto 100px auto;
55
- padding:0;
56
- border-radius:10px;
57
- box-shadow:10px 10px 80px rgba(0,0,0,0.05);
58
- overflow:hidden;
59
- }
60
-
61
- .wpo-plugin-title {
62
- width:100%;
63
- padding:30px 0 50px 0;
64
- margin:0;
65
- background-color:#fdfdfd;
66
- text-align:center;
67
- display:block;
68
- color:#61707d;
69
- }
70
-
71
- .wpo-progress-bar {
72
- width:100%;
73
- height:36px;
74
- overflow:hidden;
75
- list-style: none;
76
- margin:-18px 0 0 0;
77
- padding:0;
78
- }
79
-
80
- .wpo-progress-bar li {
81
- width:16.66%;
82
- float:left;
83
- box-sizing: border-box;
84
- }
85
-
86
- .wpo-progress-marker {
87
- height:24px;
88
- width:24px;
89
- background-color:#fdfdfd;
90
- border:6px solid #3e9b9a;
91
- border-radius:50%;
92
- margin:0 auto;
93
- }
94
-
95
- .wpo-progress-bar .completed {
96
- background-color:#3e9b9a;
97
- }
98
-
99
- .wpo-progress-bar .active {
100
- background-color:#2d7170;
101
- }
102
-
103
- .wpo-setup-content {
104
- float:left;
105
- width:100%;
106
- overflow:hidden;
107
- }
108
-
109
- .wpo-step-description {
110
- width:50%;
111
- float:left;
112
- padding:50px;
113
- box-sizing: border-box;
114
- }
115
-
116
- .wpo-step-description ul {
117
- padding-left:16px;
118
- }
119
-
120
- .wpo-setup-input {
121
- width:50%;
122
- float:left;
123
- padding:50px 50px 50px 0;
124
- box-sizing: border-box;
125
- position:relative;
126
- }
127
-
128
- .wpo-setup-input select {
129
- width:100%;
130
- border:none;
131
- font-size:1.4em;
132
- background-color:#fdfdfd;
133
- color:#444;
134
- border:1px solid #3e9b9a;
135
- height:40px;
136
- }
137
-
138
- .wpo-setup-buttons {
139
- width:100%;
140
- float:left;
141
- padding:0px 50px 50px 50px;
142
- box-sizing: border-box;
143
- }
144
-
145
- .wpo-button-next, .wpo-button-previous, .wpo-skip-step {
146
- background-color:#3e9b9a;
147
- border-radius:5px;
148
- padding:10px 20px;
149
- border:none;
150
- box-sizing: border-box;
151
- font-size:1em;
152
- text-decoration: none;
153
- cursor:pointer;
154
- color:#fdfdfd;
155
- font-size:1.4em;
156
- box-sizing: border-box;
157
- }
158
-
159
- .wpo-button-next:hover, .wpo-button-previous:hover {
160
- background-color:#2d7170;
161
- }
162
-
163
- .wpo-button-next, .wpo-skip-step {
164
- float:right;
165
- margin-left:10px;
166
- }
167
-
168
- .wpo-button-previous {
169
- float:left;
170
- }
171
-
172
- .wpo-skip-step {
173
- background-color:#fdfdfd;
174
- color:#61707d;
175
- }
176
-
177
- .wpo-skip-step:hover {
178
- color:#333;
179
- }
180
-
181
- /* Shop address */
182
-
183
- .wpo-setup-input .shop-name {
184
- width:100%;
185
- height:40px;
186
- padding:10px 15px;
187
- box-sizing: border-box;
188
- font-size:1.2em;
189
- margin-bottom:20px;
190
- border:1px solid #3e9b9a;
191
- font-family: 'Ubuntu', sans-serif;
192
- }
193
-
194
- .wpo-setup-input .shop-address {
195
- width:100%;
196
- height:200px;
197
- padding:15px 15px;
198
- font-size:1.2em;
199
- line-height:1.4em;
200
- box-sizing: border-box;
201
- border:1px solid #3e9b9a;
202
- resize: none;
203
- float:left;
204
- margin:0;
205
- font-family: 'Ubuntu', sans-serif;
206
- text-align:left!important;
207
- }
208
-
209
- /* Your logo */
210
-
211
- .wpo-setup-input #img-header_logo {
212
- width:100%;
213
- height:auto;
214
- background:#fdfdfd;
215
- margin-bottom:20px;
216
- padding:20px;
217
- box-sizing: border-box;
218
- position:relative;
219
- }
220
-
221
- .wpo-setup-input #logo-preview img {
222
- height:80%;
223
- position:absolute;
224
- left:50%;
225
- -ms-transform: translate(-50%, 0%); /* IE 9 */
226
- -webkit-transform: translate(-50%, 0%); /* Safari */
227
- transform: translate(-50%, 0%);
228
- }
229
-
230
- /* Attach to */
231
-
232
- .wpo-setup-input input[type=checkbox] {
233
- -webkit-appearance: none;
234
- background-color: #fdfdfd;
235
- border: 1px solid #cacece;
236
- box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px -15px 10px -12px rgba(0,0,0,0.05);
237
- padding: 14px;
238
- border-radius: 3px;
239
- display: inline-block;
240
- position: relative;
241
- }
242
-
243
- .wpo-setup-input input[type=checkbox]:active, .wpo-setup-input input[type=checkbox]:checked:active {
244
- box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px 1px 3px rgba(0,0,0,0.1);
245
- }
246
-
247
- .wpo-setup-input input[type=checkbox]:checked {
248
- background-color: #fdfdfd;
249
- border: 1px solid #adb8c0;
250
- box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px -15px 10px -12px rgba(0,0,0,0.05), inset 15px 10px -12px rgba(255,255,255,0.1);
251
- color: #99a1a7;
252
- }
253
-
254
- .wpo-setup-input input[type=checkbox]:checked:after {
255
- content: '\2714';
256
- font-size: 24px;
257
- position: absolute;
258
- top: 0px;
259
- left: 3px;
260
- color: #3e9b9a;
261
- }
262
-
263
- .wpo-setup-input .checkbox {
264
- font-size:1.2em;
265
- margin-left:50px;
266
- margin-top:-35px;
267
- margin-bottom:-8px;
268
- display:block;
269
- }
270
-
271
- /* Customizer */
272
-
273
- .wpo-setup-input .how-to-box {
274
- float:right;
275
- width:auto;
276
- max-width:100%;
277
- height:auto;
278
- border:1px solid #3e9b9a;
279
- overflow:hidden;
280
- background:#fff;
281
- }
282
-
283
- .wpo-setup-input .how-to-box img {
284
- width:100%;
285
- }
286
-
287
- .wpo-step-description a:link, .wpo-step-description a:visited {
288
- color:#3e9b9a;
289
- text-decoration:none;
290
- }
291
-
292
- /* Good to go */
293
-
294
- .wpo-final {
295
- text-align:center;
296
- width:100%;
297
- padding:50px 200px;
298
- }
299
-
300
- .wpo-final h1 {
301
- font-size:3em;
302
- line-height:1em;
303
- }
304
-
305
- /* Portrait tablets and small desktops */
306
- @media (min-width: 768px) and (max-width: 991px) {
307
- .wpo-setup-card {
308
- width:80%;
309
- }
310
- }
311
-
312
- /* Landscape phones and portrait tablets */
313
- @media (max-width: 767px) {
314
- .wpo-setup-card {
315
- width:100%;
316
- min-height:100%;
317
- border-radius:0px;
318
- margin:0;
319
- }
320
-
321
- .wpo-step-description, .wpo-setup-input {
322
- width:100%;
323
- padding-left:50px;
324
- }
325
-
326
- .wpo-final {
327
- padding:50px;
328
- }
329
-
330
- .wpo-progress-bar {
331
- margin-top:-12px;
332
- }
333
-
334
- .wpo-progress-marker {
335
- height:16px;
336
- width:16px;
337
- border-width:4px;
338
- }
339
-
340
- .wpo-button-next, .wpo-button-previous, .wpo-skip-step {
341
- font-size:1em;
342
- padding:8px 12px;
343
- }
344
- }
345
-
346
- /* Landscape phones and smaller */
347
- @media (max-width: 480px) {
348
-
349
- .wpo-wizzard, .wpo-wcpdf-setup {
350
- margin:0;
351
- height:100%;
352
- }
353
-
354
- .wpo-wcpdf-setup form {
355
- height:100%;
356
- }
357
-
358
- .wpo-setup-card {
359
- width:100%;
360
- min-height:100%;
361
- border-radius:0px;
362
- margin:0;
363
- }
364
-
365
- .wpo-plugin-title {
366
- padding:25px 0 30px 0;
367
- font-size:1.4em;
368
- }
369
-
370
- .wpo-step-description, .wpo-setup-input, .wpo-setup-buttons {
371
- width:100%;
372
- padding:20px;
373
- }
374
-
375
- .wpo-step-description {
376
- padding-bottom:0;
377
- }
378
-
379
- .wpo-progress-bar {
380
- margin-top:-12px;
381
- }
382
-
383
- .wpo-progress-marker {
384
- height:16px;
385
- width:16px;
386
- border-width:4px;
387
- }
388
-
389
- .wpo-button-next, .wpo-button-previous, .wpo-skip-step {
390
- font-size:1em;
391
- padding:8px 12px;
392
- }
393
-
394
- .wpo-setup-input .checkbox {
395
- font-size:1em;
396
- }
397
- }
398
-
399
-
1
+ .wpo-wizzard {
2
+ background:#f9f9f9;
3
+ }
4
+
5
+ .wpo-wcpdf-setup {
6
+ padding:0;
7
+ font-family: 'Ubuntu', sans-serif;
8
+ font-size: 14px;
9
+ line-height: 22px;
10
+ color:#444;
11
+ background:none;
12
+ -webkit-box-shadow: none;
13
+ box-shadow: none;
14
+ }
15
+
16
+ .wpo-wcpdf-setup h1, .wpo-wcpdf-setup h2 {
17
+ border:none;
18
+ color:#444;
19
+ margin:0;
20
+ }
21
+
22
+ #confetti {
23
+ width:100%;
24
+ height:100%;
25
+ position:absolute;
26
+ left:0;
27
+ top:0;
28
+ z-index:-999;
29
+ }
30
+
31
+ .wpo-setup {
32
+ background-color:#f9f9f9;
33
+ font-family: 'Ubuntu', sans-serif;
34
+ font-size: 14px;
35
+ line-height: 22px;
36
+ color:#444;
37
+ width:100%;
38
+ height:100%;
39
+ margin:0;
40
+ padding:0;
41
+ }
42
+
43
+ .confetti {
44
+ width:100%;
45
+ height:100%;
46
+ z-index:-999;
47
+ position:relative;
48
+ }
49
+
50
+ .wpo-setup-card {
51
+ display:block;
52
+ background-color:#f2fafa;
53
+ max-width:900px;
54
+ margin:100px auto 100px auto;
55
+ padding:0;
56
+ border-radius:10px;
57
+ box-shadow:10px 10px 80px rgba(0,0,0,0.05);
58
+ overflow:hidden;
59
+ }
60
+
61
+ .wpo-plugin-title {
62
+ width:100%;
63
+ padding:30px 0 50px 0;
64
+ margin:0;
65
+ background-color:#fdfdfd;
66
+ text-align:center;
67
+ display:block;
68
+ color:#61707d;
69
+ }
70
+
71
+ .wpo-progress-bar {
72
+ width:100%;
73
+ height:36px;
74
+ overflow:hidden;
75
+ list-style: none;
76
+ margin:-18px 0 0 0;
77
+ padding:0;
78
+ }
79
+
80
+ .wpo-progress-bar li {
81
+ width:14.285%;
82
+ float:left;
83
+ box-sizing: border-box;
84
+ }
85
+
86
+ .wpo-progress-marker {
87
+ height:24px;
88
+ width:24px;
89
+ background-color:#fdfdfd;
90
+ border:6px solid #3e9b9a;
91
+ border-radius:50%;
92
+ margin:0 auto;
93
+ }
94
+
95
+ .wpo-progress-bar .completed {
96
+ background-color:#3e9b9a;
97
+ }
98
+
99
+ .wpo-progress-bar .active {
100
+ background-color:#2d7170;
101
+ }
102
+
103
+ .wpo-setup-content {
104
+ float:left;
105
+ width:100%;
106
+ overflow:hidden;
107
+ }
108
+
109
+ .wpo-step-description {
110
+ width:50%;
111
+ float:left;
112
+ padding:50px;
113
+ box-sizing: border-box;
114
+ }
115
+
116
+ .wpo-step-description ul {
117
+ padding-left:16px;
118
+ }
119
+
120
+ .wpo-setup-input {
121
+ width:50%;
122
+ float:left;
123
+ padding:50px 50px 50px 0;
124
+ box-sizing: border-box;
125
+ position:relative;
126
+ }
127
+
128
+ .wpo-setup-input select {
129
+ width:100%;
130
+ border:none;
131
+ font-size:1.4em;
132
+ background-color:#fdfdfd;
133
+ color:#444;
134
+ border:1px solid #3e9b9a;
135
+ height:40px;
136
+ }
137
+
138
+ .wpo-setup-buttons {
139
+ width:100%;
140
+ float:left;
141
+ padding:0px 50px 50px 50px;
142
+ box-sizing: border-box;
143
+ }
144
+
145
+ .wpo-button-next, .wpo-button-previous, .wpo-skip-step {
146
+ background-color:#3e9b9a;
147
+ border-radius:5px;
148
+ padding:10px 20px;
149
+ border:none;
150
+ box-sizing: border-box;
151
+ font-size:1em;
152
+ text-decoration: none;
153
+ cursor:pointer;
154
+ color:#fdfdfd;
155
+ font-size:1.4em;
156
+ box-sizing: border-box;
157
+ }
158
+
159
+ .wpo-button-next:hover, .wpo-button-previous:hover {
160
+ background-color:#2d7170;
161
+ }
162
+
163
+ .wpo-button-next, .wpo-skip-step {
164
+ float:right;
165
+ margin-left:10px;
166
+ }
167
+
168
+ .wpo-button-previous {
169
+ float:left;
170
+ }
171
+
172
+ .wpo-skip-step {
173
+ background-color:#fdfdfd;
174
+ color:#61707d;
175
+ }
176
+
177
+ .wpo-skip-step:hover {
178
+ color:#333;
179
+ }
180
+
181
+ /* Shop address */
182
+
183
+ .wpo-setup-input .shop-name {
184
+ width:100%;
185
+ height:40px;
186
+ padding:10px 15px;
187
+ box-sizing: border-box;
188
+ font-size:1.2em;
189
+ margin-bottom:20px;
190
+ border:1px solid #3e9b9a;
191
+ font-family: 'Ubuntu', sans-serif;
192
+ }
193
+
194
+ .wpo-setup-input .shop-address {
195
+ width:100%;
196
+ height:200px;
197
+ padding:15px 15px;
198
+ font-size:1.2em;
199
+ line-height:1.4em;
200
+ box-sizing: border-box;
201
+ border:1px solid #3e9b9a;
202
+ resize: none;
203
+ float:left;
204
+ margin:0;
205
+ font-family: 'Ubuntu', sans-serif;
206
+ text-align:left!important;
207
+ }
208
+
209
+ /* Your logo */
210
+
211
+ .wpo-setup-input #img-header_logo {
212
+ width:100%;
213
+ height:auto;
214
+ background:#fdfdfd;
215
+ margin-bottom:20px;
216
+ padding:20px;
217
+ box-sizing: border-box;
218
+ position:relative;
219
+ }
220
+
221
+ .wpo-setup-input #logo-preview img {
222
+ height:80%;
223
+ position:absolute;
224
+ left:50%;
225
+ -ms-transform: translate(-50%, 0%); /* IE 9 */
226
+ -webkit-transform: translate(-50%, 0%); /* Safari */
227
+ transform: translate(-50%, 0%);
228
+ }
229
+
230
+ /* Attach to */
231
+
232
+ .wpo-setup-input input[type=checkbox] {
233
+ -webkit-appearance: none;
234
+ background-color: #fdfdfd;
235
+ border: 1px solid #cacece;
236
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px -15px 10px -12px rgba(0,0,0,0.05);
237
+ padding: 14px;
238
+ border-radius: 3px;
239
+ display: inline-block;
240
+ position: relative;
241
+ }
242
+
243
+ .wpo-setup-input input[type=checkbox]:active, .wpo-setup-input input[type=checkbox]:checked:active {
244
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px 1px 3px rgba(0,0,0,0.1);
245
+ }
246
+
247
+ .wpo-setup-input input[type=checkbox]:checked {
248
+ background-color: #fdfdfd;
249
+ border: 1px solid #adb8c0;
250
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px -15px 10px -12px rgba(0,0,0,0.05), inset 15px 10px -12px rgba(255,255,255,0.1);
251
+ color: #99a1a7;
252
+ }
253
+
254
+ .wpo-setup-input input[type=checkbox]:checked:after {
255
+ content: '\2714';
256
+ font-size: 24px;
257
+ position: absolute;
258
+ top: 0px;
259
+ left: 3px;
260
+ color: #3e9b9a;
261
+ }
262
+
263
+ .wpo-setup-input .checkbox {
264
+ font-size:1.2em;
265
+ margin-left:50px;
266
+ margin-top:-35px;
267
+ margin-bottom:-8px;
268
+ display:block;
269
+ }
270
+
271
+ /* Customizer */
272
+
273
+ .wpo-setup-input .how-to-box {
274
+ float:right;
275
+ width:auto;
276
+ max-width:100%;
277
+ height:auto;
278
+ border:1px solid #3e9b9a;
279
+ overflow:hidden;
280
+ background:#fff;
281
+ }
282
+
283
+ .wpo-setup-input .how-to-box img {
284
+ width:100%;
285
+ }
286
+
287
+ .wpo-step-description a:link, .wpo-step-description a:visited {
288
+ color:#3e9b9a;
289
+ text-decoration:none;
290
+ }
291
+
292
+ /* Good to go */
293
+
294
+ .wpo-final {
295
+ text-align:center;
296
+ width:100%;
297
+ padding:50px 200px;
298
+ }
299
+
300
+ .wpo-final h1 {
301
+ font-size:3em;
302
+ line-height:1em;
303
+ }
304
+
305
+ /* Portrait tablets and small desktops */
306
+ @media (min-width: 768px) and (max-width: 991px) {
307
+ .wpo-setup-card {
308
+ width:80%;
309
+ }
310
+ }
311
+
312
+ /* Landscape phones and portrait tablets */
313
+ @media (max-width: 767px) {
314
+ .wpo-setup-card {
315
+ width:100%;
316
+ min-height:100%;
317
+ border-radius:0px;
318
+ margin:0;
319
+ }
320
+
321
+ .wpo-step-description, .wpo-setup-input {
322
+ width:100%;
323
+ padding-left:50px;
324
+ }
325
+
326
+ .wpo-final {
327
+ padding:50px;
328
+ }
329
+
330
+ .wpo-progress-bar {
331
+ margin-top:-12px;
332
+ }
333
+
334
+ .wpo-progress-marker {
335
+ height:16px;
336
+ width:16px;
337
+ border-width:4px;
338
+ }
339
+
340
+ .wpo-button-next, .wpo-button-previous, .wpo-skip-step {
341
+ font-size:1em;
342
+ padding:8px 12px;
343
+ }
344
+ }
345
+
346
+ /* Landscape phones and smaller */
347
+ @media (max-width: 480px) {
348
+
349
+ .wpo-wizzard, .wpo-wcpdf-setup {
350
+ margin:0;
351
+ height:100%;
352
+ }
353
+
354
+ .wpo-wcpdf-setup form {
355
+ height:100%;
356
+ }
357
+
358
+ .wpo-setup-card {
359
+ width:100%;
360
+ min-height:100%;
361
+ border-radius:0px;
362
+ margin:0;
363
+ }
364
+
365
+ .wpo-plugin-title {
366
+ padding:25px 0 30px 0;
367
+ font-size:1.4em;
368
+ }
369
+
370
+ .wpo-step-description, .wpo-setup-input, .wpo-setup-buttons {
371
+ width:100%;
372
+ padding:20px;
373
+ }
374
+
375
+ .wpo-step-description {
376
+ padding-bottom:0;
377
+ }
378
+
379
+ .wpo-progress-bar {
380
+ margin-top:-12px;
381
+ }
382
+
383
+ .wpo-progress-marker {
384
+ height:16px;
385
+ width:16px;
386
+ border-width:4px;
387
+ }
388
+
389
+ .wpo-button-next, .wpo-button-previous, .wpo-skip-step {
390
+ font-size:1em;
391
+ padding:8px 12px;
392
+ }
393
+
394
+ .wpo-setup-input .checkbox {
395
+ font-size:1em;
396
+ }
397
+ }
398
+
399
+
includes/class-wcpdf-admin.php CHANGED
@@ -1,644 +1,665 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
- use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
- use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly
10
- }
11
-
12
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Admin' ) ) :
13
-
14
- class Admin {
15
- function __construct() {
16
- add_action( 'woocommerce_admin_order_actions_end', array( $this, 'add_listing_actions' ) );
17
- add_filter( 'manage_edit-shop_order_columns', array( $this, 'add_invoice_number_column' ), 999 );
18
- add_action( 'manage_shop_order_posts_custom_column', array( $this, 'invoice_number_column_data' ), 2 );
19
- add_action( 'add_meta_boxes_shop_order', array( $this, 'add_meta_boxes' ) );
20
- add_action( 'admin_footer', array( $this, 'bulk_actions' ) );
21
- add_filter( 'woocommerce_shop_order_search_fields', array( $this, 'search_fields' ) );
22
-
23
- add_action( 'save_post', array( $this,'save_invoice_number_date' ) );
24
-
25
- // manually send emails
26
- // WooCommerce core processes order actions at priority 50
27
- add_action( 'woocommerce_process_shop_order_meta', array( $this, 'send_emails' ), 60, 2 );
28
-
29
- add_action( 'admin_notices', array( $this, 'review_plugin_notice' ) );
30
- add_action( 'admin_notices', array( $this, 'install_wizard_notice' ) );
31
-
32
- add_action( 'init', array( $this, 'setup_wizard') );
33
- // add_action( 'wpo_wcpdf_after_pdf', array( $this,'update_pdf_counter' ), 10, 2 );
34
-
35
- add_action( 'admin_bar_menu', array( $this, 'debug_enabled_warning' ), 999 );
36
-
37
-
38
- add_filter( 'manage_edit-shop_order_sortable_columns', array( $this, 'invoice_number_column_sortable' ) );
39
- if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.0', '>=' ) ) {
40
- add_filter( 'request', array( $this, 'request_query_sort_by_invoice_number' ) );
41
- } else {
42
- add_filter( 'pre_get_posts', array( $this, 'pre_get_posts_sort_by_invoice_number' ) );
43
- }
44
-
45
- // AJAX action for deleting document data
46
- add_action( 'wp_ajax_wpo_wcpdf_delete_document', array($this, 'delete_document' ) );
47
- }
48
-
49
- // display review admin notice after 100 pdf downloads
50
- public function review_plugin_notice() {
51
- if ( $this->is_order_page() === false && !( isset( $_GET['page'] ) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
52
- return;
53
- }
54
-
55
- if ( get_option( 'wpo_wcpdf_review_notice_dismissed' ) !== false ) {
56
- return;
57
- } else {
58
- if ( isset( $_GET['wpo_wcpdf_dismis_review'] ) ) {
59
- update_option( 'wpo_wcpdf_review_notice_dismissed', true );
60
- return;
61
- }
62
-
63
- // get invoice count to determine whether notice should be shown
64
- $invoice_count = $this->get_invoice_count();
65
- if ( $invoice_count > 100 ) {
66
- // keep track of how many days this notice is show so we can remove it after 7 days
67
- $notice_shown_on = get_option( 'wpo_wcpdf_review_notice_shown', array() );
68
- $today = date('Y-m-d');
69
- if ( !in_array($today, $notice_shown_on) ) {
70
- $notice_shown_on[] = $today;
71
- update_option( 'wpo_wcpdf_review_notice_shown', $notice_shown_on );
72
- }
73
- // count number of days review is shown, dismiss forever if shown more than 7
74
- if (count($notice_shown_on) > 7) {
75
- update_option( 'wpo_wcpdf_review_notice_dismissed', true );
76
- return;
77
- }
78
-
79
- $rounded_count = (int) substr( (string) $invoice_count, 0, 1 ) * pow( 10, strlen( (string) $invoice_count ) - 1);
80
- ?>
81
- <div class="notice notice-info is-dismissible wpo-wcpdf-review-notice">
82
- <h3><?php printf( __( 'Wow, you have created more than %d invoices with our plugin!', 'woocommerce-pdf-invoices-packing-slips' ), $rounded_count ); ?></h3>
83
- <p><?php _e( 'It would mean a lot to us if you would quickly give our plugin a 5-star rating. Help us spread the word and boost our motivation!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
84
- <ul>
85
- <li><a href="https://wordpress.org/support/plugin/woocommerce-pdf-invoices-packing-slips/reviews/?rate=5#new-post" class="button"><?php _e( 'Yes you deserve it!', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></a></li>
86
- <li><a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_dismis_review', true ) ); ?>" class="wpo-wcpdf-dismiss"><?php _e( 'Hide this message', 'woocommerce-pdf-invoices-packing-slips' ); ?> / <?php _e( 'Already did!', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
87
- <li><a href="mailto:support@wpovernight.com?Subject=Here%20is%20how%20I%20think%20you%20can%20do%20better"><?php _e( 'Actually, I have a complaint...', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
88
- </ul>
89
- </div>
90
- <script type="text/javascript">
91
- jQuery( function( $ ) {
92
- $( '.wpo-wcpdf-review-notice' ).on( 'click', '.notice-dismiss', function( event ) {
93
- event.preventDefault();
94
- window.location.href = $( '.wpo-wcpdf-dismiss' ).attr('href');
95
- });
96
- });
97
- </script>
98
- <!-- Hide extensions ad if this is shown -->
99
- <style>.wcpdf-extensions-ad { display: none; }</style>
100
- <?php
101
- }
102
- }
103
- }
104
-
105
- public function install_wizard_notice() {
106
- // automatically remove notice after 1 week, set transient the first time
107
- if ( $this->is_order_page() === false && !( isset( $_GET['page'] ) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
108
- return;
109
- }
110
-
111
- if ( get_option( 'wpo_wcpdf_install_notice_dismissed' ) !== false ) {
112
- return;
113
- } else {
114
- if ( isset( $_GET['wpo_wcpdf_dismis_install'] ) ) {
115
- update_option( 'wpo_wcpdf_install_notice_dismissed', true );
116
- return;
117
- }
118
-
119
- if ( get_transient( 'wpo_wcpdf_new_install' ) !== false ) {
120
- ?>
121
- <div class="notice notice-info is-dismissible wpo-wcpdf-install-notice">
122
- <p><strong><?php _e( 'New to WooCommerce PDF Invoices & Packing Slips?', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong> &#8211; <?php _e( 'Jumpstart the plugin by following our wizard!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
123
- <p class="submit"><a href="<?php echo esc_url( admin_url( 'admin.php?page=wpo-wcpdf-setup' ) ); ?>" class="button-primary"><?php _e( 'Run the Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></a> <a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_dismis_install', true ) ); ?>" class="wpo-wcpdf-dismiss-wizard"><?php _e( 'I am the wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></p>
124
- </div>
125
- <script type="text/javascript">
126
- jQuery( function( $ ) {
127
- $( '.wpo-wcpdf-install-notice' ).on( 'click', '.notice-dismiss', function( event ) {
128
- event.preventDefault();
129
- window.location.href = $( '.wpo-wcpdf-dismiss-wizard' ).attr('href');
130
- });
131
- });
132
- </script>
133
- <?php
134
- }
135
- }
136
-
137
- }
138
-
139
- public function setup_wizard() {
140
- // Setup/welcome
141
- if ( ! empty( $_GET['page'] ) && $_GET['page'] == 'wpo-wcpdf-setup' ) {
142
- delete_transient( 'wpo_wcpdf_new_install' );
143
- include_once( WPO_WCPDF()->plugin_path() . '/includes/class-wcpdf-setup-wizard.php' );
144
- }
145
- }
146
-
147
- public function get_invoice_count() {
148
- global $wpdb;
149
- $invoice_count = $wpdb->get_var( $wpdb->prepare( "SELECT count(*) FROM {$wpdb->postmeta} WHERE meta_key = %s", '_wcpdf_invoice_number' ) );
150
- return (int) $invoice_count;
151
- }
152
-
153
- public function update_pdf_counter( $document_type, $document ) {
154
- if ( in_array( $document_type, array('invoice','packing-slip') ) ) {
155
- $pdf_count = (int) get_option( 'wpo_wcpdf_count_'.$document_type, 0 );
156
- update_option( 'wpo_wcpdf_count_'.$document_type, $pdf_count + 1 );
157
- }
158
- }
159
-
160
- /**
161
- * Add PDF actions to the orders listing
162
- */
163
- public function add_listing_actions( $order ) {
164
- // do not show buttons for trashed orders
165
- if ( $order->get_status() == 'trash' ) {
166
- return;
167
- }
168
-
169
- $listing_actions = array();
170
- $documents = WPO_WCPDF()->documents->get_documents();
171
- foreach ($documents as $document) {
172
- $document_title = $document->get_title();
173
- $icon = !empty($document->icon) ? $document->icon : WPO_WCPDF()->plugin_url() . "/assets/images/generic_document.png";
174
- if ( $document = wcpdf_get_document( $document->get_type(), $order ) ) {
175
- $document_title = method_exists($document, 'get_title') ? $document->get_title() : $document_title;
176
- $listing_actions[$document->get_type()] = array(
177
- 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . WCX_Order::get_id( $order ) ), 'generate_wpo_wcpdf' ),
178
- 'img' => $icon,
179
- 'alt' => "PDF " . $document_title,
180
- 'exists' => method_exists($document, 'exists') ? $document->exists() : false,
181
- );
182
- }
183
- }
184
-
185
- $listing_actions = apply_filters( 'wpo_wcpdf_listing_actions', $listing_actions, $order );
186
-
187
- foreach ($listing_actions as $action => $data) {
188
- ?>
189
- <a href="<?php echo $data['url']; ?>" class="button tips wpo_wcpdf <?php echo $data['exists'] == true ? "exists " . $action : $action; ?>" target="_blank" alt="<?php echo $data['alt']; ?>" data-tip="<?php echo $data['alt']; ?>">
190
- <img src="<?php echo $data['img']; ?>" alt="<?php echo $data['alt']; ?>" width="16">
191
- </a>
192
- <?php
193
- }
194
- }
195
-
196
- /**
197
- * Create additional Shop Order column for Invoice Numbers
198
- * @param array $columns shop order columns
199
- */
200
- public function add_invoice_number_column( $columns ) {
201
- // get invoice settings
202
- $invoice = wcpdf_get_invoice( null );
203
- $invoice_settings = $invoice->get_settings();
204
- if ( !isset( $invoice_settings['invoice_number_column'] ) ) {
205
- return $columns;
206
- }
207
-
208
- // put the column after the Status column
209
- $new_columns = array_slice($columns, 0, 2, true) +
210
- array( 'pdf_invoice_number' => __( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ) ) +
211
- array_slice($columns, 2, count($columns) - 1, true) ;
212
- return $new_columns;
213
- }
214
-
215
- /**
216
- * Display Invoice Number in Shop Order column (if available)
217
- * @param string $column column slug
218
- */
219
- public function invoice_number_column_data( $column ) {
220
- global $post, $the_order;
221
-
222
- if ( $column == 'pdf_invoice_number' ) {
223
- if ( empty( $the_order ) || WCX_Order::get_id( $the_order ) != $post->ID ) {
224
- $order = WCX::get_order( $post->ID );
225
- if ( $invoice = wcpdf_get_invoice( $order ) ) {
226
- echo $invoice->get_number();
227
- }
228
- do_action( 'wcpdf_invoice_number_column_end', $order );
229
- } else {
230
- if ( $invoice = wcpdf_get_invoice( $the_order ) ) {
231
- echo $invoice->get_number();
232
- }
233
- do_action( 'wcpdf_invoice_number_column_end', $the_order );
234
- }
235
- }
236
- }
237
-
238
- /**
239
- * Add the meta box on the single order page
240
- */
241
- public function add_meta_boxes() {
242
- // resend order emails
243
- if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.2', '>=' ) ) {
244
- add_meta_box(
245
- 'wpo_wcpdf_send_emails',
246
- __( 'Send order email', 'woocommerce-pdf-invoices-packing-slips' ),
247
- array( $this, 'send_order_email_meta_box' ),
248
- 'shop_order',
249
- 'side',
250
- 'high'
251
- );
252
- }
253
-
254
- // create PDF buttons
255
- add_meta_box(
256
- 'wpo_wcpdf-box',
257
- __( 'Create PDF', 'woocommerce-pdf-invoices-packing-slips' ),
258
- array( $this, 'pdf_actions_meta_box' ),
259
- 'shop_order',
260
- 'side',
261
- 'default'
262
- );
263
-
264
- // Invoice number & date
265
- add_meta_box(
266
- 'wpo_wcpdf-data-input-box',
267
- __( 'PDF Invoice data', 'woocommerce-pdf-invoices-packing-slips' ),
268
- array( $this, 'data_input_box_content' ),
269
- 'shop_order',
270
- 'normal',
271
- 'default'
272
- );
273
- }
274
-
275
- /**
276
- * Resend order emails
277
- */
278
- public function send_order_email_meta_box( $post ) {
279
- global $theorder;
280
- // This is used by some callbacks attached to hooks such as woocommerce_resend_order_emails_available
281
- // which rely on the global to determine if emails should be displayed for certain orders.
282
- if ( ! is_object( $theorder ) ) {
283
- $theorder = wc_get_order( $post->ID );
284
- }
285
- ?>
286
- <ul class="wpo_wcpdf_send_emails submitbox">
287
- <li class="wide" id="actions">
288
- <select name="wpo_wcpdf_send_emails">
289
- <option value=""></option>
290
- <?php
291
- $mailer = WC()->mailer();
292
- $available_emails = apply_filters( 'woocommerce_resend_order_emails_available', array( 'new_order', 'cancelled_order', 'customer_processing_order', 'customer_completed_order', 'customer_invoice' ) );
293
- $mails = $mailer->get_emails();
294
- if ( ! empty( $mails ) && ! empty( $available_emails ) ) { ?>
295
- <?php
296
- foreach ( $mails as $mail ) {
297
- if ( in_array( $mail->id, $available_emails ) && 'no' !== $mail->enabled ) {
298
- echo '<option value="send_email_' . esc_attr( $mail->id ) . '">' . esc_html( $mail->title ) . '</option>';
299
- }
300
- } ?>
301
- <?php
302
- }
303
- ?>
304
- </select>
305
- <input type="submit" class="button save_order button-primary" name="save" value="<?php esc_attr_e( 'Save order & send email', 'woocommerce-pdf-invoices-packing-slips' ); ?>" />
306
- <?php
307
- $title = __( 'Send email', 'woocommerce-pdf-invoices-packing-slips' );
308
- $url = wp_nonce_url( add_query_arg('wpo_wcpdf_action','resend_email'), 'generate_wpo_wcpdf' );
309
- // printf('<a href="%s" class="button wpo_wcpdf_send_email"><span>%s</span></a>')
310
- ?>
311
- </li>
312
- </ul>
313
- <?php
314
- }
315
-
316
- /**
317
- * Create the meta box content on the single order page
318
- */
319
- public function pdf_actions_meta_box( $post ) {
320
- global $post_id;
321
-
322
- $meta_box_actions = array();
323
- $documents = WPO_WCPDF()->documents->get_documents();
324
- $order = WCX::get_order( $post->ID );
325
- foreach ($documents as $document) {
326
- $document_title = $document->get_title();
327
- if ( $document = wcpdf_get_document( $document->get_type(), $order ) ) {
328
- $document_title = method_exists($document, 'get_title') ? $document->get_title() : $document_title;
329
- $meta_box_actions[$document->get_type()] = array(
330
- 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . $post_id ), 'generate_wpo_wcpdf' ),
331
- 'alt' => esc_attr( "PDF " . $document_title ),
332
- 'title' => "PDF " . $document_title,
333
- 'exists' => method_exists($document, 'exists') ? $document->exists() : false,
334
- );
335
- }
336
- }
337
-
338
- $meta_box_actions = apply_filters( 'wpo_wcpdf_meta_box_actions', $meta_box_actions, $post_id );
339
-
340
- ?>
341
- <ul class="wpo_wcpdf-actions">
342
- <?php
343
- foreach ($meta_box_actions as $document_type => $data) {
344
- $exists = ( isset( $data['exists'] ) && $data['exists'] == true ) ? 'exists' : '';
345
- printf('<li><a href="%1$s" class="button %4$s" target="_blank" alt="%2$s">%3$s</a></li>', $data['url'], $data['alt'], $data['title'], $exists);
346
- }
347
- ?>
348
- </ul>
349
- <?php
350
- }
351
-
352
- /**
353
- * Add metabox for invoice number & date
354
- */
355
- public function data_input_box_content ( $post ) {
356
- $order = WCX::get_order( $post->ID );
357
-
358
- do_action( 'wpo_wcpdf_meta_box_start', $post->ID );
359
-
360
- if ( $invoice = wcpdf_get_invoice( $order ) ) {
361
- $invoice_number = $invoice->get_number();
362
- $invoice_date = $invoice->get_date();
363
- ?>
364
- <div class="wcpdf-data-fields" data-document="invoice" data-order_id="<?php echo WCX_Order::get_id( $order ); ?>">
365
- <h4><?php echo $invoice->get_title(); ?><?php if ($invoice->exists()) : ?><span class="wpo-wcpdf-edit-date-number dashicons dashicons-edit"></span><span class="wpo-wcpdf-delete-document dashicons dashicons-trash" data-nonce="<?php echo wp_create_nonce( "wpo_wcpdf_delete_document" ); ?>"></span><?php endif; ?></h4>
366
-
367
- <!-- Read only -->
368
- <div class="read-only">
369
- <?php if ($invoice->exists()) : ?>
370
- <div class="invoice-number">
371
- <p class="form-field _wcpdf_invoice_number_field ">
372
- <p>
373
- <span><strong><?php _e( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</strong></span>
374
- <span><?php if (!empty($invoice_number)) echo $invoice_number->get_formatted(); ?></span>
375
- </p>
376
- </p>
377
- </div>
378
-
379
- <div class="invoice-date">
380
- <p class="form-field form-field-wide">
381
- <p>
382
- <span><strong><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></span>
383
- <span><?php if (!empty($invoice_date)) echo $invoice_date->date_i18n( wc_date_format().' @ '.wc_time_format() ); ?></span>
384
- </p>
385
- </p>
386
- </div>
387
- <?php else : ?>
388
- <span class="wpo-wcpdf-set-date-number button"><?php _e( 'Set invoice number & date', 'woocommerce-pdf-invoices-packing-slips' ) ?></span>
389
- <?php endif; ?>
390
- </div>
391
-
392
- <!-- Editable -->
393
- <div class="editable">
394
- <p class="form-field _wcpdf_invoice_number_field ">
395
- <label for="_wcpdf_invoice_number"><?php _e( 'Invoice Number (unformatted!)', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</label>
396
- <?php if ( $invoice->exists() && !empty($invoice_number) ) : ?>
397
- <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="<?php echo $invoice_number->get_plain(); ?>" disabled="disabled">
398
- <?php else : ?>
399
- <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="" disabled="disabled">
400
- <?php endif; ?>
401
- </p>
402
- <p class="form-field form-field-wide">
403
- <label for="wcpdf_invoice_date"><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
404
- <?php if ( $invoice->exists() && !empty($invoice_date) ) : ?>
405
- <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" value="<?php echo $invoice_date->date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" disabled="disabled"/>@<input type="number" class="hour" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo $invoice_date->date_i18n( 'H' ) ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo $invoice_date->date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" />
406
- <?php else : ?>
407
- <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" disabled="disabled" value="" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" disabled="disabled" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="" pattern="[0-5]{1}[0-9]{1}" disabled="disabled" />
408
- <?php endif; ?>
409
- </p>
410
- </div>
411
- </div>
412
- <?php
413
- }
414
-
415
- do_action( 'wpo_wcpdf_meta_box_end', $post->ID );
416
- }
417
-
418
- /**
419
- * Add actions to menu
420
- */
421
- public function bulk_actions() {
422
- if ( $this->is_order_page() ) {
423
- $bulk_actions = array();
424
- $documents = WPO_WCPDF()->documents->get_documents();
425
- foreach ($documents as $document) {
426
- $bulk_actions[$document->get_type()] = "PDF " . $document->get_title();
427
- }
428
-
429
- $bulk_actions = apply_filters( 'wpo_wcpdf_bulk_actions', $bulk_actions );
430
-
431
- ?>
432
- <script type="text/javascript">
433
- jQuery(document).ready(function() {
434
- <?php foreach ($bulk_actions as $action => $title) { ?>
435
- jQuery('<option>').val('<?php echo $action; ?>').html('<?php echo esc_attr( $title ); ?>').appendTo("select[name='action'], select[name='action2']");
436
- <?php } ?>
437
- });
438
- </script>
439
- <?php
440
- }
441
- }
442
-
443
- /**
444
- * Save invoice number
445
- */
446
- public function save_invoice_number_date($post_id) {
447
- $post_type = get_post_type( $post_id );
448
- if( $post_type == 'shop_order' ) {
449
- // bail if this is not an actual 'Save order' action
450
- if (!isset($_POST['action']) || $_POST['action'] != 'editpost') {
451
- return;
452
- }
453
-
454
- $order = WCX::get_order( $post_id );
455
- if ( $invoice = wcpdf_get_invoice( $order ) ) {
456
- if ( !empty( $_POST['wcpdf_invoice_date'] ) ) {
457
- $date = $_POST['wcpdf_invoice_date'];
458
- $hour = !empty( $_POST['wcpdf_invoice_date_hour'] ) ? $_POST['wcpdf_invoice_date_hour'] : '00';
459
- $minute = !empty( $_POST['wcpdf_invoice_date_minute'] ) ? $_POST['wcpdf_invoice_date_minute'] : '00';
460
-
461
- // clean & sanitize input
462
- $date = date( 'Y-m-d', strtotime( $date ) );
463
- $hour = sprintf('%02d', intval( $hour ));
464
- $minute = sprintf('%02d', intval( $minute ) );
465
- $invoice_date = "{$date} {$hour}:{$minute}:00";
466
-
467
- // set date
468
- $invoice->set_date( $invoice_date );
469
- } elseif ( empty( $_POST['wcpdf_invoice_date'] ) && !empty( $_POST['_wcpdf_invoice_number'] ) ) {
470
- $invoice->set_date( current_time( 'timestamp', true ) );
471
- }
472
-
473
- if ( isset( $_POST['_wcpdf_invoice_number'] ) ) {
474
- // sanitize
475
- $invoice_number = sanitize_text_field( $_POST['_wcpdf_invoice_number'] );
476
- // set number
477
- $invoice->set_number( $invoice_number );
478
- }
479
-
480
- $invoice->save();
481
- }
482
- }
483
- }
484
-
485
- /**
486
- * Send emails manually
487
- */
488
- public function send_emails( $post_id, $post ) {
489
- if ( ! empty( $_POST['wpo_wcpdf_send_emails'] ) ) {
490
- $order = wc_get_order( $post_id );
491
- $action = wc_clean( $_POST['wpo_wcpdf_send_emails'] );
492
- if ( strstr( $action, 'send_email_' ) ) {
493
- // Switch back to the site locale.
494
- wc_switch_to_site_locale();
495
- do_action( 'woocommerce_before_resend_order_emails', $order );
496
- // Ensure gateways are loaded in case they need to insert data into the emails.
497
- WC()->payment_gateways();
498
- WC()->shipping();
499
- // Load mailer.
500
- $mailer = WC()->mailer();
501
- $email_to_send = str_replace( 'send_email_', '', $action );
502
- $mails = $mailer->get_emails();
503
- if ( ! empty( $mails ) ) {
504
- foreach ( $mails as $mail ) {
505
- if ( $mail->id == $email_to_send ) {
506
- $mail->trigger( $order->get_id(), $order );
507
- /* translators: %s: email title */
508
- $order->add_order_note( sprintf( __( '%s email notification manually sent.', 'woocommerce-pdf-invoices-packing-slips' ), $mail->title ), false, true );
509
- }
510
- }
511
- }
512
- do_action( 'woocommerce_after_resend_order_email', $order, $email_to_send );
513
- // Restore user locale.
514
- wc_restore_locale();
515
- // Change the post saved message.
516
- add_filter( 'redirect_post_location', function( $location ) {
517
- // messages in includes/admin/class-wc-admin-post-types.php
518
- // 11 => 'Order updated and sent.'
519
- return add_query_arg( 'message', 11, $location );
520
- } );
521
- }
522
- }
523
- }
524
-
525
- /**
526
- * Add invoice number to order search scope
527
- */
528
- public function search_fields ( $custom_fields ) {
529
- $custom_fields[] = '_wcpdf_invoice_number';
530
- $custom_fields[] = '_wcpdf_formatted_invoice_number';
531
- return $custom_fields;
532
- }
533
-
534
- /**
535
- * Check if this is a shop_order page (edit or list)
536
- */
537
- public function is_order_page() {
538
- global $post_type;
539
- if( $post_type == 'shop_order' ) {
540
- return true;
541
- } else {
542
- return false;
543
- }
544
- }
545
-
546
- /**
547
- * Add invoice number to order search scope
548
- */
549
- public function invoice_number_column_sortable( $columns ) {
550
- $columns['pdf_invoice_number'] = 'pdf_invoice_number';
551
- return $columns;
552
- }
553
-
554
-
555
- /**
556
- * Pre WC3.X sorting
557
- */
558
- public function pre_get_posts_sort_by_invoice_number( $query ) {
559
- if( ! is_admin() ) {
560
- return;
561
- }
562
- $orderby = $query->get( 'orderby');
563
- if( 'pdf_invoice_number' == $orderby ) {
564
- $query->set( 'meta_key', '_wcpdf_invoice_number' );
565
- $query->set( 'orderby', apply_filters( 'wpo_wcpdf_invoice_number_column_orderby', 'meta_value' ) );
566
- }
567
- }
568
-
569
- /**
570
- * WC3.X+ sorting
571
- */
572
- public function request_query_sort_by_invoice_number( $query_vars ) {
573
- global $typenow;
574
-
575
- if ( in_array( $typenow, wc_get_order_types( 'order-meta-boxes' ), true ) ) {
576
- if ( isset( $query_vars['orderby'] ) ) {
577
- if ( 'pdf_invoice_number' === $query_vars['orderby'] ) {
578
- $query_vars = array_merge( $query_vars, array(
579
- 'meta_key' => '_wcpdf_invoice_number',
580
- 'orderby' => apply_filters( 'wpo_wcpdf_invoice_number_column_orderby', 'meta_value' ),
581
- ) );
582
- }
583
- }
584
- }
585
-
586
- return $query_vars;
587
- }
588
-
589
- public function delete_document() {
590
- if ( check_ajax_referer( "wpo_wcpdf_delete_document", 'security', false ) === false ) {
591
- wp_send_json_error( array(
592
- 'message' => 'nonce expired',
593
- ) );
594
- }
595
- if ( empty($_POST['order_id']) || empty($_POST['document']) ) {
596
- wp_send_json_error( array(
597
- 'message' => 'incomplete request',
598
- ) );
599
- }
600
- if ( !current_user_can('manage_woocommerce') ) {
601
- wp_send_json_error( array(
602
- 'message' => 'no permissions',
603
- ) );
604
- }
605
-
606
- $order_id = absint($_POST['order_id']);
607
- $document = sanitize_text_field($_POST['document']);
608
-
609
- try {
610
- $document = wcpdf_get_document( $document, wc_get_order( $order_id ) );
611
- if ( !empty($document) && $document->exists() ) {
612
- $document->delete();
613
- $response = array(
614
- 'message' => $document->get_type()." deleted",
615
- );
616
- wp_send_json_success($response);
617
- } else {
618
- wp_send_json_error( array(
619
- 'message' => 'document does not exist',
620
- ) );
621
- }
622
- } catch (\Exception $e) {
623
- wp_send_json_error( array(
624
- 'message' => 'error: '.$e->getMessage(),
625
- ) );
626
- }
627
- }
628
-
629
- public function debug_enabled_warning( $wp_admin_bar ) {
630
- if ( isset(WPO_WCPDF()->settings->debug_settings['enable_debug']) && current_user_can( 'administrator' ) ) {
631
- $status_settings_url = 'admin.php?page=wpo_wcpdf_options_page&tab=debug';
632
- $title = __( 'DEBUG output enabled', 'woocommerce-pdf-invoices-packing-slips' );
633
- $args = array(
634
- 'id' => 'admin_bar_wpo_debug_mode',
635
- 'title' => sprintf( '<a href="%s" style="background-color: red; color: white;">%s</a>', $status_settings_url, $title ),
636
- );
637
- $wp_admin_bar->add_node( $args );
638
- }
639
- }
640
- }
641
-
642
- endif; // class_exists
643
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
  return new Admin();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
+ use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
+ use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly
10
+ }
11
+
12
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Admin' ) ) :
13
+
14
+ class Admin {
15
+ function __construct() {
16
+ add_action( 'woocommerce_admin_order_actions_end', array( $this, 'add_listing_actions' ) );
17
+ add_filter( 'manage_edit-shop_order_columns', array( $this, 'add_invoice_number_column' ), 999 );
18
+ add_action( 'manage_shop_order_posts_custom_column', array( $this, 'invoice_number_column_data' ), 2 );
19
+ add_action( 'add_meta_boxes_shop_order', array( $this, 'add_meta_boxes' ) );
20
+ add_action( 'admin_footer', array( $this, 'bulk_actions' ) );
21
+ add_filter( 'woocommerce_shop_order_search_fields', array( $this, 'search_fields' ) );
22
+
23
+ add_action( 'save_post', array( $this,'save_invoice_number_date' ) );
24
+
25
+ // manually send emails
26
+ // WooCommerce core processes order actions at priority 50
27
+ add_action( 'woocommerce_process_shop_order_meta', array( $this, 'send_emails' ), 60, 2 );
28
+
29
+ add_action( 'admin_notices', array( $this, 'review_plugin_notice' ) );
30
+ add_action( 'admin_notices', array( $this, 'install_wizard_notice' ) );
31
+
32
+ add_action( 'init', array( $this, 'setup_wizard') );
33
+ // add_action( 'wpo_wcpdf_after_pdf', array( $this,'update_pdf_counter' ), 10, 2 );
34
+
35
+ add_action( 'admin_bar_menu', array( $this, 'debug_enabled_warning' ), 999 );
36
+
37
+
38
+ add_filter( 'manage_edit-shop_order_sortable_columns', array( $this, 'invoice_number_column_sortable' ) );
39
+ if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.0', '>=' ) ) {
40
+ add_filter( 'request', array( $this, 'request_query_sort_by_invoice_number' ) );
41
+ } else {
42
+ add_filter( 'pre_get_posts', array( $this, 'pre_get_posts_sort_by_invoice_number' ) );
43
+ }
44
+
45
+ // AJAX action for deleting document data
46
+ add_action( 'wp_ajax_wpo_wcpdf_delete_document', array($this, 'delete_document' ) );
47
+ }
48
+
49
+ // display review admin notice after 100 pdf downloads
50
+ public function review_plugin_notice() {
51
+ if ( $this->is_order_page() === false && !( isset( $_GET['page'] ) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
52
+ return;
53
+ }
54
+
55
+ if ( get_option( 'wpo_wcpdf_review_notice_dismissed' ) !== false ) {
56
+ return;
57
+ } else {
58
+ if ( isset( $_GET['wpo_wcpdf_dismis_review'] ) ) {
59
+ update_option( 'wpo_wcpdf_review_notice_dismissed', true );
60
+ return;
61
+ }
62
+
63
+ // get invoice count to determine whether notice should be shown
64
+ $invoice_count = $this->get_invoice_count();
65
+ if ( $invoice_count > 100 ) {
66
+ // keep track of how many days this notice is show so we can remove it after 7 days
67
+ $notice_shown_on = get_option( 'wpo_wcpdf_review_notice_shown', array() );
68
+ $today = date('Y-m-d');
69
+ if ( !in_array($today, $notice_shown_on) ) {
70
+ $notice_shown_on[] = $today;
71
+ update_option( 'wpo_wcpdf_review_notice_shown', $notice_shown_on );
72
+ }
73
+ // count number of days review is shown, dismiss forever if shown more than 7
74
+ if (count($notice_shown_on) > 7) {
75
+ update_option( 'wpo_wcpdf_review_notice_dismissed', true );
76
+ return;
77
+ }
78
+
79
+ $rounded_count = (int) substr( (string) $invoice_count, 0, 1 ) * pow( 10, strlen( (string) $invoice_count ) - 1);
80
+ ?>
81
+ <div class="notice notice-info is-dismissible wpo-wcpdf-review-notice">
82
+ <h3><?php printf( __( 'Wow, you have created more than %d invoices with our plugin!', 'woocommerce-pdf-invoices-packing-slips' ), $rounded_count ); ?></h3>
83
+ <p><?php _e( 'It would mean a lot to us if you would quickly give our plugin a 5-star rating. Help us spread the word and boost our motivation!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
84
+ <ul>
85
+ <li><a href="https://wordpress.org/support/plugin/woocommerce-pdf-invoices-packing-slips/reviews/?rate=5#new-post" class="button"><?php _e( 'Yes you deserve it!', 'woocommerce-pdf-invoices-packing-slips' ); ?></span></a></li>
86
+ <li><a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_dismis_review', true ) ); ?>" class="wpo-wcpdf-dismiss"><?php _e( 'Hide this message', 'woocommerce-pdf-invoices-packing-slips' ); ?> / <?php _e( 'Already did!', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
87
+ <li><a href="mailto:support@wpovernight.com?Subject=Here%20is%20how%20I%20think%20you%20can%20do%20better"><?php _e( 'Actually, I have a complaint...', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></li>
88
+ </ul>
89
+ </div>
90
+ <script type="text/javascript">
91
+ jQuery( function( $ ) {
92
+ $( '.wpo-wcpdf-review-notice' ).on( 'click', '.notice-dismiss', function( event ) {
93
+ event.preventDefault();
94
+ window.location.href = $( '.wpo-wcpdf-dismiss' ).attr('href');
95
+ });
96
+ });
97
+ </script>
98
+ <!-- Hide extensions ad if this is shown -->
99
+ <style>.wcpdf-extensions-ad { display: none; }</style>
100
+ <?php
101
+ }
102
+ }
103
+ }
104
+
105
+ public function install_wizard_notice() {
106
+ // automatically remove notice after 1 week, set transient the first time
107
+ if ( $this->is_order_page() === false && !( isset( $_GET['page'] ) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
108
+ return;
109
+ }
110
+
111
+ if ( get_option( 'wpo_wcpdf_install_notice_dismissed' ) !== false ) {
112
+ return;
113
+ } else {
114
+ if ( isset( $_GET['wpo_wcpdf_dismis_install'] ) ) {
115
+ update_option( 'wpo_wcpdf_install_notice_dismissed', true );
116
+ return;
117
+ }
118
+
119
+ if ( get_transient( 'wpo_wcpdf_new_install' ) !== false ) {
120
+ ?>
121
+ <div class="notice notice-info is-dismissible wpo-wcpdf-install-notice">
122
+ <p><strong><?php _e( 'New to WooCommerce PDF Invoices & Packing Slips?', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong> &#8211; <?php _e( 'Jumpstart the plugin by following our wizard!', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
123
+ <p class="submit"><a href="<?php echo esc_url( admin_url( 'admin.php?page=wpo-wcpdf-setup' ) ); ?>" class="button-primary"><?php _e( 'Run the Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></a> <a href="<?php echo esc_url( add_query_arg( 'wpo_wcpdf_dismis_install', true ) ); ?>" class="wpo-wcpdf-dismiss-wizard"><?php _e( 'I am the wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></a></p>
124
+ </div>
125
+ <script type="text/javascript">
126
+ jQuery( function( $ ) {
127
+ $( '.wpo-wcpdf-install-notice' ).on( 'click', '.notice-dismiss', function( event ) {
128
+ event.preventDefault();
129
+ window.location.href = $( '.wpo-wcpdf-dismiss-wizard' ).attr('href');
130
+ });
131
+ });
132
+ </script>
133
+ <?php
134
+ }
135
+ }
136
+
137
+ }
138
+
139
+ public function setup_wizard() {
140
+ // Setup/welcome
141
+ if ( ! empty( $_GET['page'] ) && $_GET['page'] == 'wpo-wcpdf-setup' ) {
142
+ delete_transient( 'wpo_wcpdf_new_install' );
143
+ include_once( WPO_WCPDF()->plugin_path() . '/includes/class-wcpdf-setup-wizard.php' );
144
+ }
145
+ }
146
+
147
+ public function get_invoice_count() {
148
+ global $wpdb;
149
+ $invoice_count = $wpdb->get_var( $wpdb->prepare( "SELECT count(*) FROM {$wpdb->postmeta} WHERE meta_key = %s", '_wcpdf_invoice_number' ) );
150
+ return (int) $invoice_count;
151
+ }
152
+
153
+ public function update_pdf_counter( $document_type, $document ) {
154
+ if ( in_array( $document_type, array('invoice','packing-slip') ) ) {
155
+ $pdf_count = (int) get_option( 'wpo_wcpdf_count_'.$document_type, 0 );
156
+ update_option( 'wpo_wcpdf_count_'.$document_type, $pdf_count + 1 );
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Add PDF actions to the orders listing
162
+ */
163
+ public function add_listing_actions( $order ) {
164
+ // do not show buttons for trashed orders
165
+ if ( $order->get_status() == 'trash' ) {
166
+ return;
167
+ }
168
+ $this->disable_storing_document_settings();
169
+
170
+ $listing_actions = array();
171
+ $documents = WPO_WCPDF()->documents->get_documents();
172
+ foreach ($documents as $document) {
173
+ $document_title = $document->get_title();
174
+ $icon = !empty($document->icon) ? $document->icon : WPO_WCPDF()->plugin_url() . "/assets/images/generic_document.png";
175
+ if ( $document = wcpdf_get_document( $document->get_type(), $order ) ) {
176
+ $document_title = method_exists($document, 'get_title') ? $document->get_title() : $document_title;
177
+ $listing_actions[$document->get_type()] = array(
178
+ 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . WCX_Order::get_id( $order ) ), 'generate_wpo_wcpdf' ),
179
+ 'img' => $icon,
180
+ 'alt' => "PDF " . $document_title,
181
+ 'exists' => method_exists($document, 'exists') ? $document->exists() : false,
182
+ );
183
+ }
184
+ }
185
+
186
+ $listing_actions = apply_filters( 'wpo_wcpdf_listing_actions', $listing_actions, $order );
187
+
188
+ foreach ($listing_actions as $action => $data) {
189
+ ?>
190
+ <a href="<?php echo $data['url']; ?>" class="button tips wpo_wcpdf <?php echo $data['exists'] == true ? "exists " . $action : $action; ?>" target="_blank" alt="<?php echo $data['alt']; ?>" data-tip="<?php echo $data['alt']; ?>">
191
+ <img src="<?php echo $data['img']; ?>" alt="<?php echo $data['alt']; ?>" width="16">
192
+ </a>
193
+ <?php
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Create additional Shop Order column for Invoice Numbers
199
+ * @param array $columns shop order columns
200
+ */
201
+ public function add_invoice_number_column( $columns ) {
202
+ // get invoice settings
203
+ $invoice = wcpdf_get_invoice( null );
204
+ $invoice_settings = $invoice->get_settings();
205
+ if ( !isset( $invoice_settings['invoice_number_column'] ) ) {
206
+ return $columns;
207
+ }
208
+
209
+ // put the column after the Status column
210
+ $new_columns = array_slice($columns, 0, 2, true) +
211
+ array( 'pdf_invoice_number' => __( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ) ) +
212
+ array_slice($columns, 2, count($columns) - 1, true) ;
213
+ return $new_columns;
214
+ }
215
+
216
+ /**
217
+ * Display Invoice Number in Shop Order column (if available)
218
+ * @param string $column column slug
219
+ */
220
+ public function invoice_number_column_data( $column ) {
221
+ global $post, $the_order;
222
+
223
+ if ( $column == 'pdf_invoice_number' ) {
224
+ $this->disable_storing_document_settings();
225
+ if ( empty( $the_order ) || WCX_Order::get_id( $the_order ) != $post->ID ) {
226
+ $order = WCX::get_order( $post->ID );
227
+ if ( $invoice = wcpdf_get_invoice( $order ) ) {
228
+ echo $invoice->get_number();
229
+ }
230
+ do_action( 'wcpdf_invoice_number_column_end', $order );
231
+ } else {
232
+ if ( $invoice = wcpdf_get_invoice( $the_order ) ) {
233
+ echo $invoice->get_number();
234
+ }
235
+ do_action( 'wcpdf_invoice_number_column_end', $the_order );
236
+ }
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Add the meta box on the single order page
242
+ */
243
+ public function add_meta_boxes() {
244
+ // resend order emails
245
+ if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.2', '>=' ) ) {
246
+ add_meta_box(
247
+ 'wpo_wcpdf_send_emails',
248
+ __( 'Send order email', 'woocommerce-pdf-invoices-packing-slips' ),
249
+ array( $this, 'send_order_email_meta_box' ),
250
+ 'shop_order',
251
+ 'side',
252
+ 'high'
253
+ );
254
+ }
255
+
256
+ // create PDF buttons
257
+ add_meta_box(
258
+ 'wpo_wcpdf-box',
259
+ __( 'Create PDF', 'woocommerce-pdf-invoices-packing-slips' ),
260
+ array( $this, 'pdf_actions_meta_box' ),
261
+ 'shop_order',
262
+ 'side',
263
+ 'default'
264
+ );
265
+
266
+ // Invoice number & date
267
+ add_meta_box(
268
+ 'wpo_wcpdf-data-input-box',
269
+ __( 'PDF Invoice data', 'woocommerce-pdf-invoices-packing-slips' ),
270
+ array( $this, 'data_input_box_content' ),
271
+ 'shop_order',
272
+ 'normal',
273
+ 'default'
274
+ );
275
+ }
276
+
277
+ /**
278
+ * Resend order emails
279
+ */
280
+ public function send_order_email_meta_box( $post ) {
281
+ global $theorder;
282
+ // This is used by some callbacks attached to hooks such as woocommerce_resend_order_emails_available
283
+ // which rely on the global to determine if emails should be displayed for certain orders.
284
+ if ( ! is_object( $theorder ) ) {
285
+ $theorder = wc_get_order( $post->ID );
286
+ }
287
+ ?>
288
+ <ul class="wpo_wcpdf_send_emails submitbox">
289
+ <li class="wide" id="actions">
290
+ <select name="wpo_wcpdf_send_emails">
291
+ <option value=""></option>
292
+ <?php
293
+ $mailer = WC()->mailer();
294
+ $available_emails = apply_filters( 'woocommerce_resend_order_emails_available', array( 'new_order', 'cancelled_order', 'customer_processing_order', 'customer_completed_order', 'customer_invoice' ) );
295
+ $mails = $mailer->get_emails();
296
+ if ( ! empty( $mails ) && ! empty( $available_emails ) ) { ?>
297
+ <?php
298
+ foreach ( $mails as $mail ) {
299
+ if ( in_array( $mail->id, $available_emails ) && 'no' !== $mail->enabled ) {
300
+ echo '<option value="send_email_' . esc_attr( $mail->id ) . '">' . esc_html( $mail->title ) . '</option>';
301
+ }
302
+ } ?>
303
+ <?php
304
+ }
305
+ ?>
306
+ </select>
307
+ <input type="submit" class="button save_order button-primary" name="save" value="<?php esc_attr_e( 'Save order & send email', 'woocommerce-pdf-invoices-packing-slips' ); ?>" />
308
+ <?php
309
+ $title = __( 'Send email', 'woocommerce-pdf-invoices-packing-slips' );
310
+ $url = wp_nonce_url( add_query_arg('wpo_wcpdf_action','resend_email'), 'generate_wpo_wcpdf' );
311
+ // printf('<a href="%s" class="button wpo_wcpdf_send_email"><span>%s</span></a>')
312
+ ?>
313
+ </li>
314
+ </ul>
315
+ <?php
316
+ }
317
+
318
+ /**
319
+ * Create the meta box content on the single order page
320
+ */
321
+ public function pdf_actions_meta_box( $post ) {
322
+ global $post_id;
323
+ $this->disable_storing_document_settings();
324
+
325
+ $meta_box_actions = array();
326
+ $documents = WPO_WCPDF()->documents->get_documents();
327
+ $order = WCX::get_order( $post->ID );
328
+ foreach ($documents as $document) {
329
+ $document_title = $document->get_title();
330
+ if ( $document = wcpdf_get_document( $document->get_type(), $order ) ) {
331
+ $document_title = method_exists($document, 'get_title') ? $document->get_title() : $document_title;
332
+ $meta_box_actions[$document->get_type()] = array(
333
+ 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=generate_wpo_wcpdf&document_type={$document->get_type()}&order_ids=" . $post_id ), 'generate_wpo_wcpdf' ),
334
+ 'alt' => esc_attr( "PDF " . $document_title ),
335
+ 'title' => "PDF " . $document_title,
336
+ 'exists' => method_exists($document, 'exists') ? $document->exists() : false,
337
+ );
338
+ }
339
+ }
340
+
341
+ $meta_box_actions = apply_filters( 'wpo_wcpdf_meta_box_actions', $meta_box_actions, $post_id );
342
+
343
+ ?>
344
+ <ul class="wpo_wcpdf-actions">
345
+ <?php
346
+ foreach ($meta_box_actions as $document_type => $data) {
347
+ $exists = ( isset( $data['exists'] ) && $data['exists'] == true ) ? 'exists' : '';
348
+ printf('<li><a href="%1$s" class="button %4$s" target="_blank" alt="%2$s">%3$s</a></li>', $data['url'], $data['alt'], $data['title'], $exists);
349
+ }
350
+ ?>
351
+ </ul>
352
+ <?php
353
+ }
354
+
355
+ /**
356
+ * Add metabox for invoice number & date
357
+ */
358
+ public function data_input_box_content ( $post ) {
359
+ $order = WCX::get_order( $post->ID );
360
+ $this->disable_storing_document_settings();
361
+
362
+ do_action( 'wpo_wcpdf_meta_box_start', $post->ID );
363
+
364
+ if ( $invoice = wcpdf_get_invoice( $order ) ) {
365
+ $invoice_number = $invoice->get_number();
366
+ $invoice_date = $invoice->get_date();
367
+ ?>
368
+ <div class="wcpdf-data-fields" data-document="invoice" data-order_id="<?php echo WCX_Order::get_id( $order ); ?>">
369
+ <h4><?php echo $invoice->get_title(); ?><?php if ($invoice->exists()) : ?><span class="wpo-wcpdf-edit-date-number dashicons dashicons-edit"></span><span class="wpo-wcpdf-delete-document dashicons dashicons-trash" data-nonce="<?php echo wp_create_nonce( "wpo_wcpdf_delete_document" ); ?>"></span><?php endif; ?></h4>
370
+
371
+ <!-- Read only -->
372
+ <div class="read-only">
373
+ <?php if ($invoice->exists()) : ?>
374
+ <div class="invoice-number">
375
+ <p class="form-field _wcpdf_invoice_number_field ">
376
+ <p>
377
+ <span><strong><?php _e( 'Invoice Number', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</strong></span>
378
+ <span><?php if (!empty($invoice_number)) echo $invoice_number->get_formatted(); ?></span>
379
+ </p>
380
+ </p>
381
+ </div>
382
+
383
+ <div class="invoice-date">
384
+ <p class="form-field form-field-wide">
385
+ <p>
386
+ <span><strong><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></strong></span>
387
+ <span><?php if (!empty($invoice_date)) echo $invoice_date->date_i18n( wc_date_format().' @ '.wc_time_format() ); ?></span>
388
+ </p>
389
+ </p>
390
+ </div>
391
+ <?php else : ?>
392
+ <span class="wpo-wcpdf-set-date-number button"><?php _e( 'Set invoice number & date', 'woocommerce-pdf-invoices-packing-slips' ) ?></span>
393
+ <?php endif; ?>
394
+ </div>
395
+
396
+ <!-- Editable -->
397
+ <div class="editable">
398
+ <p class="form-field _wcpdf_invoice_number_field ">
399
+ <label for="_wcpdf_invoice_number"><?php _e( 'Invoice Number (unformatted!)', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</label>
400
+ <?php if ( $invoice->exists() && !empty($invoice_number) ) : ?>
401
+ <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="<?php echo $invoice_number->get_plain(); ?>" disabled="disabled">
402
+ <?php else : ?>
403
+ <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="" disabled="disabled">
404
+ <?php endif; ?>
405
+ </p>
406
+ <p class="form-field form-field-wide">
407
+ <label for="wcpdf_invoice_date"><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
408
+ <?php if ( $invoice->exists() && !empty($invoice_date) ) : ?>
409
+ <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" value="<?php echo $invoice_date->date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" disabled="disabled"/>@<input type="number" class="hour" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo $invoice_date->date_i18n( 'H' ) ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo $invoice_date->date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" />
410
+ <?php else : ?>
411
+ <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" disabled="disabled" value="" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" disabled="disabled" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="" pattern="[0-5]{1}[0-9]{1}" disabled="disabled" />
412
+ <?php endif; ?>
413
+ </p>
414
+ </div>
415
+ </div>
416
+ <?php
417
+ }
418
+
419
+ do_action( 'wpo_wcpdf_meta_box_end', $post->ID );
420
+ }
421
+
422
+ /**
423
+ * Add actions to menu
424
+ */
425
+ public function bulk_actions() {
426
+ if ( $this->is_order_page() ) {
427
+ $bulk_actions = array();
428
+ $documents = WPO_WCPDF()->documents->get_documents();
429
+ foreach ($documents as $document) {
430
+ $bulk_actions[$document->get_type()] = "PDF " . $document->get_title();
431
+ }
432
+
433
+ $bulk_actions = apply_filters( 'wpo_wcpdf_bulk_actions', $bulk_actions );
434
+
435
+ ?>
436
+ <script type="text/javascript">
437
+ jQuery(document).ready(function() {
438
+ <?php foreach ($bulk_actions as $action => $title) { ?>
439
+ jQuery('<option>').val('<?php echo $action; ?>').html('<?php echo esc_attr( $title ); ?>').appendTo("select[name='action'], select[name='action2']");
440
+ <?php } ?>
441
+ });
442
+ </script>
443
+ <?php
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Save invoice number
449
+ */
450
+ public function save_invoice_number_date($post_id) {
451
+ $post_type = get_post_type( $post_id );
452
+ if( $post_type == 'shop_order' ) {
453
+ // bail if this is not an actual 'Save order' action
454
+ if (!isset($_POST['action']) || $_POST['action'] != 'editpost') {
455
+ return;
456
+ }
457
+
458
+ $order = WCX::get_order( $post_id );
459
+ if ( $invoice = wcpdf_get_invoice( $order ) ) {
460
+ if ( !empty( $_POST['wcpdf_invoice_date'] ) ) {
461
+ $date = $_POST['wcpdf_invoice_date'];
462
+ $hour = !empty( $_POST['wcpdf_invoice_date_hour'] ) ? $_POST['wcpdf_invoice_date_hour'] : '00';
463
+ $minute = !empty( $_POST['wcpdf_invoice_date_minute'] ) ? $_POST['wcpdf_invoice_date_minute'] : '00';
464
+
465
+ // clean & sanitize input
466
+ $date = date( 'Y-m-d', strtotime( $date ) );
467
+ $hour = sprintf('%02d', intval( $hour ));
468
+ $minute = sprintf('%02d', intval( $minute ) );
469
+ $invoice_date = "{$date} {$hour}:{$minute}:00";
470
+
471
+ // set date
472
+ $invoice->set_date( $invoice_date );
473
+ } elseif ( empty( $_POST['wcpdf_invoice_date'] ) && !empty( $_POST['_wcpdf_invoice_number'] ) ) {
474
+ $invoice->set_date( current_time( 'timestamp', true ) );
475
+ }
476
+
477
+ if ( isset( $_POST['_wcpdf_invoice_number'] ) ) {
478
+ // sanitize
479
+ $invoice_number = sanitize_text_field( $_POST['_wcpdf_invoice_number'] );
480
+ // set number
481
+ $invoice->set_number( $invoice_number );
482
+ }
483
+
484
+ $invoice->save();
485
+ }
486
+ }
487
+ }
488
+
489
+ /**
490
+ * Document objects are created in order to check for existence and retrieve data,
491
+ * but we don't want to store the settings for uninitialized documents.
492
+ * Only use in frontend/backed (page requests), otherwise settings will never be stored!
493
+ */
494
+ public function disable_storing_document_settings() {
495
+ add_filter( 'wpo_wcpdf_document_store_settings', array( $this, 'return_false' ), 9999 );
496
+ }
497
+
498
+ public function restore_storing_document_settings() {
499
+ remove_filter( 'wpo_wcpdf_document_store_settings', array( $this, 'return_false' ), 9999 );
500
+ }
501
+
502
+ public function return_false(){
503
+ return false;
504
+ }
505
+
506
+ /**
507
+ * Send emails manually
508
+ */
509
+ public function send_emails( $post_id, $post ) {
510
+ if ( ! empty( $_POST['wpo_wcpdf_send_emails'] ) ) {
511
+ $order = wc_get_order( $post_id );
512
+ $action = wc_clean( $_POST['wpo_wcpdf_send_emails'] );
513
+ if ( strstr( $action, 'send_email_' ) ) {
514
+ // Switch back to the site locale.
515
+ wc_switch_to_site_locale();
516
+ do_action( 'woocommerce_before_resend_order_emails', $order );
517
+ // Ensure gateways are loaded in case they need to insert data into the emails.
518
+ WC()->payment_gateways();
519
+ WC()->shipping();
520
+ // Load mailer.
521
+ $mailer = WC()->mailer();
522
+ $email_to_send = str_replace( 'send_email_', '', $action );
523
+ $mails = $mailer->get_emails();
524
+ if ( ! empty( $mails ) ) {
525
+ foreach ( $mails as $mail ) {
526
+ if ( $mail->id == $email_to_send ) {
527
+ $mail->trigger( $order->get_id(), $order );
528
+ /* translators: %s: email title */
529
+ $order->add_order_note( sprintf( __( '%s email notification manually sent.', 'woocommerce-pdf-invoices-packing-slips' ), $mail->title ), false, true );
530
+ }
531
+ }
532
+ }
533
+ do_action( 'woocommerce_after_resend_order_email', $order, $email_to_send );
534
+ // Restore user locale.
535
+ wc_restore_locale();
536
+ // Change the post saved message.
537
+ add_filter( 'redirect_post_location', function( $location ) {
538
+ // messages in includes/admin/class-wc-admin-post-types.php
539
+ // 11 => 'Order updated and sent.'
540
+ return add_query_arg( 'message', 11, $location );
541
+ } );
542
+ }
543
+ }
544
+ }
545
+
546
+ /**
547
+ * Add invoice number to order search scope
548
+ */
549
+ public function search_fields ( $custom_fields ) {
550
+ $custom_fields[] = '_wcpdf_invoice_number';
551
+ $custom_fields[] = '_wcpdf_formatted_invoice_number';
552
+ return $custom_fields;
553
+ }
554
+
555
+ /**
556
+ * Check if this is a shop_order page (edit or list)
557
+ */
558
+ public function is_order_page() {
559
+ global $post_type;
560
+ if( $post_type == 'shop_order' ) {
561
+ return true;
562
+ } else {
563
+ return false;
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Add invoice number to order search scope
569
+ */
570
+ public function invoice_number_column_sortable( $columns ) {
571
+ $columns['pdf_invoice_number'] = 'pdf_invoice_number';
572
+ return $columns;
573
+ }
574
+
575
+
576
+ /**
577
+ * Pre WC3.X sorting
578
+ */
579
+ public function pre_get_posts_sort_by_invoice_number( $query ) {
580
+ if( ! is_admin() ) {
581
+ return;
582
+ }
583
+ $orderby = $query->get( 'orderby');
584
+ if( 'pdf_invoice_number' == $orderby ) {
585
+ $query->set( 'meta_key', '_wcpdf_invoice_number' );
586
+ $query->set( 'orderby', apply_filters( 'wpo_wcpdf_invoice_number_column_orderby', 'meta_value' ) );
587
+ }
588
+ }
589
+
590
+ /**
591
+ * WC3.X+ sorting
592
+ */
593
+ public function request_query_sort_by_invoice_number( $query_vars ) {
594
+ global $typenow;
595
+
596
+ if ( in_array( $typenow, wc_get_order_types( 'order-meta-boxes' ), true ) ) {
597
+ if ( isset( $query_vars['orderby'] ) ) {
598
+ if ( 'pdf_invoice_number' === $query_vars['orderby'] ) {
599
+ $query_vars = array_merge( $query_vars, array(
600
+ 'meta_key' => '_wcpdf_invoice_number',
601
+ 'orderby' => apply_filters( 'wpo_wcpdf_invoice_number_column_orderby', 'meta_value' ),
602
+ ) );
603
+ }
604
+ }
605
+ }
606
+
607
+ return $query_vars;
608
+ }
609
+
610
+ public function delete_document() {
611
+ if ( check_ajax_referer( "wpo_wcpdf_delete_document", 'security', false ) === false ) {
612
+ wp_send_json_error( array(
613
+ 'message' => 'nonce expired',
614
+ ) );
615
+ }
616
+ if ( empty($_POST['order_id']) || empty($_POST['document']) ) {
617
+ wp_send_json_error( array(
618
+ 'message' => 'incomplete request',
619
+ ) );
620
+ }
621
+ if ( !current_user_can('manage_woocommerce') ) {
622
+ wp_send_json_error( array(
623
+ 'message' => 'no permissions',
624
+ ) );
625
+ }
626
+
627
+ $order_id = absint($_POST['order_id']);
628
+ $document = sanitize_text_field($_POST['document']);
629
+
630
+ try {
631
+ $document = wcpdf_get_document( $document, wc_get_order( $order_id ) );
632
+ if ( !empty($document) && $document->exists() ) {
633
+ $document->delete();
634
+ $response = array(
635
+ 'message' => $document->get_type()." deleted",
636
+ );
637
+ wp_send_json_success($response);
638
+ } else {
639
+ wp_send_json_error( array(
640
+ 'message' => 'document does not exist',
641
+ ) );
642
+ }
643
+ } catch (\Exception $e) {
644
+ wp_send_json_error( array(
645
+ 'message' => 'error: '.$e->getMessage(),
646
+ ) );
647
+ }
648
+ }
649
+
650
+ public function debug_enabled_warning( $wp_admin_bar ) {
651
+ if ( isset(WPO_WCPDF()->settings->debug_settings['enable_debug']) && current_user_can( 'administrator' ) ) {
652
+ $status_settings_url = 'admin.php?page=wpo_wcpdf_options_page&tab=debug';
653
+ $title = __( 'DEBUG output enabled', 'woocommerce-pdf-invoices-packing-slips' );
654
+ $args = array(
655
+ 'id' => 'admin_bar_wpo_debug_mode',
656
+ 'title' => sprintf( '<a href="%s" style="background-color: red; color: white;">%s</a>', $status_settings_url, $title ),
657
+ );
658
+ $wp_admin_bar->add_node( $args );
659
+ }
660
+ }
661
+ }
662
+
663
+ endif; // class_exists
664
+
665
  return new Admin();
includes/class-wcpdf-assets.php CHANGED
@@ -1,139 +1,140 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- if ( ! defined( 'ABSPATH' ) ) {
5
- exit; // Exit if accessed directly
6
- }
7
-
8
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Assets' ) ) :
9
-
10
- class Assets {
11
-
12
- function __construct() {
13
- add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts_styles' ) );
14
- add_action( 'admin_enqueue_scripts', array( $this, 'backend_scripts_styles' ) );
15
- }
16
-
17
- /**
18
- * Load styles & scripts
19
- */
20
- public function frontend_scripts_styles ( $hook ) {
21
- # none yet
22
- }
23
-
24
- /**
25
- * Load styles & scripts
26
- */
27
- public function backend_scripts_styles ( $hook ) {
28
- if( $this->is_order_page() ) {
29
- // STYLES
30
- wp_enqueue_style( 'thickbox' );
31
-
32
- wp_enqueue_style(
33
- 'wpo-wcpdf-order-styles',
34
- WPO_WCPDF()->plugin_url() . '/assets/css/order-styles.css',
35
- array(),
36
- WPO_WCPDF_VERSION
37
- );
38
-
39
- if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
40
- // WC 2.1 or newer (MP6) is used: bigger buttons
41
- wp_enqueue_style(
42
- 'wpo-wcpdf-order-styles-buttons',
43
- WPO_WCPDF()->plugin_url() . '/assets/css/order-styles-buttons.css',
44
- array(),
45
- WPO_WCPDF_VERSION
46
- );
47
- } else {
48
- // legacy WC 2.0 styles
49
- wp_enqueue_style(
50
- 'wpo-wcpdf-order-styles-buttons',
51
- WPO_WCPDF()->plugin_url() . '/assets/css/order-styles-buttons-wc20.css',
52
- array(),
53
- WPO_WCPDF_VERSION
54
- );
55
- }
56
-
57
- // SCRIPTS
58
- wp_enqueue_script(
59
- 'wpo-wcpdf',
60
- WPO_WCPDF()->plugin_url() . '/assets/js/order-script.js',
61
- array( 'jquery' ),
62
- WPO_WCPDF_VERSION
63
- );
64
-
65
- $bulk_actions = array();
66
- $documents = WPO_WCPDF()->documents->get_documents();
67
- foreach ($documents as $document) {
68
- $bulk_actions[$document->get_type()] = "PDF " . $document->get_title();
69
- }
70
- $bulk_actions = apply_filters( 'wpo_wcpdf_bulk_actions', $bulk_actions );
71
-
72
- wp_localize_script(
73
- 'wpo-wcpdf',
74
- 'wpo_wcpdf_ajax',
75
- array(
76
- 'ajaxurl' => admin_url( 'admin-ajax.php' ), // URL to WordPress ajax handling page
77
- 'nonce' => wp_create_nonce('generate_wpo_wcpdf'),
78
- 'bulk_actions' => array_keys( $bulk_actions ),
79
- 'confirm_delete' => __( 'Are you sure you want to delete this document? This cannot be undone.', 'woocommerce-pdf-invoices-packing-slips'),
80
- )
81
- );
82
- }
83
-
84
- // only load on our own settings page
85
- // maybe find a way to refer directly to WPO\WC\PDF_Invoices\Settings::$options_page_hook ?
86
- if ( $hook == 'woocommerce_page_wpo_wcpdf_options_page' || $hook == 'settings_page_wpo_wcpdf_options_page' || ( isset($_GET['page']) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
87
- wp_enqueue_style(
88
- 'wpo-wcpdf-settings-styles',
89
- WPO_WCPDF()->plugin_url() . '/assets/css/settings-styles.css',
90
- array(),
91
- WPO_WCPDF_VERSION
92
- );
93
- wp_add_inline_style( 'wpo-wcpdf-settings-styles', ".next-number-input.ajax-waiting {
94
- background-image: url(".WPO_WCPDF()->plugin_url().'/assets/images/spinner.gif'.") !important;
95
- background-position: 95% 50% !important;
96
- background-repeat: no-repeat !important;
97
- }" );
98
-
99
- // SCRIPTS
100
- wp_enqueue_script(
101
- 'wpo-wcpdf-admin',
102
- WPO_WCPDF()->plugin_url() . '/assets/js/admin-script.js',
103
- array( 'jquery' ),
104
- WPO_WCPDF_VERSION
105
- );
106
- wp_localize_script(
107
- 'wpo-wcpdf-admin',
108
- 'wpo_wcpdf_admin',
109
- array(
110
- 'ajaxurl' => admin_url( 'admin-ajax.php' ),
111
- )
112
- );
113
-
114
- wp_enqueue_media();
115
- wp_enqueue_script(
116
- 'wpo-wcpdf-media-upload',
117
- WPO_WCPDF()->plugin_url() . '/assets/js/media-upload.js',
118
- array( 'jquery' ),
119
- WPO_WCPDF_VERSION
120
- );
121
- }
122
- }
123
-
124
- /**
125
- * Check if this is a shop_order page (edit or list)
126
- */
127
- public function is_order_page() {
128
- global $post_type;
129
- if( $post_type == 'shop_order' ) {
130
- return true;
131
- } else {
132
- return false;
133
- }
134
- }
135
- }
136
-
137
- endif; // class_exists
138
-
 
139
  return new Assets();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
+ exit; // Exit if accessed directly
6
+ }
7
+
8
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Assets' ) ) :
9
+
10
+ class Assets {
11
+
12
+ function __construct() {
13
+ add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts_styles' ) );
14
+ add_action( 'admin_enqueue_scripts', array( $this, 'backend_scripts_styles' ) );
15
+ }
16
+
17
+ /**
18
+ * Load styles & scripts
19
+ */
20
+ public function frontend_scripts_styles ( $hook ) {
21
+ # none yet
22
+ }
23
+
24
+ /**
25
+ * Load styles & scripts
26
+ */
27
+ public function backend_scripts_styles ( $hook ) {
28
+ if( $this->is_order_page() ) {
29
+ // STYLES
30
+ wp_enqueue_style( 'thickbox' );
31
+
32
+ wp_enqueue_style(
33
+ 'wpo-wcpdf-order-styles',
34
+ WPO_WCPDF()->plugin_url() . '/assets/css/order-styles.css',
35
+ array(),
36
+ WPO_WCPDF_VERSION
37
+ );
38
+
39
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.1' ) >= 0 ) {
40
+ // WC 2.1 or newer (MP6) is used: bigger buttons
41
+ wp_enqueue_style(
42
+ 'wpo-wcpdf-order-styles-buttons',
43
+ WPO_WCPDF()->plugin_url() . '/assets/css/order-styles-buttons.css',
44
+ array(),
45
+ WPO_WCPDF_VERSION
46
+ );
47
+ } else {
48
+ // legacy WC 2.0 styles
49
+ wp_enqueue_style(
50
+ 'wpo-wcpdf-order-styles-buttons',
51
+ WPO_WCPDF()->plugin_url() . '/assets/css/order-styles-buttons-wc20.css',
52
+ array(),
53
+ WPO_WCPDF_VERSION
54
+ );
55
+ }
56
+
57
+ // SCRIPTS
58
+ wp_enqueue_script(
59
+ 'wpo-wcpdf',
60
+ WPO_WCPDF()->plugin_url() . '/assets/js/order-script.js',
61
+ array( 'jquery' ),
62
+ WPO_WCPDF_VERSION
63
+ );
64
+
65
+ $bulk_actions = array();
66
+ $documents = WPO_WCPDF()->documents->get_documents();
67
+ foreach ($documents as $document) {
68
+ $bulk_actions[$document->get_type()] = "PDF " . $document->get_title();
69
+ }
70
+ $bulk_actions = apply_filters( 'wpo_wcpdf_bulk_actions', $bulk_actions );
71
+
72
+ wp_localize_script(
73
+ 'wpo-wcpdf',
74
+ 'wpo_wcpdf_ajax',
75
+ array(
76
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ), // URL to WordPress ajax handling page
77
+ 'nonce' => wp_create_nonce('generate_wpo_wcpdf'),
78
+ 'bulk_actions' => array_keys( $bulk_actions ),
79
+ 'confirm_delete' => __( 'Are you sure you want to delete this document? This cannot be undone.', 'woocommerce-pdf-invoices-packing-slips'),
80
+ )
81
+ );
82
+ }
83
+
84
+ // only load on our own settings page
85
+ // maybe find a way to refer directly to WPO\WC\PDF_Invoices\Settings::$options_page_hook ?
86
+ if ( $hook == 'woocommerce_page_wpo_wcpdf_options_page' || $hook == 'settings_page_wpo_wcpdf_options_page' || ( isset($_GET['page']) && $_GET['page'] == 'wpo_wcpdf_options_page' ) ) {
87
+ wp_enqueue_style(
88
+ 'wpo-wcpdf-settings-styles',
89
+ WPO_WCPDF()->plugin_url() . '/assets/css/settings-styles.css',
90
+ array(),
91
+ WPO_WCPDF_VERSION
92
+ );
93
+ wp_add_inline_style( 'wpo-wcpdf-settings-styles', ".next-number-input.ajax-waiting {
94
+ background-image: url(".WPO_WCPDF()->plugin_url().'/assets/images/spinner.gif'.") !important;
95
+ background-position: 95% 50% !important;
96
+ background-repeat: no-repeat !important;
97
+ }" );
98
+
99
+ // SCRIPTS
100
+ wp_enqueue_script( 'wc-enhanced-select' );
101
+ wp_enqueue_script(
102
+ 'wpo-wcpdf-admin',
103
+ WPO_WCPDF()->plugin_url() . '/assets/js/admin-script.js',
104
+ array( 'jquery', 'wc-enhanced-select' ),
105
+ WPO_WCPDF_VERSION
106
+ );
107
+ wp_localize_script(
108
+ 'wpo-wcpdf-admin',
109
+ 'wpo_wcpdf_admin',
110
+ array(
111
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
112
+ )
113
+ );
114
+
115
+ wp_enqueue_media();
116
+ wp_enqueue_script(
117
+ 'wpo-wcpdf-media-upload',
118
+ WPO_WCPDF()->plugin_url() . '/assets/js/media-upload.js',
119
+ array( 'jquery' ),
120
+ WPO_WCPDF_VERSION
121
+ );
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Check if this is a shop_order page (edit or list)
127
+ */
128
+ public function is_order_page() {
129
+ global $post_type;
130
+ if( $post_type == 'shop_order' ) {
131
+ return true;
132
+ } else {
133
+ return false;
134
+ }
135
+ }
136
+ }
137
+
138
+ endif; // class_exists
139
+
140
  return new Assets();
includes/class-wcpdf-frontend.php CHANGED
@@ -1,88 +1,108 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
- use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
- use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly
10
- }
11
-
12
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Frontend' ) ) :
13
-
14
- class Frontend {
15
-
16
- function __construct() {
17
- add_filter( 'woocommerce_my_account_my_orders_actions', array( $this, 'my_account_pdf_link' ), 10, 2 );
18
- add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_number' ), 10, 2 );
19
- }
20
-
21
- /**
22
- * Display download link on My Account page
23
- */
24
- public function my_account_pdf_link( $actions, $order ) {
25
- $invoice = wcpdf_get_invoice( $order );
26
- if ( $invoice && $invoice->is_enabled() ) {
27
- $pdf_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=generate_wpo_wcpdf&document_type=invoice&order_ids=' . WCX_Order::get_id( $order ) . '&my-account'), 'generate_wpo_wcpdf' );
28
-
29
- // check my account button settings
30
- $button_setting = $invoice->get_setting('my_account_buttons', 'available');
31
- switch ($button_setting) {
32
- case 'available':
33
- $invoice_allowed = $invoice->exists();
34
- break;
35
- case 'always':
36
- $invoice_allowed = true;
37
- break;
38
- case 'never':
39
- $invoice_allowed = false;
40
- break;
41
- case 'custom':
42
- $allowed_statuses = $button_setting = $invoice->get_setting('my_account_restrict', array());
43
- if ( !empty( $allowed_statuses ) && in_array( WCX_Order::get_status( $order ), array_keys( $allowed_statuses ) ) ) {
44
- $invoice_allowed = true;
45
- } else {
46
- $invoice_allowed = false;
47
- }
48
- break;
49
- }
50
-
51
- // Check if invoice has been created already or if status allows download (filter your own array of allowed statuses)
52
- if ( $invoice_allowed || in_array(WCX_Order::get_status( $order ), apply_filters( 'wpo_wcpdf_myaccount_allowed_order_statuses', array() ) ) ) {
53
- $document_title = array_filter( $invoice->get_setting( 'title', array() ) );
54
- if ( !empty($document_title) ) {
55
- $button_text = sprintf ( __( 'Download %s (PDF)', 'woocommerce-pdf-invoices-packing-slips' ), $invoice->get_title() );
56
- } else {
57
- $button_text = __( 'Download invoice (PDF)', 'woocommerce-pdf-invoices-packing-slips' );
58
- }
59
- $actions['invoice'] = array(
60
- 'url' => $pdf_url,
61
- 'name' => apply_filters( 'wpo_wcpdf_myaccount_button_text', $button_text, $invoice )
62
- );
63
- }
64
- }
65
-
66
- return apply_filters( 'wpo_wcpdf_myaccount_actions', $actions, $order );
67
- }
68
-
69
- /**
70
- * Add invoice number to WC REST API
71
- */
72
- public function woocommerce_api_invoice_number ( $data, $order ) {
73
- $data['wpo_wcpdf_invoice_number'] = '';
74
- if ( $invoice = wcpdf_get_invoice( $order ) ) {
75
- $invoice_number = $invoice->get_number();
76
- if ( !empty( $invoice_number ) ) {
77
- $data['wpo_wcpdf_invoice_number'] = $invoice_number->get_formatted();
78
- }
79
- }
80
-
81
- return $data;
82
- }
83
-
84
- }
85
-
86
- endif; // class_exists
87
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  return new Frontend();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
+ use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
+ use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly
10
+ }
11
+
12
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Frontend' ) ) :
13
+
14
+ class Frontend {
15
+
16
+ function __construct() {
17
+ add_filter( 'woocommerce_my_account_my_orders_actions', array( $this, 'my_account_pdf_link' ), 10, 2 );
18
+ add_filter( 'woocommerce_api_order_response', array( $this, 'woocommerce_api_invoice_number' ), 10, 2 );
19
+ }
20
+
21
+ /**
22
+ * Display download link on My Account page
23
+ */
24
+ public function my_account_pdf_link( $actions, $order ) {
25
+ $this->disable_storing_document_settings();
26
+
27
+ $invoice = wcpdf_get_invoice( $order );
28
+ if ( $invoice && $invoice->is_enabled() ) {
29
+ $pdf_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=generate_wpo_wcpdf&document_type=invoice&order_ids=' . WCX_Order::get_id( $order ) . '&my-account'), 'generate_wpo_wcpdf' );
30
+
31
+ // check my account button settings
32
+ $button_setting = $invoice->get_setting('my_account_buttons', 'available');
33
+ switch ($button_setting) {
34
+ case 'available':
35
+ $invoice_allowed = $invoice->exists();
36
+ break;
37
+ case 'always':
38
+ $invoice_allowed = true;
39
+ break;
40
+ case 'never':
41
+ $invoice_allowed = false;
42
+ break;
43
+ case 'custom':
44
+ $allowed_statuses = $button_setting = $invoice->get_setting('my_account_restrict', array());
45
+ if ( !empty( $allowed_statuses ) && in_array( WCX_Order::get_status( $order ), array_keys( $allowed_statuses ) ) ) {
46
+ $invoice_allowed = true;
47
+ } else {
48
+ $invoice_allowed = false;
49
+ }
50
+ break;
51
+ }
52
+
53
+ // Check if invoice has been created already or if status allows download (filter your own array of allowed statuses)
54
+ if ( $invoice_allowed || in_array(WCX_Order::get_status( $order ), apply_filters( 'wpo_wcpdf_myaccount_allowed_order_statuses', array() ) ) ) {
55
+ $document_title = array_filter( $invoice->get_setting( 'title', array() ) );
56
+ if ( !empty($document_title) ) {
57
+ $button_text = sprintf ( __( 'Download %s (PDF)', 'woocommerce-pdf-invoices-packing-slips' ), $invoice->get_title() );
58
+ } else {
59
+ $button_text = __( 'Download invoice (PDF)', 'woocommerce-pdf-invoices-packing-slips' );
60
+ }
61
+ $actions['invoice'] = array(
62
+ 'url' => $pdf_url,
63
+ 'name' => apply_filters( 'wpo_wcpdf_myaccount_button_text', $button_text, $invoice )
64
+ );
65
+ }
66
+ }
67
+
68
+ return apply_filters( 'wpo_wcpdf_myaccount_actions', $actions, $order );
69
+ }
70
+
71
+ /**
72
+ * Add invoice number to WC REST API
73
+ */
74
+ public function woocommerce_api_invoice_number ( $data, $order ) {
75
+ $this->disable_storing_document_settings();
76
+ $data['wpo_wcpdf_invoice_number'] = '';
77
+ if ( $invoice = wcpdf_get_invoice( $order ) ) {
78
+ $invoice_number = $invoice->get_number();
79
+ if ( !empty( $invoice_number ) ) {
80
+ $data['wpo_wcpdf_invoice_number'] = $invoice_number->get_formatted();
81
+ }
82
+ }
83
+
84
+ return $data;
85
+ $this->restore_storing_document_settings();
86
+ }
87
+
88
+ /**
89
+ * Document objects are created in order to check for existence and retrieve data,
90
+ * but we don't want to store the settings for uninitialized documents.
91
+ * Only use in frontend/backed (page requests), otherwise settings will never be stored!
92
+ */
93
+ public function disable_storing_document_settings() {
94
+ add_filter( 'wpo_wcpdf_document_store_settings', array( $this, 'return_false' ), 9999 );
95
+ }
96
+
97
+ public function restore_storing_document_settings() {
98
+ remove_filter( 'wpo_wcpdf_document_store_settings', array( $this, 'return_false' ), 9999 );
99
+ }
100
+
101
+ public function return_false(){
102
+ return false;
103
+ }
104
+ }
105
+
106
+ endif; // class_exists
107
+
108
  return new Frontend();
includes/class-wcpdf-main.php CHANGED
@@ -439,7 +439,9 @@ class Main {
439
  $subfolders = array( 'attachments', 'fonts', 'dompdf' );
440
  foreach ( $subfolders as $subfolder ) {
441
  $path = $tmp_base . $subfolder . '/';
442
- mkdir( $path );
 
 
443
 
444
  // copy font files
445
  if ( $subfolder == 'fonts' ) {
439
  $subfolders = array( 'attachments', 'fonts', 'dompdf' );
440
  foreach ( $subfolders as $subfolder ) {
441
  $path = $tmp_base . $subfolder . '/';
442
+ if ( !is_dir( $path ) ) {
443
+ mkdir( $path );
444
+ }
445
 
446
  // copy font files
447
  if ( $subfolder == 'fonts' ) {
includes/class-wcpdf-settings-callbacks.php CHANGED
@@ -1,558 +1,578 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- use WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store;
5
-
6
- if ( ! defined( 'ABSPATH' ) ) {
7
- exit; // Exit if accessed directly
8
- }
9
-
10
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings_Callbacks' ) ) :
11
-
12
- class Settings_Callbacks {
13
- /**
14
- * Section null callback.
15
- *
16
- * @return void.
17
- */
18
- public function section() {
19
- }
20
-
21
- /**
22
- * Debug section callback.
23
- *
24
- * @return void.
25
- */
26
- public function debug_section() {
27
- _e( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'woocommerce-pdf-invoices-packing-slips' );
28
- }
29
-
30
- /**
31
- * Custom fields section callback.
32
- *
33
- * @return void.
34
- */
35
- public function custom_fields_section() {
36
- _e( 'These are used for the (optional) footer columns in the <em>Modern (Premium)</em> template, but can also be used for other elements in your custom template' , 'woocommerce-pdf-invoices-packing-slips' );
37
- }
38
-
39
- /**
40
- * Checkbox callback.
41
- *
42
- * args:
43
- * option_name - name of the main option
44
- * id - key of the setting
45
- * value - value if not 1 (optional)
46
- * default - default setting (optional)
47
- * description - description (optional)
48
- *
49
- * @return void.
50
- */
51
- public function checkbox( $args ) {
52
- extract( $this->normalize_settings_args( $args ) );
53
-
54
- // output checkbox
55
- printf( '<input type="checkbox" id="%1$s" name="%2$s" value="%3$s" %4$s %5$s/>', $id, $setting_name, $value, checked( $value, $current, false ), !empty($disabled) ? 'disabled="disabled"' : '' );
56
-
57
- // output description.
58
- if ( isset( $description ) ) {
59
- printf( '<p class="description">%s</p>', $description );
60
- }
61
- }
62
-
63
- /**
64
- * Text input callback.
65
- *
66
- * args:
67
- * option_name - name of the main option
68
- * id - key of the setting
69
- * size - size of the text input (em)
70
- * default - default setting (optional)
71
- * description - description (optional)
72
- * type - type (optional)
73
- *
74
- * @return void.
75
- */
76
- public function text_input( $args ) {
77
- extract( $this->normalize_settings_args( $args ) );
78
-
79
- if (empty($type)) {
80
- $type = 'text';
81
- }
82
-
83
- printf( '<input type="%1$s" id="%2$s" name="%3$s" value="%4$s" size="%5$s" placeholder="%6$s" %7$s/>', $type, $id, $setting_name, esc_attr( $current ), $size, $placeholder, !empty($disabled) ? 'disabled="disabled"' : '' );
84
-
85
- // output description.
86
- if ( isset( $description ) ) {
87
- printf( '<p class="description">%s</p>', $description );
88
- }
89
- }
90
-
91
- /**
92
- * Combined checkbox & text input callback.
93
- *
94
- * args:
95
- * option_name - name of the main option
96
- * id - key of the setting
97
- * value - value if not 1 (optional)
98
- * default - default setting (optional)
99
- * description - description (optional)
100
- *
101
- * @return void.
102
- */
103
- public function checkbox_text_input( $args ) {
104
- $args = $this->normalize_settings_args( $args );
105
- extract( $args );
106
- unset($args['description']); // already extracted, should only be used here
107
-
108
- // get checkbox
109
- ob_start();
110
- $this->checkbox( $args );
111
- $checkbox = ob_get_clean();
112
-
113
- // get text input for insertion in wrapper
114
- $input_args = array(
115
- 'id' => $args['text_input_id'],
116
- 'default' => isset( $args['text_input_default'] ) ? (string) $args['text_input_default'] : NULL,
117
- 'size' => isset( $args['text_input_size'] ) ? $args['text_input_size'] : NULL,
118
- ) + $args;
119
- unset($input_args['current']);
120
-
121
- ob_start();
122
- $this->text_input( $input_args );
123
- $text_input = ob_get_clean();
124
-
125
- if (!empty($text_input_wrap)) {
126
- printf( "{$checkbox} {$text_input_wrap}", $text_input);
127
- } else {
128
- echo "{$checkbox} {$text_input}";
129
- }
130
-
131
- // output description.
132
- if ( isset( $description ) ) {
133
- printf( '<p class="description">%s</p>', $description );
134
- }
135
- }
136
-
137
-
138
- // Single text option (not part of any settings array)
139
- public function singular_text_element( $args ) {
140
- $option_name = $args['option_name'];
141
- $id = $args['id'];
142
- $size = isset( $args['size'] ) ? $args['size'] : '25';
143
- $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
144
-
145
- $option = get_option( $option_name );
146
-
147
- if ( isset( $option ) ) {
148
- $current = $option;
149
- } else {
150
- $current = isset( $args['default'] ) ? $args['default'] : '';
151
- }
152
-
153
- $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $option_name, $current, $size, $class );
154
-
155
- // Displays option description.
156
- if ( isset( $args['description'] ) ) {
157
- $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
158
- }
159
-
160
- echo $html;
161
- }
162
-
163
-
164
- /**
165
- * Textarea callback.
166
- *
167
- * args:
168
- * option_name - name of the main option
169
- * id - key of the setting
170
- * width - width of the text input (em)
171
- * height - height of the text input (lines)
172
- * default - default setting (optional)
173
- * description - description (optional)
174
- *
175
- * @return void.
176
- */
177
- public function textarea( $args ) {
178
- extract( $this->normalize_settings_args( $args ) );
179
-
180
- printf( '<textarea id="%1$s" name="%2$s" cols="%4$s" rows="%5$s" placeholder="%6$s"/>%3$s</textarea>', $id, $setting_name, esc_textarea( $current ), $width, $height, $placeholder );
181
-
182
- // output description.
183
- if ( isset( $description ) ) {
184
- printf( '<p class="description">%s</p>', $description );
185
- }
186
- }
187
-
188
- /**
189
- * Select element callback.
190
- *
191
- * @param array $args Field arguments.
192
- *
193
- * @return string Select field.
194
- */
195
- public function select( $args ) {
196
- extract( $this->normalize_settings_args( $args ) );
197
-
198
- printf( '<select id="%1$s" name="%2$s">', $id, $setting_name );
199
-
200
- foreach ( $options as $key => $label ) {
201
- printf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
202
- }
203
-
204
- echo '</select>';
205
-
206
- if (isset($custom)) {
207
- printf( '<div class="%1$s_custom custom">', $id );
208
-
209
- if (is_callable( array( $this, $custom['type'] ) ) ) {
210
- $this->{$custom['type']}( $custom['args'] );
211
- }
212
- echo '</div>';
213
- ?>
214
- <script type="text/javascript">
215
- jQuery(document).ready(function($) {
216
- function check_<?php echo $id; ?>_custom() {
217
- var custom = $('#<?php echo $id; ?>').val();
218
- if (custom == 'custom') {
219
- $( '.<?php echo $id; ?>_custom').show();
220
- } else {
221
- $( '.<?php echo $id; ?>_custom').hide();
222
- }
223
- }
224
-
225
- check_<?php echo $id; ?>_custom();
226
-
227
- $( '#<?php echo $id; ?>' ).change(function() {
228
- check_<?php echo $id; ?>_custom();
229
- });
230
-
231
- });
232
- </script>
233
- <?php
234
- }
235
-
236
- // Displays option description.
237
- if ( isset( $args['description'] ) ) {
238
- printf( '<p class="description">%s</p>', $args['description'] );
239
- }
240
-
241
- }
242
-
243
- public function radio_button( $args ) {
244
- extract( $this->normalize_settings_args( $args ) );
245
-
246
- foreach ( $options as $key => $label ) {
247
- printf( '<input type="radio" class="radio" id="%1$s[%3$s]" name="%2$s" value="%3$s"%4$s />', $id, $setting_name, $key, checked( $current, $key, false ) );
248
- printf( '<label for="%1$s[%3$s]"> %4$s</label><br>', $id, $setting_name, $key, $label);
249
- }
250
-
251
-
252
- // Displays option description.
253
- if ( isset( $args['description'] ) ) {
254
- printf( '<p class="description">%s</p>', $args['description'] );
255
- }
256
-
257
- }
258
-
259
- /**
260
- * Multiple text element callback.
261
- * @param array $args Field arguments.
262
- * @return string Text input field.
263
- */
264
- public function multiple_text_input( $args ) {
265
- extract( $this->normalize_settings_args( $args ) );
266
-
267
- if (!empty($header)) {
268
- echo "<p><strong>{$header}</strong>:</p>";
269
- }
270
-
271
- printf('<p class="%s multiple-text-input">', $id);
272
- foreach ($fields as $name => $field) {
273
- $size = $field['size'];
274
- $placeholder = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
275
-
276
- if (isset($field['label_width'])) {
277
- $style = sprintf( 'style="display:inline-block; width:%1$s;"', $field['label_width'] );
278
- } else {
279
- $style = '';
280
- }
281
-
282
- $description = isset( $field['description'] ) ? '<span style="font-style:italic;">'.$field['description'].'</span>' : '';
283
-
284
- // output field label
285
- if (isset($field['label'])) {
286
- printf( '<label for="%1$s_%2$s" %3$s>%4$s:</label>', $id, $name, $style, $field['label'] );
287
- }
288
-
289
- // output field
290
- $field_current = isset($current[$name]) ? $current[$name] : '';
291
- $type = isset( $field['type'] ) ? $field['type'] : 'text';
292
- printf( '<input type="%1$s" id="%2$s_%4$s" name="%3$s[%4$s]" value="%5$s" size="%6$s" placeholder="%7$s"/> %8$s<br/>', $type, $id, $setting_name, $name, esc_attr( $field_current ), $size, $placeholder, $description );
293
- }
294
- echo "</p>";
295
-
296
- // Displays option description.
297
- if ( isset( $args['description'] ) ) {
298
- printf( '<p class="description">%s</p>', $args['description'] );
299
- }
300
- }
301
-
302
- /**
303
- * Multiple text element callback.
304
- * @param array $args Field arguments.
305
- * @return string Text input field.
306
- */
307
- public function multiple_checkboxes( $args ) {
308
- extract( $this->normalize_settings_args( $args ) );
309
-
310
- foreach ($fields as $name => $label) {
311
- // $label = $field['label'];
312
-
313
- // output checkbox
314
- $field_current = isset($current[$name]) ? $current[$name] : '';
315
- printf( '<input type="checkbox" id="%1$s_%3$s" name="%2$s[%3$s]" value="%4$s"%5$s />', $id, $setting_name, $name, $value, checked( $value, $field_current, false ) );
316
-
317
- // output field label
318
- printf( '<label for="%1$s_%2$s">%3$s</label><br>', $id, $name, $label );
319
-
320
- }
321
-
322
- // Displays option description.
323
- if ( isset( $args['description'] ) ) {
324
- printf( '<p class="description">%s</p>', $args['description'] );
325
- }
326
- }
327
-
328
- /**
329
- * Media upload callback.
330
- *
331
- * @param array $args Field arguments.
332
- *
333
- * @return string Media upload button & preview.
334
- */
335
- public function media_upload( $args ) {
336
- extract( $this->normalize_settings_args( $args ) );
337
-
338
- if( !empty($current) ) {
339
- $attachment = wp_get_attachment_image_src( $current, 'full', false );
340
-
341
- $attachment_src = $attachment[0];
342
- $attachment_width = $attachment[1];
343
- $attachment_height = $attachment[2];
344
- $attachment_resolution = round($attachment_height/(3/2.54));
345
-
346
- printf('<img src="%1$s" style="display:block" id="img-%4$s"/>', $attachment_src, $attachment_width, $attachment_height, $id );
347
- printf('<div class="attachment-resolution"><p class="description">%s: %sdpi (default height = 3cm)</p></div>', __('Image resolution'), $attachment_resolution );
348
- printf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span>', $id, $remove_button_text );
349
- }
350
-
351
- printf( '<input id="%1$s" name="%2$s" type="hidden" value="%3$s" />', $id, $setting_name, $current );
352
-
353
- printf( '<span class="button wpo_upload_image_button %4$s" data-uploader_title="%1$s" data-uploader_button_text="%2$s" data-remove_button_text="%3$s" data-input_id="%4$s">%2$s</span>', $uploader_title, $uploader_button_text, $remove_button_text, $id );
354
-
355
- // Displays option description.
356
- if ( isset( $description ) ) {
357
- printf( '<p class="description">%s</p>', $description );
358
- }
359
- }
360
-
361
- /**
362
- * Next document number edit callback.
363
- *
364
- * @param array $args Field arguments.
365
- */
366
- public function next_number_edit( $args ) {
367
- extract( $args );
368
- $number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
369
- $number_store = new Sequential_Number_Store( $store, $number_store_method );
370
- $next_number = $number_store->get_next();
371
- $nonce = wp_create_nonce( "wpo_wcpdf_next_{$store}" );
372
- printf( '<input id="next_%1$s" class="next-number-input" type="text" size="%2$s" value="%3$s" disabled="disabled" data-store="%1$s" data-nonce="%4$s"/> <span class="edit-next-number dashicons dashicons-edit"></span><span class="save-next-number button secondary" style="display:none;">%5$s</span>', $store, $size, $next_number, $nonce, __( 'Save', 'woocommerce-pdf-invoices-packing-slips' ) );
373
- // Displays option description.
374
- if ( isset( $description ) ) {
375
- printf( '<p class="description">%s</p>', $description );
376
- }
377
- }
378
-
379
- /**
380
- * Wrapper function to create tabs for settings in different languages
381
- * @param [type] $args [description]
382
- * @param [type] $callback [description]
383
- * @return [type] [description]
384
- */
385
- public function i18n_wrap ( $args ) {
386
- extract( $this->normalize_settings_args( $args ) );
387
-
388
- if ( $languages = $this->get_languages() ) {
389
- printf( '<div id="%s-%s-translations" class="translations">', $option_name, $id)
390
- ?>
391
- <ul>
392
- <?php foreach ( $languages as $lang_code => $language_name ) {
393
- $translation_id = "{$option_name}_{$id}_{$lang_code}";
394
- printf('<li><a href="#%s">%s</a></li>', $translation_id, $language_name );
395
- }
396
- ?>
397
- </ul>
398
- <?php foreach ( $languages as $lang_code => $language_name ) {
399
- $translation_id = "{$option_name}_{$id}_{$lang_code}";
400
- printf( '<div id="%s">', $translation_id );
401
- $args['lang'] = $lang_code;
402
- // don't use internationalized placeholders since they're not translated,
403
- // to avoid confusion (user thinking they're all the same)
404
- if ( $callback == 'multiple_text_input' ) {
405
- foreach ($fields as $key => $field_args) {
406
- if (!empty($field_args['placeholder']) && isset($field_args['i18n_placeholder'])) {
407
- $args['fields'][$key]['placeholder'] = '';
408
- }
409
- }
410
- } else {
411
- if (!empty($args['placeholder']) && isset($args['i18n_placeholder'])) {
412
- $args['placeholder'] = '';
413
- }
414
- }
415
- // specific description for internationalized fields (to compensate for missing placeholder)
416
- if (!empty($args['i18n_description'])) {
417
- $args['description'] = $args['i18n_description'];
418
- }
419
- if ( is_array( $callback ) ) {
420
- call_user_func( $callback, $args );
421
- } else {
422
- call_user_func( array( $this, $callback ), $args );
423
- }
424
- echo '</div>';
425
- }
426
- ?>
427
-
428
- </div>
429
- <?php
430
- } else {
431
- $args['lang'] = 'default';
432
- if ( is_array( $callback ) ) {
433
- call_user_func( $callback, $args );
434
- } else {
435
- call_user_func( array( $this, $callback ), $args );
436
- }
437
- }
438
- }
439
-
440
- public function get_languages () {
441
- $multilingual = function_exists('icl_get_languages');
442
- // $multilingual = true; // for development
443
-
444
- if ($multilingual) {
445
- // use this instead of function call for development outside of WPML
446
- // $icl_get_languages = 'a:3:{s:2:"en";a:8:{s:2:"id";s:1:"1";s:6:"active";s:1:"1";s:11:"native_name";s:7:"English";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"English";s:13:"language_code";s:2:"en";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/en.png";s:3:"url";s:23:"http://yourdomain/about";}s:2:"fr";a:8:{s:2:"id";s:1:"4";s:6:"active";s:1:"0";s:11:"native_name";s:9:"Français";s:7:"missing";s:1:"0";s:15:"translated_name";s:6:"French";s:13:"language_code";s:2:"fr";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/fr.png";s:3:"url";s:29:"http://yourdomain/fr/a-propos";}s:2:"it";a:8:{s:2:"id";s:2:"27";s:6:"active";s:1:"0";s:11:"native_name";s:8:"Italiano";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"Italian";s:13:"language_code";s:2:"it";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/it.png";s:3:"url";s:26:"http://yourdomain/it/circa";}}';
447
- // $icl_get_languages = unserialize($icl_get_languages);
448
-
449
- $icl_get_languages = icl_get_languages('skip_missing=0');
450
- $languages = array();
451
- foreach ($icl_get_languages as $lang => $data) {
452
- $languages[$data['language_code']] = $data['native_name'];
453
- }
454
- } else {
455
- return false;
456
- }
457
-
458
- return $languages;
459
- }
460
-
461
- public function normalize_settings_args ( $args ) {
462
- $args['value'] = isset( $args['value'] ) ? $args['value'] : 1;
463
-
464
- $args['placeholder'] = isset( $args['placeholder'] ) ? $args['placeholder'] : '';
465
-
466
- // get main settings array
467
- $option = get_option( $args['option_name'] );
468
-
469
- $args['setting_name'] = "{$args['option_name']}[{$args['id']}]";
470
-
471
- if ( !isset($args['lang']) && !empty($args['translatable']) ) {
472
- $args['lang'] = 'default';
473
- }
474
-
475
- if (isset($args['lang'])) {
476
- // i18n settings name
477
- $args['setting_name'] = "{$args['setting_name']}[{$args['lang']}]";
478
- // copy current option value if set
479
-
480
- if ( $args['lang'] == 'default' && !empty($option[$args['id']]) && !isset( $option[$args['id']]['default'] ) ) {
481
- // we're switching back from WPML to normal
482
- // try english first
483
- if ( isset( $option[$args['id']]['en'] ) ) {
484
- $args['current'] = $option[$args['id']]['en'];
485
- } elseif ( is_array( $option[$args['id']] ) ) {
486
- // fallback to the first language if english not found
487
- $first = array_shift($option[$args['id']]);
488
- if (!empty($first)) {
489
- $args['current'] = $first;
490
- }
491
- } elseif ( is_string( $option[$args['id']] ) ) {
492
- $args['current'] = $option[$args['id']];
493
- } else {
494
- // nothing, really?
495
- $args['current'] = '';
496
- }
497
- } else {
498
- if ( isset( $option[$args['id']][$args['lang']] ) ) {
499
- $args['current'] = $option[$args['id']][$args['lang']];
500
- } elseif (isset( $option[$args['id']]['default'] )) {
501
- $args['current'] = $option[$args['id']]['default'];
502
- }
503
- }
504
- } else {
505
- // copy current option value if set
506
- if ( isset( $option[$args['id']] ) ) {
507
- $args['current'] = $option[$args['id']];
508
- }
509
- }
510
-
511
- // falback to default or empty if no value in option
512
- if ( !isset($args['current']) ) {
513
- $args['current'] = isset( $args['default'] ) ? $args['default'] : '';
514
- }
515
-
516
- return $args;
517
- }
518
-
519
- /**
520
- * Validate options.
521
- *
522
- * @param array $input options to valid.
523
- *
524
- * @return array validated options.
525
- */
526
- public function validate( $input ) {
527
- // echo '<pre>';var_dump($input);die('</pre>');
528
- // Create our array for storing the validated options.
529
- $output = array();
530
-
531
- if (empty($input) || !is_array($input)) {
532
- return $input;
533
- }
534
-
535
- // Loop through each of the incoming options.
536
- foreach ( $input as $key => $value ) {
537
-
538
- // Check to see if the current option has a value. If so, process it.
539
- if ( isset( $input[$key] ) ) {
540
- if ( is_array( $input[$key] ) ) {
541
- foreach ( $input[$key] as $sub_key => $sub_value ) {
542
- $output[$key][$sub_key] = $input[$key][$sub_key];
543
- }
544
- } else {
545
- $output[$key] = $input[$key];
546
- }
547
- }
548
- }
549
-
550
- // Return the array processing any additional functions filtered by this action.
551
- return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
552
- }
553
- }
554
-
555
-
556
- endif; // class_exists
557
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  return new Settings_Callbacks();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ use WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store;
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit; // Exit if accessed directly
8
+ }
9
+
10
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Settings_Callbacks' ) ) :
11
+
12
+ class Settings_Callbacks {
13
+ /**
14
+ * Section null callback.
15
+ *
16
+ * @return void.
17
+ */
18
+ public function section() {
19
+ }
20
+
21
+ /**
22
+ * Debug section callback.
23
+ *
24
+ * @return void.
25
+ */
26
+ public function debug_section() {
27
+ _e( '<b>Warning!</b> The settings below are meant for debugging/development only. Do not use them on a live website!' , 'woocommerce-pdf-invoices-packing-slips' );
28
+ }
29
+
30
+ /**
31
+ * Custom fields section callback.
32
+ *
33
+ * @return void.
34
+ */
35
+ public function custom_fields_section() {
36
+ _e( 'These are used for the (optional) footer columns in the <em>Modern (Premium)</em> template, but can also be used for other elements in your custom template' , 'woocommerce-pdf-invoices-packing-slips' );
37
+ }
38
+
39
+ /**
40
+ * Checkbox callback.
41
+ *
42
+ * args:
43
+ * option_name - name of the main option
44
+ * id - key of the setting
45
+ * value - value if not 1 (optional)
46
+ * default - default setting (optional)
47
+ * description - description (optional)
48
+ *
49
+ * @return void.
50
+ */
51
+ public function checkbox( $args ) {
52
+ extract( $this->normalize_settings_args( $args ) );
53
+
54
+ // output checkbox
55
+ printf( '<input type="checkbox" id="%1$s" name="%2$s" value="%3$s" %4$s %5$s/>', $id, $setting_name, $value, checked( $value, $current, false ), !empty($disabled) ? 'disabled="disabled"' : '' );
56
+
57
+ // output description.
58
+ if ( isset( $description ) ) {
59
+ printf( '<p class="description">%s</p>', $description );
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Text input callback.
65
+ *
66
+ * args:
67
+ * option_name - name of the main option
68
+ * id - key of the setting
69
+ * size - size of the text input (em)
70
+ * default - default setting (optional)
71
+ * description - description (optional)
72
+ * type - type (optional)
73
+ *
74
+ * @return void.
75
+ */
76
+ public function text_input( $args ) {
77
+ extract( $this->normalize_settings_args( $args ) );
78
+
79
+ if (empty($type)) {
80
+ $type = 'text';
81
+ }
82
+
83
+ printf( '<input type="%1$s" id="%2$s" name="%3$s" value="%4$s" size="%5$s" placeholder="%6$s" %7$s/>', $type, $id, $setting_name, esc_attr( $current ), $size, $placeholder, !empty($disabled) ? 'disabled="disabled"' : '' );
84
+
85
+ // output description.
86
+ if ( isset( $description ) ) {
87
+ printf( '<p class="description">%s</p>', $description );
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Combined checkbox & text input callback.
93
+ *
94
+ * args:
95
+ * option_name - name of the main option
96
+ * id - key of the setting
97
+ * value - value if not 1 (optional)
98
+ * default - default setting (optional)
99
+ * description - description (optional)
100
+ *
101
+ * @return void.
102
+ */
103
+ public function checkbox_text_input( $args ) {
104
+ $args = $this->normalize_settings_args( $args );
105
+ extract( $args );
106
+ unset($args['description']); // already extracted, should only be used here
107
+
108
+ // get checkbox
109
+ ob_start();
110
+ $this->checkbox( $args );
111
+ $checkbox = ob_get_clean();
112
+
113
+ // get text input for insertion in wrapper
114
+ $input_args = array(
115
+ 'id' => $args['text_input_id'],
116
+ 'default' => isset( $args['text_input_default'] ) ? (string) $args['text_input_default'] : NULL,
117
+ 'size' => isset( $args['text_input_size'] ) ? $args['text_input_size'] : NULL,
118
+ ) + $args;
119
+ unset($input_args['current']);
120
+
121
+ ob_start();
122
+ $this->text_input( $input_args );
123
+ $text_input = ob_get_clean();
124
+
125
+ if (!empty($text_input_wrap)) {
126
+ printf( "{$checkbox} {$text_input_wrap}", $text_input);
127
+ } else {
128
+ echo "{$checkbox} {$text_input}";
129
+ }
130
+
131
+ // output description.
132
+ if ( isset( $description ) ) {
133
+ printf( '<p class="description">%s</p>', $description );
134
+ }
135
+ }
136
+
137
+
138
+ // Single text option (not part of any settings array)
139
+ public function singular_text_element( $args ) {
140
+ $option_name = $args['option_name'];
141
+ $id = $args['id'];
142
+ $size = isset( $args['size'] ) ? $args['size'] : '25';
143
+ $class = isset( $args['translatable'] ) && $args['translatable'] === true ? 'translatable' : '';
144
+
145
+ $option = get_option( $option_name );
146
+
147
+ if ( isset( $option ) ) {
148
+ $current = $option;
149
+ } else {
150
+ $current = isset( $args['default'] ) ? $args['default'] : '';
151
+ }
152
+
153
+ $html = sprintf( '<input type="text" id="%1$s" name="%2$s" value="%3$s" size="%4$s" class="%5$s"/>', $id, $option_name, $current, $size, $class );
154
+
155
+ // Displays option description.
156
+ if ( isset( $args['description'] ) ) {
157
+ $html .= sprintf( '<p class="description">%s</p>', $args['description'] );
158
+ }
159
+
160
+ echo $html;
161
+ }
162
+
163
+
164
+ /**
165
+ * Textarea callback.
166
+ *
167
+ * args:
168
+ * option_name - name of the main option
169
+ * id - key of the setting
170
+ * width - width of the text input (em)
171
+ * height - height of the text input (lines)
172
+ * default - default setting (optional)
173
+ * description - description (optional)
174
+ *
175
+ * @return void.
176
+ */
177
+ public function textarea( $args ) {
178
+ extract( $this->normalize_settings_args( $args ) );
179
+
180
+ printf( '<textarea id="%1$s" name="%2$s" cols="%4$s" rows="%5$s" placeholder="%6$s"/>%3$s</textarea>', $id, $setting_name, esc_textarea( $current ), $width, $height, $placeholder );
181
+
182
+ // output description.
183
+ if ( isset( $description ) ) {
184
+ printf( '<p class="description">%s</p>', $description );
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Select element callback.
190
+ *
191
+ * @param array $args Field arguments.
192
+ *
193
+ * @return string Select field.
194
+ */
195
+ public function select( $args ) {
196
+ extract( $this->normalize_settings_args( $args ) );
197
+
198
+ if ( isset( $enhanced_select ) ) {
199
+ if ( isset( $multiple ) ) {
200
+ $setting_name = "{$setting_name}[]";
201
+ $multiple = 'multiple=multiple';
202
+ } else {
203
+ $multiple = '';
204
+ }
205
+
206
+ $placeholder = isset($placeholder) ? esc_attr( $placeholder ) : '';
207
+ $title = isset($title) ? esc_attr( $title ) : '';
208
+ $class = 'wc-enhanced-select wpo-wcpdf-enhanced-select';
209
+ $css = 'width:400px';
210
+ printf( '<select id="%1$s" name="%2$s" data-placeholder="%3$s" title="%4$s" class="%5$s" style="%6$s" %7$s>', $id, $setting_name, $placeholder, $title, $class, $css, $multiple );
211
+ } else {
212
+ printf( '<select id="%1$s" name="%2$s">', $id, $setting_name );
213
+ }
214
+
215
+ foreach ( $options as $key => $label ) {
216
+ if ( isset( $multiple ) && is_array( $current ) ) {
217
+ $selected = in_array($key, $current) ? ' selected="selected"' : '';
218
+ printf( '<option value="%s"%s>%s</option>', $key, $selected, $label );
219
+ } else {
220
+ printf( '<option value="%s"%s>%s</option>', $key, selected( $current, $key, false ), $label );
221
+ }
222
+ }
223
+
224
+ echo '</select>';
225
+
226
+ if (isset($custom)) {
227
+ printf( '<div class="%1$s_custom custom">', $id );
228
+
229
+ if (is_callable( array( $this, $custom['type'] ) ) ) {
230
+ $this->{$custom['type']}( $custom['args'] );
231
+ }
232
+ echo '</div>';
233
+ ?>
234
+ <script type="text/javascript">
235
+ jQuery(document).ready(function($) {
236
+ function check_<?php echo $id; ?>_custom() {
237
+ var custom = $('#<?php echo $id; ?>').val();
238
+ if (custom == 'custom') {
239
+ $( '.<?php echo $id; ?>_custom').show();
240
+ } else {
241
+ $( '.<?php echo $id; ?>_custom').hide();
242
+ }
243
+ }
244
+
245
+ check_<?php echo $id; ?>_custom();
246
+
247
+ $( '#<?php echo $id; ?>' ).change(function() {
248
+ check_<?php echo $id; ?>_custom();
249
+ });
250
+
251
+ });
252
+ </script>
253
+ <?php
254
+ }
255
+
256
+ // Displays option description.
257
+ if ( isset( $args['description'] ) ) {
258
+ printf( '<p class="description">%s</p>', $args['description'] );
259
+ }
260
+
261
+ }
262
+
263
+ public function radio_button( $args ) {
264
+ extract( $this->normalize_settings_args( $args ) );
265
+
266
+ foreach ( $options as $key => $label ) {
267
+ printf( '<input type="radio" class="radio" id="%1$s[%3$s]" name="%2$s" value="%3$s"%4$s />', $id, $setting_name, $key, checked( $current, $key, false ) );
268
+ printf( '<label for="%1$s[%3$s]"> %4$s</label><br>', $id, $setting_name, $key, $label);
269
+ }
270
+
271
+
272
+ // Displays option description.
273
+ if ( isset( $args['description'] ) ) {
274
+ printf( '<p class="description">%s</p>', $args['description'] );
275
+ }
276
+
277
+ }
278
+
279
+ /**
280
+ * Multiple text element callback.
281
+ * @param array $args Field arguments.
282
+ * @return string Text input field.
283
+ */
284
+ public function multiple_text_input( $args ) {
285
+ extract( $this->normalize_settings_args( $args ) );
286
+
287
+ if (!empty($header)) {
288
+ echo "<p><strong>{$header}</strong>:</p>";
289
+ }
290
+
291
+ printf('<p class="%s multiple-text-input">', $id);
292
+ foreach ($fields as $name => $field) {
293
+ $size = $field['size'];
294
+ $placeholder = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
295
+
296
+ if (isset($field['label_width'])) {
297
+ $style = sprintf( 'style="display:inline-block; width:%1$s;"', $field['label_width'] );
298
+ } else {
299
+ $style = '';
300
+ }
301
+
302
+ $description = isset( $field['description'] ) ? '<span style="font-style:italic;">'.$field['description'].'</span>' : '';
303
+
304
+ // output field label
305
+ if (isset($field['label'])) {
306
+ printf( '<label for="%1$s_%2$s" %3$s>%4$s:</label>', $id, $name, $style, $field['label'] );
307
+ }
308
+
309
+ // output field
310
+ $field_current = isset($current[$name]) ? $current[$name] : '';
311
+ $type = isset( $field['type'] ) ? $field['type'] : 'text';
312
+ printf( '<input type="%1$s" id="%2$s_%4$s" name="%3$s[%4$s]" value="%5$s" size="%6$s" placeholder="%7$s"/> %8$s<br/>', $type, $id, $setting_name, $name, esc_attr( $field_current ), $size, $placeholder, $description );
313
+ }
314
+ echo "</p>";
315
+
316
+ // Displays option description.
317
+ if ( isset( $args['description'] ) ) {
318
+ printf( '<p class="description">%s</p>', $args['description'] );
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Multiple text element callback.
324
+ * @param array $args Field arguments.
325
+ * @return string Text input field.
326
+ */
327
+ public function multiple_checkboxes( $args ) {
328
+ extract( $this->normalize_settings_args( $args ) );
329
+
330
+ foreach ($fields as $name => $label) {
331
+ // $label = $field['label'];
332
+
333
+ // output checkbox
334
+ $field_current = isset($current[$name]) ? $current[$name] : '';
335
+ printf( '<input type="checkbox" id="%1$s_%3$s" name="%2$s[%3$s]" value="%4$s"%5$s />', $id, $setting_name, $name, $value, checked( $value, $field_current, false ) );
336
+
337
+ // output field label
338
+ printf( '<label for="%1$s_%2$s">%3$s</label><br>', $id, $name, $label );
339
+
340
+ }
341
+
342
+ // Displays option description.
343
+ if ( isset( $args['description'] ) ) {
344
+ printf( '<p class="description">%s</p>', $args['description'] );
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Media upload callback.
350
+ *
351
+ * @param array $args Field arguments.
352
+ *
353
+ * @return string Media upload button & preview.
354
+ */
355
+ public function media_upload( $args ) {
356
+ extract( $this->normalize_settings_args( $args ) );
357
+
358
+ if( !empty($current) ) {
359
+ $attachment = wp_get_attachment_image_src( $current, 'full', false );
360
+
361
+ $attachment_src = $attachment[0];
362
+ $attachment_width = $attachment[1];
363
+ $attachment_height = $attachment[2];
364
+ $attachment_resolution = round($attachment_height/(3/2.54));
365
+
366
+ printf('<img src="%1$s" style="display:block" id="img-%4$s"/>', $attachment_src, $attachment_width, $attachment_height, $id );
367
+ printf('<div class="attachment-resolution"><p class="description">%s: %sdpi (default height = 3cm)</p></div>', __('Image resolution','woocommerce-pdf-invoices-packing-slips'), $attachment_resolution );
368
+ printf('<span class="button wpo_remove_image_button" data-input_id="%1$s">%2$s</span>', $id, $remove_button_text );
369
+ }
370
+
371
+ printf( '<input id="%1$s" name="%2$s" type="hidden" value="%3$s" />', $id, $setting_name, $current );
372
+
373
+ printf( '<span class="button wpo_upload_image_button %4$s" data-uploader_title="%1$s" data-uploader_button_text="%2$s" data-remove_button_text="%3$s" data-input_id="%4$s">%2$s</span>', $uploader_title, $uploader_button_text, $remove_button_text, $id );
374
+
375
+ // Displays option description.
376
+ if ( isset( $description ) ) {
377
+ printf( '<p class="description">%s</p>', $description );
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Next document number edit callback.
383
+ *
384
+ * @param array $args Field arguments.
385
+ */
386
+ public function next_number_edit( $args ) {
387
+ extract( $args );
388
+ $number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
389
+ $number_store = new Sequential_Number_Store( $store, $number_store_method );
390
+ $next_number = $number_store->get_next();
391
+ $nonce = wp_create_nonce( "wpo_wcpdf_next_{$store}" );
392
+ printf( '<input id="next_%1$s" class="next-number-input" type="text" size="%2$s" value="%3$s" disabled="disabled" data-store="%1$s" data-nonce="%4$s"/> <span class="edit-next-number dashicons dashicons-edit"></span><span class="save-next-number button secondary" style="display:none;">%5$s</span>', $store, $size, $next_number, $nonce, __( 'Save', 'woocommerce-pdf-invoices-packing-slips' ) );
393
+ // Displays option description.
394
+ if ( isset( $description ) ) {
395
+ printf( '<p class="description">%s</p>', $description );
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Wrapper function to create tabs for settings in different languages
401
+ * @param [type] $args [description]
402
+ * @param [type] $callback [description]
403
+ * @return [type] [description]
404
+ */
405
+ public function i18n_wrap ( $args ) {
406
+ extract( $this->normalize_settings_args( $args ) );
407
+
408
+ if ( $languages = $this->get_languages() ) {
409
+ printf( '<div id="%s-%s-translations" class="translations">', $option_name, $id)
410
+ ?>
411
+ <ul>
412
+ <?php foreach ( $languages as $lang_code => $language_name ) {
413
+ $translation_id = "{$option_name}_{$id}_{$lang_code}";
414
+ printf('<li><a href="#%s">%s</a></li>', $translation_id, $language_name );
415
+ }
416
+ ?>
417
+ </ul>
418
+ <?php foreach ( $languages as $lang_code => $language_name ) {
419
+ $translation_id = "{$option_name}_{$id}_{$lang_code}";
420
+ printf( '<div id="%s">', $translation_id );
421
+ $args['lang'] = $lang_code;
422
+ // don't use internationalized placeholders since they're not translated,
423
+ // to avoid confusion (user thinking they're all the same)
424
+ if ( $callback == 'multiple_text_input' ) {
425
+ foreach ($fields as $key => $field_args) {
426
+ if (!empty($field_args['placeholder']) && isset($field_args['i18n_placeholder'])) {
427
+ $args['fields'][$key]['placeholder'] = '';
428
+ }
429
+ }
430
+ } else {
431
+ if (!empty($args['placeholder']) && isset($args['i18n_placeholder'])) {
432
+ $args['placeholder'] = '';
433
+ }
434
+ }
435
+ // specific description for internationalized fields (to compensate for missing placeholder)
436
+ if (!empty($args['i18n_description'])) {
437
+ $args['description'] = $args['i18n_description'];
438
+ }
439
+ if ( is_array( $callback ) ) {
440
+ call_user_func( $callback, $args );
441
+ } else {
442
+ call_user_func( array( $this, $callback ), $args );
443
+ }
444
+ echo '</div>';
445
+ }
446
+ ?>
447
+
448
+ </div>
449
+ <?php
450
+ } else {
451
+ $args['lang'] = 'default';
452
+ if ( is_array( $callback ) ) {
453
+ call_user_func( $callback, $args );
454
+ } else {
455
+ call_user_func( array( $this, $callback ), $args );
456
+ }
457
+ }
458
+ }
459
+
460
+ public function get_languages () {
461
+ $multilingual = function_exists('icl_get_languages');
462
+ // $multilingual = true; // for development
463
+
464
+ if ($multilingual) {
465
+ // use this instead of function call for development outside of WPML
466
+ // $icl_get_languages = 'a:3:{s:2:"en";a:8:{s:2:"id";s:1:"1";s:6:"active";s:1:"1";s:11:"native_name";s:7:"English";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"English";s:13:"language_code";s:2:"en";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/en.png";s:3:"url";s:23:"http://yourdomain/about";}s:2:"fr";a:8:{s:2:"id";s:1:"4";s:6:"active";s:1:"0";s:11:"native_name";s:9:"Français";s:7:"missing";s:1:"0";s:15:"translated_name";s:6:"French";s:13:"language_code";s:2:"fr";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/fr.png";s:3:"url";s:29:"http://yourdomain/fr/a-propos";}s:2:"it";a:8:{s:2:"id";s:2:"27";s:6:"active";s:1:"0";s:11:"native_name";s:8:"Italiano";s:7:"missing";s:1:"0";s:15:"translated_name";s:7:"Italian";s:13:"language_code";s:2:"it";s:16:"country_flag_url";s:43:"http://yourdomain/wpmlpath/res/flags/it.png";s:3:"url";s:26:"http://yourdomain/it/circa";}}';
467
+ // $icl_get_languages = unserialize($icl_get_languages);
468
+
469
+ $icl_get_languages = icl_get_languages('skip_missing=0');
470
+ $languages = array();
471
+ foreach ($icl_get_languages as $lang => $data) {
472
+ $languages[$data['language_code']] = $data['native_name'];
473
+ }
474
+ } else {
475
+ return false;
476
+ }
477
+
478
+ return $languages;
479
+ }
480
+
481
+ public function normalize_settings_args ( $args ) {
482
+ $args['value'] = isset( $args['value'] ) ? $args['value'] : 1;
483
+
484
+ $args['placeholder'] = isset( $args['placeholder'] ) ? $args['placeholder'] : '';
485
+
486
+ // get main settings array
487
+ $option = get_option( $args['option_name'] );
488
+
489
+ $args['setting_name'] = "{$args['option_name']}[{$args['id']}]";
490
+
491
+ if ( !isset($args['lang']) && !empty($args['translatable']) ) {
492
+ $args['lang'] = 'default';
493
+ }
494
+
495
+ if (isset($args['lang'])) {
496
+ // i18n settings name
497
+ $args['setting_name'] = "{$args['setting_name']}[{$args['lang']}]";
498
+ // copy current option value if set
499
+
500
+ if ( $args['lang'] == 'default' && !empty($option[$args['id']]) && !isset( $option[$args['id']]['default'] ) ) {
501
+ // we're switching back from WPML to normal
502
+ // try english first
503
+ if ( isset( $option[$args['id']]['en'] ) ) {
504
+ $args['current'] = $option[$args['id']]['en'];
505
+ } elseif ( is_array( $option[$args['id']] ) ) {
506
+ // fallback to the first language if english not found
507
+ $first = array_shift($option[$args['id']]);
508
+ if (!empty($first)) {
509
+ $args['current'] = $first;
510
+ }
511
+ } elseif ( is_string( $option[$args['id']] ) ) {
512
+ $args['current'] = $option[$args['id']];
513
+ } else {
514
+ // nothing, really?
515
+ $args['current'] = '';
516
+ }
517
+ } else {
518
+ if ( isset( $option[$args['id']][$args['lang']] ) ) {
519
+ $args['current'] = $option[$args['id']][$args['lang']];
520
+ } elseif (isset( $option[$args['id']]['default'] )) {
521
+ $args['current'] = $option[$args['id']]['default'];
522
+ }
523
+ }
524
+ } else {
525
+ // copy current option value if set
526
+ if ( isset( $option[$args['id']] ) ) {
527
+ $args['current'] = $option[$args['id']];
528
+ }
529
+ }
530
+
531
+ // falback to default or empty if no value in option
532
+ if ( !isset($args['current']) ) {
533
+ $args['current'] = isset( $args['default'] ) ? $args['default'] : '';
534
+ }
535
+
536
+ return $args;
537
+ }
538
+
539
+ /**
540
+ * Validate options.
541
+ *
542
+ * @param array $input options to valid.
543
+ *
544
+ * @return array validated options.
545
+ */
546
+ public function validate( $input ) {
547
+ // echo '<pre>';var_dump($input);die('</pre>');
548
+ // Create our array for storing the validated options.
549
+ $output = array();
550
+
551
+ if (empty($input) || !is_array($input)) {
552
+ return $input;
553
+ }
554
+
555
+ // Loop through each of the incoming options.
556
+ foreach ( $input as $key => $value ) {
557
+
558
+ // Check to see if the current option has a value. If so, process it.
559
+ if ( isset( $input[$key] ) ) {
560
+ if ( is_array( $input[$key] ) ) {
561
+ foreach ( $input[$key] as $sub_key => $sub_value ) {
562
+ $output[$key][$sub_key] = $input[$key][$sub_key];
563
+ }
564
+ } else {
565
+ $output[$key] = $input[$key];
566
+ }
567
+ }
568
+ }
569
+
570
+ // Return the array processing any additional functions filtered by this action.
571
+ return apply_filters( 'wpo_wcpdf_validate_input', $output, $input );
572
+ }
573
+ }
574
+
575
+
576
+ endif; // class_exists
577
+
578
  return new Settings_Callbacks();
includes/class-wcpdf-setup-wizard.php CHANGED
@@ -1,247 +1,268 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices;
3
-
4
- if ( ! defined( 'ABSPATH' ) ) {
5
- exit; // Exit if accessed directly
6
- }
7
-
8
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Setup_Wizard' ) ) :
9
-
10
- class Setup_Wizard {
11
-
12
- /** @var string Currenct Step */
13
- private $step = '';
14
-
15
- /** @var array Steps for the setup wizard */
16
- private $steps = array();
17
-
18
- public function __construct() {
19
- if ( current_user_can( 'manage_woocommerce' ) ) {
20
- add_action( 'admin_menu', array( $this, 'admin_menus' ) );
21
- add_action( 'admin_init', array( $this, 'setup_wizard' ) );
22
- }
23
-
24
- }
25
-
26
- /**
27
- * Add admin menus/screens.
28
- */
29
- public function admin_menus() {
30
- add_dashboard_page( '', '', 'manage_options', 'wpo-wcpdf-setup', '' );
31
- }
32
-
33
- /**
34
- * Show the setup wizard.
35
- */
36
- public function setup_wizard() {
37
- if ( empty( $_GET['page'] ) || 'wpo-wcpdf-setup' !== $_GET['page'] ) {
38
- return;
39
- }
40
- $this->steps = array(
41
- 'shop-name' => array(
42
- 'name' => __( 'Shop Name', 'woocommerce-pdf-invoices-packing-slips' ),
43
- 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/shop-name.php',
44
- ),
45
- 'logo' => array(
46
- 'name' => __( 'Your logo', 'woocommerce-pdf-invoices-packing-slips' ),
47
- 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/logo.php',
48
- ),
49
- 'attach-to' => array(
50
- 'name' => __( 'Attachments', 'woocommerce-pdf-invoices-packing-slips' ),
51
- 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/attach-to.php',
52
- ),
53
- 'display-options' => array(
54
- 'name' => __( 'Display options', 'woocommerce-pdf-invoices-packing-slips' ),
55
- 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/display-options.php',
56
- ),
57
- 'paper-format' => array(
58
- 'name' => __( 'Paper format', 'woocommerce-pdf-invoices-packing-slips' ),
59
- 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/paper-format.php',
60
- ),
61
- 'good-to-go' => array(
62
- 'name' => __( 'Ready!', 'woocommerce-pdf-invoices-packing-slips' ),
63
- 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/good-to-go.php',
64
- ),
65
- );
66
- $this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : current( array_keys( $this->steps ) );
67
-
68
- wp_enqueue_style(
69
- 'wpo-wcpdf-setup',
70
- WPO_WCPDF()->plugin_url() . '/assets/css/setup-wizard.css',
71
- array( 'dashicons', 'install' ),
72
- WPO_WCPDF_VERSION
73
- );
74
- wp_register_script(
75
- 'wpo-wcpdf-media-upload',
76
- WPO_WCPDF()->plugin_url() . '/assets/js/media-upload.js',
77
- array( 'jquery', 'media-editor', 'mce-view' ),
78
- WPO_WCPDF_VERSION
79
- );
80
- wp_register_script(
81
- 'wpo-wcpdf-setup',
82
- WPO_WCPDF()->plugin_url() . '/assets/js/setup-wizard.js',
83
- array( 'jquery', 'wpo-wcpdf-media-upload' ),
84
- WPO_WCPDF_VERSION
85
- );
86
- wp_enqueue_media();
87
-
88
-
89
-
90
- $step_keys = array_keys($this->steps);
91
- if ( end( $step_keys ) === $this->step ) {
92
- wp_register_script(
93
- 'wpo-wcpdf-setup-confetti',
94
- WPO_WCPDF()->plugin_url() . '/assets/js/confetti.js',
95
- array( 'jquery' ),
96
- WPO_WCPDF_VERSION
97
- );
98
- }
99
-
100
- if ( ! empty( $_POST['save_step'] ) ) {
101
- $this->save_step();
102
- // echo '<pre>';var_dump($_POST);echo '</pre>';die();
103
- // call_user_func( $this->steps[ $this->step ]['handler'], $this );
104
- }
105
-
106
- ob_start();
107
- $this->setup_wizard_header();
108
- $this->setup_wizard_steps();
109
- $this->setup_wizard_content();
110
- $this->setup_wizard_footer();
111
- exit;
112
- }
113
-
114
- /**
115
- * Setup Wizard Header.
116
- */
117
- public function setup_wizard_header() {
118
- ?>
119
- <!DOCTYPE html>
120
- <html <?php language_attributes(); ?> class="wpo-wizzard">
121
- <head>
122
- <meta name="viewport" content="width=device-width" />
123
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
124
- <title><?php esc_html_e( 'WooCommerce PDF Invoices & Packing Slips &rsaquo; Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></title>
125
- <?php wp_print_scripts( 'wpo-wcpdf-setup' ); ?>
126
- <?php wp_print_scripts( 'wpo-wcpdf-setup-confetti' ); ?>
127
- <?php do_action( 'admin_print_styles' ); ?>
128
- <?php do_action( 'admin_head' ); ?>
129
- </head>
130
- <body class="wpo-wcpdf-setup wp-core-ui">
131
- <?php if( $this->step == 'good-to-go' ) { echo "<div id='confetti'></div>"; } ?>
132
- <form method="post">
133
- <?php
134
- }
135
-
136
- /**
137
- * Output the steps.
138
- */
139
- public function setup_wizard_steps() {
140
- $output_steps = $this->steps;
141
- // array_shift( $output_steps );
142
- ?>
143
- <div class="wpo-setup-card">
144
- <h1 class="wpo-plugin-title">PDF Invoices & Packing Slips</h1>
145
- <ol class="wpo-progress-bar">
146
- <?php foreach ( $output_steps as $step_key => $step ) : ?>
147
- <a href="<?php echo $this->get_step_link($step_key); ?>" ><li><div class="wpo-progress-marker <?php
148
- if ( $step_key === $this->step ) {
149
- echo 'active';
150
- } elseif ( array_search( $this->step, array_keys( $this->steps ) ) > array_search( $step_key, array_keys( $this->steps ) ) ) {
151
- echo 'completed';
152
- }
153
- ?>"><?php //echo esc_html( $step['name'] ); ?></div></li></a>
154
- <?php endforeach; ?>
155
- </ol>
156
- <?php
157
- }
158
-
159
- /**
160
- * Output the content for the current step.
161
- */
162
- public function setup_wizard_content() {
163
- echo '<div class="wpo-setup-content">';
164
- include( $this->steps[ $this->step ]['view'] );
165
- echo '</div>';
166
- }
167
-
168
- /**
169
- * Setup Wizard Footer.
170
- */
171
- public function setup_wizard_footer() {
172
- ?>
173
- <div class="wpo-setup-buttons">
174
- <?php if ($step = $this->get_step(-1)): ?>
175
- <a href="<?php echo $this->get_step_link($step); ?>" class="wpo-button-previous"><?php _e( 'Previous', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
176
- <?php endif ?>
177
- <!-- <input type="submit" class="wpo-button-next" value="Next" /> -->
178
- <?php if ($step = $this->get_step(1)): ?>
179
- <?php wp_nonce_field( 'wpo-wcpdf-setup' ); ?>
180
- <input type="submit" class="wpo-button-next" value="<?php esc_attr_e( 'Next', 'woocommerce-pdf-invoices-packing-slips' ); ?>" name="save_step" />
181
- <a href="<?php echo $this->get_step_link($step); ?>" class="wpo-skip-step"><?php _e( 'Skip this step', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
182
- <?php else: ?>
183
- <a href="<?php echo $this->get_step_link($step); ?>" class="wpo-button-next"><?php _e( 'Finish', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
184
- <?php endif ?>
185
- </div>
186
- </div>
187
- </form>
188
- <?php do_action( 'admin_footer' ); // for media uploader templates ?>
189
- </body>
190
- </html>
191
- <?php
192
- }
193
-
194
- public function get_step_link( $step ) {
195
- $step_keys = array_keys( $this->steps );
196
- if ( end( $step_keys ) === $this->step && empty($step)) {
197
- return admin_url('admin.php?page=wpo_wcpdf_options_page');
198
- }
199
- return add_query_arg( 'step', $step );
200
- }
201
-
202
-
203
- public function get_step( $delta ) {
204
- $step_keys = array_keys( $this->steps );
205
- $current_step_pos = array_search( $this->step, $step_keys );
206
- $new_step_pos = $current_step_pos + $delta;
207
- if (isset($step_keys[$new_step_pos])) {
208
- return $step_keys[$new_step_pos];
209
- } else {
210
- return false;
211
- }
212
- }
213
-
214
- public function save_step() {
215
- if ( isset( $this->steps[ $this->step ]['handler'] ) ) {
216
- check_admin_referer( 'wpo-wcpdf-setup' );
217
- // for doing more than just saving an option value
218
- call_user_func( $this->steps[ $this->step ]['handler'] );
219
- } else {
220
- if (!empty($_POST['wcpdf_settings']) && is_array($_POST['wcpdf_settings'])) {
221
- check_admin_referer( 'wpo-wcpdf-setup' );
222
- foreach ($_POST['wcpdf_settings'] as $option => $settings) {
223
- // sanitize posted settings
224
- foreach ($settings as $key => $value) {
225
- if (is_array($value)) {
226
- $settings[$key] = array_map('sanitize_text_field', $value);
227
- } else {
228
- $settings[$key] = sanitize_text_field( $value );
229
- }
230
- }
231
- $current_settings = get_option( $option, array() );
232
- $new_settings = $settings + $current_settings;
233
- // echo "<pre>".var_export($settings,true)."</pre>";
234
- // echo "<pre>".var_export($new_settings,true)."</pre>";die();
235
- update_option( $option, $new_settings );
236
- }
237
- }
238
- }
239
-
240
- wp_redirect( esc_url_raw( $this->get_step_link( $this->get_step(1) ) ) );
241
- }
242
-
243
- }
244
-
245
- endif; // class_exists
246
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  return new Setup_Wizard();
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices;
3
+
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
+ exit; // Exit if accessed directly
6
+ }
7
+
8
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Setup_Wizard' ) ) :
9
+
10
+ class Setup_Wizard {
11
+
12
+ /** @var string Currenct Step */
13
+ private $step = '';
14
+
15
+ /** @var array Steps for the setup wizard */
16
+ private $steps = array();
17
+
18
+ public function __construct() {
19
+ if ( current_user_can( 'manage_woocommerce' ) ) {
20
+ add_action( 'admin_menu', array( $this, 'admin_menus' ) );
21
+ add_action( 'admin_init', array( $this, 'setup_wizard' ) );
22
+ }
23
+
24
+ }
25
+
26
+ /**
27
+ * Add admin menus/screens.
28
+ */
29
+ public function admin_menus() {
30
+ add_dashboard_page( '', '', 'manage_options', 'wpo-wcpdf-setup', '' );
31
+ }
32
+
33
+ /**
34
+ * Show the setup wizard.
35
+ */
36
+ public function setup_wizard() {
37
+ if ( empty( $_GET['page'] ) || 'wpo-wcpdf-setup' !== $_GET['page'] ) {
38
+ return;
39
+ }
40
+ $this->steps = array(
41
+ 'shop-name' => array(
42
+ 'name' => __( 'Shop Name', 'woocommerce-pdf-invoices-packing-slips' ),
43
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/shop-name.php',
44
+ ),
45
+ 'logo' => array(
46
+ 'name' => __( 'Your logo', 'woocommerce-pdf-invoices-packing-slips' ),
47
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/logo.php',
48
+ ),
49
+ 'attach-to' => array(
50
+ 'name' => __( 'Attachments', 'woocommerce-pdf-invoices-packing-slips' ),
51
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/attach-to.php',
52
+ ),
53
+ 'display-options' => array(
54
+ 'name' => __( 'Display options', 'woocommerce-pdf-invoices-packing-slips' ),
55
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/display-options.php',
56
+ ),
57
+ 'paper-format' => array(
58
+ 'name' => __( 'Paper format', 'woocommerce-pdf-invoices-packing-slips' ),
59
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/paper-format.php',
60
+ ),
61
+ 'show-action-buttons' => array(
62
+ 'name' => __( 'Action buttons', 'woocommerce-pdf-invoices-packing-slips' ),
63
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/show-action-buttons.php',
64
+ ),
65
+ 'good-to-go' => array(
66
+ 'name' => __( 'Ready!', 'woocommerce-pdf-invoices-packing-slips' ),
67
+ 'view' => WPO_WCPDF()->plugin_path() . '/includes/views/setup-wizard/good-to-go.php',
68
+ ),
69
+ );
70
+ $this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : current( array_keys( $this->steps ) );
71
+
72
+ wp_enqueue_style(
73
+ 'wpo-wcpdf-setup',
74
+ WPO_WCPDF()->plugin_url() . '/assets/css/setup-wizard.css',
75
+ array( 'dashicons', 'install' ),
76
+ WPO_WCPDF_VERSION
77
+ );
78
+ wp_register_script(
79
+ 'wpo-wcpdf-media-upload',
80
+ WPO_WCPDF()->plugin_url() . '/assets/js/media-upload.js',
81
+ array( 'jquery', 'media-editor', 'mce-view' ),
82
+ WPO_WCPDF_VERSION
83
+ );
84
+ wp_register_script(
85
+ 'wpo-wcpdf-setup',
86
+ WPO_WCPDF()->plugin_url() . '/assets/js/setup-wizard.js',
87
+ array( 'jquery', 'wpo-wcpdf-media-upload' ),
88
+ WPO_WCPDF_VERSION
89
+ );
90
+ wp_enqueue_media();
91
+
92
+
93
+
94
+ $step_keys = array_keys($this->steps);
95
+ if ( end( $step_keys ) === $this->step ) {
96
+ wp_register_script(
97
+ 'wpo-wcpdf-setup-confetti',
98
+ WPO_WCPDF()->plugin_url() . '/assets/js/confetti.js',
99
+ array( 'jquery' ),
100
+ WPO_WCPDF_VERSION
101
+ );
102
+ }
103
+
104
+ if ( ! empty( $_POST['save_step'] ) ) {
105
+ $this->save_step();
106
+ // echo '<pre>';var_dump($_POST);echo '</pre>';die();
107
+ // call_user_func( $this->steps[ $this->step ]['handler'], $this );
108
+ }
109
+
110
+ ob_start();
111
+ $this->setup_wizard_header();
112
+ $this->setup_wizard_steps();
113
+ $this->setup_wizard_content();
114
+ $this->setup_wizard_footer();
115
+ exit;
116
+ }
117
+
118
+ /**
119
+ * Setup Wizard Header.
120
+ */
121
+ public function setup_wizard_header() {
122
+ ?>
123
+ <!DOCTYPE html>
124
+ <html <?php language_attributes(); ?> class="wpo-wizzard">
125
+ <head>
126
+ <meta name="viewport" content="width=device-width" />
127
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
128
+ <title><?php esc_html_e( 'WooCommerce PDF Invoices & Packing Slips &rsaquo; Setup Wizard', 'woocommerce-pdf-invoices-packing-slips' ); ?></title>
129
+ <?php wp_print_scripts( 'wpo-wcpdf-setup' ); ?>
130
+ <?php wp_print_scripts( 'wpo-wcpdf-setup-confetti' ); ?>
131
+ <?php do_action( 'admin_print_styles' ); ?>
132
+ <?php do_action( 'admin_head' ); ?>
133
+ </head>
134
+ <body class="wpo-wcpdf-setup wp-core-ui">
135
+ <?php if( $this->step == 'good-to-go' ) { echo "<div id='confetti'></div>"; } ?>
136
+ <form method="post">
137
+ <?php
138
+ }
139
+
140
+ /**
141
+ * Output the steps.
142
+ */
143
+ public function setup_wizard_steps() {
144
+ $output_steps = $this->steps;
145
+ // array_shift( $output_steps );
146
+ ?>
147
+ <div class="wpo-setup-card">
148
+ <h1 class="wpo-plugin-title">PDF Invoices & Packing Slips</h1>
149
+ <ol class="wpo-progress-bar">
150
+ <?php foreach ( $output_steps as $step_key => $step ) : ?>
151
+ <a href="<?php echo $this->get_step_link($step_key); ?>" ><li><div class="wpo-progress-marker <?php
152
+ if ( $step_key === $this->step ) {
153
+ echo 'active';
154
+ } elseif ( array_search( $this->step, array_keys( $this->steps ) ) > array_search( $step_key, array_keys( $this->steps ) ) ) {
155
+ echo 'completed';
156
+ }
157
+ ?>"><?php //echo esc_html( $step['name'] ); ?></div></li></a>
158
+ <?php endforeach; ?>
159
+ </ol>
160
+ <?php
161
+ }
162
+
163
+ /**
164
+ * Output the content for the current step.
165
+ */
166
+ public function setup_wizard_content() {
167
+ echo '<div class="wpo-setup-content">';
168
+ include( $this->steps[ $this->step ]['view'] );
169
+ echo '</div>';
170
+ }
171
+
172
+ /**
173
+ * Setup Wizard Footer.
174
+ */
175
+ public function setup_wizard_footer() {
176
+ ?>
177
+ <input type="hidden" name="wpo_wcpdf_step" value="<?php echo $this->step ?>">
178
+ <div class="wpo-setup-buttons">
179
+ <?php if ($step = $this->get_step(-1)): ?>
180
+ <a href="<?php echo $this->get_step_link($step); ?>" class="wpo-button-previous"><?php _e( 'Previous', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
181
+ <?php endif ?>
182
+ <!-- <input type="submit" class="wpo-button-next" value="Next" /> -->
183
+ <?php if ($step = $this->get_step(1)): ?>
184
+ <?php wp_nonce_field( 'wpo-wcpdf-setup' ); ?>
185
+ <input type="submit" class="wpo-button-next" value="<?php esc_attr_e( 'Next', 'woocommerce-pdf-invoices-packing-slips' ); ?>" name="save_step" />
186
+ <a href="<?php echo $this->get_step_link($step); ?>" class="wpo-skip-step"><?php _e( 'Skip this step', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
187
+ <?php else: ?>
188
+ <a href="<?php echo $this->get_step_link($step); ?>" class="wpo-button-next"><?php _e( 'Finish', 'woocommerce-pdf-invoices-packing-slips' ); ?></a>
189
+ <?php endif ?>
190
+ </div>
191
+ </div>
192
+ </form>
193
+ <?php do_action( 'admin_footer' ); // for media uploader templates ?>
194
+ </body>
195
+ </html>
196
+ <?php
197
+ }
198
+
199
+ public function get_step_link( $step ) {
200
+ $step_keys = array_keys( $this->steps );
201
+ if ( end( $step_keys ) === $this->step && empty($step)) {
202
+ return admin_url('admin.php?page=wpo_wcpdf_options_page');
203
+ }
204
+ return add_query_arg( 'step', $step );
205
+ }
206
+
207
+
208
+ public function get_step( $delta ) {
209
+ $step_keys = array_keys( $this->steps );
210
+ $current_step_pos = array_search( $this->step, $step_keys );
211
+ $new_step_pos = $current_step_pos + $delta;
212
+ if (isset($step_keys[$new_step_pos])) {
213
+ return $step_keys[$new_step_pos];
214
+ } else {
215
+ return false;
216
+ }
217
+ }
218
+
219
+ public function save_step() {
220
+ if ( isset( $this->steps[ $this->step ]['handler'] ) ) {
221
+ check_admin_referer( 'wpo-wcpdf-setup' );
222
+ // for doing more than just saving an option value
223
+ call_user_func( $this->steps[ $this->step ]['handler'] );
224
+ } else {
225
+ $user_id = get_current_user_id();
226
+ $hidden = get_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', true );
227
+ if (!empty($_POST['wcpdf_settings']) && is_array($_POST['wcpdf_settings'])) {
228
+ check_admin_referer( 'wpo-wcpdf-setup' );
229
+ foreach ($_POST['wcpdf_settings'] as $option => $settings) {
230
+ // sanitize posted settings
231
+ foreach ($settings as $key => $value) {
232
+ if ( $key == 'shop_address' && function_exists('sanitize_textarea_field') ) {
233
+ $sanitize_function == 'sanitize_textarea_field';
234
+ } else {
235
+ $sanitize_function == 'sanitize_text_field';
236
+ }
237
+
238
+ if (is_array($value)) {
239
+ $settings[$key] = array_map($sanitize_function, $value);
240
+ } else {
241
+ $settings[$key] = call_user_func($sanitize_function, $value );
242
+ }
243
+ }
244
+ $current_settings = get_option( $option, array() );
245
+ $new_settings = $settings + $current_settings;
246
+ // echo "<pre>".var_export($settings,true)."</pre>";
247
+ // echo "<pre>".var_export($new_settings,true)."</pre>";die();
248
+ update_option( $option, $new_settings );
249
+ }
250
+ } elseif ( $_POST['wpo_wcpdf_step'] == 'show-action-buttons' ) {
251
+ if ( !empty( $_POST['wc_show_action_buttons'] ) ) {
252
+ $hidden = array_filter( $hidden, function( $setting ){ return $setting !== 'wc_actions'; } );
253
+ update_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', $hidden );
254
+ } else {
255
+ array_push($hidden, 'wc_actions');
256
+ update_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', $hidden );
257
+ }
258
+ }
259
+ }
260
+
261
+ wp_redirect( esc_url_raw( $this->get_step_link( $this->get_step(1) ) ) );
262
+ }
263
+
264
+ }
265
+
266
+ endif; // class_exists
267
+
268
  return new Setup_Wizard();
includes/compatibility/class-wcpdf-compatibility-third-party-plugins.php CHANGED
@@ -46,7 +46,11 @@ class Third_Party_Plugins {
46
  add_action( 'wpo_wcpdf_before_html', array( $this, 'aelia_currency_formatting' ), 10, 2 );
47
  }
48
 
49
-
 
 
 
 
50
  }
51
 
52
  /**
@@ -217,6 +221,22 @@ class Third_Party_Plugins {
217
  }
218
  return $args;
219
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
 
222
 
46
  add_action( 'wpo_wcpdf_before_html', array( $this, 'aelia_currency_formatting' ), 10, 2 );
47
  }
48
 
49
+ // Avoid double images from WooCommerce German Market
50
+ if ( class_exists('WGM_Product') ) {
51
+ add_action( 'wpo_wcpdf_before_html', array( $this, 'remove_wgm_thumbnails' ), 10, 2 );
52
+ add_action( 'wpo_wcpdf_after_html', array( $this, 'restore_wgm_thumbnails' ), 10, 2 );
53
+ }
54
  }
55
 
56
  /**
221
  }
222
  return $args;
223
  }
224
+
225
+ /**
226
+ * Avoid double images from German Market: remove filter
227
+ */
228
+ function remove_wgm_thumbnails( $document_type, $document ) {
229
+ remove_filter( 'woocommerce_order_item_name', array( 'WGM_Product', 'add_thumbnail_to_order' ), 100, 3 );
230
+ }
231
+
232
+ /**
233
+ * Restore above
234
+ */
235
+ function restore_wgm_thumbnails( $document_type, $document ) {
236
+ if ( is_callable( array( 'WGM_Product', 'add_thumbnail_to_order' ) ) ) {
237
+ add_filter( 'woocommerce_order_item_name', array( 'WGM_Product', 'add_thumbnail_to_order' ), 100, 3 );
238
+ }
239
+ }
240
  }
241
 
242
 
includes/documents/abstract-wcpdf-order-document.php CHANGED
@@ -1,774 +1,798 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices\Documents;
3
-
4
- use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
- use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
- use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
- use WPO\WC\PDF_Invoices\Compatibility\WC_DateTime;
8
-
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- exit; // Exit if accessed directly
11
- }
12
-
13
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Order_Document' ) ) :
14
-
15
- /**
16
- * Abstract Document
17
- *
18
- * Handles generic pdf document & order data and database interaction
19
- * which is extended by both Invoices & Packing Slips
20
- *
21
- * @class \WPO\WC\PDF_Invoices\Documents\Order_Document
22
- * @version 2.0
23
- * @category Class
24
- * @author Ewout Fernhout
25
- */
26
-
27
- abstract class Order_Document {
28
- /**
29
- * Document type.
30
- * @var String
31
- */
32
- public $type;
33
-
34
- /**
35
- * Document slug.
36
- * @var String
37
- */
38
- public $slug;
39
-
40
- /**
41
- * Document title.
42
- * @var string
43
- */
44
- public $title;
45
-
46
- /**
47
- * Document icon.
48
- * @var string
49
- */
50
- public $icon;
51
-
52
- /**
53
- * WC Order object
54
- * @var object
55
- */
56
- public $order;
57
-
58
- /**
59
- * WC Order ID
60
- * @var object
61
- */
62
- public $order_id;
63
-
64
- /**
65
- * Document settings.
66
- * @var array
67
- */
68
- public $settings;
69
-
70
- /**
71
- * TRUE if document is enabled.
72
- * @var bool
73
- */
74
- public $enabled;
75
-
76
- /**
77
- * Linked documents, used for data retrieval
78
- * @var array
79
- */
80
- protected $linked_documents = array();
81
-
82
- /**
83
- * Core data for this object. Name value pairs (name + default value).
84
- * @var array
85
- */
86
- protected $data = array();
87
-
88
- /**
89
- * Init/load the order object.
90
- *
91
- * @param int|object|WC_Order $order Order to init.
92
- */
93
- public function __construct( $order = 0 ) {
94
- if ( is_numeric( $order ) && $order > 0 ) {
95
- $this->order_id = $order;
96
- $this->order = WCX::get_order( $this->order_id );
97
- } elseif ( $order instanceof \WC_Order || is_subclass_of( $order, '\WC_Abstract_Order') ) {
98
- $this->order_id = WCX_Order::get_id( $order );
99
- $this->order = $order;
100
- }
101
-
102
- // set properties
103
- $this->slug = str_replace('-', '_', $this->type);
104
-
105
- // load data
106
- if ( $this->order ) {
107
- $this->read_data( $this->order );
108
- if ( WPO_WCPDF()->legacy_mode_enabled() ) {
109
- global $wpo_wcpdf;
110
- $wpo_wcpdf->export->order = $this->order;
111
- $wpo_wcpdf->export->document = $this;
112
- $wpo_wcpdf->export->order_id = $this->order_id;
113
- $wpo_wcpdf->export->template_type = $this->type;
114
- }
115
- }
116
-
117
- // load settings
118
- $this->settings = $this->get_settings();
119
- $this->latest_settings = $this->get_settings( true );
120
- $this->enabled = $this->get_setting( 'enabled', false );
121
- }
122
-
123
- public function init_settings() {
124
- return;
125
- }
126
-
127
- public function get_settings( $latest = false ) {
128
- // get most current settings
129
- $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
130
- $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
131
- $settings = (array) $document_settings + (array) $common_settings;
132
-
133
- // return only most current if forced
134
- if ( $latest == true ) {
135
- return $settings;
136
- }
137
-
138
- // get historical settings if enabled
139
- if ( !empty( $this->order ) && $this->use_historical_settings() == true ) {
140
- $order_settings = WCX_Order::get_meta( $this->order, "_wcpdf_{$this->slug}_settings" );
141
- if (!empty($order_settings)) {
142
- // not sure what happens if combining with current settings will have unwanted side effects
143
- // like unchecked options being enabled because missing = unchecked in historical - disabled for now
144
- // $settings = (array) $order_settings + (array) $settings;
145
- $settings = $order_settings;
146
- }
147
- }
148
- if ( empty( $order_settings ) && !empty( $this->order ) ) {
149
- // this is either the first time the document is generated, or historical settings are disabled
150
- // in both cases, we store the document settings
151
- WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
152
- }
153
-
154
- return $settings;
155
- }
156
-
157
- public function use_historical_settings() {
158
- return apply_filters( 'wpo_wcpdf_document_use_historical_settings', false, $this );
159
- }
160
-
161
- public function get_setting( $key, $default = '' ) {
162
- $non_historical_settings = apply_filters( 'wpo_wcpdf_non_historical_settings', array(
163
- 'enabled',
164
- 'attach_to_email_ids',
165
- 'number_format', // this is stored in the number data already!
166
- 'my_account_buttons',
167
- 'my_account_restrict',
168
- 'invoice_number_column',
169
- 'paper_size',
170
- 'font_subsetting',
171
- ) );
172
- if ( in_array( $key, $non_historical_settings ) && isset($this->latest_settings) ) {
173
- $setting = isset( $this->latest_settings[$key] ) ? $this->latest_settings[$key] : $default;
174
- } else {
175
- $setting = isset( $this->settings[$key] ) ? $this->settings[$key] : $default;
176
- }
177
- return $setting;
178
- }
179
-
180
- public function get_attach_to_email_ids() {
181
- $email_ids = isset( $this->settings['attach_to_email_ids'] ) ? array_keys( $this->settings['attach_to_email_ids'] ) : array();
182
- return $email_ids;
183
- }
184
-
185
- public function get_type() {
186
- return $this->type;
187
- }
188
-
189
- public function is_enabled() {
190
- return apply_filters( 'wpo_wcpdf_document_is_enabled', $this->enabled, $this->type );
191
- }
192
-
193
- public function get_hook_prefix() {
194
- return 'wpo_wcpdf_' . $this->slug . '_get_';
195
- }
196
-
197
- public function read_data( $order ) {
198
- $number = WCX_Order::get_meta( $order, "_wcpdf_{$this->slug}_number_data", true );
199
- // fallback to legacy data for number
200
- if ( empty( $number ) ) {
201
- $number = WCX_Order::get_meta( $order, "_wcpdf_{$this->slug}_number", true );
202
- $formatted_number = WCX_Order::get_meta( $order, "_wcpdf_formatted_{$this->slug}_number", true );
203
- if (!empty($formatted_number)) {
204
- $number = compact( 'number', 'formatted_number' );
205
- }
206
- }
207
-
208
- // pass data to setter functions
209
- $this->set_data( array(
210
- // always load date before number, because date is used in number formatting
211
- 'date' => WCX_Order::get_meta( $order, "_wcpdf_{$this->slug}_date", true ),
212
- 'number' => $number,
213
- ), $order );
214
-
215
- return;
216
- }
217
-
218
- public function init() {
219
- // store settings in order
220
- if ( !empty( $this->order ) ) {
221
- $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
222
- $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
223
- $settings = (array) $document_settings + (array) $common_settings;
224
- WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
225
- }
226
-
227
- $this->set_date( current_time( 'timestamp', true ) );
228
- do_action( 'wpo_wcpdf_init_document', $this );
229
- }
230
-
231
- public function save( $order = null ) {
232
- $order = empty( $order ) ? $this->order : $order;
233
- if ( empty( $order ) ) {
234
- return; // nowhere to save to...
235
- }
236
-
237
- foreach ($this->data as $key => $value) {
238
- if ( empty( $value ) ) {
239
- WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$key}" );
240
- if ( $key == 'date' ) {
241
- WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_formatted" );
242
- } elseif ( $key == 'number' ) {
243
- WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_data" );
244
- // deleting the number = deleting the document, so also delete document settings
245
- WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_settings" );
246
- }
247
- } else {
248
- if ( $key == 'date' ) {
249
- // store dates as timestamp and formatted as mysql time
250
- WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}", $value->getTimestamp() );
251
- WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_formatted", $value->date( 'Y-m-d H:i:s' ) );
252
- } elseif ( $key == 'number' ) {
253
- // store both formatted number and number data
254
- WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}", $value->formatted_number );
255
- WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_data", $value->to_array() );
256
- }
257
- }
258
- }
259
- }
260
-
261
- public function delete( $order = null ) {
262
- $order = empty( $order ) ? $this->order : $order;
263
- if ( empty( $order ) ) {
264
- return; // nothing to delete
265
- }
266
-
267
- $data_to_remove = apply_filters( 'wpo_wcpdf_delete_document_data_keys', array(
268
- 'settings',
269
- 'date',
270
- 'date_formatted',
271
- 'number',
272
- 'number_data',
273
- ), $this );
274
- foreach ($data_to_remove as $data_key) {
275
- WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$data_key}" );
276
- }
277
-
278
- do_action( 'wpo_wcpdf_delete_document', $this );
279
- }
280
-
281
- public function is_allowed() {
282
- return apply_filters( 'wpo_wcpdf_document_is_allowed', true, $this );
283
- }
284
-
285
- public function exists() {
286
- return !empty( $this->data['date'] );
287
- }
288
-
289
- /*
290
- |--------------------------------------------------------------------------
291
- | Data getters
292
- |--------------------------------------------------------------------------
293
- */
294
-
295
- public function get_data( $key, $document_type = '', $order = null, $context = 'view' ) {
296
- $document_type = empty( $document_type ) ? $this->type : $document_type;
297
- $order = empty( $order ) ? $this->order : $order;
298
-
299
- // redirect get_data call for linked documents
300
- if ( $document_type != $this->type ) {
301
- if ( !isset( $this->linked_documents[ $document_type ] ) ) {
302
- // always assume parent for documents linked to credit notes
303
- if ($this->type == 'credit-note') {
304
- $order = $this->get_refund_parent( $order );
305
- }
306
- // order is not loaded to avoid overhead - we pass this by reference directly to the read_data method instead
307
- $this->linked_documents[ $document_type ] = wcpdf_get_document( $document_type, null );
308
- $this->linked_documents[ $document_type ]->read_data( $order );
309
- }
310
- return $this->linked_documents[ $document_type ]->get_data( $key, $document_type );
311
- }
312
-
313
- $value = null;
314
-
315
- if ( array_key_exists( $key, $this->data ) ) {
316
- $value = $this->data[ $key ];
317
-
318
- if ( 'view' === $context ) {
319
- $value = apply_filters( $this->get_hook_prefix() . $key, $value, $this );
320
- }
321
- }
322
-
323
- return $value;
324
- }
325
-
326
- public function get_number( $document_type = '', $order = null, $context = 'view' ) {
327
- return $this->get_data( 'number', $document_type, $order, $context );
328
- }
329
-
330
- public function get_date( $document_type = '', $order = null, $context = 'view' ) {
331
- return $this->get_data( 'date', $document_type, $order, $context );
332
- }
333
-
334
- public function get_title() {
335
- return apply_filters( "wpo_wcpdf_{$this->slug}_title", $this->title, $this );
336
- }
337
-
338
- /*
339
- |--------------------------------------------------------------------------
340
- | Data setters
341
- |--------------------------------------------------------------------------
342
- |
343
- | Functions for setting order data. These should not update anything in the
344
- | order itself and should only change what is stored in the class
345
- | object.
346
- */
347
-
348
- public function set_data( $data, $order ) {
349
- $order = empty( $order ) ? $this->order : $order;
350
- foreach ($data as $key => $value) {
351
- $setter = "set_$key";
352
- if ( is_callable( array( $this, $setter ) ) ) {
353
- $this->$setter( $value, $order );
354
- } else {
355
- $this->data[ $key ] = $value;
356
- }
357
- }
358
- }
359
-
360
- public function set_date( $value, $order = null ) {
361
- $order = empty( $order ) ? $this->order : $order;
362
- try {
363
- if ( empty( $value ) ) {
364
- $this->data[ 'date' ] = null;
365
- return;
366
- }
367
-
368
- if ( is_a( $value, 'WC_DateTime' ) ) {
369
- $datetime = $value;
370
- } elseif ( is_numeric( $value ) ) {
371
- // Timestamps are handled as UTC timestamps in all cases.
372
- $datetime = new WC_DateTime( "@{$value}", new \DateTimeZone( 'UTC' ) );
373
- } else {
374
- // Strings are defined in local WP timezone. Convert to UTC.
375
- if ( 1 === preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|((-|\+)\d{2}:\d{2}))$/', $value, $date_bits ) ) {
376
- $offset = ! empty( $date_bits[7] ) ? iso8601_timezone_to_offset( $date_bits[7] ) : wc_timezone_offset();
377
- $timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] ) - $offset;
378
- } else {
379
- $timestamp = wc_string_to_timestamp( get_gmt_from_date( gmdate( 'Y-m-d H:i:s', wc_string_to_timestamp( $value ) ) ) );
380
- }
381
- $datetime = new WC_DateTime( "@{$timestamp}", new \DateTimeZone( 'UTC' ) );
382
- }
383
-
384
- // Set local timezone or offset.
385
- if ( get_option( 'timezone_string' ) ) {
386
- $datetime->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
387
- } else {
388
- $datetime->set_utc_offset( wc_timezone_offset() );
389
- }
390
-
391
- $this->data[ 'date' ] = $datetime;
392
- } catch ( \Exception $e ) {
393
- wcpdf_log_error( $e->getMessage() );
394
- } catch ( \Error $e ) {
395
- wcpdf_log_error( $e->getMessage() );
396
- }
397
-
398
- }
399
-
400
- public function set_number( $value, $order = null ) {
401
- $order = empty( $order ) ? $this->order : $order;
402
-
403
- if ( is_array( $value ) ) {
404
- $filtered_value = array_filter( $value );
405
- }
406
-
407
- if ( empty( $value ) || ( is_array( $value ) && empty( $filtered_value ) ) ) {
408
- $document_number = null;
409
- } elseif ( $value instanceof Document_Number ) {
410
- // WCPDF 2.0 number data
411
- $document_number = $value;
412
- } elseif ( is_array( $value ) ) {
413
- // WCPDF 2.0 number data as array
414
- $document_number = new Document_Number( $value, $this->get_number_settings(), $this, $order );
415
- } else {
416
- // plain number
417
- $document_number = new Document_Number( $value, $this->get_number_settings(), $this, $order );
418
- }
419
-
420
- $this->data[ 'number' ] = $document_number;
421
- }
422
-
423
- /*
424
- |--------------------------------------------------------------------------
425
- | Settings getters / outputters
426
- |--------------------------------------------------------------------------
427
- */
428
-
429
- public function get_number_settings() {
430
- if (empty($this->settings)) {
431
- $settings = $this->get_settings( true ); // we always want the latest settings
432
- $number_settings = isset($settings['number_format'])?$settings['number_format']:array();
433
- } else {
434
- $number_settings = $this->get_setting( 'number_format', array() );
435
- }
436
- return apply_filters( 'wpo_wcpdf_document_number_settings', $number_settings, $this );
437
- }
438
-
439
- /**
440
- * Output template styles
441
- */
442
- public function template_styles() {
443
- $css = apply_filters( 'wpo_wcpdf_template_styles_file', $this->locate_template_file( "style.css" ) );
444
-
445
- ob_start();
446
- if (file_exists($css)) {
447
- include($css);
448
- }
449
- $css = ob_get_clean();
450
- $css = apply_filters( 'wpo_wcpdf_template_styles', $css, $this );
451
-
452
- echo $css;
453
- }
454
-
455
- public function has_header_logo() {
456
- return !empty( $this->settings['header_logo'] );
457
- }
458
-
459
- /**
460
- * Return logo id
461
- */
462
- public function get_header_logo_id() {
463
- if ( !empty( $this->settings['header_logo'] ) ) {
464
- return apply_filters( 'wpo_wcpdf_header_logo_id', $this->settings['header_logo'], $this );
465
- }
466
- }
467
-
468
- /**
469
- * Show logo html
470
- */
471
- public function header_logo() {
472
- if ($this->get_header_logo_id()) {
473
- $attachment_id = $this->get_header_logo_id();
474
- $company = $this->get_shop_name();
475
- if( $attachment_id ) {
476
- $attachment = wp_get_attachment_image_src( $attachment_id, 'full', false );
477
-
478
- $attachment_src = $attachment[0];
479
- $attachment_width = $attachment[1];
480
- $attachment_height = $attachment[2];
481
-
482
- $attachment_path = get_attached_file( $attachment_id );
483
-
484
- if ( apply_filters('wpo_wcpdf_use_path', true) && file_exists($attachment_path) ) {
485
- $src = $attachment_path;
486
- } else {
487
- $src = $attachment_src;
488
- }
489
-
490
- $img_element = sprintf('<img src="%1$s" alt="%4$s" />', $src, $attachment_width, $attachment_height, esc_attr( $company ) );
491
-
492
- echo apply_filters( 'wpo_wcpdf_header_logo_img_element', $img_element, $attachment, $this );
493
- }
494
- }
495
- }
496
-
497
- public function get_settings_text( $settings_key, $default = false, $autop = true ) {
498
- if ( !empty( $this->settings[$settings_key]['default'] ) ) {
499
- $text = wptexturize( trim( $this->settings[$settings_key]['default'] ) );
500
- if ($autop === true) {
501
- $text = wpautop( $text );
502
- }
503
- } else {
504
- $text = $default;
505
- }
506
- // legacy filters
507
- if ( in_array( $settings_key, array( 'shop_name', 'shop_address', 'footer', 'extra_1', 'extra_2', 'extra_3' ) ) ) {
508
- $text = apply_filters( "wpo_wcpdf_{$settings_key}", $text, $this );
509
- }
510
-
511
- return apply_filters( "wpo_wcpdf_{$settings_key}_settings_text", $text, $this );
512
- }
513
-
514
- /**
515
- * Return/Show custom company name or default to blog name
516
- */
517
- public function get_shop_name() {
518
- $default = get_bloginfo( 'name' );
519
- return $this->get_settings_text( 'shop_name', $default, false );
520
- }
521
- public function shop_name() {
522
- echo $this->get_shop_name();
523
- }
524
-
525
- /**
526
- * Return/Show shop/company address if provided
527
- */
528
- public function get_shop_address() {
529
- return $this->get_settings_text( 'shop_address' );
530
- }
531
- public function shop_address() {
532
- echo $this->get_shop_address();
533
- }
534
-
535
- /**
536
- * Return/Show shop/company footer imprint, copyright etc.
537
- */
538
- public function get_footer() {
539
- return $this->get_settings_text( 'footer' );
540
- }
541
- public function footer() {
542
- echo $this->get_footer();
543
- }
544
-
545
- /**
546
- * Return/Show Extra field 1
547
- */
548
- public function get_extra_1() {
549
- return $this->get_settings_text( 'extra_1' );
550
-
551
- }
552
- public function extra_1() {
553
- echo $this->get_extra_1();
554
- }
555
-
556
- /**
557
- * Return/Show Extra field 2
558
- */
559
- public function get_extra_2() {
560
- return $this->get_settings_text( 'extra_2' );
561
- }
562
- public function extra_2() {
563
- echo $this->get_extra_2();
564
- }
565
-
566
- /**
567
- * Return/Show Extra field 3
568
- */
569
- public function get_extra_3() {
570
- return $this->get_settings_text( 'extra_3' );
571
- }
572
- public function extra_3() {
573
- echo $this->get_extra_3();
574
- }
575
-
576
- /*
577
- |--------------------------------------------------------------------------
578
- | Output functions
579
- |--------------------------------------------------------------------------
580
- */
581
-
582
- public function get_pdf() {
583
- do_action( 'wpo_wcpdf_before_pdf', $this->get_type(), $this );
584
-
585
- $pdf_settings = array(
586
- 'paper_size' => apply_filters( 'wpo_wcpdf_paper_format', $this->get_setting( 'paper_size', 'A4' ), $this->get_type(), $this ),
587
- 'paper_orientation' => apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $this->get_type(), $this ),
588
- 'font_subsetting' => $this->get_setting( 'font_subsetting', false ),
589
- );
590
- $pdf_maker = wcpdf_get_pdf_maker( $this->get_html(), $pdf_settings );
591
- $pdf = $pdf_maker->output();
592
-
593
- do_action( 'wpo_wcpdf_after_pdf', $this->get_type(), $this );
594
- do_action( 'wpo_wcpdf_pdf_created', $pdf, $this );
595
-
596
- return apply_filters( 'wpo_wcpdf_get_pdf', $pdf, $this );
597
- }
598
-
599
- public function get_html( $args = array() ) {
600
- do_action( 'wpo_wcpdf_before_html', $this->get_type(), $this );
601
- $default_args = array (
602
- 'wrap_html_content' => true,
603
- );
604
- $args = $args + $default_args;
605
-
606
- $html = $this->render_template( $this->locate_template_file( "{$this->type}.php" ), array(
607
- 'order' => $this->order,
608
- 'order_id' => $this->order_id,
609
- )
610
- );
611
- if ($args['wrap_html_content']) {
612
- $html = $this->wrap_html_content( $html );
613
- }
614
-
615
- // clean up special characters
616
- if ( function_exists('utf8_decode') && function_exists('mb_convert_encoding') ) {
617
- $html = utf8_decode(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
618
- }
619
-
620
- do_action( 'wpo_wcpdf_after_html', $this->get_type(), $this );
621
-
622
- return apply_filters( 'wpo_wcpdf_get_html', $html, $this );
623
- }
624
-
625
- public function output_pdf( $output_mode = 'download' ) {
626
- $pdf = $this->get_pdf();
627
- wcpdf_pdf_headers( $this->get_filename(), $output_mode, $pdf );
628
- echo $pdf;
629
- die();
630
- }
631
-
632
- public function output_html() {
633
- echo $this->get_html();
634
- die();
635
- }
636
-
637
- public function wrap_html_content( $content ) {
638
- if ( WPO_WCPDF()->legacy_mode_enabled() ) {
639
- $GLOBALS['wpo_wcpdf']->export->output_body = $content;
640
- }
641
-
642
- $html = $this->render_template( $this->locate_template_file( "html-document-wrapper.php" ), array(
643
- 'content' => $content,
644
- )
645
- );
646
- return $html;
647
- }
648
-
649
- public function get_filename( $context = 'download', $args = array() ) {
650
- $order_count = isset($args['order_ids']) ? count($args['order_ids']) : 1;
651
-
652
- $name = $this->get_type();
653
- if ( get_post_type( $this->order_id ) == 'shop_order_refund' ) {
654
- $number = $this->order_id;
655
- } else {
656
- $number = method_exists( $this->order, 'get_order_number' ) ? $this->order->get_order_number() : '';
657
- }
658
-
659
- if ( $order_count == 1 ) {
660
- $suffix = $number;
661
- } else {
662
- $suffix = date('Y-m-d'); // 2020-11-11
663
- }
664
-
665
- $filename = $name . '-' . $suffix . '.pdf';
666
-
667
- // Filter filename
668
- $order_ids = isset($args['order_ids']) ? $args['order_ids'] : array( $this->order_id );
669
- $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $this->get_type(), $order_ids, $context );
670
-
671
- // sanitize filename (after filters to prevent human errors)!
672
- return sanitize_file_name( $filename );
673
- }
674
-
675
- public function get_template_path() {
676
- return WPO_WCPDF()->settings->get_template_path();
677
- }
678
-
679
- public function locate_template_file( $file ) {
680
- if (empty($file)) {
681
- $file = $this->type.'.php';
682
- }
683
- $path = WPO_WCPDF()->settings->get_template_path( $file );
684
- $file_path = "{$path}/{$file}";
685
-
686
- $fallback_file_path = WPO_WCPDF()->plugin_path() . '/templates/Simple/' . $file;
687
- if ( !file_exists( $file_path ) && file_exists( $fallback_file_path ) ) {
688
- $file_path = $fallback_file_path;
689
- }
690
-
691
- $file_path = apply_filters( 'wpo_wcpdf_template_file', $file_path, $this->type, $this->order );
692
-
693
- return $file_path;
694
- }
695
-
696
- public function render_template( $file, $args = array() ) {
697
- do_action( 'wpo_wcpdf_process_template', $this->get_type(), $this );
698
-
699
- if ( ! empty( $args ) && is_array( $args ) ) {
700
- extract( $args );
701
- }
702
- ob_start();
703
- if (file_exists($file)) {
704
- include($file);
705
- }
706
- return ob_get_clean();
707
- }
708
-
709
- /*
710
- |--------------------------------------------------------------------------
711
- | Settings helper functions
712
- |--------------------------------------------------------------------------
713
- */
714
-
715
- /**
716
- * get all emails registered in WooCommerce
717
- * @param boolean $remove_defaults switch to remove default woocommerce emails
718
- * @return array $emails list of all email ids/slugs and names
719
- */
720
- public function get_wc_emails() {
721
- // get emails from WooCommerce
722
- global $woocommerce;
723
- $mailer = $woocommerce->mailer();
724
- $wc_emails = $mailer->get_emails();
725
-
726
- $non_order_emails = array(
727
- 'customer_reset_password',
728
- 'customer_new_account'
729
- );
730
-
731
- $emails = array();
732
- foreach ($wc_emails as $class => $email) {
733
- if ( !is_object( $email ) ) {
734
- continue;
735
- }
736
- if ( !in_array( $email->id, $non_order_emails ) ) {
737
- switch ($email->id) {
738
- case 'new_order':
739
- $emails[$email->id] = sprintf('%s (%s)', $email->title, __( 'Admin email', 'woocommerce-pdf-invoices-packing-slips' ) );
740
- break;
741
- case 'customer_invoice':
742
- $emails[$email->id] = sprintf('%s (%s)', $email->title, __( 'Manual email', 'woocommerce-pdf-invoices-packing-slips' ) );
743
- break;
744
- default:
745
- $emails[$email->id] = $email->title;
746
- break;
747
- }
748
- }
749
- }
750
-
751
- return apply_filters( 'wpo_wcpdf_wc_emails', $emails );
752
- }
753
-
754
- // get list of WooCommerce statuses
755
- public function get_wc_order_status_list() {
756
- if ( version_compare( WOOCOMMERCE_VERSION, '2.2', '<' ) ) {
757
- $statuses = (array) get_terms( 'shop_order_status', array( 'hide_empty' => 0, 'orderby' => 'id' ) );
758
- foreach ( $statuses as $status ) {
759
- $order_statuses[esc_attr( $status->slug )] = esc_html__( $status->name, 'woocommerce' );
760
- }
761
- } else {
762
- $statuses = wc_get_order_statuses();
763
- foreach ( $statuses as $status_slug => $status ) {
764
- $status_slug = 'wc-' === substr( $status_slug, 0, 3 ) ? substr( $status_slug, 3 ) : $status_slug;
765
- $order_statuses[$status_slug] = $status;
766
- }
767
- }
768
- return $order_statuses;
769
- }
770
-
771
-
772
- }
773
-
774
- endif; // class_exists
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices\Documents;
3
+
4
+ use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
+ use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
+ use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
+ use WPO\WC\PDF_Invoices\Compatibility\WC_DateTime;
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit; // Exit if accessed directly
11
+ }
12
+
13
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Order_Document' ) ) :
14
+
15
+ /**
16
+ * Abstract Document
17
+ *
18
+ * Handles generic pdf document & order data and database interaction
19
+ * which is extended by both Invoices & Packing Slips
20
+ *
21
+ * @class \WPO\WC\PDF_Invoices\Documents\Order_Document
22
+ * @version 2.0
23
+ * @category Class
24
+ * @author Ewout Fernhout
25
+ */
26
+
27
+ abstract class Order_Document {
28
+ /**
29
+ * Document type.
30
+ * @var String
31
+ */
32
+ public $type;
33
+
34
+ /**
35
+ * Document slug.
36
+ * @var String
37
+ */
38
+ public $slug;
39
+
40
+ /**
41
+ * Document title.
42
+ * @var string
43
+ */
44
+ public $title;
45
+
46
+ /**
47
+ * Document icon.
48
+ * @var string
49
+ */
50
+ public $icon;
51
+
52
+ /**
53
+ * WC Order object
54
+ * @var object
55
+ */
56
+ public $order;
57
+
58
+ /**
59
+ * WC Order ID
60
+ * @var object
61
+ */
62
+ public $order_id;
63
+
64
+ /**
65
+ * Document settings.
66
+ * @var array
67
+ */
68
+ public $settings;
69
+
70
+ /**
71
+ * TRUE if document is enabled.
72
+ * @var bool
73
+ */
74
+ public $enabled;
75
+
76
+ /**
77
+ * Linked documents, used for data retrieval
78
+ * @var array
79
+ */
80
+ protected $linked_documents = array();
81
+
82
+ /**
83
+ * Core data for this object. Name value pairs (name + default value).
84
+ * @var array
85
+ */
86
+ protected $data = array();
87
+
88
+ /**
89
+ * Init/load the order object.
90
+ *
91
+ * @param int|object|WC_Order $order Order to init.
92
+ */
93
+ public function __construct( $order = 0 ) {
94
+ if ( is_numeric( $order ) && $order > 0 ) {
95
+ $this->order_id = $order;
96
+ $this->order = WCX::get_order( $this->order_id );
97
+ } elseif ( $order instanceof \WC_Order || is_subclass_of( $order, '\WC_Abstract_Order') ) {
98
+ $this->order_id = WCX_Order::get_id( $order );
99
+ $this->order = $order;
100
+ }
101
+
102
+ // set properties
103
+ $this->slug = str_replace('-', '_', $this->type);
104
+
105
+ // load data
106
+ if ( $this->order ) {
107
+ $this->read_data( $this->order );
108
+ if ( WPO_WCPDF()->legacy_mode_enabled() ) {
109
+ global $wpo_wcpdf;
110
+ $wpo_wcpdf->export->order = $this->order;
111
+ $wpo_wcpdf->export->document = $this;
112
+ $wpo_wcpdf->export->order_id = $this->order_id;
113
+ $wpo_wcpdf->export->template_type = $this->type;
114
+ }
115
+ }
116
+
117
+ // load settings
118
+ $this->settings = $this->get_settings();
119
+ $this->latest_settings = $this->get_settings( true );
120
+ $this->enabled = $this->get_setting( 'enabled', false );
121
+ }
122
+
123
+ public function init_settings() {
124
+ return;
125
+ }
126
+
127
+ public function get_settings( $latest = false ) {
128
+ // get most current settings
129
+ $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
130
+ $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
131
+ $settings = (array) $document_settings + (array) $common_settings;
132
+
133
+ // return only most current if forced
134
+ if ( $latest == true ) {
135
+ return $settings;
136
+ }
137
+
138
+ // get historical settings if enabled
139
+ if ( !empty( $this->order ) && $this->use_historical_settings() == true ) {
140
+ $order_settings = WCX_Order::get_meta( $this->order, "_wcpdf_{$this->slug}_settings" );
141
+ if (!empty($order_settings)) {
142
+ // not sure what happens if combining with current settings will have unwanted side effects
143
+ // like unchecked options being enabled because missing = unchecked in historical - disabled for now
144
+ // $settings = (array) $order_settings + (array) $settings;
145
+ $settings = $order_settings;
146
+ }
147
+ }
148
+ if ( $this->storing_settings_enabled() && empty( $order_settings ) && !empty( $this->order ) ) {
149
+ // this is either the first time the document is generated, or historical settings are disabled
150
+ // in both cases, we store the document settings
151
+ WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
152
+ }
153
+
154
+ return $settings;
155
+ }
156
+
157
+ public function use_historical_settings() {
158
+ return apply_filters( 'wpo_wcpdf_document_use_historical_settings', false, $this );
159
+ }
160
+
161
+ public function storing_settings_enabled() {
162
+ return apply_filters( 'wpo_wcpdf_document_store_settings', false, $this );
163
+ }
164
+
165
+ public function get_setting( $key, $default = '' ) {
166
+ $non_historical_settings = apply_filters( 'wpo_wcpdf_non_historical_settings', array(
167
+ 'enabled',
168
+ 'attach_to_email_ids',
169
+ 'number_format', // this is stored in the number data already!
170
+ 'my_account_buttons',
171
+ 'my_account_restrict',
172
+ 'invoice_number_column',
173
+ 'paper_size',
174
+ 'font_subsetting',
175
+ ) );
176
+ if ( in_array( $key, $non_historical_settings ) && isset($this->latest_settings) ) {
177
+ $setting = isset( $this->latest_settings[$key] ) ? $this->latest_settings[$key] : $default;
178
+ } else {
179
+ $setting = isset( $this->settings[$key] ) ? $this->settings[$key] : $default;
180
+ }
181
+ return $setting;
182
+ }
183
+
184
+ public function get_attach_to_email_ids() {
185
+ $email_ids = isset( $this->settings['attach_to_email_ids'] ) ? array_keys( $this->settings['attach_to_email_ids'] ) : array();
186
+ return $email_ids;
187
+ }
188
+
189
+ public function get_type() {
190
+ return $this->type;
191
+ }
192
+
193
+ public function is_enabled() {
194
+ return apply_filters( 'wpo_wcpdf_document_is_enabled', $this->enabled, $this->type );
195
+ }
196
+
197
+ public function get_hook_prefix() {
198
+ return 'wpo_wcpdf_' . $this->slug . '_get_';
199
+ }
200
+
201
+ public function read_data( $order ) {
202
+ $number = WCX_Order::get_meta( $order, "_wcpdf_{$this->slug}_number_data", true );
203
+ // fallback to legacy data for number
204
+ if ( empty( $number ) ) {
205
+ $number = WCX_Order::get_meta( $order, "_wcpdf_{$this->slug}_number", true );
206
+ $formatted_number = WCX_Order::get_meta( $order, "_wcpdf_formatted_{$this->slug}_number", true );
207
+ if (!empty($formatted_number)) {
208
+ $number = compact( 'number', 'formatted_number' );
209
+ }
210
+ }
211
+
212
+ // pass data to setter functions
213
+ $this->set_data( array(
214
+ // always load date before number, because date is used in number formatting
215
+ 'date' => WCX_Order::get_meta( $order, "_wcpdf_{$this->slug}_date", true ),
216
+ 'number' => $number,
217
+ ), $order );
218
+
219
+ return;
220
+ }
221
+
222
+ public function init() {
223
+ // store settings in order
224
+ if ( $this->storing_settings_enabled() && !empty( $this->order ) ) {
225
+ $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
226
+ $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
227
+ $settings = (array) $document_settings + (array) $common_settings;
228
+ WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
229
+ }
230
+
231
+ $this->set_date( current_time( 'timestamp', true ) );
232
+ do_action( 'wpo_wcpdf_init_document', $this );
233
+ }
234
+
235
+ public function save( $order = null ) {
236
+ $order = empty( $order ) ? $this->order : $order;
237
+ if ( empty( $order ) ) {
238
+ return; // nowhere to save to...
239
+ }
240
+
241
+ foreach ($this->data as $key => $value) {
242
+ if ( empty( $value ) ) {
243
+ WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$key}" );
244
+ if ( $key == 'date' ) {
245
+ WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_formatted" );
246
+ } elseif ( $key == 'number' ) {
247
+ WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_data" );
248
+ // deleting the number = deleting the document, so also delete document settings
249
+ WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_settings" );
250
+ }
251
+ } else {
252
+ if ( $key == 'date' ) {
253
+ // store dates as timestamp and formatted as mysql time
254
+ WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}", $value->getTimestamp() );
255
+ WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_formatted", $value->date( 'Y-m-d H:i:s' ) );
256
+ } elseif ( $key == 'number' ) {
257
+ // store both formatted number and number data
258
+ WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}", $value->formatted_number );
259
+ WCX_Order::update_meta_data( $order, "_wcpdf_{$this->slug}_{$key}_data", $value->to_array() );
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ public function delete( $order = null ) {
266
+ $order = empty( $order ) ? $this->order : $order;
267
+ if ( empty( $order ) ) {
268
+ return; // nothing to delete
269
+ }
270
+
271
+ $data_to_remove = apply_filters( 'wpo_wcpdf_delete_document_data_keys', array(
272
+ 'settings',
273
+ 'date',
274
+ 'date_formatted',
275
+ 'number',
276
+ 'number_data',
277
+ ), $this );
278
+ foreach ($data_to_remove as $data_key) {
279
+ WCX_Order::delete_meta_data( $order, "_wcpdf_{$this->slug}_{$data_key}" );
280
+ }
281
+
282
+ do_action( 'wpo_wcpdf_delete_document', $this );
283
+ }
284
+
285
+ public function is_allowed() {
286
+ $allowed = true;
287
+ if ( !empty( $this->settings['disable_for_statuses'] ) && !empty( $this->order ) && is_callable( array( $this->order, 'get_status' ) ) ) {
288
+ $status = $this->order->get_status();
289
+
290
+ $disabled_statuses = array_map( function($status){
291
+ $status = 'wc-' === substr( $status, 0, 3 ) ? substr( $status, 3 ) : $status;
292
+ return $status;
293
+ }, $this->settings['disable_for_statuses'] );
294
+
295
+ if ( in_array( $status, $disabled_statuses ) ) {
296
+ $allowed = false;
297
+ }
298
+ }
299
+ return apply_filters( 'wpo_wcpdf_document_is_allowed', $allowed, $this );
300
+ }
301
+
302
+ public function exists() {
303
+ return !empty( $this->data['date'] );
304
+ }
305
+
306
+ /*
307
+ |--------------------------------------------------------------------------
308
+ | Data getters
309
+ |--------------------------------------------------------------------------
310
+ */
311
+
312
+ public function get_data( $key, $document_type = '', $order = null, $context = 'view' ) {
313
+ $document_type = empty( $document_type ) ? $this->type : $document_type;
314
+ $order = empty( $order ) ? $this->order : $order;
315
+
316
+ // redirect get_data call for linked documents
317
+ if ( $document_type != $this->type ) {
318
+ if ( !isset( $this->linked_documents[ $document_type ] ) ) {
319
+ // always assume parent for documents linked to credit notes
320
+ if ($this->type == 'credit-note') {
321
+ $order = $this->get_refund_parent( $order );
322
+ }
323
+ // order is not loaded to avoid overhead - we pass this by reference directly to the read_data method instead
324
+ $this->linked_documents[ $document_type ] = wcpdf_get_document( $document_type, null );
325
+ $this->linked_documents[ $document_type ]->read_data( $order );
326
+ }
327
+ return $this->linked_documents[ $document_type ]->get_data( $key, $document_type );
328
+ }
329
+
330
+ $value = null;
331
+
332
+ if ( array_key_exists( $key, $this->data ) ) {
333
+ $value = $this->data[ $key ];
334
+
335
+ if ( 'view' === $context ) {
336
+ $value = apply_filters( $this->get_hook_prefix() . $key, $value, $this );
337
+ }
338
+ }
339
+
340
+ return $value;
341
+ }
342
+
343
+ public function get_number( $document_type = '', $order = null, $context = 'view' ) {
344
+ return $this->get_data( 'number', $document_type, $order, $context );
345
+ }
346
+
347
+ public function get_date( $document_type = '', $order = null, $context = 'view' ) {
348
+ return $this->get_data( 'date', $document_type, $order, $context );
349
+ }
350
+
351
+ public function get_title() {
352
+ return apply_filters( "wpo_wcpdf_{$this->slug}_title", $this->title, $this );
353
+ }
354
+
355
+ /*
356
+ |--------------------------------------------------------------------------
357
+ | Data setters
358
+ |--------------------------------------------------------------------------
359
+ |
360
+ | Functions for setting order data. These should not update anything in the
361
+ | order itself and should only change what is stored in the class
362
+ | object.
363
+ */
364
+
365
+ public function set_data( $data, $order ) {
366
+ $order = empty( $order ) ? $this->order : $order;
367
+ foreach ($data as $key => $value) {
368
+ $setter = "set_$key";
369
+ if ( is_callable( array( $this, $setter ) ) ) {
370
+ $this->$setter( $value, $order );
371
+ } else {
372
+ $this->data[ $key ] = $value;
373
+ }
374
+ }
375
+ }
376
+
377
+ public function set_date( $value, $order = null ) {
378
+ $order = empty( $order ) ? $this->order : $order;
379
+ try {
380
+ if ( empty( $value ) ) {
381
+ $this->data[ 'date' ] = null;
382
+ return;
383
+ }
384
+
385
+ if ( is_a( $value, 'WC_DateTime' ) ) {
386
+ $datetime = $value;
387
+ } elseif ( is_numeric( $value ) ) {
388
+ // Timestamps are handled as UTC timestamps in all cases.
389
+ $datetime = new WC_DateTime( "@{$value}", new \DateTimeZone( 'UTC' ) );
390
+ } else {
391
+ // Strings are defined in local WP timezone. Convert to UTC.
392
+ if ( 1 === preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|((-|\+)\d{2}:\d{2}))$/', $value, $date_bits ) ) {
393
+ $offset = ! empty( $date_bits[7] ) ? iso8601_timezone_to_offset( $date_bits[7] ) : wc_timezone_offset();
394
+ $timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] ) - $offset;
395
+ } else {
396
+ $timestamp = wc_string_to_timestamp( get_gmt_from_date( gmdate( 'Y-m-d H:i:s', wc_string_to_timestamp( $value ) ) ) );
397
+ }
398
+ $datetime = new WC_DateTime( "@{$timestamp}", new \DateTimeZone( 'UTC' ) );
399
+ }
400
+
401
+ // Set local timezone or offset.
402
+ if ( get_option( 'timezone_string' ) ) {
403
+ $datetime->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
404
+ } else {
405
+ $datetime->set_utc_offset( wc_timezone_offset() );
406
+ }
407
+
408
+ $this->data[ 'date' ] = $datetime;
409
+ } catch ( \Exception $e ) {
410
+ wcpdf_log_error( $e->getMessage() );
411
+ } catch ( \Error $e ) {
412
+ wcpdf_log_error( $e->getMessage() );
413
+ }
414
+
415
+ }
416
+
417
+ public function set_number( $value, $order = null ) {
418
+ $order = empty( $order ) ? $this->order : $order;
419
+
420
+ if ( is_array( $value ) ) {
421
+ $filtered_value = array_filter( $value );
422
+ }
423
+
424
+ if ( empty( $value ) || ( is_array( $value ) && empty( $filtered_value ) ) ) {
425
+ $document_number = null;
426
+ } elseif ( $value instanceof Document_Number ) {
427
+ // WCPDF 2.0 number data
428
+ $document_number = $value;
429
+ } elseif ( is_array( $value ) ) {
430
+ // WCPDF 2.0 number data as array
431
+ $document_number = new Document_Number( $value, $this->get_number_settings(), $this, $order );
432
+ } else {
433
+ // plain number
434
+ $document_number = new Document_Number( $value, $this->get_number_settings(), $this, $order );
435
+ }
436
+
437
+ $this->data[ 'number' ] = $document_number;
438
+ }
439
+
440
+ /*
441
+ |--------------------------------------------------------------------------
442
+ | Settings getters / outputters
443
+ |--------------------------------------------------------------------------
444
+ */
445
+
446
+ public function get_number_settings() {
447
+ if (empty($this->settings)) {
448
+ $settings = $this->get_settings( true ); // we always want the latest settings
449
+ $number_settings = isset($settings['number_format'])?$settings['number_format']:array();
450
+ } else {
451
+ $number_settings = $this->get_setting( 'number_format', array() );
452
+ }
453
+ return apply_filters( 'wpo_wcpdf_document_number_settings', $number_settings, $this );
454
+ }
455
+
456
+ /**
457
+ * Output template styles
458
+ */
459
+ public function template_styles() {
460
+ $css = apply_filters( 'wpo_wcpdf_template_styles_file', $this->locate_template_file( "style.css" ) );
461
+
462
+ ob_start();
463
+ if (file_exists($css)) {
464
+ include($css);
465
+ }
466
+ $css = ob_get_clean();
467
+ $css = apply_filters( 'wpo_wcpdf_template_styles', $css, $this );
468
+
469
+ echo $css;
470
+ }
471
+
472
+ public function has_header_logo() {
473
+ return !empty( $this->settings['header_logo'] );
474
+ }
475
+
476
+ /**
477
+ * Return logo id
478
+ */
479
+ public function get_header_logo_id() {
480
+ if ( !empty( $this->settings['header_logo'] ) ) {
481
+ return apply_filters( 'wpo_wcpdf_header_logo_id', $this->settings['header_logo'], $this );
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Show logo html
487
+ */
488
+ public function header_logo() {
489
+ if ($this->get_header_logo_id()) {
490
+ $attachment_id = $this->get_header_logo_id();
491
+ $company = $this->get_shop_name();
492
+ if( $attachment_id ) {
493
+ $attachment = wp_get_attachment_image_src( $attachment_id, 'full', false );
494
+
495
+ $attachment_src = $attachment[0];
496
+ $attachment_width = $attachment[1];
497
+ $attachment_height = $attachment[2];
498
+
499
+ $attachment_path = get_attached_file( $attachment_id );
500
+
501
+ if ( apply_filters('wpo_wcpdf_use_path', true) && file_exists($attachment_path) ) {
502
+ $src = $attachment_path;
503
+ } else {
504
+ $src = $attachment_src;
505
+ }
506
+
507
+ $img_element = sprintf('<img src="%1$s" alt="%4$s" />', $src, $attachment_width, $attachment_height, esc_attr( $company ) );
508
+
509
+ echo apply_filters( 'wpo_wcpdf_header_logo_img_element', $img_element, $attachment, $this );
510
+ }
511
+ }
512
+ }
513
+
514
+ public function get_settings_text( $settings_key, $default = false, $autop = true ) {
515
+ if ( !empty( $this->settings[$settings_key]['default'] ) ) {
516
+ $text = wptexturize( trim( $this->settings[$settings_key]['default'] ) );
517
+ if ($autop === true) {
518
+ $text = wpautop( $text );
519
+ }
520
+ } else {
521
+ $text = $default;
522
+ }
523
+ // legacy filters
524
+ if ( in_array( $settings_key, array( 'shop_name', 'shop_address', 'footer', 'extra_1', 'extra_2', 'extra_3' ) ) ) {
525
+ $text = apply_filters( "wpo_wcpdf_{$settings_key}", $text, $this );
526
+ }
527
+
528
+ return apply_filters( "wpo_wcpdf_{$settings_key}_settings_text", $text, $this );
529
+ }
530
+
531
+ /**
532
+ * Return/Show custom company name or default to blog name
533
+ */
534
+ public function get_shop_name() {
535
+ $default = get_bloginfo( 'name' );
536
+ return $this->get_settings_text( 'shop_name', $default, false );
537
+ }
538
+ public function shop_name() {
539
+ echo $this->get_shop_name();
540
+ }
541
+
542
+ /**
543
+ * Return/Show shop/company address if provided
544
+ */
545
+ public function get_shop_address() {
546
+ return $this->get_settings_text( 'shop_address' );
547
+ }
548
+ public function shop_address() {
549
+ echo $this->get_shop_address();
550
+ }
551
+
552
+ /**
553
+ * Return/Show shop/company footer imprint, copyright etc.
554
+ */
555
+ public function get_footer() {
556
+ return $this->get_settings_text( 'footer' );
557
+ }
558
+ public function footer() {
559
+ echo $this->get_footer();
560
+ }
561
+
562
+ /**
563
+ * Return/Show Extra field 1
564
+ */
565
+ public function get_extra_1() {
566
+ return $this->get_settings_text( 'extra_1' );
567
+
568
+ }
569
+ public function extra_1() {
570
+ echo $this->get_extra_1();
571
+ }
572
+
573
+ /**
574
+ * Return/Show Extra field 2
575
+ */
576
+ public function get_extra_2() {
577
+ return $this->get_settings_text( 'extra_2' );
578
+ }
579
+ public function extra_2() {
580
+ echo $this->get_extra_2();
581
+ }
582
+
583
+ /**
584
+ * Return/Show Extra field 3
585
+ */
586
+ public function get_extra_3() {
587
+ return $this->get_settings_text( 'extra_3' );
588
+ }
589
+ public function extra_3() {
590
+ echo $this->get_extra_3();
591
+ }
592
+
593
+ /*
594
+ |--------------------------------------------------------------------------
595
+ | Output functions
596
+ |--------------------------------------------------------------------------
597
+ */
598
+
599
+ public function get_pdf() {
600
+ if ( $pdf_file = apply_filters( 'wpo_wcpdf_load_pdf_file_path', null, $this ) ) {
601
+ $pdf = file_get_contents( $pdf_file );
602
+ if ( !empty( $pdf ) ) {
603
+ return $pdf;
604
+ }
605
+ }
606
+
607
+ do_action( 'wpo_wcpdf_before_pdf', $this->get_type(), $this );
608
+
609
+ $pdf_settings = array(
610
+ 'paper_size' => apply_filters( 'wpo_wcpdf_paper_format', $this->get_setting( 'paper_size', 'A4' ), $this->get_type(), $this ),
611
+ 'paper_orientation' => apply_filters( 'wpo_wcpdf_paper_orientation', 'portrait', $this->get_type(), $this ),
612
+ 'font_subsetting' => $this->get_setting( 'font_subsetting', false ),
613
+ );
614
+ $pdf_maker = wcpdf_get_pdf_maker( $this->get_html(), $pdf_settings );
615
+ $pdf = $pdf_maker->output();
616
+
617
+ do_action( 'wpo_wcpdf_after_pdf', $this->get_type(), $this );
618
+ do_action( 'wpo_wcpdf_pdf_created', $pdf, $this );
619
+
620
+ return apply_filters( 'wpo_wcpdf_get_pdf', $pdf, $this );
621
+ }
622
+
623
+ public function get_html( $args = array() ) {
624
+ do_action( 'wpo_wcpdf_before_html', $this->get_type(), $this );
625
+ $default_args = array (
626
+ 'wrap_html_content' => true,
627
+ );
628
+ $args = $args + $default_args;
629
+
630
+ $html = $this->render_template( $this->locate_template_file( "{$this->type}.php" ), array(
631
+ 'order' => $this->order,
632
+ 'order_id' => $this->order_id,
633
+ )
634
+ );
635
+ if ($args['wrap_html_content']) {
636
+ $html = $this->wrap_html_content( $html );
637
+ }
638
+
639
+ // clean up special characters
640
+ if ( function_exists('utf8_decode') && function_exists('mb_convert_encoding') ) {
641
+ $html = utf8_decode(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
642
+ }
643
+
644
+ do_action( 'wpo_wcpdf_after_html', $this->get_type(), $this );
645
+
646
+ return apply_filters( 'wpo_wcpdf_get_html', $html, $this );
647
+ }
648
+
649
+ public function output_pdf( $output_mode = 'download' ) {
650
+ $pdf = $this->get_pdf();
651
+ wcpdf_pdf_headers( $this->get_filename(), $output_mode, $pdf );
652
+ echo $pdf;
653
+ die();
654
+ }
655
+
656
+ public function output_html() {
657
+ echo $this->get_html();
658
+ die();
659
+ }
660
+
661
+ public function wrap_html_content( $content ) {
662
+ if ( WPO_WCPDF()->legacy_mode_enabled() ) {
663
+ $GLOBALS['wpo_wcpdf']->export->output_body = $content;
664
+ }
665
+
666
+ $html = $this->render_template( $this->locate_template_file( "html-document-wrapper.php" ), array(
667
+ 'content' => $content,
668
+ )
669
+ );
670
+ return $html;
671
+ }
672
+
673
+ public function get_filename( $context = 'download', $args = array() ) {
674
+ $order_count = isset($args['order_ids']) ? count($args['order_ids']) : 1;
675
+
676
+ $name = $this->get_type();
677
+ if ( get_post_type( $this->order_id ) == 'shop_order_refund' ) {
678
+ $number = $this->order_id;
679
+ } else {
680
+ $number = method_exists( $this->order, 'get_order_number' ) ? $this->order->get_order_number() : '';
681
+ }
682
+
683
+ if ( $order_count == 1 ) {
684
+ $suffix = $number;
685
+ } else {
686
+ $suffix = date('Y-m-d'); // 2020-11-11
687
+ }
688
+
689
+ $filename = $name . '-' . $suffix . '.pdf';
690
+
691
+ // Filter filename
692
+ $order_ids = isset($args['order_ids']) ? $args['order_ids'] : array( $this->order_id );
693
+ $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $this->get_type(), $order_ids, $context );
694
+
695
+ // sanitize filename (after filters to prevent human errors)!
696
+ return sanitize_file_name( $filename );
697
+ }
698
+
699
+ public function get_template_path() {
700
+ return WPO_WCPDF()->settings->get_template_path();
701
+ }
702
+
703
+ public function locate_template_file( $file ) {
704
+ if (empty($file)) {
705
+ $file = $this->type.'.php';
706
+ }
707
+ $path = WPO_WCPDF()->settings->get_template_path( $file );
708
+ $file_path = "{$path}/{$file}";
709
+
710
+ $fallback_file_path = WPO_WCPDF()->plugin_path() . '/templates/Simple/' . $file;
711
+ if ( !file_exists( $file_path ) && file_exists( $fallback_file_path ) ) {
712
+ $file_path = $fallback_file_path;
713
+ }
714
+
715
+ $file_path = apply_filters( 'wpo_wcpdf_template_file', $file_path, $this->type, $this->order );
716
+
717
+ return $file_path;
718
+ }
719
+
720
+ public function render_template( $file, $args = array() ) {
721
+ do_action( 'wpo_wcpdf_process_template', $this->get_type(), $this );
722
+
723
+ if ( ! empty( $args ) && is_array( $args ) ) {
724
+ extract( $args );
725
+ }
726
+ ob_start();
727
+ if (file_exists($file)) {
728
+ include($file);
729
+ }
730
+ return ob_get_clean();
731
+ }
732
+
733
+ /*
734
+ |--------------------------------------------------------------------------
735
+ | Settings helper functions
736
+ |--------------------------------------------------------------------------
737
+ */
738
+
739
+ /**
740
+ * get all emails registered in WooCommerce
741
+ * @param boolean $remove_defaults switch to remove default woocommerce emails
742
+ * @return array $emails list of all email ids/slugs and names
743
+ */
744
+ public function get_wc_emails() {
745
+ // get emails from WooCommerce
746
+ global $woocommerce;
747
+ $mailer = $woocommerce->mailer();
748
+ $wc_emails = $mailer->get_emails();
749
+
750
+ $non_order_emails = array(
751
+ 'customer_reset_password',
752
+ 'customer_new_account'
753
+ );
754
+
755
+ $emails = array();
756
+ foreach ($wc_emails as $class => $email) {
757
+ if ( !is_object( $email ) ) {
758
+ continue;
759
+ }
760
+ if ( !in_array( $email->id, $non_order_emails ) ) {
761
+ switch ($email->id) {
762
+ case 'new_order':
763
+ $emails[$email->id] = sprintf('%s (%s)', $email->title, __( 'Admin email', 'woocommerce-pdf-invoices-packing-slips' ) );
764
+ break;
765
+ case 'customer_invoice':
766
+ $emails[$email->id] = sprintf('%s (%s)', $email->title, __( 'Manual email', 'woocommerce-pdf-invoices-packing-slips' ) );
767
+ break;
768
+ default:
769
+ $emails[$email->id] = $email->title;
770
+ break;
771
+ }
772
+ }
773
+ }
774
+
775
+ return apply_filters( 'wpo_wcpdf_wc_emails', $emails );
776
+ }
777
+
778
+ // get list of WooCommerce statuses
779
+ public function get_wc_order_status_list() {
780
+ if ( version_compare( WOOCOMMERCE_VERSION, '2.2', '<' ) ) {
781
+ $statuses = (array) get_terms( 'shop_order_status', array( 'hide_empty' => 0, 'orderby' => 'id' ) );
782
+ foreach ( $statuses as $status ) {
783
+ $order_statuses[esc_attr( $status->slug )] = esc_html__( $status->name, 'woocommerce' );
784
+ }
785
+ } else {
786
+ $statuses = wc_get_order_statuses();
787
+ foreach ( $statuses as $status_slug => $status ) {
788
+ $status_slug = 'wc-' === substr( $status_slug, 0, 3 ) ? substr( $status_slug, 3 ) : $status_slug;
789
+ $order_statuses[$status_slug] = $status;
790
+ }
791
+ }
792
+ return $order_statuses;
793
+ }
794
+
795
+
796
+ }
797
+
798
+ endif; // class_exists
includes/documents/class-wcpdf-invoice.php CHANGED
@@ -1,383 +1,402 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices\Documents;
3
-
4
- use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
- use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
- use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly
10
- }
11
-
12
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Invoice' ) ) :
13
-
14
- /**
15
- * Invoice Document
16
- *
17
- * @class \WPO\WC\PDF_Invoices\Documents\Invoice
18
- * @version 2.0
19
- * @category Class
20
- * @author Ewout Fernhout
21
- */
22
-
23
- class Invoice extends Order_Document_Methods {
24
- /**
25
- * Init/load the order object.
26
- *
27
- * @param int|object|WC_Order $order Order to init.
28
- */
29
- public function __construct( $order = 0 ) {
30
- // set properties
31
- $this->type = 'invoice';
32
- $this->title = __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' );
33
- $this->icon = WPO_WCPDF()->plugin_url() . "/assets/images/invoice.png";
34
-
35
- // Call parent constructor
36
- parent::__construct( $order );
37
- }
38
-
39
- public function use_historical_settings() {
40
- $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
41
- // this setting is inverted on the frontend so that it needs to be actively/purposely enabled to be used
42
- if (!empty($document_settings) && isset($document_settings['use_latest_settings'])) {
43
- $use_historical_settings = false;
44
- } else {
45
- $use_historical_settings = true;
46
- }
47
- return apply_filters( 'wpo_wcpdf_document_use_historical_settings', $use_historical_settings, $this );
48
- }
49
-
50
- public function get_title() {
51
- // override/not using $this->title to allow for language switching!
52
- return apply_filters( "wpo_wcpdf_{$this->slug}_title", __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' ), $this );
53
- }
54
-
55
- public function init() {
56
- // store settings in order
57
- if ( !empty( $this->order ) ) {
58
- $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
59
- $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
60
- $settings = (array) $document_settings + (array) $common_settings;
61
- WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
62
- }
63
-
64
- $this->set_date( current_time( 'timestamp', true ) );
65
- $this->init_number();
66
- }
67
-
68
- public function exists() {
69
- return !empty( $this->data['number'] );
70
- }
71
-
72
- public function init_number() {
73
- global $wpdb;
74
- // If a third-party plugin claims to generate invoice numbers, trigger this instead
75
- if ( apply_filters( 'woocommerce_invoice_number_by_plugin', false ) || apply_filters( 'wpo_wcpdf_external_invoice_number_enabled', false, $this ) ) {
76
- $invoice_number = apply_filters( 'woocommerce_generate_invoice_number', null, $this->order );
77
- $invoice_number = apply_filters( 'wpo_wcpdf_external_invoice_number', $invoice_number, $this );
78
- if ( is_numeric($invoice_number) || $invoice_number instanceof Document_Number ) {
79
- $this->set_number( $invoice_number );
80
- } else {
81
- // invoice number is not numeric, treat as formatted
82
- // try to extract meaningful number data
83
- $formatted_number = $invoice_number;
84
- $number = (int) preg_replace('/\D/', '', $invoice_number);
85
- $invoice_number = compact( 'number', 'formatted_number' );
86
- $this->set_number( $invoice_number );
87
- }
88
- return $invoice_number;
89
- }
90
-
91
- $number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
92
- $number_store = new Sequential_Number_Store( 'invoice_number', $number_store_method );
93
- // reset invoice number yearly
94
- if ( isset( $this->settings['reset_number_yearly'] ) ) {
95
- $current_year = date("Y");
96
- $last_number_year = $number_store->get_last_date('Y');
97
- // check if we need to reset
98
- if ( $current_year != $last_number_year ) {
99
- $number_store->set_next( 1 );
100
- }
101
- }
102
-
103
- $invoice_date = $this->get_date();
104
- $invoice_number = $number_store->increment( $this->order_id, $invoice_date->date_i18n( 'Y-m-d H:i:s' ) );
105
-
106
- $this->set_number( $invoice_number );
107
-
108
- return $invoice_number;
109
- }
110
-
111
- public function get_filename( $context = 'download', $args = array() ) {
112
- $order_count = isset($args['order_ids']) ? count($args['order_ids']) : 1;
113
-
114
- $name = _n( 'invoice', 'invoices', $order_count, 'woocommerce-pdf-invoices-packing-slips' );
115
-
116
- if ( $order_count == 1 ) {
117
- if ( isset( $this->settings['display_number'] ) ) {
118
- $suffix = (string) $this->get_number();
119
- } else {
120
- if ( empty( $this->order ) ) {
121
- $order = WCX::get_order ( $order_ids[0] );
122
- $suffix = method_exists( $order, 'get_order_number' ) ? $order->get_order_number() : '';
123
- } else {
124
- $suffix = method_exists( $this->order, 'get_order_number' ) ? $this->order->get_order_number() : '';
125
- }
126
- }
127
- } else {
128
- $suffix = date('Y-m-d'); // 2020-11-11
129
- }
130
-
131
- $filename = $name . '-' . $suffix . '.pdf';
132
-
133
- // Filter filename
134
- $order_ids = isset($args['order_ids']) ? $args['order_ids'] : array( $this->order_id );
135
- $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $this->get_type(), $order_ids, $context );
136
-
137
- // sanitize filename (after filters to prevent human errors)!
138
- return sanitize_file_name( $filename );
139
- }
140
-
141
-
142
- /**
143
- * Initialise settings
144
- */
145
- public function init_settings() {
146
- // Register settings.
147
- $page = $option_group = $option_name = 'wpo_wcpdf_documents_settings_invoice';
148
-
149
- $settings_fields = array(
150
- array(
151
- 'type' => 'section',
152
- 'id' => 'invoice',
153
- 'title' => '',
154
- 'callback' => 'section',
155
- ),
156
- array(
157
- 'type' => 'setting',
158
- 'id' => 'enabled',
159
- 'title' => __( 'Enable', 'woocommerce-pdf-invoices-packing-slips' ),
160
- 'callback' => 'checkbox',
161
- 'section' => 'invoice',
162
- 'args' => array(
163
- 'option_name' => $option_name,
164
- 'id' => 'enabled',
165
- )
166
- ),
167
- array(
168
- 'type' => 'setting',
169
- 'id' => 'attach_to_email_ids',
170
- 'title' => __( 'Attach to:', 'woocommerce-pdf-invoices-packing-slips' ),
171
- 'callback' => 'multiple_checkboxes',
172
- 'section' => 'invoice',
173
- 'args' => array(
174
- 'option_name' => $option_name,
175
- 'id' => 'attach_to_email_ids',
176
- 'fields' => $this->get_wc_emails(),
177
- 'description' => !is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? '<span class="wpo-warning">' . sprintf( __( 'It looks like the temp folder (<code>%s</code>) is not writable, check the permissions for this folder! Without having write access to this folder, the plugin will not be able to email invoices.', 'woocommerce-pdf-invoices-packing-slips' ), WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ).'</span>':'',
178
- )
179
- ),
180
- array(
181
- 'type' => 'setting',
182
- 'id' => 'display_shipping_address',
183
- 'title' => __( 'Display shipping address', 'woocommerce-pdf-invoices-packing-slips' ),
184
- 'callback' => 'checkbox',
185
- 'section' => 'invoice',
186
- 'args' => array(
187
- 'option_name' => $option_name,
188
- 'id' => 'display_shipping_address',
189
- 'description' => __( 'Display shipping address (in addition to the default billing address) if different from billing address', 'woocommerce-pdf-invoices-packing-slips' ),
190
- )
191
- ),
192
- array(
193
- 'type' => 'setting',
194
- 'id' => 'display_email',
195
- 'title' => __( 'Display email address', 'woocommerce-pdf-invoices-packing-slips' ),
196
- 'callback' => 'checkbox',
197
- 'section' => 'invoice',
198
- 'args' => array(
199
- 'option_name' => $option_name,
200
- 'id' => 'display_email',
201
- )
202
- ),
203
- array(
204
- 'type' => 'setting',
205
- 'id' => 'display_phone',
206
- 'title' => __( 'Display phone number', 'woocommerce-pdf-invoices-packing-slips' ),
207
- 'callback' => 'checkbox',
208
- 'section' => 'invoice',
209
- 'args' => array(
210
- 'option_name' => $option_name,
211
- 'id' => 'display_phone',
212
- )
213
- ),
214
- array(
215
- 'type' => 'setting',
216
- 'id' => 'display_date',
217
- 'title' => __( 'Display invoice date', 'woocommerce-pdf-invoices-packing-slips' ),
218
- 'callback' => 'checkbox',
219
- 'section' => 'invoice',
220
- 'args' => array(
221
- 'option_name' => $option_name,
222
- 'id' => 'display_date',
223
- 'value' => 'invoice_date',
224
- )
225
- ),
226
- array(
227
- 'type' => 'setting',
228
- 'id' => 'display_number',
229
- 'title' => __( 'Display invoice number', 'woocommerce-pdf-invoices-packing-slips' ),
230
- 'callback' => 'checkbox',
231
- 'section' => 'invoice',
232
- 'args' => array(
233
- 'option_name' => $option_name,
234
- 'id' => 'display_number',
235
- 'value' => 'invoice_number',
236
- )
237
- ),
238
- array(
239
- 'type' => 'setting',
240
- 'id' => 'next_invoice_number',
241
- 'title' => __( 'Next invoice number (without prefix/suffix etc.)', 'woocommerce-pdf-invoices-packing-slips' ),
242
- 'callback' => 'next_number_edit',
243
- 'section' => 'invoice',
244
- 'args' => array(
245
- 'store' => 'invoice_number',
246
- 'size' => '10',
247
- 'description' => __( 'This is the number that will be used for the next document. By default, numbering starts from 1 and increases for every new document. Note that if you override this and set it lower than the current/highest number, this could create duplicate numbers!', 'woocommerce-pdf-invoices-packing-slips' ),
248
- )
249
- ),
250
- array(
251
- 'type' => 'setting',
252
- 'id' => 'number_format',
253
- 'title' => __( 'Number format', 'woocommerce-pdf-invoices-packing-slips' ),
254
- 'callback' => 'multiple_text_input',
255
- 'section' => 'invoice',
256
- 'args' => array(
257
- 'option_name' => $option_name,
258
- 'id' => 'number_format',
259
- 'fields' => array(
260
- 'prefix' => array(
261
- 'placeholder' => __( 'Prefix' , 'woocommerce-pdf-invoices-packing-slips' ),
262
- 'size' => 20,
263
- 'description' => __( 'to use the invoice year and/or month, use [invoice_year] or [invoice_month] respectively' , 'woocommerce-pdf-invoices-packing-slips' ),
264
- ),
265
- 'suffix' => array(
266
- 'placeholder' => __( 'Suffix' , 'woocommerce-pdf-invoices-packing-slips' ),
267
- 'size' => 20,
268
- 'description' => '',
269
- ),
270
- 'padding' => array(
271
- 'placeholder' => __( 'Padding' , 'woocommerce-pdf-invoices-packing-slips' ),
272
- 'size' => 20,
273
- 'type' => 'number',
274
- 'description' => __( 'enter the number of digits here - enter "6" to display 42 as 000042' , 'woocommerce-pdf-invoices-packing-slips' ),
275
- ),
276
- ),
277
- 'description' => __( 'note: if you have already created a custom invoice number format with a filter, the above settings will be ignored' , 'woocommerce-pdf-invoices-packing-slips' ),
278
- )
279
- ),
280
- array(
281
- 'type' => 'setting',
282
- 'id' => 'reset_number_yearly',
283
- 'title' => __( 'Reset invoice number yearly', 'woocommerce-pdf-invoices-packing-slips' ),
284
- 'callback' => 'checkbox',
285
- 'section' => 'invoice',
286
- 'args' => array(
287
- 'option_name' => $option_name,
288
- 'id' => 'reset_number_yearly',
289
- )
290
- ),
291
- array(
292
- 'type' => 'setting',
293
- 'id' => 'my_account_buttons',
294
- 'title' => __( 'Allow My Account invoice download', 'woocommerce-pdf-invoices-packing-slips' ),
295
- 'callback' => 'select',
296
- 'section' => 'invoice',
297
- 'args' => array(
298
- 'option_name' => $option_name,
299
- 'id' => 'my_account_buttons',
300
- 'options' => array(
301
- 'available' => __( 'Only when an invoice is already created/emailed' , 'woocommerce-pdf-invoices-packing-slips' ),
302
- 'custom' => __( 'Only for specific order statuses (define below)' , 'woocommerce-pdf-invoices-packing-slips' ),
303
- 'always' => __( 'Always' , 'woocommerce-pdf-invoices-packing-slips' ),
304
- 'never' => __( 'Never' , 'woocommerce-pdf-invoices-packing-slips' ),
305
- ),
306
- 'custom' => array(
307
- 'type' => 'multiple_checkboxes',
308
- 'args' => array(
309
- 'option_name' => $option_name,
310
- 'id' => 'my_account_restrict',
311
- 'fields' => $this->get_wc_order_status_list(),
312
- ),
313
- ),
314
- )
315
- ),
316
- array(
317
- 'type' => 'setting',
318
- 'id' => 'invoice_number_column',
319
- 'title' => __( 'Enable invoice number column in the orders list', 'woocommerce-pdf-invoices-packing-slips' ),
320
- 'callback' => 'checkbox',
321
- 'section' => 'invoice',
322
- 'args' => array(
323
- 'option_name' => $option_name,
324
- 'id' => 'invoice_number_column',
325
- )
326
- ),
327
- array(
328
- 'type' => 'setting',
329
- 'id' => 'disable_free',
330
- 'title' => __( 'Disable for free products', 'woocommerce-pdf-invoices-packing-slips' ),
331
- 'callback' => 'checkbox',
332
- 'section' => 'invoice',
333
- 'args' => array(
334
- 'option_name' => $option_name,
335
- 'id' => 'disable_free',
336
- 'description' => __( "Disable automatic creation/attachment when only free products are ordered", 'woocommerce-pdf-invoices-packing-slips' ),
337
- )
338
- ),
339
- array(
340
- 'type' => 'setting',
341
- 'id' => 'use_latest_settings',
342
- 'title' => __( 'Always use most current settings', 'woocommerce-pdf-invoices-packing-slips' ),
343
- 'callback' => 'checkbox',
344
- 'section' => 'invoice',
345
- 'args' => array(
346
- 'option_name' => $option_name,
347
- 'id' => 'use_latest_settings',
348
- 'description' => __( "When enabled, the document will always reflect the most current settings (such as footer text, document name, etc.) rather than using historical settings.", 'woocommerce-pdf-invoices-packing-slips' )
349
- . "<br>"
350
- . __( "<strong>Caution:</strong> enabling this will also mean that if you change your company name or address in the future, previously generated documents will also be affected.", 'woocommerce-pdf-invoices-packing-slips' ),
351
- )
352
- ),
353
- );
354
-
355
- // remove/rename some fields when invoice number is controlled externally
356
- if( apply_filters('woocommerce_invoice_number_by_plugin', false) ) {
357
- $remove_settings = array( 'next_invoice_number', 'number_format', 'reset_number_yearly' );
358
- foreach ($settings_fields as $key => $settings_field) {
359
- if (in_array($settings_field['id'], $remove_settings)) {
360
- unset($settings_fields[$key]);
361
- } elseif ( $settings_field['id'] == 'display_number' ) {
362
- // alternate description for invoice number
363
- $invoice_number_desc = __( 'Invoice numbers are created by a third-party extension.', 'woocommerce-pdf-invoices-packing-slips' );
364
- if ( $config_link = apply_filters( 'woocommerce_invoice_number_configuration_link', null ) ) {
365
- $invoice_number_desc .= ' '.sprintf(__( 'Configure it <a href="%s">here</a>.', 'woocommerce-pdf-invoices-packing-slips' ), esc_attr( $config_link ) );
366
- }
367
- $settings_fields[$key]['args']['description'] = '<i>'.$invoice_number_desc.'</i>';
368
- }
369
- }
370
- }
371
-
372
- // allow plugins to alter settings fields
373
- $settings_fields = apply_filters( 'wpo_wcpdf_settings_fields_documents_invoice', $settings_fields, $page, $option_group, $option_name );
374
- WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
375
- return;
376
-
377
- }
378
-
379
- }
380
-
381
- endif; // class_exists
382
-
383
- return new Invoice();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices\Documents;
3
+
4
+ use WPO\WC\PDF_Invoices\Compatibility\WC_Core as WCX;
5
+ use WPO\WC\PDF_Invoices\Compatibility\Order as WCX_Order;
6
+ use WPO\WC\PDF_Invoices\Compatibility\Product as WCX_Product;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly
10
+ }
11
+
12
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Invoice' ) ) :
13
+
14
+ /**
15
+ * Invoice Document
16
+ *
17
+ * @class \WPO\WC\PDF_Invoices\Documents\Invoice
18
+ * @version 2.0
19
+ * @category Class
20
+ * @author Ewout Fernhout
21
+ */
22
+
23
+ class Invoice extends Order_Document_Methods {
24
+ /**
25
+ * Init/load the order object.
26
+ *
27
+ * @param int|object|WC_Order $order Order to init.
28
+ */
29
+ public function __construct( $order = 0 ) {
30
+ // set properties
31
+ $this->type = 'invoice';
32
+ $this->title = __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' );
33
+ $this->icon = WPO_WCPDF()->plugin_url() . "/assets/images/invoice.png";
34
+
35
+ // Call parent constructor
36
+ parent::__construct( $order );
37
+ }
38
+
39
+ public function use_historical_settings() {
40
+ $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
41
+ // this setting is inverted on the frontend so that it needs to be actively/purposely enabled to be used
42
+ if (!empty($document_settings) && isset($document_settings['use_latest_settings'])) {
43
+ $use_historical_settings = false;
44
+ } else {
45
+ $use_historical_settings = true;
46
+ }
47
+ return apply_filters( 'wpo_wcpdf_document_use_historical_settings', $use_historical_settings, $this );
48
+ }
49
+
50
+ public function storing_settings_enabled() {
51
+ return apply_filters( 'wpo_wcpdf_document_store_settings', true, $this );
52
+ }
53
+
54
+ public function get_title() {
55
+ // override/not using $this->title to allow for language switching!
56
+ return apply_filters( "wpo_wcpdf_{$this->slug}_title", __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' ), $this );
57
+ }
58
+
59
+ public function init() {
60
+ // store settings in order
61
+ if ( $this->storing_settings_enabled() && !empty( $this->order ) ) {
62
+ $common_settings = WPO_WCPDF()->settings->get_common_document_settings();
63
+ $document_settings = get_option( 'wpo_wcpdf_documents_settings_'.$this->get_type() );
64
+ $settings = (array) $document_settings + (array) $common_settings;
65
+ WCX_Order::update_meta_data( $this->order, "_wcpdf_{$this->slug}_settings", $settings );
66
+ }
67
+
68
+ $this->set_date( current_time( 'timestamp', true ) );
69
+ $this->init_number();
70
+ }
71
+
72
+ public function exists() {
73
+ return !empty( $this->data['number'] );
74
+ }
75
+
76
+ public function init_number() {
77
+ global $wpdb;
78
+ // If a third-party plugin claims to generate invoice numbers, trigger this instead
79
+ if ( apply_filters( 'woocommerce_invoice_number_by_plugin', false ) || apply_filters( 'wpo_wcpdf_external_invoice_number_enabled', false, $this ) ) {
80
+ $invoice_number = apply_filters( 'woocommerce_generate_invoice_number', null, $this->order );
81
+ $invoice_number = apply_filters( 'wpo_wcpdf_external_invoice_number', $invoice_number, $this );
82
+ if ( is_numeric($invoice_number) || $invoice_number instanceof Document_Number ) {
83
+ $this->set_number( $invoice_number );
84
+ } else {
85
+ // invoice number is not numeric, treat as formatted
86
+ // try to extract meaningful number data
87
+ $formatted_number = $invoice_number;
88
+ $number = (int) preg_replace('/\D/', '', $invoice_number);
89
+ $invoice_number = compact( 'number', 'formatted_number' );
90
+ $this->set_number( $invoice_number );
91
+ }
92
+ return $invoice_number;
93
+ }
94
+
95
+ $number_store_method = WPO_WCPDF()->settings->get_sequential_number_store_method();
96
+ $number_store = new Sequential_Number_Store( 'invoice_number', $number_store_method );
97
+ // reset invoice number yearly
98
+ if ( isset( $this->settings['reset_number_yearly'] ) ) {
99
+ $current_year = date("Y");
100
+ $last_number_year = $number_store->get_last_date('Y');
101
+ // check if we need to reset
102
+ if ( $current_year != $last_number_year ) {
103
+ $number_store->set_next( 1 );
104
+ }
105
+ }
106
+
107
+ $invoice_date = $this->get_date();
108
+ $invoice_number = $number_store->increment( $this->order_id, $invoice_date->date_i18n( 'Y-m-d H:i:s' ) );
109
+
110
+ $this->set_number( $invoice_number );
111
+
112
+ return $invoice_number;
113
+ }
114
+
115
+ public function get_filename( $context = 'download', $args = array() ) {
116
+ $order_count = isset($args['order_ids']) ? count($args['order_ids']) : 1;
117
+
118
+ $name = _n( 'invoice', 'invoices', $order_count, 'woocommerce-pdf-invoices-packing-slips' );
119
+
120
+ if ( $order_count == 1 ) {
121
+ if ( isset( $this->settings['display_number'] ) ) {
122
+ $suffix = (string) $this->get_number();
123
+ } else {
124
+ if ( empty( $this->order ) ) {
125
+ $order = WCX::get_order ( $order_ids[0] );
126
+ $suffix = method_exists( $order, 'get_order_number' ) ? $order->get_order_number() : '';
127
+ } else {
128
+ $suffix = method_exists( $this->order, 'get_order_number' ) ? $this->order->get_order_number() : '';
129
+ }
130
+ }
131
+ } else {
132
+ $suffix = date('Y-m-d'); // 2020-11-11
133
+ }
134
+
135
+ $filename = $name . '-' . $suffix . '.pdf';
136
+
137
+ // Filter filename
138
+ $order_ids = isset($args['order_ids']) ? $args['order_ids'] : array( $this->order_id );
139
+ $filename = apply_filters( 'wpo_wcpdf_filename', $filename, $this->get_type(), $order_ids, $context );
140
+
141
+ // sanitize filename (after filters to prevent human errors)!
142
+ return sanitize_file_name( $filename );
143
+ }
144
+
145
+
146
+ /**
147
+ * Initialise settings
148
+ */
149
+ public function init_settings() {
150
+ // Register settings.
151
+ $page = $option_group = $option_name = 'wpo_wcpdf_documents_settings_invoice';
152
+
153
+ $settings_fields = array(
154
+ array(
155
+ 'type' => 'section',
156
+ 'id' => 'invoice',
157
+ 'title' => '',
158
+ 'callback' => 'section',
159
+ ),
160
+ array(
161
+ 'type' => 'setting',
162
+ 'id' => 'enabled',
163
+ 'title' => __( 'Enable', 'woocommerce-pdf-invoices-packing-slips' ),
164
+ 'callback' => 'checkbox',
165
+ 'section' => 'invoice',
166
+ 'args' => array(
167
+ 'option_name' => $option_name,
168
+ 'id' => 'enabled',
169
+ )
170
+ ),
171
+ array(
172
+ 'type' => 'setting',
173
+ 'id' => 'attach_to_email_ids',
174
+ 'title' => __( 'Attach to:', 'woocommerce-pdf-invoices-packing-slips' ),
175
+ 'callback' => 'multiple_checkboxes',
176
+ 'section' => 'invoice',
177
+ 'args' => array(
178
+ 'option_name' => $option_name,
179
+ 'id' => 'attach_to_email_ids',
180
+ 'fields' => $this->get_wc_emails(),
181
+ 'description' => !is_writable( WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ) ? '<span class="wpo-warning">' . sprintf( __( 'It looks like the temp folder (<code>%s</code>) is not writable, check the permissions for this folder! Without having write access to this folder, the plugin will not be able to email invoices.', 'woocommerce-pdf-invoices-packing-slips' ), WPO_WCPDF()->main->get_tmp_path( 'attachments' ) ).'</span>':'',
182
+ )
183
+ ),
184
+ array(
185
+ 'type' => 'setting',
186
+ 'id' => 'disable_for_statuses',
187
+ 'title' => __( 'Disable for:', 'woocommerce-pdf-invoices-packing-slips' ),
188
+ 'callback' => 'select',
189
+ 'section' => 'invoice',
190
+ 'args' => array(
191
+ 'option_name' => $option_name,
192
+ 'id' => 'disable_for_statuses',
193
+ 'options' => wc_get_order_statuses(),
194
+ 'multiple' => true,
195
+ 'enhanced_select' => true,
196
+ 'placeholder' => __( 'Select one or more statuses', 'woocommerce-pdf-invoices-packing-slips' ),
197
+ )
198
+ ),
199
+ array(
200
+ 'type' => 'setting',
201
+ 'id' => 'display_shipping_address',
202
+ 'title' => __( 'Display shipping address', 'woocommerce-pdf-invoices-packing-slips' ),
203
+ 'callback' => 'checkbox',
204
+ 'section' => 'invoice',
205
+ 'args' => array(
206
+ 'option_name' => $option_name,
207
+ 'id' => 'display_shipping_address',
208
+ 'description' => __( 'Display shipping address (in addition to the default billing address) if different from billing address', 'woocommerce-pdf-invoices-packing-slips' ),
209
+ )
210
+ ),
211
+ array(
212
+ 'type' => 'setting',
213
+ 'id' => 'display_email',
214
+ 'title' => __( 'Display email address', 'woocommerce-pdf-invoices-packing-slips' ),
215
+ 'callback' => 'checkbox',
216
+ 'section' => 'invoice',
217
+ 'args' => array(
218
+ 'option_name' => $option_name,
219
+ 'id' => 'display_email',
220
+ )
221
+ ),
222
+ array(
223
+ 'type' => 'setting',
224
+ 'id' => 'display_phone',
225
+ 'title' => __( 'Display phone number', 'woocommerce-pdf-invoices-packing-slips' ),
226
+ 'callback' => 'checkbox',
227
+ 'section' => 'invoice',
228
+ 'args' => array(
229
+ 'option_name' => $option_name,
230
+ 'id' => 'display_phone',
231
+ )
232
+ ),
233
+ array(
234
+ 'type' => 'setting',
235
+ 'id' => 'display_date',
236
+ 'title' => __( 'Display invoice date', 'woocommerce-pdf-invoices-packing-slips' ),
237
+ 'callback' => 'checkbox',
238
+ 'section' => 'invoice',
239
+ 'args' => array(
240
+ 'option_name' => $option_name,
241
+ 'id' => 'display_date',
242
+ 'value' => 'invoice_date',
243
+ )
244
+ ),
245
+ array(
246
+ 'type' => 'setting',
247
+ 'id' => 'display_number',
248
+ 'title' => __( 'Display invoice number', 'woocommerce-pdf-invoices-packing-slips' ),
249
+ 'callback' => 'checkbox',
250
+ 'section' => 'invoice',
251
+ 'args' => array(
252
+ 'option_name' => $option_name,
253
+ 'id' => 'display_number',
254
+ 'value' => 'invoice_number',
255
+ )
256
+ ),
257
+ array(
258
+ 'type' => 'setting',
259
+ 'id' => 'next_invoice_number',
260
+ 'title' => __( 'Next invoice number (without prefix/suffix etc.)', 'woocommerce-pdf-invoices-packing-slips' ),
261
+ 'callback' => 'next_number_edit',
262
+ 'section' => 'invoice',
263
+ 'args' => array(
264
+ 'store' => 'invoice_number',
265
+ 'size' => '10',
266
+ 'description' => __( 'This is the number that will be used for the next document. By default, numbering starts from 1 and increases for every new document. Note that if you override this and set it lower than the current/highest number, this could create duplicate numbers!', 'woocommerce-pdf-invoices-packing-slips' ),
267
+ )
268
+ ),
269
+ array(
270
+ 'type' => 'setting',
271
+ 'id' => 'number_format',
272
+ 'title' => __( 'Number format', 'woocommerce-pdf-invoices-packing-slips' ),
273
+ 'callback' => 'multiple_text_input',
274
+ 'section' => 'invoice',
275
+ 'args' => array(
276
+ 'option_name' => $option_name,
277
+ 'id' => 'number_format',
278
+ 'fields' => array(
279
+ 'prefix' => array(
280
+ 'placeholder' => __( 'Prefix' , 'woocommerce-pdf-invoices-packing-slips' ),
281
+ 'size' => 20,
282
+ 'description' => __( 'to use the invoice year and/or month, use [invoice_year] or [invoice_month] respectively' , 'woocommerce-pdf-invoices-packing-slips' ),
283
+ ),
284
+ 'suffix' => array(
285
+ 'placeholder' => __( 'Suffix' , 'woocommerce-pdf-invoices-packing-slips' ),
286
+ 'size' => 20,
287
+ 'description' => '',
288
+ ),
289
+ 'padding' => array(
290
+ 'placeholder' => __( 'Padding' , 'woocommerce-pdf-invoices-packing-slips' ),
291
+ 'size' => 20,
292
+ 'type' => 'number',
293
+ 'description' => __( 'enter the number of digits here - enter "6" to display 42 as 000042' , 'woocommerce-pdf-invoices-packing-slips' ),
294
+ ),
295
+ ),
296
+ 'description' => __( 'note: if you have already created a custom invoice number format with a filter, the above settings will be ignored' , 'woocommerce-pdf-invoices-packing-slips' ),
297
+ )
298
+ ),
299
+ array(
300
+ 'type' => 'setting',
301
+ 'id' => 'reset_number_yearly',
302
+ 'title' => __( 'Reset invoice number yearly', 'woocommerce-pdf-invoices-packing-slips' ),
303
+ 'callback' => 'checkbox',
304
+ 'section' => 'invoice',
305
+ 'args' => array(
306
+ 'option_name' => $option_name,
307
+ 'id' => 'reset_number_yearly',
308
+ )
309
+ ),
310
+ array(
311
+ 'type' => 'setting',
312
+ 'id' => 'my_account_buttons',
313
+ 'title' => __( 'Allow My Account invoice download', 'woocommerce-pdf-invoices-packing-slips' ),
314
+ 'callback' => 'select',
315
+ 'section' => 'invoice',
316
+ 'args' => array(
317
+ 'option_name' => $option_name,
318
+ 'id' => 'my_account_buttons',
319
+ 'options' => array(
320
+ 'available' => __( 'Only when an invoice is already created/emailed' , 'woocommerce-pdf-invoices-packing-slips' ),
321
+ 'custom' => __( 'Only for specific order statuses (define below)' , 'woocommerce-pdf-invoices-packing-slips' ),
322
+ 'always' => __( 'Always' , 'woocommerce-pdf-invoices-packing-slips' ),
323
+ 'never' => __( 'Never' , 'woocommerce-pdf-invoices-packing-slips' ),
324
+ ),
325
+ 'custom' => array(
326
+ 'type' => 'multiple_checkboxes',
327
+ 'args' => array(
328
+ 'option_name' => $option_name,
329
+ 'id' => 'my_account_restrict',
330
+ 'fields' => $this->get_wc_order_status_list(),
331
+ ),
332
+ ),
333
+ )
334
+ ),
335
+ array(
336
+ 'type' => 'setting',
337
+ 'id' => 'invoice_number_column',
338
+ 'title' => __( 'Enable invoice number column in the orders list', 'woocommerce-pdf-invoices-packing-slips' ),
339
+ 'callback' => 'checkbox',
340
+ 'section' => 'invoice',
341
+ 'args' => array(
342
+ 'option_name' => $option_name,
343
+ 'id' => 'invoice_number_column',
344
+ )
345
+ ),
346
+ array(
347
+ 'type' => 'setting',
348
+ 'id' => 'disable_free',
349
+ 'title' => __( 'Disable for free products', 'woocommerce-pdf-invoices-packing-slips' ),
350
+ 'callback' => 'checkbox',
351
+ 'section' => 'invoice',
352
+ 'args' => array(
353
+ 'option_name' => $option_name,
354
+ 'id' => 'disable_free',
355
+ 'description' => __( "Disable automatic creation/attachment when only free products are ordered", 'woocommerce-pdf-invoices-packing-slips' ),
356
+ )
357
+ ),
358
+ array(
359
+ 'type' => 'setting',
360
+ 'id' => 'use_latest_settings',
361
+ 'title' => __( 'Always use most current settings', 'woocommerce-pdf-invoices-packing-slips' ),
362
+ 'callback' => 'checkbox',
363
+ 'section' => 'invoice',
364
+ 'args' => array(
365
+ 'option_name' => $option_name,
366
+ 'id' => 'use_latest_settings',
367
+ 'description' => __( "When enabled, the document will always reflect the most current settings (such as footer text, document name, etc.) rather than using historical settings.", 'woocommerce-pdf-invoices-packing-slips' )
368
+ . "<br>"
369
+ . __( "<strong>Caution:</strong> enabling this will also mean that if you change your company name or address in the future, previously generated documents will also be affected.", 'woocommerce-pdf-invoices-packing-slips' ),
370
+ )
371
+ ),
372
+ );
373
+
374
+ // remove/rename some fields when invoice number is controlled externally
375
+ if( apply_filters('woocommerce_invoice_number_by_plugin', false) ) {
376
+ $remove_settings = array( 'next_invoice_number', 'number_format', 'reset_number_yearly' );
377
+ foreach ($settings_fields as $key => $settings_field) {
378
+ if (in_array($settings_field['id'], $remove_settings)) {
379
+ unset($settings_fields[$key]);
380
+ } elseif ( $settings_field['id'] == 'display_number' ) {
381
+ // alternate description for invoice number
382
+ $invoice_number_desc = __( 'Invoice numbers are created by a third-party extension.', 'woocommerce-pdf-invoices-packing-slips' );
383
+ if ( $config_link = apply_filters( 'woocommerce_invoice_number_configuration_link', null ) ) {
384
+ $invoice_number_desc .= ' '.sprintf(__( 'Configure it <a href="%s">here</a>.', 'woocommerce-pdf-invoices-packing-slips' ), esc_attr( $config_link ) );
385
+ }
386
+ $settings_fields[$key]['args']['description'] = '<i>'.$invoice_number_desc.'</i>';
387
+ }
388
+ }
389
+ }
390
+
391
+ // allow plugins to alter settings fields
392
+ $settings_fields = apply_filters( 'wpo_wcpdf_settings_fields_documents_invoice', $settings_fields, $page, $option_group, $option_name );
393
+ WPO_WCPDF()->settings->add_settings_fields( $settings_fields, $page, $option_group, $option_name );
394
+ return;
395
+
396
+ }
397
+
398
+ }
399
+
400
+ endif; // class_exists
401
+
402
+ return new Invoice();
includes/views/setup-wizard/show-action-buttons.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php defined( 'ABSPATH' ) or exit; ?>
2
+ <div class="wpo-step-description">
3
+ <h2><?php _e( 'Action buttons', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
4
+ <p><?php _e( 'Would you like to display the action buttons in your WooCommerce order list? The action buttons allow you to manually create a PDF.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
5
+ <p><small><?php _e( '(You can always change this setting later via the Screen Options menu)', 'woocommerce-pdf-invoices-packing-slips' ); ?></small></p>
6
+ </div>
7
+ <div class="wpo-setup-input">
8
+ <?php
9
+ $user_id = get_current_user_id();
10
+ $hidden = get_user_meta( $user_id, 'manageedit-shop_ordercolumnshidden', true );
11
+ ?>
12
+ <input type="checkbox" <?php echo !in_array( 'wc_actions', $hidden ) ? 'checked' : ''; ?> name="wc_show_action_buttons" value="1"><span class="checkbox"><?php _e( 'Show action buttons', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><br>
13
+ </div>
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice,
5
  Requires at least: 3.5
6
  Tested up to: 5.2
7
  Requires PHP: 5.3
8
- Stable tag: 2.2.14
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -103,6 +103,16 @@ There's a setting on the Status tab of the settings page that allows you to togg
103
 
104
  == Changelog ==
105
 
 
 
 
 
 
 
 
 
 
 
106
  = 2.2.14 =
107
  * Fix: Set default PHPMailer validator to 'php' (fixing 'setFrom' errors on PHP 7.3)
108
  * Fix: Attachment path for file lock check
5
  Requires at least: 3.5
6
  Tested up to: 5.2
7
  Requires PHP: 5.3
8
+ Stable tag: 2.3.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
103
 
104
  == Changelog ==
105
 
106
+ = 2.3.0 =
107
+ * Feature: Setting to disable invoices globally for specific order statuses
108
+ * Feature: Control action buttons visibility from settings wizard.
109
+ * Feature: Allow loading of existing PDF file instead of generating on the fly via filter (`wpo_wcpdf_load_pdf_file_path`)
110
+ * Fix: Check if temp folder exists before creating
111
+ * Fix: Newlines in address from settings wizard
112
+ * Fix: Double images issue with WooCommerce German Market
113
+ * Fix: Only store document settings when creating one
114
+ * Tested with WooCommerce 3.7
115
+
116
  = 2.2.14 =
117
  * Fix: Set default PHPMailer validator to 'php' (fixing 'setFrom' errors on PHP 7.3)
118
  * Fix: Attachment path for file lock check
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,14 +3,14 @@
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
- * Version: 2.2.14
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
10
  * License URI: http://www.opensource.org/licenses/gpl-license.php
11
  * Text Domain: woocommerce-pdf-invoices-packing-slips
12
  * WC requires at least: 2.2.0
13
- * WC tested up to: 3.6.0
14
  */
15
 
16
  if ( ! defined( 'ABSPATH' ) ) {
@@ -21,7 +21,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
21
 
22
  class WPO_WCPDF {
23
 
24
- public $version = '2.2.14';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
 
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
+ * Version: 2.3.0
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
10
  * License URI: http://www.opensource.org/licenses/gpl-license.php
11
  * Text Domain: woocommerce-pdf-invoices-packing-slips
12
  * WC requires at least: 2.2.0
13
+ * WC tested up to: 3.7.0
14
  */
15
 
16
  if ( ! defined( 'ABSPATH' ) ) {
21
 
22
  class WPO_WCPDF {
23
 
24
+ public $version = '2.3.0';
25
  public $plugin_basename;
26
  public $legacy_mode;
27