WooCommerce PDF Invoices & Packing Slips - Version 2.0.14

Version Description

  • Feature: Manually resend specific order emails in WooCommerce 3.2+
  • Tweak: Show full size logo preview in settings
  • Tweak: Custom field fallback to underscore prefixed meta key
  • Dev: added wpo_wcpdf_before_sequential_number_increment action
Download this release

Release Info

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

Code changes from version 2.0.13 to 2.0.14

assets/css/setup-wizard.css ADDED
@@ -0,0 +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
+
assets/js/confetti.js ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+ var frameRate = 30;
3
+ var dt = 1.0 / frameRate;
4
+ var DEG_TO_RAD = Math.PI / 180;
5
+ var RAD_TO_DEG = 180 / Math.PI;
6
+ var colors = [
7
+ ["#df0049", "#660671"],
8
+ ["#00e857", "#005291"],
9
+ ["#2bebbc", "#05798a"],
10
+ ["#ffd200", "#b06c00"]
11
+ ];
12
+
13
+ function Vector2(_x, _y) {
14
+ this.x = _x, this.y = _y;
15
+ this.Length = function() {
16
+ return Math.sqrt(this.SqrLength());
17
+ }
18
+ this.SqrLength = function() {
19
+ return this.x * this.x + this.y * this.y;
20
+ }
21
+ this.Equals = function(_vec0, _vec1) {
22
+ return _vec0.x == _vec1.x && _vec0.y == _vec1.y;
23
+ }
24
+ this.Add = function(_vec) {
25
+ this.x += _vec.x;
26
+ this.y += _vec.y;
27
+ }
28
+ this.Sub = function(_vec) {
29
+ this.x -= _vec.x;
30
+ this.y -= _vec.y;
31
+ }
32
+ this.Div = function(_f) {
33
+ this.x /= _f;
34
+ this.y /= _f;
35
+ }
36
+ this.Mul = function(_f) {
37
+ this.x *= _f;
38
+ this.y *= _f;
39
+ }
40
+ this.Normalize = function() {
41
+ var sqrLen = this.SqrLength();
42
+ if (sqrLen != 0) {
43
+ var factor = 1.0 / Math.sqrt(sqrLen);
44
+ this.x *= factor;
45
+ this.y *= factor;
46
+ }
47
+ }
48
+ this.Normalized = function() {
49
+ var sqrLen = this.SqrLength();
50
+ if (sqrLen != 0) {
51
+ var factor = 1.0 / Math.sqrt(sqrLen);
52
+ return new Vector2(this.x * factor, this.y * factor);
53
+ }
54
+ return new Vector2(0, 0);
55
+ }
56
+ }
57
+ Vector2.Lerp = function(_vec0, _vec1, _t) {
58
+ return new Vector2((_vec1.x - _vec0.x) * _t + _vec0.x, (_vec1.y - _vec0.y) * _t + _vec0.y);
59
+ }
60
+ Vector2.Distance = function(_vec0, _vec1) {
61
+ return Math.sqrt(Vector2.SqrDistance(_vec0, _vec1));
62
+ }
63
+ Vector2.SqrDistance = function(_vec0, _vec1) {
64
+ var x = _vec0.x - _vec1.x;
65
+ var y = _vec0.y - _vec1.y;
66
+ return (x * x + y * y + z * z);
67
+ }
68
+ Vector2.Scale = function(_vec0, _vec1) {
69
+ return new Vector2(_vec0.x * _vec1.x, _vec0.y * _vec1.y);
70
+ }
71
+ Vector2.Min = function(_vec0, _vec1) {
72
+ return new Vector2(Math.min(_vec0.x, _vec1.x), Math.min(_vec0.y, _vec1.y));
73
+ }
74
+ Vector2.Max = function(_vec0, _vec1) {
75
+ return new Vector2(Math.max(_vec0.x, _vec1.x), Math.max(_vec0.y, _vec1.y));
76
+ }
77
+ Vector2.ClampMagnitude = function(_vec0, _len) {
78
+ var vecNorm = _vec0.Normalized;
79
+ return new Vector2(vecNorm.x * _len, vecNorm.y * _len);
80
+ }
81
+ Vector2.Sub = function(_vec0, _vec1) {
82
+ return new Vector2(_vec0.x - _vec1.x, _vec0.y - _vec1.y, _vec0.z - _vec1.z);
83
+ }
84
+
85
+ function EulerMass(_x, _y, _mass, _drag) {
86
+ this.position = new Vector2(_x, _y);
87
+ this.mass = _mass;
88
+ this.drag = _drag;
89
+ this.force = new Vector2(0, 0);
90
+ this.velocity = new Vector2(0, 0);
91
+ this.AddForce = function(_f) {
92
+ this.force.Add(_f);
93
+ }
94
+ this.Integrate = function(_dt) {
95
+ var acc = this.CurrentForce(this.position);
96
+ acc.Div(this.mass);
97
+ var posDelta = new Vector2(this.velocity.x, this.velocity.y);
98
+ posDelta.Mul(_dt);
99
+ this.position.Add(posDelta);
100
+ acc.Mul(_dt);
101
+ this.velocity.Add(acc);
102
+ this.force = new Vector2(0, 0);
103
+ }
104
+ this.CurrentForce = function(_pos, _vel) {
105
+ var totalForce = new Vector2(this.force.x, this.force.y);
106
+ var speed = this.velocity.Length();
107
+ var dragVel = new Vector2(this.velocity.x, this.velocity.y);
108
+ dragVel.Mul(this.drag * this.mass * speed);
109
+ totalForce.Sub(dragVel);
110
+ return totalForce;
111
+ }
112
+ }
113
+
114
+ function ConfettiPaper(_x, _y) {
115
+ this.pos = new Vector2(_x, _y);
116
+ this.rotationSpeed = Math.random() * 600 + 800;
117
+ this.angle = DEG_TO_RAD * Math.random() * 360;
118
+ this.rotation = DEG_TO_RAD * Math.random() * 360;
119
+ this.cosA = 1.0;
120
+ this.size = 5.0;
121
+ this.oscillationSpeed = Math.random() * 1.5 + 0.5;
122
+ this.xSpeed = 40.0;
123
+ this.ySpeed = Math.random() * 60 + 50.0;
124
+ this.corners = new Array();
125
+ this.time = Math.random();
126
+ var ci = Math.round(Math.random() * (colors.length - 1));
127
+ this.frontColor = colors[ci][0];
128
+ this.backColor = colors[ci][1];
129
+ for (var i = 0; i < 4; i++) {
130
+ var dx = Math.cos(this.angle + DEG_TO_RAD * (i * 90 + 45));
131
+ var dy = Math.sin(this.angle + DEG_TO_RAD * (i * 90 + 45));
132
+ this.corners[i] = new Vector2(dx, dy);
133
+ }
134
+ this.Update = function(_dt) {
135
+ this.time += _dt;
136
+ this.rotation += this.rotationSpeed * _dt;
137
+ this.cosA = Math.cos(DEG_TO_RAD * this.rotation);
138
+ this.pos.x += Math.cos(this.time * this.oscillationSpeed) * this.xSpeed * _dt
139
+ this.pos.y += this.ySpeed * _dt;
140
+ if (this.pos.y > ConfettiPaper.bounds.y) {
141
+ this.pos.x = Math.random() * ConfettiPaper.bounds.x;
142
+ this.pos.y = 0;
143
+ }
144
+ }
145
+ this.Draw = function(_g) {
146
+ if (this.cosA > 0) {
147
+ _g.fillStyle = this.frontColor;
148
+ } else {
149
+ _g.fillStyle = this.backColor;
150
+ }
151
+ _g.beginPath();
152
+ _g.moveTo(this.pos.x + this.corners[0].x * this.size, this.pos.y + this.corners[0].y * this.size * this.cosA);
153
+ for (var i = 1; i < 4; i++) {
154
+ _g.lineTo(this.pos.x + this.corners[i].x * this.size, this.pos.y + this.corners[i].y * this.size * this.cosA);
155
+ }
156
+ _g.closePath();
157
+ _g.fill();
158
+ }
159
+ }
160
+ ConfettiPaper.bounds = new Vector2(0, 0);
161
+
162
+ function ConfettiRibbon(_x, _y, _count, _dist, _thickness, _angle, _mass, _drag) {
163
+ this.particleDist = _dist;
164
+ this.particleCount = _count;
165
+ this.particleMass = _mass;
166
+ this.particleDrag = _drag;
167
+ this.particles = new Array();
168
+ var ci = Math.round(Math.random() * (colors.length - 1));
169
+ this.frontColor = colors[ci][0];
170
+ this.backColor = colors[ci][1];
171
+ this.xOff = Math.cos(DEG_TO_RAD * _angle) * _thickness;
172
+ this.yOff = Math.sin(DEG_TO_RAD * _angle) * _thickness;
173
+ this.position = new Vector2(_x, _y);
174
+ this.prevPosition = new Vector2(_x, _y);
175
+ this.velocityInherit = Math.random() * 2 + 4;
176
+ this.time = Math.random() * 100;
177
+ this.oscillationSpeed = Math.random() * 2 + 2;
178
+ this.oscillationDistance = Math.random() * 40 + 40;
179
+ this.ySpeed = Math.random() * 40 + 80;
180
+ for (var i = 0; i < this.particleCount; i++) {
181
+ this.particles[i] = new EulerMass(_x, _y - i * this.particleDist, this.particleMass, this.particleDrag);
182
+ }
183
+ this.Update = function(_dt) {
184
+ var i = 0;
185
+ this.time += _dt * this.oscillationSpeed;
186
+ this.position.y += this.ySpeed * _dt;
187
+ this.position.x += Math.cos(this.time) * this.oscillationDistance * _dt;
188
+ this.particles[0].position = this.position;
189
+ var dX = this.prevPosition.x - this.position.x;
190
+ var dY = this.prevPosition.y - this.position.y;
191
+ var delta = Math.sqrt(dX * dX + dY * dY);
192
+ this.prevPosition = new Vector2(this.position.x, this.position.y);
193
+ for (i = 1; i < this.particleCount; i++) {
194
+ var dirP = Vector2.Sub(this.particles[i - 1].position, this.particles[i].position);
195
+ dirP.Normalize();
196
+ dirP.Mul((delta / _dt) * this.velocityInherit);
197
+ this.particles[i].AddForce(dirP);
198
+ }
199
+ for (i = 1; i < this.particleCount; i++) {
200
+ this.particles[i].Integrate(_dt);
201
+ }
202
+ for (i = 1; i < this.particleCount; i++) {
203
+ var rp2 = new Vector2(this.particles[i].position.x, this.particles[i].position.y);
204
+ rp2.Sub(this.particles[i - 1].position);
205
+ rp2.Normalize();
206
+ rp2.Mul(this.particleDist);
207
+ rp2.Add(this.particles[i - 1].position);
208
+ this.particles[i].position = rp2;
209
+ }
210
+ if (this.position.y > ConfettiRibbon.bounds.y + this.particleDist * this.particleCount) {
211
+ this.Reset();
212
+ }
213
+ }
214
+ this.Reset = function() {
215
+ this.position.y = -Math.random() * ConfettiRibbon.bounds.y;
216
+ this.position.x = Math.random() * ConfettiRibbon.bounds.x;
217
+ this.prevPosition = new Vector2(this.position.x, this.position.y);
218
+ this.velocityInherit = Math.random() * 2 + 4;
219
+ this.time = Math.random() * 100;
220
+ this.oscillationSpeed = Math.random() * 2.0 + 1.5;
221
+ this.oscillationDistance = Math.random() * 40 + 40;
222
+ this.ySpeed = Math.random() * 40 + 80;
223
+ var ci = Math.round(Math.random() * (colors.length - 1));
224
+ this.frontColor = colors[ci][0];
225
+ this.backColor = colors[ci][1];
226
+ this.particles = new Array();
227
+ for (var i = 0; i < this.particleCount; i++) {
228
+ this.particles[i] = new EulerMass(this.position.x, this.position.y - i * this.particleDist, this.particleMass, this.particleDrag);
229
+ }
230
+ }
231
+ this.Draw = function(_g) {
232
+ for (var i = 0; i < this.particleCount - 1; i++) {
233
+ var p0 = new Vector2(this.particles[i].position.x + this.xOff, this.particles[i].position.y + this.yOff);
234
+ var p1 = new Vector2(this.particles[i + 1].position.x + this.xOff, this.particles[i + 1].position.y + this.yOff);
235
+ if (this.Side(this.particles[i].position.x, this.particles[i].position.y, this.particles[i + 1].position.x, this.particles[i + 1].position.y, p1.x, p1.y) < 0) {
236
+ _g.fillStyle = this.frontColor;
237
+ _g.strokeStyle = this.frontColor;
238
+ } else {
239
+ _g.fillStyle = this.backColor;
240
+ _g.strokeStyle = this.backColor;
241
+ }
242
+ if (i == 0) {
243
+ _g.beginPath();
244
+ _g.moveTo(this.particles[i].position.x, this.particles[i].position.y);
245
+ _g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y);
246
+ _g.lineTo((this.particles[i + 1].position.x + p1.x) * 0.5, (this.particles[i + 1].position.y + p1.y) * 0.5);
247
+ _g.closePath();
248
+ _g.stroke();
249
+ _g.fill();
250
+ _g.beginPath();
251
+ _g.moveTo(p1.x, p1.y);
252
+ _g.lineTo(p0.x, p0.y);
253
+ _g.lineTo((this.particles[i + 1].position.x + p1.x) * 0.5, (this.particles[i + 1].position.y + p1.y) * 0.5);
254
+ _g.closePath();
255
+ _g.stroke();
256
+ _g.fill();
257
+ } else if (i == this.particleCount - 2) {
258
+ _g.beginPath();
259
+ _g.moveTo(this.particles[i].position.x, this.particles[i].position.y);
260
+ _g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y);
261
+ _g.lineTo((this.particles[i].position.x + p0.x) * 0.5, (this.particles[i].position.y + p0.y) * 0.5);
262
+ _g.closePath();
263
+ _g.stroke();
264
+ _g.fill();
265
+ _g.beginPath();
266
+ _g.moveTo(p1.x, p1.y);
267
+ _g.lineTo(p0.x, p0.y);
268
+ _g.lineTo((this.particles[i].position.x + p0.x) * 0.5, (this.particles[i].position.y + p0.y) * 0.5);
269
+ _g.closePath();
270
+ _g.stroke();
271
+ _g.fill();
272
+ } else {
273
+ _g.beginPath();
274
+ _g.moveTo(this.particles[i].position.x, this.particles[i].position.y);
275
+ _g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y);
276
+ _g.lineTo(p1.x, p1.y);
277
+ _g.lineTo(p0.x, p0.y);
278
+ _g.closePath();
279
+ _g.stroke();
280
+ _g.fill();
281
+ }
282
+ }
283
+ }
284
+ this.Side = function(x1, y1, x2, y2, x3, y3) {
285
+ return ((x1 - x2) * (y3 - y2) - (y1 - y2) * (x3 - x2));
286
+ }
287
+ }
288
+ ConfettiRibbon.bounds = new Vector2(0, 0);
289
+ confetti = {};
290
+ confetti.Context = function(parent) {
291
+ var i = 0;
292
+ var canvasParent = document.getElementById(parent);
293
+ var canvas = document.createElement('canvas');
294
+ canvas.width = canvasParent.offsetWidth;
295
+ canvas.height = canvasParent.offsetHeight;
296
+ canvasParent.appendChild(canvas);
297
+ var context = canvas.getContext('2d');
298
+ var interval = null;
299
+ var confettiRibbonCount = 7;
300
+ var rpCount = 30;
301
+ var rpDist = 8.0;
302
+ var rpThick = 8.0;
303
+ var confettiRibbons = new Array();
304
+ ConfettiRibbon.bounds = new Vector2(canvas.width, canvas.height);
305
+ for (i = 0; i < confettiRibbonCount; i++) {
306
+ confettiRibbons[i] = new ConfettiRibbon(Math.random() * canvas.width, -Math.random() * canvas.height * 2, rpCount, rpDist, rpThick, 45, 1, 0.05);
307
+ }
308
+ var confettiPaperCount = 25;
309
+ var confettiPapers = new Array();
310
+ ConfettiPaper.bounds = new Vector2(canvas.width, canvas.height);
311
+ for (i = 0; i < confettiPaperCount; i++) {
312
+ confettiPapers[i] = new ConfettiPaper(Math.random() * canvas.width, Math.random() * canvas.height);
313
+ }
314
+ this.resize = function() {
315
+ canvas.width = canvasParent.offsetWidth;
316
+ canvas.height = canvasParent.offsetHeight;
317
+ ConfettiPaper.bounds = new Vector2(canvas.width, canvas.height);
318
+ ConfettiRibbon.bounds = new Vector2(canvas.width, canvas.height);
319
+ }
320
+ this.start = function() {
321
+ this.stop()
322
+ var context = this
323
+ this.interval = setInterval(function() {
324
+ confetti.update();
325
+ }, 1000.0 / frameRate)
326
+ }
327
+ this.stop = function() {
328
+ clearInterval(this.interval);
329
+ }
330
+ this.update = function() {
331
+ var i = 0;
332
+ context.clearRect(0, 0, canvas.width, canvas.height);
333
+ for (i = 0; i < confettiPaperCount; i++) {
334
+ confettiPapers[i].Update(dt);
335
+ confettiPapers[i].Draw(context);
336
+ }
337
+ for (i = 0; i < confettiRibbonCount; i++) {
338
+ confettiRibbons[i].Update(dt);
339
+ confettiRibbons[i].Draw(context);
340
+ }
341
+ }
342
+ }
343
+ var confetti = new confetti.Context('confetti');
344
+ confetti.start();
345
+ $(window).resize(function() {
346
+ confetti.resize();
347
+ });
348
+ });
assets/js/setup-wizard.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function( $ ) {
2
+
3
+ $( '.tab' ).click(function() {
4
+ $( this ).closest('.extra-field').find('.tab').removeClass( 'active' );
5
+ $( this ).addClass( 'active' );
6
+ var $language = $( this ).attr('id');
7
+ console.log($language);
8
+ $( this ).siblings('.extra-field-input').hide();
9
+ $('.' + $language ).show();
10
+ });
11
+
12
+ // Show Preview of logo
13
+ $('#file-upload').change( function(event) {
14
+ if ( event.target.files[0] ) {
15
+ var tmppath = URL.createObjectURL(event.target.files[0]);
16
+ $( '#logo-preview' ).find( "img" ).attr( 'src',tmppath );
17
+ }
18
+ });
19
+
20
+ });
includes/class-wcpdf-admin.php CHANGED
@@ -23,7 +23,13 @@ class Admin {
23
 
24
  add_action( 'save_post', array( $this,'save_invoice_number_date' ) );
25
 
 
 
 
 
26
  add_action( 'admin_notices', array( $this, 'review_plugin_notice' ) );
 
 
27
  // add_action( 'wpo_wcpdf_after_pdf', array( $this,'update_pdf_counter' ), 10, 2 );
28
  }
29
 
@@ -75,6 +81,17 @@ class Admin {
75
  }
76
  }
77
 
 
 
 
 
 
 
 
 
 
 
 
78
  public function get_invoice_count() {
79
  global $wpdb;
80
  $invoice_count = $wpdb->get_var( $wpdb->prepare( "SELECT count(*) FROM {$wpdb->postmeta} WHERE meta_key = %s", '_wcpdf_invoice_number' ) );
@@ -164,11 +181,23 @@ class Admin {
164
  * Add the meta box on the single order page
165
  */
166
  public function add_meta_boxes() {
 
 
 
 
 
 
 
 
 
 
 
 
167
  // create PDF buttons
168
  add_meta_box(
169
  'wpo_wcpdf-box',
170
  __( 'Create PDF', 'woocommerce-pdf-invoices-packing-slips' ),
171
- array( $this, 'sidebar_box_content' ),
172
  'shop_order',
173
  'side',
174
  'default'
@@ -185,10 +214,45 @@ class Admin {
185
  );
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  /**
189
  * Create the meta box content on the single order page
190
  */
191
- public function sidebar_box_content( $post ) {
192
  global $post_id;
193
 
194
  $meta_box_actions = array();
@@ -337,6 +401,47 @@ class Admin {
337
  }
338
  }
339
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  /**
341
  * Add invoice number to order search scope
342
  */
23
 
24
  add_action( 'save_post', array( $this,'save_invoice_number_date' ) );
25
 
26
+ // manually send emails
27
+ // WooCommerce core processes order actions at priority 50
28
+ add_action( 'woocommerce_process_shop_order_meta', array( $this, 'send_emails' ), 60, 2 );
29
+
30
  add_action( 'admin_notices', array( $this, 'review_plugin_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
 
81
  }
82
  }
83
 
84
+ public function setup_wizard() {
85
+ // Setup/welcome
86
+ if ( ! empty( $_GET['page'] ) ) {
87
+ switch ( $_GET['page'] ) {
88
+ case 'wpo-wcpdf-setup' :
89
+ include_once( WPO_WCPDF()->plugin_path() . '/includes/class-wcpdf-setup-wizard.php' );
90
+ break;
91
+ }
92
+ }
93
+ }
94
+
95
  public function get_invoice_count() {
96
  global $wpdb;
97
  $invoice_count = $wpdb->get_var( $wpdb->prepare( "SELECT count(*) FROM {$wpdb->postmeta} WHERE meta_key = %s", '_wcpdf_invoice_number' ) );
181
  * Add the meta box on the single order page
182
  */
183
  public function add_meta_boxes() {
184
+ // resend order emails
185
+ if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.2', '>=' ) ) {
186
+ add_meta_box(
187
+ 'wpo_wcpdf_send_emails',
188
+ __( 'Send order email', 'woocommerce-pdf-invoices-packing-slips' ),
189
+ array( $this, 'send_order_email_meta_box' ),
190
+ 'shop_order',
191
+ 'side',
192
+ 'high'
193
+ );
194
+ }
195
+
196
  // create PDF buttons
197
  add_meta_box(
198
  'wpo_wcpdf-box',
199
  __( 'Create PDF', 'woocommerce-pdf-invoices-packing-slips' ),
200
+ array( $this, 'pdf_actions_meta_box' ),
201
  'shop_order',
202
  'side',
203
  'default'
214
  );
215
  }
216
 
217
+ /**
218
+ * Resend order emails
219
+ */
220
+ public function send_order_email_meta_box( $post ) {
221
+ ?>
222
+ <ul class="wpo_wcpdf_send_emails submitbox">
223
+ <li class="wide" id="actions">
224
+ <select name="wpo_wcpdf_send_emails">
225
+ <option value=""></option>
226
+ <?php
227
+ $mailer = WC()->mailer();
228
+ $available_emails = apply_filters( 'woocommerce_resend_order_emails_available', array( 'new_order', 'cancelled_order', 'customer_processing_order', 'customer_completed_order', 'customer_invoice' ) );
229
+ $mails = $mailer->get_emails();
230
+ if ( ! empty( $mails ) && ! empty( $available_emails ) ) { ?>
231
+ <?php
232
+ foreach ( $mails as $mail ) {
233
+ if ( in_array( $mail->id, $available_emails ) && 'no' !== $mail->enabled ) {
234
+ echo '<option value="send_email_' . esc_attr( $mail->id ) . '">' . esc_html( $mail->title ) . '</option>';
235
+ }
236
+ } ?>
237
+ <?php
238
+ }
239
+ ?>
240
+ </select>
241
+ <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' ); ?>" />
242
+ <?php
243
+ $title = __( 'Send email', 'woocommerce-pdf-invoices-packing-slips' );
244
+ $url = wp_nonce_url( add_query_arg('wpo_wcpdf_action','resend_email'), 'generate_wpo_wcpdf' );
245
+ // printf('<a href="%s" class="button wpo_wcpdf_send_email"><span>%s</span></a>')
246
+ ?>
247
+ </li>
248
+ </ul>
249
+ <?php
250
+ }
251
+
252
  /**
253
  * Create the meta box content on the single order page
254
  */
255
+ public function pdf_actions_meta_box( $post ) {
256
  global $post_id;
257
 
258
  $meta_box_actions = array();
401
  }
402
  }
403
 
404
+ /**
405
+ * Send emails manually
406
+ */
407
+ public function send_emails( $post_id, $post ) {
408
+ if ( ! empty( $_POST['wpo_wcpdf_send_emails'] ) ) {
409
+ $order = wc_get_order( $post_id );
410
+ $action = wc_clean( $_POST['wpo_wcpdf_send_emails'] );
411
+ if ( strstr( $action, 'send_email_' ) ) {
412
+ // Switch back to the site locale.
413
+ wc_switch_to_site_locale();
414
+ do_action( 'woocommerce_before_resend_order_emails', $order );
415
+ // Ensure gateways are loaded in case they need to insert data into the emails.
416
+ WC()->payment_gateways();
417
+ WC()->shipping();
418
+ // Load mailer.
419
+ $mailer = WC()->mailer();
420
+ $email_to_send = str_replace( 'send_email_', '', $action );
421
+ $mails = $mailer->get_emails();
422
+ if ( ! empty( $mails ) ) {
423
+ foreach ( $mails as $mail ) {
424
+ if ( $mail->id == $email_to_send ) {
425
+ $mail->trigger( $order->get_id(), $order );
426
+ /* translators: %s: email title */
427
+ $order->add_order_note( sprintf( __( '%s email notification manually sent.', 'woocommerce-pdf-invoices-packing-slips' ), $mail->title ), false, true );
428
+ }
429
+ }
430
+ }
431
+ do_action( 'woocommerce_after_resend_order_email', $order, $email_to_send );
432
+ // Restore user locale.
433
+ wc_restore_locale();
434
+ // Change the post saved message.
435
+ add_filter( 'redirect_post_location', function( $location ) {
436
+ // messages in includes/admin/class-wc-admin-post-types.php
437
+ // 11 => 'Order updated and sent.'
438
+ return add_query_arg( 'message', 11, $location );
439
+ } );
440
+ }
441
+ }
442
+ }
443
+
444
+
445
  /**
446
  * Add invoice number to order search scope
447
  */
includes/class-wcpdf-settings-callbacks.php CHANGED
@@ -289,7 +289,7 @@ class Settings_Callbacks {
289
  extract( $this->normalize_settings_args( $args ) );
290
 
291
  if( !empty($current) ) {
292
- $attachment = wp_get_attachment_image_src( $current, 'thumbnail', false );
293
 
294
  $attachment_src = $attachment[0];
295
  $attachment_width = $attachment[1];
289
  extract( $this->normalize_settings_args( $args ) );
290
 
291
  if( !empty($current) ) {
292
+ $attachment = wp_get_attachment_image_src( $current, 'full', false );
293
 
294
  $attachment_src = $attachment[0];
295
  $attachment_width = $attachment[1];
includes/class-wcpdf-setup-wizard.php ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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();
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();
includes/documents/abstract-wcpdf-order-document-methods.php CHANGED
@@ -187,6 +187,10 @@ abstract class Order_Document_Methods extends Order_Document {
187
  */
188
  public function get_custom_field( $field_name ) {
189
  $custom_field = WCX_Order::get_meta( $this->order, $field_name, true );
 
 
 
 
190
 
191
  // WC3.0 fallback to properties
192
  $property = str_replace('-', '_', sanitize_title( ltrim($field_name, '_') ) );
187
  */
188
  public function get_custom_field( $field_name ) {
189
  $custom_field = WCX_Order::get_meta( $this->order, $field_name, true );
190
+ // if not found, try prefixed with underscore
191
+ if ( !$custom_field && substr( $field_name, 0, 1 ) !== '_' ) {
192
+ $custom_field = WCX_Order::get_meta( $this->order, "_{$field_name}", true );
193
+ }
194
 
195
  // WC3.0 fallback to properties
196
  $property = str_replace('-', '_', sanitize_title( ltrim($field_name, '_') ) );
includes/documents/class-wcpdf-sequential-number-store.php CHANGED
@@ -1,165 +1,167 @@
1
- <?php
2
- namespace WPO\WC\PDF_Invoices\Documents;
3
-
4
- if ( ! defined( 'ABSPATH' ) ) {
5
- exit; // Exit if accessed directly
6
- }
7
-
8
- if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Sequential_Number_Store' ) ) :
9
-
10
- /**
11
- * Class handling database interaction for sequential numbers
12
- *
13
- * @class \WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store
14
- * @version 2.0
15
- * @category Class
16
- * @author Ewout Fernhout
17
- */
18
-
19
- class Sequential_Number_Store {
20
- /**
21
- * Name of the table that stores the number sequence (without the wp_wcpdf_ table prefix)
22
- * @var String
23
- */
24
- public $table_name;
25
-
26
- /**
27
- * Number store method, either 'auto_increment' or 'calculate'
28
- * @var String
29
- */
30
- public $method;
31
-
32
- public function __construct( $table_name, $method = 'auto_increment' ) {
33
- global $wpdb;
34
- $this->table_name = "{$wpdb->prefix}wcpdf_{$table_name}"; // i.e. wp_wcpdf_invoice_number
35
- $this->method = $method;
36
-
37
- $this->init();
38
- }
39
-
40
- public function init() {
41
- global $wpdb;
42
- // check if table exists
43
- if( $wpdb->get_var("SHOW TABLES LIKE '{$this->table_name}'") == $this->table_name) {
44
- // check calculated_number column if using 'calculate' method
45
- if ( $this->method == 'calculate' ) {
46
- $column_exists = $wpdb->get_var("SHOW COLUMNS FROM `{$this->table_name}` LIKE 'calculated_number'");
47
- if (empty($column_exists)) {
48
- $wpdb->query("ALTER TABLE {$this->table_name} ADD calculated_number int (16)");
49
- }
50
- }
51
- return; // no further business
52
- }
53
-
54
- // create table (in case of concurrent requests, this does no harm if it already exists)
55
- $charset_collate = $wpdb->get_charset_collate();
56
- // dbDelta is a sensitive kid, so we omit indentation
57
- $sql = "CREATE TABLE {$this->table_name} (
58
- id int(16) NOT NULL AUTO_INCREMENT,
59
- order_id int(16),
60
- date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
61
- calculated_number int (16),
62
- PRIMARY KEY (id)
63
- ) $charset_collate;";
64
-
65
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
66
- $result = dbDelta( $sql );
67
-
68
- return $result;
69
- }
70
-
71
- /**
72
- * Consume/create the next number and return it
73
- * @param integer $order_id WooCommerce Order ID
74
- * @param string $date Local date, formatted as Y-m-d H:i:s
75
- * @return int Number that was consumed/created
76
- */
77
- public function increment( $order_id = 0, $date = null ) {
78
- global $wpdb;
79
- if ( empty( $date ) ) {
80
- $date = get_date_from_gmt( date( 'Y-m-d H:i:s' ) );
81
- }
82
-
83
- $data = array(
84
- 'order_id' => (int) $order_id,
85
- 'date' => $date,
86
- );
87
-
88
- if ( $this->method == 'auto_increment' ) {
89
- $wpdb->insert( $this->table_name, $data );
90
- $number = $wpdb->insert_id;
91
- } elseif ( $this->method == 'calculate' ) {
92
- $number = $data['calculated_number'] = $this->get_next();
93
- $wpdb->insert( $this->table_name, $data );
94
- }
95
-
96
- // return generated number
97
- return $number;
98
- }
99
-
100
- /**
101
- * Get the number that will be used on the next increment
102
- * @return int next number
103
- */
104
- public function get_next() {
105
- global $wpdb;
106
- if ( $this->method == 'auto_increment' ) {
107
- // get next auto_increment value
108
- $table_status = $wpdb->get_row("SHOW TABLE STATUS LIKE '{$this->table_name}'");
109
- $next = $table_status->Auto_increment;
110
- } elseif ( $this->method == 'calculate' ) {
111
- $last_row = $wpdb->get_row( "SELECT * FROM {$this->table_name} WHERE id = ( SELECT MAX(id) from {$this->table_name} )" );
112
- if ( empty( $last_row ) ) {
113
- $next = 1;
114
- } elseif ( !empty( $last_row->calculated_number ) ) {
115
- $next = (int) $last_row->calculated_number + 1;
116
- } else {
117
- $next = (int) $last_row->id + 1;
118
- }
119
- }
120
- return $next;
121
- }
122
-
123
- /**
124
- * Set the number that will be used on the next increment
125
- */
126
- public function set_next( $number = 1 ) {
127
- global $wpdb;
128
-
129
- // delete all rows
130
- $delete = $wpdb->query("TRUNCATE TABLE {$this->table_name}");
131
-
132
- // set auto_increment
133
- if ( $number > 1 ) {
134
- // if AUTO_INCREMENT is not 1, we need to make sure we have a 'highest value' in case of server restarts
135
- // https://serverfault.com/questions/228690/mysql-auto-increment-fields-resets-by-itself
136
- $highest_number = (int) $number - 1;
137
- $wpdb->query("ALTER TABLE {$this->table_name} AUTO_INCREMENT={$highest_number};");
138
- $data = array(
139
- 'order_id' => 0,
140
- 'date' => get_date_from_gmt( date( 'Y-m-d H:i:s' ) ),
141
- );
142
-
143
- if ( $this->method == 'calculate' ) {
144
- $data['calculated_number'] = $highest_number;
145
- }
146
-
147
- // after this insert, AUTO_INCREMENT will be equal to $number
148
- $wpdb->insert( $this->table_name, $data );
149
- } else {
150
- // simple scenario, no need to insert any rows
151
- $wpdb->query("ALTER TABLE {$this->table_name} AUTO_INCREMENT={$number};");
152
- }
153
- }
154
-
155
- public function get_last_date( $format = 'Y-m-d H:i:s' ) {
156
- global $wpdb;
157
- $row = $wpdb->get_row( "SELECT * FROM {$this->table_name} WHERE id = ( SELECT MAX(id) from {$this->table_name} )" );
158
- $date = isset( $row->date ) ? $row->date : 'now';
159
- $formatted_date = date( $format, strtotime( $date ) );
160
-
161
- return $formatted_date;
162
- }
163
- }
164
-
165
- endif; // class_exists
 
 
1
+ <?php
2
+ namespace WPO\WC\PDF_Invoices\Documents;
3
+
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
+ exit; // Exit if accessed directly
6
+ }
7
+
8
+ if ( !class_exists( '\\WPO\\WC\\PDF_Invoices\\Documents\\Sequential_Number_Store' ) ) :
9
+
10
+ /**
11
+ * Class handling database interaction for sequential numbers
12
+ *
13
+ * @class \WPO\WC\PDF_Invoices\Documents\Sequential_Number_Store
14
+ * @version 2.0
15
+ * @category Class
16
+ * @author Ewout Fernhout
17
+ */
18
+
19
+ class Sequential_Number_Store {
20
+ /**
21
+ * Name of the table that stores the number sequence (without the wp_wcpdf_ table prefix)
22
+ * @var String
23
+ */
24
+ public $table_name;
25
+
26
+ /**
27
+ * Number store method, either 'auto_increment' or 'calculate'
28
+ * @var String
29
+ */
30
+ public $method;
31
+
32
+ public function __construct( $table_name, $method = 'auto_increment' ) {
33
+ global $wpdb;
34
+ $this->table_name = "{$wpdb->prefix}wcpdf_{$table_name}"; // i.e. wp_wcpdf_invoice_number
35
+ $this->method = $method;
36
+
37
+ $this->init();
38
+ }
39
+
40
+ public function init() {
41
+ global $wpdb;
42
+ // check if table exists
43
+ if( $wpdb->get_var("SHOW TABLES LIKE '{$this->table_name}'") == $this->table_name) {
44
+ // check calculated_number column if using 'calculate' method
45
+ if ( $this->method == 'calculate' ) {
46
+ $column_exists = $wpdb->get_var("SHOW COLUMNS FROM `{$this->table_name}` LIKE 'calculated_number'");
47
+ if (empty($column_exists)) {
48
+ $wpdb->query("ALTER TABLE {$this->table_name} ADD calculated_number int (16)");
49
+ }
50
+ }
51
+ return; // no further business
52
+ }
53
+
54
+ // create table (in case of concurrent requests, this does no harm if it already exists)
55
+ $charset_collate = $wpdb->get_charset_collate();
56
+ // dbDelta is a sensitive kid, so we omit indentation
57
+ $sql = "CREATE TABLE {$this->table_name} (
58
+ id int(16) NOT NULL AUTO_INCREMENT,
59
+ order_id int(16),
60
+ date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
61
+ calculated_number int (16),
62
+ PRIMARY KEY (id)
63
+ ) $charset_collate;";
64
+
65
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
66
+ $result = dbDelta( $sql );
67
+
68
+ return $result;
69
+ }
70
+
71
+ /**
72
+ * Consume/create the next number and return it
73
+ * @param integer $order_id WooCommerce Order ID
74
+ * @param string $date Local date, formatted as Y-m-d H:i:s
75
+ * @return int Number that was consumed/created
76
+ */
77
+ public function increment( $order_id = 0, $date = null ) {
78
+ global $wpdb;
79
+ if ( empty( $date ) ) {
80
+ $date = get_date_from_gmt( date( 'Y-m-d H:i:s' ) );
81
+ }
82
+
83
+ do_action( 'wpo_wcpdf_before_sequential_number_increment', $this, $order_id, $date );
84
+
85
+ $data = array(
86
+ 'order_id' => (int) $order_id,
87
+ 'date' => $date,
88
+ );
89
+
90
+ if ( $this->method == 'auto_increment' ) {
91
+ $wpdb->insert( $this->table_name, $data );
92
+ $number = $wpdb->insert_id;
93
+ } elseif ( $this->method == 'calculate' ) {
94
+ $number = $data['calculated_number'] = $this->get_next();
95
+ $wpdb->insert( $this->table_name, $data );
96
+ }
97
+
98
+ // return generated number
99
+ return $number;
100
+ }
101
+
102
+ /**
103
+ * Get the number that will be used on the next increment
104
+ * @return int next number
105
+ */
106
+ public function get_next() {
107
+ global $wpdb;
108
+ if ( $this->method == 'auto_increment' ) {
109
+ // get next auto_increment value
110
+ $table_status = $wpdb->get_row("SHOW TABLE STATUS LIKE '{$this->table_name}'");
111
+ $next = $table_status->Auto_increment;
112
+ } elseif ( $this->method == 'calculate' ) {
113
+ $last_row = $wpdb->get_row( "SELECT * FROM {$this->table_name} WHERE id = ( SELECT MAX(id) from {$this->table_name} )" );
114
+ if ( empty( $last_row ) ) {
115
+ $next = 1;
116
+ } elseif ( !empty( $last_row->calculated_number ) ) {
117
+ $next = (int) $last_row->calculated_number + 1;
118
+ } else {
119
+ $next = (int) $last_row->id + 1;
120
+ }
121
+ }
122
+ return $next;
123
+ }
124
+
125
+ /**
126
+ * Set the number that will be used on the next increment
127
+ */
128
+ public function set_next( $number = 1 ) {
129
+ global $wpdb;
130
+
131
+ // delete all rows
132
+ $delete = $wpdb->query("TRUNCATE TABLE {$this->table_name}");
133
+
134
+ // set auto_increment
135
+ if ( $number > 1 ) {
136
+ // if AUTO_INCREMENT is not 1, we need to make sure we have a 'highest value' in case of server restarts
137
+ // https://serverfault.com/questions/228690/mysql-auto-increment-fields-resets-by-itself
138
+ $highest_number = (int) $number - 1;
139
+ $wpdb->query("ALTER TABLE {$this->table_name} AUTO_INCREMENT={$highest_number};");
140
+ $data = array(
141
+ 'order_id' => 0,
142
+ 'date' => get_date_from_gmt( date( 'Y-m-d H:i:s' ) ),
143
+ );
144
+
145
+ if ( $this->method == 'calculate' ) {
146
+ $data['calculated_number'] = $highest_number;
147
+ }
148
+
149
+ // after this insert, AUTO_INCREMENT will be equal to $number
150
+ $wpdb->insert( $this->table_name, $data );
151
+ } else {
152
+ // simple scenario, no need to insert any rows
153
+ $wpdb->query("ALTER TABLE {$this->table_name} AUTO_INCREMENT={$number};");
154
+ }
155
+ }
156
+
157
+ public function get_last_date( $format = 'Y-m-d H:i:s' ) {
158
+ global $wpdb;
159
+ $row = $wpdb->get_row( "SELECT * FROM {$this->table_name} WHERE id = ( SELECT MAX(id) from {$this->table_name} )" );
160
+ $date = isset( $row->date ) ? $row->date : 'now';
161
+ $formatted_date = date( $format, strtotime( $date ) );
162
+
163
+ return $formatted_date;
164
+ }
165
+ }
166
+
167
+ endif; // class_exists
includes/views/setup-wizard/attach-to.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wpo-step-description">
2
+ <h2><?php _e( 'Attach too...', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
3
+ <p><?php _e( 'Select to which emails you would like to attach your invoice.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
4
+ </div>
5
+ <div class="wpo-setup-input">
6
+ <?php
7
+ $current_settings = get_option( 'wpo_wcpdf_documents_settings_invoice', array() );
8
+ // echo "<pre>".var_dump($current_settings)."</pre>";
9
+ // load invoice to reuse method to get wc emails
10
+ $invoice = wcpdf_get_invoice( null );
11
+ $wc_emails = $invoice->get_wc_emails();
12
+ foreach ($wc_emails as $email_id => $name) {
13
+ if (!empty($current_settings['attach_to_email_ids'][$email_id])) {
14
+ $checked = 'checked';
15
+ } else {
16
+ $checked = '';
17
+ }
18
+ printf('<input type="hidden" value="" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][attach_to_email_ids][%1$s]">
19
+ <input type="checkbox" %3$s name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][attach_to_email_ids][%1$s]" value="1">
20
+ <span class="checkbox">%2$s</span><br>', $email_id, $name, $checked);
21
+ }
22
+ ?>
23
+ </div>
includes/views/setup-wizard/display-options.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wpo-step-description">
2
+ <h2><?php _e( 'Display options', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
3
+ <p><?php _e( 'Select some additional display options for your invoice.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
4
+ </div>
5
+ <div class="wpo-setup-input">
6
+ <?php
7
+ $current_settings = get_option( 'wpo_wcpdf_documents_settings_invoice', array() );
8
+ ?>
9
+ <input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_shipping_address]" value="">
10
+ <input type="checkbox" <?php echo !empty($current_settings['display_shipping_address']) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_shipping_address]" value="1"><span class="checkbox"><?php _e( 'Display shipping address', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><br>
11
+ <input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_email]" value="">
12
+ <input type="checkbox" <?php echo !empty($current_settings['display_email']) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_email]" value="1"><span class="checkbox"><?php _e( 'Display email address', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><br>
13
+ <input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_phone]" value="">
14
+ <input type="checkbox" <?php echo !empty($current_settings['display_phone']) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_phone]" value="1"><span class="checkbox"><?php _e( 'Display phone number', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><br>
15
+ <input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_date]" value="">
16
+ <input type="checkbox" <?php echo !empty($current_settings['display_date']) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_date]" value="invoice_date"><span class="checkbox"><?php _e( 'Display invoice date', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><br>
17
+ <input type="hidden" name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_number]" value="">
18
+ <input type="checkbox" <?php echo !empty($current_settings['display_number']) ? 'checked' : ''; ?> name="wcpdf_settings[wpo_wcpdf_documents_settings_invoice][display_number]" value="invoice_number"><span class="checkbox"><?php _e( 'Display invoice number', 'woocommerce-pdf-invoices-packing-slips' ); ?></span><br>
19
+ </div>
includes/views/setup-wizard/good-to-go.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <div class="wpo-step-description wpo-final">
2
+ <h1><?php _e( 'You are good to go!' , 'woocommerce-pdf-invoices-packing-slips' ); ?></h1>
3
+ <p><?php _e( 'If you have any questions please have a look at our documentation:', 'woocommerce-pdf-invoices-packing-slips' ); ?><br>
4
+ <a href="https://docs.wpovernight.com/category/woocommerce-pdf-invoices-packing-slips/" target="_blank"><?php _e( 'Invoices & Packing Slips' , 'woocommerce-pdf-invoices-packing-slips' ); ?></a></p>
5
+ <h2><?php _e( 'Happy selling!' , 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
6
+ </div>
includes/views/setup-wizard/logo.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <div class="wpo-step-description">
2
+ <h2><?php _e( 'Your logo' , 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
3
+ <p><?php _e( 'Set the header image that will display on your invoice.' , 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
4
+ </div>
5
+ <div class="wpo-setup-input">
6
+ <img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" width="100%" height="20px" alt="" id="img-header_logo"/>
7
+ <input id="header_logo" name="wcpdf_settings[wpo_wcpdf_settings_general][header_logo]" type="hidden" value="" />
8
+ <span class="button wpo_upload_image_button header_logo" data-uploader_title="<?php _e( 'Select or upload your invoice header/logo', 'woocommerce-pdf-invoices-packing-slips' ); ?>" data-uploader_button_text="<?php _e( 'Set image', 'woocommerce-pdf-invoices-packing-slips' ); ?>" data-remove_button_text="<?php _e( 'Remove image', 'woocommerce-pdf-invoices-packing-slips' ); ?>" data-input_id="header_logo"><?php _e( 'Set image', 'woocommerce-pdf-invoices-packing-slips' ); ?></span>
9
+ </div>
includes/views/setup-wizard/paper-format.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wpo-step-description">
2
+ <h2><?php _e( 'Paper format', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
3
+ <p><?php _e( 'Select the paper format for your invoice.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
4
+ </div>
5
+ <div class="wpo-setup-input">
6
+ <?php
7
+ $current_settings = get_option( 'wpo_wcpdf_settings_general', array() );
8
+ ?>
9
+
10
+ <select name="wcpdf_settings[wpo_wcpdf_settings_general][paper_size]">
11
+ <option <?php echo $current_settings['paper_size'] == 'a4' ? 'selected' : ''; ?> value="a4"><?php _e( 'A4', 'woocommerce-pdf-invoices-packing-slips' ); ?></option>
12
+ <option <?php echo $current_settings['paper_size'] == 'letter' ? 'selected' : ''; ?> value="letter"><?php _e( 'Letter', 'woocommerce-pdf-invoices-packing-slips' ); ?></option>
13
+ </select>
14
+ </div>
includes/views/setup-wizard/shop-name.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wpo-step-description">
2
+ <h2><?php _e( 'Enter your shop name', 'woocommerce-pdf-invoices-packing-slips' ); ?></h2>
3
+ <p><?php _e( 'Lets quickly setup your invoice. Please enter the name and address of your shop in the fields on the right.', 'woocommerce-pdf-invoices-packing-slips' ); ?></p>
4
+ </div>
5
+ <div class="wpo-setup-input">
6
+ <?php
7
+ $current_settings = get_option( 'wpo_wcpdf_settings_general', array() );
8
+ ?>
9
+ <input type="text" class="shop-name" placeholder="Shop name" name="wcpdf_settings[wpo_wcpdf_settings_general][shop_name][default]" value="<?php echo !empty($current_settings['shop_name']) ? array_pop($current_settings['shop_name']) : get_bloginfo( 'name' ); ?>">
10
+ <textarea class="shop-address" placeholder="Shop address" name="wcpdf_settings[wpo_wcpdf_settings_general][shop_address][default]"><?php echo isset($current_settings['shop_address']) ? array_pop($current_settings['shop_address']) : ''; ?></textarea>
11
+ </div>
readme.txt CHANGED
@@ -4,7 +4,8 @@ Donate link: https://wpovernight.com/downloads/woocommerce-pdf-invoices-packing-
4
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
5
  Requires at least: 3.5
6
  Tested up to: 4.8
7
- Stable tag: 2.0.13
 
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -42,7 +43,7 @@ In addition to a number of default settings (including a custom header/logo) and
42
 
43
  = Minimum Requirements =
44
 
45
- * WooCommerce 2.0 or later
46
  * WordPress 3.5 or later
47
 
48
  = Automatic installation =
@@ -104,6 +105,12 @@ There's a setting on the Status tab of the settings page that allows you to togg
104
 
105
  **2.0 is a BIG update! Make a full site backup before upgrading**
106
 
 
 
 
 
 
 
107
  = 2.0.13 =
108
  * Fix: Minor XSS issue on settings screens by escaping and sanitizing 'tab' & 'section' GET variables. Discovered by Detectify.
109
  * Fix: Pakistani Rupee Symbol
@@ -198,5 +205,5 @@ There's a setting on the Status tab of the settings page that allows you to togg
198
 
199
  == Upgrade Notice ==
200
 
201
- = 2.0.13 =
202
  **2.0 is a BIG update! Make a full site backup before upgrading!**
4
  Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice, packing slip, export, email, bulk, automatic
5
  Requires at least: 3.5
6
  Tested up to: 4.8
7
+ Requires PHP: 5.3
8
+ Stable tag: 2.0.14
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
43
 
44
  = Minimum Requirements =
45
 
46
+ * WooCommerce 2.2 or later
47
  * WordPress 3.5 or later
48
 
49
  = Automatic installation =
105
 
106
  **2.0 is a BIG update! Make a full site backup before upgrading**
107
 
108
+ = 2.0.14 =
109
+ * Feature: Manually resend specific order emails in WooCommerce 3.2+
110
+ * Tweak: Show full size logo preview in settings
111
+ * Tweak: Custom field fallback to underscore prefixed meta key
112
+ * Dev: added `wpo_wcpdf_before_sequential_number_increment` action
113
+
114
  = 2.0.13 =
115
  * Fix: Minor XSS issue on settings screens by escaping and sanitizing 'tab' & 'section' GET variables. Discovered by Detectify.
116
  * Fix: Pakistani Rupee Symbol
205
 
206
  == Upgrade Notice ==
207
 
208
+ = 2.0.14 =
209
  **2.0 is a BIG update! Make a full site backup before upgrading!**
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,12 +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.0.13
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
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
@@ -19,7 +21,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
19
 
20
  class WPO_WCPDF {
21
 
22
- public $version = '2.0.13';
23
  public $plugin_basename;
24
  public $legacy_mode;
25
 
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.0.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.2.0
14
  */
15
 
16
  if ( ! defined( 'ABSPATH' ) ) {
21
 
22
  class WPO_WCPDF {
23
 
24
+ public $version = '2.0.14';
25
  public $plugin_basename;
26
  public $legacy_mode;
27