Post Views Counter - Version 1.3.2

Version Description

  • New: Introducing dashboard widget navigation
  • New: Counter support for Media (attachments)
  • Tweak: Extended views query for handling complex date/time requests
Download this release

Release Info

Developer dfactory
Plugin Icon 128x128 Post Views Counter
Version 1.3.2
Comparing to
See all releases

Code changes from version 1.3.1 to 1.3.2

css/admin-dashboard.css CHANGED
@@ -1,20 +1,29 @@
1
- #pvc_dashboard_container {
2
- color: #aaa;
3
- min-height: 240px;
4
- margin: 0 -4px;
5
- text-align: center;
6
- position: relative;
7
- }
8
- #pvc_dashboard_container .spinner {
9
- position: absolute;
10
- left: 50%;
11
- top: 40%;
12
- margin-left: -10px;
13
- }
14
- #pvc_dashboard p.sub {
15
- color: #8f8f8f;
16
- font-size: 14px;
17
- text-align: left;
18
- padding-bottom: 3px;
19
- border-bottom: 1px solid #ececec;
 
 
 
 
 
 
 
 
 
20
  }
1
+ #pvc_dashboard_container {
2
+ color: #aaa;
3
+ min-height: 240px;
4
+ margin: 0 -4px;
5
+ text-align: center;
6
+ position: relative;
7
+ }
8
+ #pvc_dashboard_container .spinner {
9
+ position: absolute;
10
+ left: 50%;
11
+ top: 40%;
12
+ margin-left: -10px;
13
+ }
14
+ #pvc_dashboard p.sub {
15
+ color: #8f8f8f;
16
+ font-size: 14px;
17
+ text-align: left;
18
+ padding-bottom: 3px;
19
+ border-bottom: 1px solid #ececec;
20
+ }
21
+ #pvc_dashboard_container .pvc_months {
22
+ margin: 6px 10px 0 10px;
23
+ }
24
+ #pvc_dashboard_container .pvc_months a.prev {
25
+ float: left;
26
+ }
27
+ #pvc_dashboard_container .pvc_months a.next, #pvc_dashboard_container .pvc_months span.next {
28
+ float: right;
29
  }
css/admin.css CHANGED
@@ -1,489 +1,497 @@
1
- /* Post Views Counter settings */
2
- .post-views-counter-settings {
3
- margin-right: 300px;
4
- }
5
-
6
- .post-views-counter-settings form {
7
- float: left;
8
- min-width: 463px;
9
- width: auto;
10
- }
11
-
12
- .post-views-counter-settings fieldset .description {
13
- font-size: 13px;
14
- margin-bottom: 8px;
15
- margin-top: 4px;
16
- display: block;
17
- }
18
-
19
- .post-views-counter-settings p.help, .post-views-counter-settings p.description, .post-views-counter-settings span.description {
20
- font-size: 13px;
21
- font-style: italic;
22
- }
23
-
24
- .post-views-counter-settings div.ip-box {
25
- margin-bottom: 3px;
26
- }
27
-
28
- .df-credits {
29
- float: right;
30
- width: 280px;
31
- background: #fff;
32
- margin: 20px -300px 20px 20px;
33
- position: relative;
34
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
35
- }
36
-
37
- .df-credits .inner {
38
- padding-left: 10px;
39
- padding-right: 10px;
40
- }
41
-
42
- .df-credits h3 {
43
- font-size: 14px;
44
- line-height: 1.4;
45
- margin: 0;
46
- padding: 8px 12px;
47
- border-bottom: 1px solid #eee;
48
- }
49
-
50
- .df-credits .df-link {
51
- font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
52
- font-style: italic;
53
- padding-bottom: 10px;
54
- margin: 0;
55
- }
56
-
57
- .df-credits .df-link a {
58
- vertical-align: middle;
59
- padding: 5px 0 0 4px;
60
- }
61
-
62
- .df-credits hr {
63
- border: solid #eee;
64
- border-width: 1px 0 0;
65
- clear: both;
66
- height: 0;
67
- }
68
-
69
- /* Single post edit screen */
70
- #misc-publishing-actions #post-views #post-views-display:before {
71
- display: inline-block;
72
- font: 400 20px/1 dashicons;
73
- left: -1px;
74
- padding: 0 2px 0 0;
75
- position: relative;
76
- text-decoration: none !important;
77
- vertical-align: top;
78
- color: #888;
79
- content: "\f185";
80
- top: -1px;
81
- }
82
-
83
- /* Listing edit screen */
84
- .edit-php .widefat th#post_views {
85
- width: 5.5em;
86
- }
87
- .edit-php .widefat th.column-post_views .dashicons,
88
- .edit-php .widefat th.column-post_views .dashicons:before {
89
- font-size: 1.1em;
90
- vertical-align: middle;
91
- }
92
- .edit-php .widefat th .dash-title {
93
- display:none;
94
- }
95
- .edit-php .metabox-prefs .dash-icon {
96
- display:none;
97
- }
98
- .edit-php .widefat td .dashicons,
99
- .edit-php .widefat td .dashicons:before {
100
- font-size: 1.1em;
101
- }
102
- .edit-php #inline-edit-post_views input {
103
- width: auto;
104
- }
105
-
106
- /*
107
- * checkBo lightweight jQuery plugin v0.1.4 by @ElmahdiMahmoud
108
- * Licensed under the MIT license - https://github.com/elmahdim/checkbo/blob/master/LICENSE
109
- *
110
- * Custom checkbox and radio
111
- * Author URL: elmahdim.com
112
- */
113
- .cb-checkbox .cb-inner, .cb-checkbox i {
114
- width:18px;
115
- height:18px;
116
- -moz-border-radius:3px;
117
- -webkit-border-radius:3px;
118
- border-radius:3px
119
- }
120
- .cb-checkbox.cb-sm i, .cb-checkbox.cb-sm .cb-inner {
121
- width:14px;
122
- height:14px
123
- }
124
- .cb-checkbox.cb-md i, .cb-checkbox.cb-md .cb-inner {
125
- width:24px;
126
- height:24px;
127
- -moz-border-radius:4px;
128
- -webkit-border-radius:4px;
129
- border-radius:4px
130
- }
131
- .cb-checkbox.cb-lg i, .cb-checkbox.cb-lg .cb-inner {
132
- width:30px;
133
- height:30px;
134
- -moz-border-radius:6px;
135
- -webkit-border-radius:6px;
136
- border-radius:6px
137
- }
138
- .cb-radio .cb-inner {
139
- width:18px;
140
- height:18px
141
- }
142
- .cb-radio.cb-sm .cb-inner {
143
- width:14px;
144
- height:14px
145
- }
146
- .cb-radio.cb-md .cb-inner {
147
- width:24px;
148
- height:24px
149
- }
150
- .cb-radio.cb-lg .cb-inner {
151
- width:30px;
152
- height:30px
153
- }
154
- .cb-checkbox, .cb-radio {
155
- color:inherit;
156
- cursor:pointer;
157
- overflow:hidden;
158
- font-size:inherit;
159
- font-weight:normal;
160
- display:inline-block;
161
- line-height:18px;
162
- margin-right: 8px;
163
- }
164
- .form-table td fieldset label.cb-checkbox,
165
- .form-table td fieldset label.cb-radio {
166
- margin-right: 8px !important;
167
- }
168
- .cb-checkbox.disabled, .cb-checkbox.disabled *, .cb-radio.disabled, .cb-radio.disabled * {
169
- cursor:default
170
- }
171
- .cb-checkbox input[type="checkbox"], .cb-radio input[type="radio"], .cb-switcher input[type="checkbox"], .cb-switcher input[type="radio"] {
172
- display:none
173
- }
174
- .cb-checkbox.disabled, .cb-checkbox.disabled *, .cb-radio.disabled, .cb-radio.disabled *, .cb-switcher.disabled, .cb-switcher.disabled * {
175
- cursor:default
176
- }
177
- .cb-checkbox.disabled {
178
- color:#ddd
179
- }
180
- .cb-checkbox.disabled .cb-inner {
181
- color:#ddd
182
- }
183
- .cb-checkbox.disabled:hover .cb-inner {
184
- border-color:#ddd
185
- }
186
- .cb-checkbox.disabled.checked .cb-inner {
187
- background-color:#ddd;
188
- border-color:#ddd
189
- }
190
- .cb-radio.disabled {
191
- color:#ddd
192
- }
193
- .cb-radio.disabled .cb-inner {
194
- border-color:#ddd
195
- }
196
- .cb-radio.disabled i {
197
- background-color:transparent
198
- }
199
- .cb-radio.disabled.checked .cb-inner {
200
- border-color:#ddd
201
- }
202
- .cb-radio.disabled.checked .cb-inner i {
203
- background-color:#ddd
204
- }
205
- .cb-radio.disabled:hover .cb-inner {
206
- border-color:#ddd
207
- }
208
- .cb-checkbox .cb-inner {
209
- float:left;
210
- overflow:hidden;
211
- margin:0 5px 0 0;
212
- position:relative;
213
- background:#f2f2f2;
214
- display:inline-block;
215
- border:1px solid #d6d6d6;
216
- -moz-transition:all 0.5s ease;
217
- -o-transition:all 0.5s ease;
218
- -webkit-transition:all 0.5s ease;
219
- transition:all 0.5s ease
220
- }
221
- .cb-checkbox i {
222
- top:1px;
223
- left:2px;
224
- display:block;
225
- position:absolute
226
- }
227
- .cb-checkbox i:before, .cb-checkbox i:after {
228
- height:0;
229
- width:2px;
230
- content:"";
231
- display:block;
232
- position:absolute;
233
- background-color:#fff;
234
- -moz-transition:all 0.2s ease;
235
- -o-transition:all 0.2s ease;
236
- -webkit-transition:all 0.2s ease;
237
- transition:all 0.2s ease
238
- }
239
- .cb-checkbox i:before {
240
- top:0;
241
- left:0;
242
- -moz-transform:rotate(-45deg);
243
- -ms-transform:rotate(-45deg);
244
- -webkit-transform:rotate(-45deg);
245
- transform:rotate(-45deg)
246
- }
247
- .cb-checkbox i:after {
248
- left:7px;
249
- bottom:5px;
250
- -moz-transition-delay:0.3s;
251
- -o-transition-delay:0.3s;
252
- -webkit-transition-delay:0.3s;
253
- transition-delay:0.3s;
254
- -moz-transform:rotate(30deg);
255
- -ms-transform:rotate(30deg);
256
- -webkit-transform:rotate(30deg);
257
- transform:rotate(30deg)
258
- }
259
- .cb-radio .cb-inner {
260
- float:left;
261
- overflow:hidden;
262
- margin:0 5px 0 0;
263
- position:relative;
264
- display:inline-block;
265
- border:1px solid #d7d7d7;
266
- background-color:#f2f2f2;
267
- -moz-border-radius:100%;
268
- -webkit-border-radius:100%;
269
- border-radius:100%;
270
- -moz-transition:all 0.1s ease;
271
- -o-transition:all 0.1s ease;
272
- -webkit-transition:all 0.1s ease;
273
- transition:all 0.1s ease
274
- }
275
- .cb-radio i {
276
- top:50%;
277
- left:50%;
278
- width:6px;
279
- height:6px;
280
- margin-top:-3px;
281
- margin-left:-3px;
282
- position:absolute;
283
- background-color:transparent;
284
- -moz-border-radius:100%;
285
- -webkit-border-radius:100%;
286
- border-radius:100%;
287
- -moz-transform:scale(0.05, 5);
288
- -ms-transform:scale(0.05, 5);
289
- -webkit-transform:scale(0.05, 5);
290
- transform:scale(0.05, 5);
291
- -moz-transition:all 0.2s ease;
292
- -o-transition:all 0.2s ease;
293
- -webkit-transition:all 0.2s ease;
294
- transition:all 0.2s ease
295
- }
296
- .cb-checkbox.cb-sm, .cb-radio.cb-sm {
297
- line-height:14px
298
- }
299
- .cb-checkbox.cb-md, .cb-radio.cb-md {
300
- line-height:24px
301
- }
302
- .cb-checkbox.cb-lg, .cb-radio.cb-lg {
303
- line-height:30px
304
- }
305
- .cb-checkbox.cb-sm i:before {
306
- top:4px;
307
- left:1px
308
- }
309
- .cb-checkbox.cb-sm i:after {
310
- left:5px
311
- }
312
- .cb-checkbox.cb-md i:before {
313
- top:10px;
314
- left:5px
315
- }
316
- .cb-checkbox.cb-md i:after {
317
- bottom:6px;
318
- left:11px
319
- }
320
- .cb-checkbox.checked .cb-inner {
321
- border-color:#0073aa;
322
- background-color:#00a0d2;
323
- box-shadow: 0 1px 0 rgba(120, 200, 230, 0.5) inset, 0 1px 0 rgba(0, 0, 0, 0.15);
324
- }
325
- .cb-checkbox.checked:hover .cb-inner {
326
- background-color:#0091cd
327
- }
328
- .cb-checkbox.checked.cb-sm i:before {
329
- top:4px;
330
- left:1px
331
- }
332
- .cb-checkbox.checked.cb-sm i:after {
333
- height:9px
334
- }
335
- .cb-checkbox.checked.cb-md i:before {
336
- top:10px;
337
- left:4px;
338
- height:8px
339
- }
340
- .cb-checkbox.checked.cb-md i:after {
341
- bottom:6px;
342
- left:11px;
343
- height:16px
344
- }
345
- .cb-checkbox.checked.cb-lg i:before {
346
- top:11px;
347
- left:6px;
348
- height:12px
349
- }
350
- .cb-checkbox.checked.cb-lg i:after {
351
- left:14px;
352
- bottom:7px;
353
- height:20px
354
- }
355
- .cb-checkbox.checked i:before {
356
- top:6px;
357
- left:2px;
358
- height:6px
359
- }
360
- .cb-checkbox.checked i:after {
361
- height:12px
362
- }
363
- .cb-radio.checked .cb-inner {
364
- background:#fff;
365
- box-shadow:0 0 3px #efefef
366
- }
367
- .cb-radio.checked i {
368
- -moz-transform:scale(1.1, 1.1);
369
- -ms-transform:scale(1.1, 1.1);
370
- -webkit-transform:scale(1.1, 1.1);
371
- transform:scale(1.1, 1.1);
372
- background-color:#00a0d2
373
- }
374
- .cb-checkbox:hover .cb-inner, .cb-radio:hover .cb-inner {
375
- border-color:#0073aa
376
- }
377
- .cb-switcher {
378
- display:inline-block;
379
- border:1px solid #eee;
380
- background-color:#fff;
381
- width:95px;
382
- height:35px;
383
- position:relative;
384
- -moz-border-radius:20px;
385
- -webkit-border-radius:20px;
386
- border-radius:20px;
387
- -moz-transition:background 0.4s ease;
388
- -o-transition:background 0.4s ease;
389
- -webkit-transition:background 0.4s ease;
390
- transition:background 0.4s ease
391
- }
392
- .cb-switcher, .cb-switcher * {
393
- cursor:pointer
394
- }
395
- .cb-switcher ::-moz-selection {
396
- background-color:transparent
397
- }
398
- .cb-switcher ::selection {
399
- background-color:transparent
400
- }
401
- .cb-switcher .cb-state {
402
- z-index:1;
403
- text-align:center;
404
- font-size:12px
405
- }
406
- .cb-switcher .cb-state, .cb-switcher:before {
407
- width:34px;
408
- height:34px;
409
- line-height:34px;
410
- position:absolute;
411
- left:0;
412
- top:-1px;
413
- -moz-border-radius:100%;
414
- -webkit-border-radius:100%;
415
- border-radius:100%;
416
- -moz-transition:all 0.4s ease;
417
- -o-transition:all 0.4s ease;
418
- -webkit-transition:all 0.4s ease;
419
- transition:all 0.4s ease
420
- }
421
- .cb-switcher:before {
422
- content:"";
423
- background-color:#eee;
424
- -moz-box-shadow:1px 1px 1px rgba(0, 0, 0, 0.1);
425
- -webkit-box-shadow:1px 1px 1px rgba(0, 0, 0, 0.1);
426
- box-shadow:1px 1px 1px rgba(0, 0, 0, 0.1)
427
- }
428
- .cb-switcher.checked {
429
- background-color:#00a0d2
430
- }
431
- .cb-switcher.checked .cb-state, .cb-switcher.checked:before {
432
- left:60px;
433
- color:#00a0d2
434
- }
435
- .cb-switcher.checked:before {
436
- background-color:#fff;
437
- -moz-box-shadow:-1px 1px 1px rgba(0, 0, 0, 0.1);
438
- -webkit-box-shadow:-1px 1px 1px rgba(0, 0, 0, 0.1);
439
- box-shadow:-1px 1px 1px rgba(0, 0, 0, 0.1)
440
- }
441
- .cb-switcher.checked .inner-switcher:before {
442
- border-top-color:#0073aa
443
- }
444
- .cb-switcher.checked .inner-switcher:after {
445
- border-bottom-color:#0073aa
446
- }
447
- .cb-switcher .inner-switcher:before, .cb-switcher .inner-switcher:after {
448
- content:"";
449
- position:absolute;
450
- left:50%;
451
- width:0;
452
- height:0;
453
- z-index:2;
454
- margin-left:-20px;
455
- border-left:20px solid transparent;
456
- border-right:20px solid transparent;
457
- -moz-transition:border 0.4s ease;
458
- -o-transition:border 0.4s ease;
459
- -webkit-transition:border 0.4s ease;
460
- transition:border 0.4s ease
461
- }
462
- .cb-switcher .inner-switcher:before {
463
- border-top:17px solid #fff;
464
- top:0
465
- }
466
- .cb-switcher .inner-switcher:after {
467
- border-bottom:17px solid #fff;
468
- bottom:0
469
- }
470
- .cb-state {
471
- color:#ccc;
472
- display:inline-block
473
- }
474
- .cb-switcher-group .cb-state {
475
- position:relative;
476
- top:7px
477
- }
478
- .is-hidden {
479
- display:none !important;
480
- visibility:hidden !important
481
- }
482
- output {
483
- display: block;
484
- font-size: 30px;
485
- font-weight: bold;
486
- text-align: center;
487
- margin: 30px 0;
488
- width: 100%;
 
 
 
 
 
 
 
 
489
  }
1
+ /* Post Views Counter settings */
2
+ .post-views-counter-settings {
3
+ margin-right: 300px;
4
+ }
5
+
6
+ .post-views-counter-settings form {
7
+ float: left;
8
+ min-width: 463px;
9
+ width: auto;
10
+ }
11
+
12
+ .post-views-counter-settings fieldset .description {
13
+ font-size: 13px;
14
+ margin-bottom: 8px;
15
+ margin-top: 4px;
16
+ display: block;
17
+ }
18
+
19
+ .post-views-counter-settings p.help, .post-views-counter-settings p.description, .post-views-counter-settings span.description {
20
+ font-size: 13px;
21
+ font-style: italic;
22
+ }
23
+
24
+ .post-views-counter-settings div.ip-box {
25
+ margin-bottom: 3px;
26
+ }
27
+
28
+ .df-credits {
29
+ float: right;
30
+ width: 280px;
31
+ background: #fff;
32
+ margin: 20px -300px 20px 20px;
33
+ position: relative;
34
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
35
+ }
36
+
37
+ .df-credits .inner {
38
+ padding-left: 10px;
39
+ padding-right: 10px;
40
+ }
41
+
42
+ .df-credits h3 {
43
+ font-size: 14px;
44
+ line-height: 1.4;
45
+ margin: 0;
46
+ padding: 8px 12px;
47
+ border-bottom: 1px solid #eee;
48
+ }
49
+
50
+ .df-credits .df-link {
51
+ padding-top: 5px;
52
+ padding-bottom: 10px;
53
+ margin: 0;
54
+ }
55
+
56
+ .df-credits .df-link a {
57
+ display: block;
58
+ text-align: center;
59
+ outline: none !important;
60
+ border: none !important;
61
+ box-shadow: none !important;
62
+ }
63
+
64
+ .df-credits .df-link a img {
65
+ display: block;
66
+ margin: 0 auto;
67
+ width: 80px;
68
+ }
69
+
70
+ .df-credits hr {
71
+ border: solid #eee;
72
+ border-width: 1px 0 0;
73
+ clear: both;
74
+ height: 0;
75
+ }
76
+
77
+ /* Single post edit screen */
78
+ #misc-publishing-actions #post-views #post-views-display:before {
79
+ display: inline-block;
80
+ font: 400 20px/1 dashicons;
81
+ left: -1px;
82
+ padding: 0 2px 0 0;
83
+ position: relative;
84
+ text-decoration: none !important;
85
+ vertical-align: top;
86
+ color: #888;
87
+ content: "\f185";
88
+ top: -1px;
89
+ }
90
+
91
+ /* Listing edit screen */
92
+ .edit-php .widefat th#post_views {
93
+ width: 5.5em;
94
+ }
95
+ .edit-php .widefat th.column-post_views .dashicons,
96
+ .edit-php .widefat th.column-post_views .dashicons:before {
97
+ font-size: 1.1em;
98
+ vertical-align: middle;
99
+ }
100
+ .edit-php .widefat th .dash-title, .upload-php .widefat th .dash-title {
101
+ display:none;
102
+ }
103
+ .edit-php .metabox-prefs .dash-icon {
104
+ display:none;
105
+ }
106
+ .edit-php .widefat td .dashicons,
107
+ .edit-php .widefat td .dashicons:before {
108
+ font-size: 1.1em;
109
+ }
110
+ .edit-php #inline-edit-post_views input {
111
+ width: auto;
112
+ }
113
+
114
+ /*
115
+ * checkBo lightweight jQuery plugin v0.1.4 by @ElmahdiMahmoud
116
+ * Licensed under the MIT license - https://github.com/elmahdim/checkbo/blob/master/LICENSE
117
+ *
118
+ * Custom checkbox and radio
119
+ * Author URL: elmahdim.com
120
+ */
121
+ .cb-checkbox .cb-inner, .cb-checkbox i {
122
+ width:18px;
123
+ height:18px;
124
+ -moz-border-radius:3px;
125
+ -webkit-border-radius:3px;
126
+ border-radius:3px
127
+ }
128
+ .cb-checkbox.cb-sm i, .cb-checkbox.cb-sm .cb-inner {
129
+ width:14px;
130
+ height:14px
131
+ }
132
+ .cb-checkbox.cb-md i, .cb-checkbox.cb-md .cb-inner {
133
+ width:24px;
134
+ height:24px;
135
+ -moz-border-radius:4px;
136
+ -webkit-border-radius:4px;
137
+ border-radius:4px
138
+ }
139
+ .cb-checkbox.cb-lg i, .cb-checkbox.cb-lg .cb-inner {
140
+ width:30px;
141
+ height:30px;
142
+ -moz-border-radius:6px;
143
+ -webkit-border-radius:6px;
144
+ border-radius:6px
145
+ }
146
+ .cb-radio .cb-inner {
147
+ width:18px;
148
+ height:18px
149
+ }
150
+ .cb-radio.cb-sm .cb-inner {
151
+ width:14px;
152
+ height:14px
153
+ }
154
+ .cb-radio.cb-md .cb-inner {
155
+ width:24px;
156
+ height:24px
157
+ }
158
+ .cb-radio.cb-lg .cb-inner {
159
+ width:30px;
160
+ height:30px
161
+ }
162
+ .cb-checkbox, .cb-radio {
163
+ color:inherit;
164
+ cursor:pointer;
165
+ overflow:hidden;
166
+ font-size:inherit;
167
+ font-weight:normal;
168
+ display:inline-block;
169
+ line-height:18px;
170
+ margin-right: 8px;
171
+ }
172
+ .form-table td fieldset label.cb-checkbox,
173
+ .form-table td fieldset label.cb-radio {
174
+ margin-right: 8px !important;
175
+ }
176
+ .cb-checkbox.disabled, .cb-checkbox.disabled *, .cb-radio.disabled, .cb-radio.disabled * {
177
+ cursor:default
178
+ }
179
+ .cb-checkbox input[type="checkbox"], .cb-radio input[type="radio"], .cb-switcher input[type="checkbox"], .cb-switcher input[type="radio"] {
180
+ display:none
181
+ }
182
+ .cb-checkbox.disabled, .cb-checkbox.disabled *, .cb-radio.disabled, .cb-radio.disabled *, .cb-switcher.disabled, .cb-switcher.disabled * {
183
+ cursor:default
184
+ }
185
+ .cb-checkbox.disabled {
186
+ color:#ddd
187
+ }
188
+ .cb-checkbox.disabled .cb-inner {
189
+ color:#ddd
190
+ }
191
+ .cb-checkbox.disabled:hover .cb-inner {
192
+ border-color:#ddd
193
+ }
194
+ .cb-checkbox.disabled.checked .cb-inner {
195
+ background-color:#ddd;
196
+ border-color:#ddd
197
+ }
198
+ .cb-radio.disabled {
199
+ color:#ddd
200
+ }
201
+ .cb-radio.disabled .cb-inner {
202
+ border-color:#ddd
203
+ }
204
+ .cb-radio.disabled i {
205
+ background-color:transparent
206
+ }
207
+ .cb-radio.disabled.checked .cb-inner {
208
+ border-color:#ddd
209
+ }
210
+ .cb-radio.disabled.checked .cb-inner i {
211
+ background-color:#ddd
212
+ }
213
+ .cb-radio.disabled:hover .cb-inner {
214
+ border-color:#ddd
215
+ }
216
+ .cb-checkbox .cb-inner {
217
+ float:left;
218
+ overflow:hidden;
219
+ margin:0 5px 0 0;
220
+ position:relative;
221
+ background:#f2f2f2;
222
+ display:inline-block;
223
+ border:1px solid #d6d6d6;
224
+ -moz-transition:all 0.5s ease;
225
+ -o-transition:all 0.5s ease;
226
+ -webkit-transition:all 0.5s ease;
227
+ transition:all 0.5s ease
228
+ }
229
+ .cb-checkbox i {
230
+ top:1px;
231
+ left:2px;
232
+ display:block;
233
+ position:absolute
234
+ }
235
+ .cb-checkbox i:before, .cb-checkbox i:after {
236
+ height:0;
237
+ width:2px;
238
+ content:"";
239
+ display:block;
240
+ position:absolute;
241
+ background-color:#fff;
242
+ -moz-transition:all 0.2s ease;
243
+ -o-transition:all 0.2s ease;
244
+ -webkit-transition:all 0.2s ease;
245
+ transition:all 0.2s ease
246
+ }
247
+ .cb-checkbox i:before {
248
+ top:0;
249
+ left:0;
250
+ -moz-transform:rotate(-45deg);
251
+ -ms-transform:rotate(-45deg);
252
+ -webkit-transform:rotate(-45deg);
253
+ transform:rotate(-45deg)
254
+ }
255
+ .cb-checkbox i:after {
256
+ left:7px;
257
+ bottom:5px;
258
+ -moz-transition-delay:0.3s;
259
+ -o-transition-delay:0.3s;
260
+ -webkit-transition-delay:0.3s;
261
+ transition-delay:0.3s;
262
+ -moz-transform:rotate(30deg);
263
+ -ms-transform:rotate(30deg);
264
+ -webkit-transform:rotate(30deg);
265
+ transform:rotate(30deg)
266
+ }
267
+ .cb-radio .cb-inner {
268
+ float:left;
269
+ overflow:hidden;
270
+ margin:0 5px 0 0;
271
+ position:relative;
272
+ display:inline-block;
273
+ border:1px solid #d7d7d7;
274
+ background-color:#f2f2f2;
275
+ -moz-border-radius:100%;
276
+ -webkit-border-radius:100%;
277
+ border-radius:100%;
278
+ -moz-transition:all 0.1s ease;
279
+ -o-transition:all 0.1s ease;
280
+ -webkit-transition:all 0.1s ease;
281
+ transition:all 0.1s ease
282
+ }
283
+ .cb-radio i {
284
+ top:50%;
285
+ left:50%;
286
+ width:6px;
287
+ height:6px;
288
+ margin-top:-3px;
289
+ margin-left:-3px;
290
+ position:absolute;
291
+ background-color:transparent;
292
+ -moz-border-radius:100%;
293
+ -webkit-border-radius:100%;
294
+ border-radius:100%;
295
+ -moz-transform:scale(0.05, 5);
296
+ -ms-transform:scale(0.05, 5);
297
+ -webkit-transform:scale(0.05, 5);
298
+ transform:scale(0.05, 5);
299
+ -moz-transition:all 0.2s ease;
300
+ -o-transition:all 0.2s ease;
301
+ -webkit-transition:all 0.2s ease;
302
+ transition:all 0.2s ease
303
+ }
304
+ .cb-checkbox.cb-sm, .cb-radio.cb-sm {
305
+ line-height:14px
306
+ }
307
+ .cb-checkbox.cb-md, .cb-radio.cb-md {
308
+ line-height:24px
309
+ }
310
+ .cb-checkbox.cb-lg, .cb-radio.cb-lg {
311
+ line-height:30px
312
+ }
313
+ .cb-checkbox.cb-sm i:before {
314
+ top:4px;
315
+ left:1px
316
+ }
317
+ .cb-checkbox.cb-sm i:after {
318
+ left:5px
319
+ }
320
+ .cb-checkbox.cb-md i:before {
321
+ top:10px;
322
+ left:5px
323
+ }
324
+ .cb-checkbox.cb-md i:after {
325
+ bottom:6px;
326
+ left:11px
327
+ }
328
+ .cb-checkbox.checked .cb-inner {
329
+ border-color:#0073aa;
330
+ background-color:#00a0d2;
331
+ box-shadow: 0 1px 0 rgba(120, 200, 230, 0.5) inset, 0 1px 0 rgba(0, 0, 0, 0.15);
332
+ }
333
+ .cb-checkbox.checked:hover .cb-inner {
334
+ background-color:#0091cd
335
+ }
336
+ .cb-checkbox.checked.cb-sm i:before {
337
+ top:4px;
338
+ left:1px
339
+ }
340
+ .cb-checkbox.checked.cb-sm i:after {
341
+ height:9px
342
+ }
343
+ .cb-checkbox.checked.cb-md i:before {
344
+ top:10px;
345
+ left:4px;
346
+ height:8px
347
+ }
348
+ .cb-checkbox.checked.cb-md i:after {
349
+ bottom:6px;
350
+ left:11px;
351
+ height:16px
352
+ }
353
+ .cb-checkbox.checked.cb-lg i:before {
354
+ top:11px;
355
+ left:6px;
356
+ height:12px
357
+ }
358
+ .cb-checkbox.checked.cb-lg i:after {
359
+ left:14px;
360
+ bottom:7px;
361
+ height:20px
362
+ }
363
+ .cb-checkbox.checked i:before {
364
+ top:6px;
365
+ left:2px;
366
+ height:6px
367
+ }
368
+ .cb-checkbox.checked i:after {
369
+ height:12px
370
+ }
371
+ .cb-radio.checked .cb-inner {
372
+ background:#fff;
373
+ box-shadow:0 0 3px #efefef
374
+ }
375
+ .cb-radio.checked i {
376
+ -moz-transform:scale(1.1, 1.1);
377
+ -ms-transform:scale(1.1, 1.1);
378
+ -webkit-transform:scale(1.1, 1.1);
379
+ transform:scale(1.1, 1.1);
380
+ background-color:#00a0d2
381
+ }
382
+ .cb-checkbox:hover .cb-inner, .cb-radio:hover .cb-inner {
383
+ border-color:#0073aa
384
+ }
385
+ .cb-switcher {
386
+ display:inline-block;
387
+ border:1px solid #eee;
388
+ background-color:#fff;
389
+ width:95px;
390
+ height:35px;
391
+ position:relative;
392
+ -moz-border-radius:20px;
393
+ -webkit-border-radius:20px;
394
+ border-radius:20px;
395
+ -moz-transition:background 0.4s ease;
396
+ -o-transition:background 0.4s ease;
397
+ -webkit-transition:background 0.4s ease;
398
+ transition:background 0.4s ease
399
+ }
400
+ .cb-switcher, .cb-switcher * {
401
+ cursor:pointer
402
+ }
403
+ .cb-switcher ::-moz-selection {
404
+ background-color:transparent
405
+ }
406
+ .cb-switcher ::selection {
407
+ background-color:transparent
408
+ }
409
+ .cb-switcher .cb-state {
410
+ z-index:1;
411
+ text-align:center;
412
+ font-size:12px
413
+ }
414
+ .cb-switcher .cb-state, .cb-switcher:before {
415
+ width:34px;
416
+ height:34px;
417
+ line-height:34px;
418
+ position:absolute;
419
+ left:0;
420
+ top:-1px;
421
+ -moz-border-radius:100%;
422
+ -webkit-border-radius:100%;
423
+ border-radius:100%;
424
+ -moz-transition:all 0.4s ease;
425
+ -o-transition:all 0.4s ease;
426
+ -webkit-transition:all 0.4s ease;
427
+ transition:all 0.4s ease
428
+ }
429
+ .cb-switcher:before {
430
+ content:"";
431
+ background-color:#eee;
432
+ -moz-box-shadow:1px 1px 1px rgba(0, 0, 0, 0.1);
433
+ -webkit-box-shadow:1px 1px 1px rgba(0, 0, 0, 0.1);
434
+ box-shadow:1px 1px 1px rgba(0, 0, 0, 0.1)
435
+ }
436
+ .cb-switcher.checked {
437
+ background-color:#00a0d2
438
+ }
439
+ .cb-switcher.checked .cb-state, .cb-switcher.checked:before {
440
+ left:60px;
441
+ color:#00a0d2
442
+ }
443
+ .cb-switcher.checked:before {
444
+ background-color:#fff;
445
+ -moz-box-shadow:-1px 1px 1px rgba(0, 0, 0, 0.1);
446
+ -webkit-box-shadow:-1px 1px 1px rgba(0, 0, 0, 0.1);
447
+ box-shadow:-1px 1px 1px rgba(0, 0, 0, 0.1)
448
+ }
449
+ .cb-switcher.checked .inner-switcher:before {
450
+ border-top-color:#0073aa
451
+ }
452
+ .cb-switcher.checked .inner-switcher:after {
453
+ border-bottom-color:#0073aa
454
+ }
455
+ .cb-switcher .inner-switcher:before, .cb-switcher .inner-switcher:after {
456
+ content:"";
457
+ position:absolute;
458
+ left:50%;
459
+ width:0;
460
+ height:0;
461
+ z-index:2;
462
+ margin-left:-20px;
463
+ border-left:20px solid transparent;
464
+ border-right:20px solid transparent;
465
+ -moz-transition:border 0.4s ease;
466
+ -o-transition:border 0.4s ease;
467
+ -webkit-transition:border 0.4s ease;
468
+ transition:border 0.4s ease
469
+ }
470
+ .cb-switcher .inner-switcher:before {
471
+ border-top:17px solid #fff;
472
+ top:0
473
+ }
474
+ .cb-switcher .inner-switcher:after {
475
+ border-bottom:17px solid #fff;
476
+ bottom:0
477
+ }
478
+ .cb-state {
479
+ color:#ccc;
480
+ display:inline-block
481
+ }
482
+ .cb-switcher-group .cb-state {
483
+ position:relative;
484
+ top:7px
485
+ }
486
+ .is-hidden {
487
+ display:none !important;
488
+ visibility:hidden !important
489
+ }
490
+ output {
491
+ display: block;
492
+ font-size: 30px;
493
+ font-weight: bold;
494
+ text-align: center;
495
+ margin: 30px 0;
496
+ width: 100%;
497
  }
images/logo-dfactory.png DELETED
Binary file
includes/columns.php CHANGED
@@ -14,11 +14,13 @@ class Post_Views_Counter_Columns {
14
  // actions
15
  add_action( 'admin_init', array( $this, 'register_new_column' ) );
16
  add_action( 'post_submitbox_misc_actions', array( $this, 'submitbox_views' ) );
 
17
  add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
 
18
  add_action( 'bulk_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
19
  add_action( 'quick_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
20
  add_action( 'wp_ajax_save_bulk_post_views', array( $this, 'save_bulk_post_views' ) );
21
-
22
  // gutenberg
23
  add_action( 'plugins_loaded', array( $this, 'init_gutemberg' ) );
24
  }
@@ -54,15 +56,19 @@ class Post_Views_Counter_Columns {
54
  */
55
  public function gutenberg_rest_api_init() {
56
  // get views route
57
- register_rest_route( 'post-views-counter', '/update-post-views/', array(
58
- 'methods' => array( 'POST' ),
59
- 'callback' => array( $this, 'gutenberg_update_callback' ),
60
- 'args' => array(
61
- 'id' => array(
62
- 'sanitize_callback' => 'absint',
 
 
 
 
63
  )
64
  )
65
- ) );
66
  }
67
 
68
  /**
@@ -97,10 +103,7 @@ class Post_Views_Counter_Columns {
97
 
98
  global $wpdb;
99
 
100
- $count = apply_filters( 'pvc_update_post_views_count', $post_views, $post_id );
101
-
102
- // insert or update db post views count
103
- $wpdb->query( $wpdb->prepare( "INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count) VALUES (%d, %d, %s, %d) ON DUPLICATE KEY UPDATE count = %d", $post_id, 4, 'total', $count, $count ) );
104
 
105
  do_action( 'pvc_after_update_post_views_count', $post_id );
106
 
@@ -156,9 +159,7 @@ class Post_Views_Counter_Columns {
156
  public function submitbox_views() {
157
  global $post;
158
 
159
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
160
-
161
- if ( ! in_array( $post->post_type, (array) $post_types ) )
162
  return;
163
 
164
  // break if current user can't edit this post
@@ -209,7 +210,12 @@ class Post_Views_Counter_Columns {
209
  * @param int $post_id
210
  * @param object $post
211
  */
212
- public function save_post( $post_id, $post ) {
 
 
 
 
 
213
  // break if doing autosave
214
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
215
  return $post_id;
@@ -232,7 +238,7 @@ class Post_Views_Counter_Columns {
232
  // break if post views in not one of the selected
233
  $post_types = Post_Views_Counter()->options['general']['post_types_count'];
234
 
235
- if ( ! in_array( $post->post_type, (array) $post_types ) )
236
  return $post_id;
237
 
238
  // break if views editing is restricted
@@ -245,12 +251,7 @@ class Post_Views_Counter_Columns {
245
  if ( ! isset( $_POST['pvc_nonce'] ) || ! wp_verify_nonce( $_POST['pvc_nonce'], 'post_views_count' ) )
246
  return $post_id;
247
 
248
- global $wpdb;
249
-
250
- $count = apply_filters( 'pvc_update_post_views_count', $post_views, $post_id );
251
-
252
- // insert or update db post views count
253
- $wpdb->query( $wpdb->prepare( "INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count) VALUES (%d, %d, %s, %d) ON DUPLICATE KEY UPDATE count = %d", $post_id, 4, 'total', $count, $count ) );
254
 
255
  do_action( 'pvc_after_update_post_views_count', $post_id );
256
  }
@@ -263,12 +264,28 @@ class Post_Views_Counter_Columns {
263
 
264
  if ( ! empty( $post_types ) ) {
265
  foreach ( $post_types as $post_type ) {
266
- // actions
267
- add_action( 'manage_' . $post_type . '_posts_custom_column', array( $this, 'add_new_column_content' ), 10, 2 );
268
-
269
- // filters
270
- add_filter( 'manage_' . $post_type . '_posts_columns', array( $this, 'add_new_column' ) );
271
- add_filter( 'manage_edit-' . $post_type . '_sortable_columns', array( $this, 'register_sortable_custom_column' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  }
273
  }
274
  }
@@ -296,10 +313,10 @@ class Post_Views_Counter_Columns {
296
  $offset = 0;
297
 
298
  if ( isset( $columns['date'] ) )
299
- $offset ++;
300
 
301
  if ( isset( $columns['comments'] ) )
302
- $offset ++;
303
 
304
  if ( $offset > 0 ) {
305
  $date = array_slice( $columns, -$offset, $offset, true );
14
  // actions
15
  add_action( 'admin_init', array( $this, 'register_new_column' ) );
16
  add_action( 'post_submitbox_misc_actions', array( $this, 'submitbox_views' ) );
17
+ add_action( 'attachment_submitbox_misc_actions', array( $this, 'submitbox_views' ) );
18
  add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
19
+ add_action( 'edit_attachment', array( $this, 'save_post' ), 10 );
20
  add_action( 'bulk_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
21
  add_action( 'quick_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
22
  add_action( 'wp_ajax_save_bulk_post_views', array( $this, 'save_bulk_post_views' ) );
23
+
24
  // gutenberg
25
  add_action( 'plugins_loaded', array( $this, 'init_gutemberg' ) );
26
  }
56
  */
57
  public function gutenberg_rest_api_init() {
58
  // get views route
59
+ register_rest_route(
60
+ 'post-views-counter',
61
+ '/update-post-views/',
62
+ array(
63
+ 'methods' => array( 'POST' ),
64
+ 'callback' => array( $this, 'gutenberg_update_callback' ),
65
+ 'args' => array(
66
+ 'id' => array(
67
+ 'sanitize_callback' => 'absint',
68
+ )
69
  )
70
  )
71
+ );
72
  }
73
 
74
  /**
103
 
104
  global $wpdb;
105
 
106
+ pvc_update_post_views( $post_id, $post_views );
 
 
 
107
 
108
  do_action( 'pvc_after_update_post_views_count', $post_id );
109
 
159
  public function submitbox_views() {
160
  global $post;
161
 
162
+ if ( ! in_array( $post->post_type, (array) Post_Views_Counter()->options['general']['post_types_count'] ) )
 
 
163
  return;
164
 
165
  // break if current user can't edit this post
210
  * @param int $post_id
211
  * @param object $post
212
  */
213
+ public function save_post( $post_id, $post = null ) {
214
+ if ( is_null( $post ) )
215
+ $post_type = get_post_type( $post_id );
216
+ else
217
+ $post_type = $post->post_type;
218
+
219
  // break if doing autosave
220
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
221
  return $post_id;
238
  // break if post views in not one of the selected
239
  $post_types = Post_Views_Counter()->options['general']['post_types_count'];
240
 
241
+ if ( ! in_array( $post_type, (array) $post_types ) )
242
  return $post_id;
243
 
244
  // break if views editing is restricted
251
  if ( ! isset( $_POST['pvc_nonce'] ) || ! wp_verify_nonce( $_POST['pvc_nonce'], 'post_views_count' ) )
252
  return $post_id;
253
 
254
+ pvc_update_post_views( $post_id, $post_views );
 
 
 
 
 
255
 
256
  do_action( 'pvc_after_update_post_views_count', $post_id );
257
  }
264
 
265
  if ( ! empty( $post_types ) ) {
266
  foreach ( $post_types as $post_type ) {
267
+ if ( $post_type === 'attachment' ) {
268
+ // actions
269
+ add_action( 'manage_media_custom_column', array( $this, 'add_new_column_content' ), 10, 2 );
270
+
271
+ // filters
272
+ add_filter( 'manage_media_columns', array( $this, 'add_new_column' ) );
273
+ add_filter( 'manage_upload_sortable_columns', array( $this, 'register_sortable_custom_column' ) );
274
+ } else {
275
+ // actions
276
+ add_action( 'manage_' . $post_type . '_posts_custom_column', array( $this, 'add_new_column_content' ), 10, 2 );
277
+
278
+ // filters
279
+ add_filter( 'manage_' . $post_type . '_posts_columns', array( $this, 'add_new_column' ) );
280
+ add_filter( 'manage_edit-' . $post_type . '_sortable_columns', array( $this, 'register_sortable_custom_column' ) );
281
+
282
+ if ( class_exists( 'bbPress' ) ) {
283
+ if ( $post_type === 'forum' )
284
+ add_filter( 'bbp_admin_forums_column_headers', array( $this, 'add_new_column' ) );
285
+ elseif ( $post_type === 'topic' )
286
+ add_filter( 'bbp_admin_topics_column_headers', array( $this, 'add_new_column' ) );
287
+ }
288
+ }
289
  }
290
  }
291
  }
313
  $offset = 0;
314
 
315
  if ( isset( $columns['date'] ) )
316
+ $offset++;
317
 
318
  if ( isset( $columns['comments'] ) )
319
+ $offset++;
320
 
321
  if ( $offset > 0 ) {
322
  $date = array_slice( $columns, -$offset, $offset, true );
includes/counter.php CHANGED
@@ -1,740 +1,795 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Counter class.
8
- *
9
- * @class Post_Views_Counter_Counter
10
- */
11
- class Post_Views_Counter_Counter {
12
-
13
- const GROUP = 'pvc';
14
- const NAME_ALLKEYS = 'cached_key_names';
15
- const CACHE_KEY_SEPARATOR = '.';
16
-
17
- private $cookie = array(
18
- 'exists' => false,
19
- 'visited_posts' => array(),
20
- 'expiration' => 0
21
- );
22
-
23
- public function __construct() {
24
- // actions
25
- add_action( 'plugins_loaded', array( $this, 'check_cookie' ), 1 );
26
- add_action( 'deleted_post', array( $this, 'delete_post_views' ) );
27
- add_action( 'wp', array( $this, 'check_post_php' ) );
28
- add_action( 'wp_ajax_pvc-check-post', array( $this, 'check_post_js' ) );
29
- add_action( 'wp_ajax_nopriv_pvc-check-post', array( $this, 'check_post_js' ) );
30
- add_action( 'pvc_ajax_pvc-check-post', array( $this, 'check_post_ajax' ) );
31
- add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
32
- }
33
-
34
- /**
35
- * Check whether to count visit.
36
- *
37
- * @param int $id
38
- */
39
- public function check_post( $id = 0 ) {
40
- // force check post in SHORTINIT mode
41
- if ( defined( 'SHORTINIT' ) && SHORTINIT )
42
- $this->check_cookie();
43
-
44
- // get post id
45
- $id = (int) ( empty( $id ) ? get_the_ID() : $id );
46
-
47
- // get user id, from current user or static var in rest api request
48
- $user_id = get_current_user_id();
49
-
50
- // get user IP address
51
- $user_ip = (string) $this->get_user_ip();
52
-
53
- // empty id?
54
- if ( empty( $id ) )
55
- return;
56
-
57
- do_action( 'pvc_before_check_visit', $id, $user_id, $user_ip );
58
-
59
- // get ips
60
- $ips = Post_Views_Counter()->options['general']['exclude_ips'];
61
-
62
- // whether to count this ip
63
- if ( ! empty( $ips ) && filter_var( preg_replace( '/[^0-9a-fA-F:., ]/', '', $user_ip ), FILTER_VALIDATE_IP ) ) {
64
- // check ips
65
- foreach ( $ips as $ip ) {
66
- if ( strpos( $ip, '*' ) !== false ) {
67
- if ( $this->ipv4_in_range( $user_ip, $ip ) )
68
- return;
69
- } else {
70
- if ( $user_ip === $ip )
71
- return;
72
- }
73
- }
74
- }
75
-
76
- // get groups to check them faster
77
- $groups = Post_Views_Counter()->options['general']['exclude']['groups'];
78
-
79
- // whether to count this user
80
- if ( ! empty( $user_id ) ) {
81
- // exclude logged in users?
82
- if ( in_array( 'users', $groups, true ) )
83
- return;
84
- // exclude specific roles?
85
- elseif ( in_array( 'roles', $groups, true ) && $this->is_user_role_excluded( $user_id, Post_Views_Counter()->options['general']['exclude']['roles'] ) )
86
- return;
87
- // exclude guests?
88
- } elseif ( in_array( 'guests', $groups, true ) )
89
- return;
90
-
91
- // whether to count robots
92
- if ( in_array( 'robots', $groups, true ) && Post_Views_Counter()->crawler_detect->is_crawler() )
93
- return;
94
-
95
- $current_time = current_time( 'timestamp', true );
96
-
97
- // cookie already existed?
98
- if ( $this->cookie['exists'] ) {
99
- // post already viewed but not expired?
100
- if ( in_array( $id, array_keys( $this->cookie['visited_posts'] ), true ) && $current_time < $this->cookie['visited_posts'][$id] ) {
101
- // update cookie but do not count visit
102
- $this->save_cookie( $id, $this->cookie, false );
103
-
104
- return;
105
- // update cookie
106
- } else
107
- $this->save_cookie( $id, $this->cookie );
108
- } else {
109
- // set new cookie
110
- $this->save_cookie( $id );
111
- }
112
-
113
- $count_visit = (bool) apply_filters( 'pvc_count_visit', true, $id );
114
-
115
- // count visit
116
- if ( $count_visit ) {
117
- // strict counts?
118
- if ( Post_Views_Counter()->options['general']['strict_counts'] )
119
- $this->save_ip( $id );
120
-
121
- return $this->count_visit( $id );
122
- } else
123
- return;
124
- }
125
-
126
- /**
127
- * Check whether to count visit via PHP request.
128
- */
129
- public function check_post_php() {
130
- // do not count admin entries
131
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
132
- return;
133
-
134
- // do we use PHP as counter?
135
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'php' )
136
- return;
137
-
138
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
139
-
140
- // whether to count this post type
141
- if ( empty( $post_types ) || ! is_singular( $post_types ) )
142
- return;
143
-
144
- $this->check_post( get_the_ID() );
145
- }
146
-
147
- /**
148
- * Check whether to count visit via Javascript(Ajax) request.
149
- */
150
- public function check_post_js() {
151
- if ( isset( $_POST['action'], $_POST['id'], $_POST['pvc_nonce'] ) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int) $_POST['id']) > 0 && wp_verify_nonce( $_POST['pvc_nonce'], 'pvc-check-post' ) !== false ) {
152
-
153
- // do we use Ajax as counter?
154
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'js' )
155
- exit;
156
-
157
- // get countable post types
158
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
159
-
160
- // check if post exists
161
- $post = get_post( $post_id );
162
-
163
- // whether to count this post type or not
164
- if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
165
- exit;
166
-
167
- $this->check_post( $post_id );
168
- }
169
-
170
- exit;
171
- }
172
-
173
- /**
174
- * Check whether to count visit via Fast AJAX request.
175
- */
176
- public function check_post_ajax() {
177
- if ( isset( $_POST['action'], $_POST['id'], $_POST['pvc_nonce'] ) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int) $_POST['id']) > 0 ) {
178
-
179
- // do we use Ajax as counter?
180
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'ajax' )
181
- exit;
182
-
183
- // get countable post types
184
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
185
-
186
- // check if post exists
187
- $post = get_post( $post_id );
188
-
189
- // whether to count this post type or not
190
- if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
191
- exit;
192
-
193
- $this->check_post( $post_id );
194
- }
195
-
196
- exit;
197
- }
198
-
199
- /**
200
- * Check whether to count visit via REST API request.
201
- *
202
- * @param array $request
203
- * @return int|bool
204
- */
205
- public function check_post_rest_api( $request ) {
206
- $post_id = absint( $request['id'] );
207
-
208
- // do we use REST API as counter?
209
- if ( Post_Views_Counter()->options['general']['counter_mode'] != 'rest_api' )
210
- return new WP_Error( 'pvc_rest_api_disabled', __( 'REST API method is disabled.', 'post-views-counter' ), array( 'status' => 404 ) );
211
-
212
- // @todo: get current user id in direct api endpoint calls
213
-
214
- // check if post exists
215
- $post = get_post( $post_id );
216
-
217
- if ( ! $post )
218
- return new WP_Error( 'pvc_post_invalid_id', __( 'Invalid post ID.', 'post-views-counter' ), array( 'status' => 404 ) );
219
-
220
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
221
-
222
- // whether to count this post type
223
- if ( empty( $post_types ) || ! in_array( $post->post_type, $post_types ) )
224
- return new WP_Error( 'pvc_post_type_excluded', __( 'Post type excluded.', 'post-views-counter' ), array( 'status' => 404 ) );
225
-
226
- return $this->check_post( $post_id );
227
- }
228
-
229
- /**
230
- * Initialize cookie session.
231
- */
232
- public function check_cookie() {
233
- // do not run in admin except for ajax requests
234
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
235
- return;
236
-
237
- // assign cookie name
238
- $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' );
239
-
240
- // is cookie set?
241
- if ( isset( $_COOKIE[$cookie_name] ) && ! empty( $_COOKIE[$cookie_name] ) ) {
242
- $visited_posts = $expirations = array();
243
-
244
- foreach ( $_COOKIE[$cookie_name] as $content ) {
245
- // is cookie valid?
246
- if ( preg_match( '/^(([0-9]+b[0-9]+a?)+)$/', $content ) === 1 ) {
247
- // get single id with expiration
248
- $expiration_ids = explode( 'a', $content );
249
-
250
- // check every expiration => id pair
251
- foreach ( $expiration_ids as $pair ) {
252
- $pair = explode( 'b', $pair );
253
- $expirations[] = (int) $pair[0];
254
- $visited_posts[(int) $pair[1]] = (int) $pair[0];
255
- }
256
- }
257
- }
258
-
259
- $this->cookie = array(
260
- 'exists' => true,
261
- 'visited_posts' => $visited_posts,
262
- 'expiration' => max( $expirations )
263
- );
264
- }
265
- }
266
-
267
- /**
268
- * Save cookie function.
269
- *
270
- * @param int $id
271
- * @param array $cookie
272
- * @param bool $expired
273
- */
274
- private function save_cookie( $id, $cookie = array(), $expired = true ) {
275
- $set_cookie = apply_filters( 'pvc_maybe_set_cookie', true );
276
-
277
- // Cookie Notice compatibility
278
- if ( function_exists( 'cn_cookies_accepted' ) && ! cn_cookies_accepted() )
279
- $set_cookie = false;
280
-
281
- if ( $set_cookie !== true )
282
- return $id;
283
-
284
- $expiration = $this->get_timestamp( Post_Views_Counter()->options['general']['time_between_counts']['type'], Post_Views_Counter()->options['general']['time_between_counts']['number'] );
285
-
286
- // assign cookie name
287
- $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' );
288
-
289
- // is this a new cookie?
290
- if ( empty( $cookie ) ) {
291
- // set cookie
292
- setcookie( $cookie_name . '[0]', $expiration . 'b' . $id, $expiration, COOKIEPATH, COOKIE_DOMAIN, (isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ? true : false ), true );
293
- } else {
294
- if ( $expired ) {
295
- // add new id or change expiration date if id already exists
296
- $cookie['visited_posts'][$id] = $expiration;
297
- }
298
-
299
- // create copy for better foreach performance
300
- $visited_posts_expirations = $cookie['visited_posts'];
301
-
302
- // get current gmt time
303
- $time = current_time( 'timestamp', true );
304
-
305
- // check whether viewed id has expired - no need to keep it in cookie (less size)
306
- foreach ( $visited_posts_expirations as $post_id => $post_expiration ) {
307
- if ( $time > $post_expiration )
308
- unset( $cookie['visited_posts'][$post_id] );
309
- }
310
-
311
- // set new last expiration date if needed
312
- $cookie['expiration'] = max( $cookie['visited_posts'] );
313
-
314
- $cookies = $imploded = array();
315
-
316
- // create pairs
317
- foreach ( $cookie['visited_posts'] as $id => $exp ) {
318
- $imploded[] = $exp . 'b' . $id;
319
- }
320
-
321
- // split cookie into chunks (4000 bytes to make sure it is safe for every browser)
322
- $chunks = str_split( implode( 'a', $imploded ), 4000 );
323
-
324
- // more then one chunk?
325
- if ( count( $chunks ) > 1 ) {
326
- $last_id = '';
327
-
328
- foreach ( $chunks as $chunk_id => $chunk ) {
329
- // new chunk
330
- $chunk_c = $last_id . $chunk;
331
-
332
- // is it full-length chunk?
333
- if ( strlen( $chunk ) === 4000 ) {
334
- // get last part
335
- $last_part = strrchr( $chunk_c, 'a' );
336
-
337
- // get last id
338
- $last_id = substr( $last_part, 1 );
339
-
340
- // add new full-lenght chunk
341
- $cookies[$chunk_id] = substr( $chunk_c, 0, strlen( $chunk_c ) - strlen( $last_part ) );
342
- } else {
343
- // add last chunk
344
- $cookies[$chunk_id] = $chunk_c;
345
- }
346
- }
347
- } else {
348
- // only one chunk
349
- $cookies[] = $chunks[0];
350
- }
351
-
352
- foreach ( $cookies as $key => $value ) {
353
- // set cookie
354
- setcookie( $cookie_name . '[' . $key . ']', $value, $cookie['expiration'], COOKIEPATH, COOKIE_DOMAIN, (isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ? true : false ), true );
355
- }
356
- }
357
- }
358
-
359
- /**
360
- * Save user IP function.
361
- *
362
- * @param int $id
363
- */
364
- private function save_ip( $id ) {
365
- $set_cookie = apply_filters( 'pvc_maybe_set_cookie', true );
366
-
367
- // Cookie Notice compatibility
368
- if ( function_exists( 'cn_cookies_accepted' ) && ! cn_cookies_accepted() )
369
- $set_cookie = false;
370
-
371
- if ( $set_cookie !== true )
372
- return $id;
373
-
374
- // get IP cached visits
375
- $ip_cache = get_transient( 'post_views_counter_ip_cache' );
376
-
377
- if ( ! $ip_cache )
378
- $ip_cache = array();
379
-
380
- // get user IP address
381
- $user_ip = (string) $this->get_user_ip();
382
-
383
- // get current time
384
- $current_time = current_time( 'timestamp', true );
385
-
386
- // visit exists in transient?
387
- if ( isset( $ip_cache[$id][$user_ip] ) ) {
388
- if ( $current_time > $ip_cache[$id][$user_ip] + $this->get_timestamp( Post_Views_Counter()->options['general']['time_between_counts']['type'], Post_Views_Counter()->options['general']['time_between_counts']['number'], false ) )
389
- $ip_cache[$id][$user_ip] = $current_time;
390
- else
391
- return;
392
- } else
393
- $ip_cache[$id][$user_ip] = $current_time;
394
-
395
- // keep it light, only 10 records per post and maximum 100 post records (=> max. 1000 ip entries)
396
- // also, the data gets deleted after a week if there's no activity during this time...
397
- if ( count( $ip_cache[$id] ) > 10 )
398
- $ip_cache[$id] = array_slice( $ip_cache[$id], -10, 10, true );
399
-
400
- if ( count( $ip_cache ) > 100 )
401
- $ip_cache = array_slice( $ip_cache, -100, 100, true );
402
-
403
- set_transient( 'post_views_counter_ip_cache', $ip_cache, WEEK_IN_SECONDS );
404
- }
405
-
406
- /**
407
- * Count visit function.
408
- *
409
- * @global object $wpdb
410
- * @param int $id
411
- * @return int $id
412
- */
413
- private function count_visit( $id ) {
414
- global $wpdb;
415
-
416
- $cache_key_names = array();
417
- $using_object_cache = $this->using_object_cache();
418
- $increment_amount = (int) apply_filters( 'pvc_views_increment_amount', 1, $id );
419
-
420
- // get day, week, month and year
421
- $date = explode( '-', date( 'W-d-m-Y', current_time( 'timestamp' ) ) );
422
-
423
- foreach ( array(
424
- 0 => $date[3] . $date[2] . $date[1], // day like 20140324
425
- 1 => $date[3] . $date[0], // week like 201439
426
- 2 => $date[3] . $date[2], // month like 201405
427
- 3 => $date[3], // year like 2014
428
- 4 => 'total' // total views
429
- ) as $type => $period ) {
430
- if ( $using_object_cache ) {
431
- $cache_key = $id . self::CACHE_KEY_SEPARATOR . $type . self::CACHE_KEY_SEPARATOR . $period;
432
- wp_cache_add( $cache_key, 0, self::GROUP );
433
- wp_cache_incr( $cache_key, $increment_amount, self::GROUP );
434
- $cache_key_names[] = $cache_key;
435
- } else {
436
- // hit the db directly
437
- // @TODO: investigate queueing these queries on the 'shutdown' hook instead of running them instantly?
438
- $this->db_insert( $id, $type, $period, $increment_amount );
439
- }
440
- }
441
-
442
- // update the list of cache keys to be flushed
443
- if ( $using_object_cache && ! empty( $cache_key_names ) )
444
- $this->update_cached_keys_list_if_needed( $cache_key_names );
445
-
446
- do_action( 'pvc_after_count_visit', $id );
447
-
448
- return $id;
449
- }
450
-
451
- /**
452
- * Remove post views from database when post is deleted.
453
- *
454
- * @global object $wpdb
455
- * @param int $post_id
456
- */
457
- public function delete_post_views( $post_id ) {
458
- global $wpdb;
459
-
460
- $wpdb->delete( $wpdb->prefix . 'post_views', array( 'id' => $post_id ), array( '%d' ) );
461
- }
462
-
463
- /**
464
- * Get timestamp convertion.
465
- *
466
- * @param string $type
467
- * @param int $number
468
- * @param int $timestamp
469
- * @return string
470
- */
471
- public function get_timestamp( $type, $number, $timestamp = true ) {
472
- $converter = array(
473
- 'minutes' => 60,
474
- 'hours' => 3600,
475
- 'days' => 86400,
476
- 'weeks' => 604800,
477
- 'months' => 2592000,
478
- 'years' => 946080000
479
- );
480
-
481
- return (int) ( ( $timestamp ? current_time( 'timestamp', true ) : 0 ) + $number * $converter[$type] );
482
- }
483
-
484
- /**
485
- * Check if object cache is in use.
486
- *
487
- * @param bool $using
488
- * @return bool
489
- */
490
- public function using_object_cache( $using = null ) {
491
- $using = wp_using_ext_object_cache( $using );
492
-
493
- if ( $using ) {
494
- // check if explicitly disabled by flush_interval setting/option <= 0
495
- $flush_interval_number = Post_Views_Counter()->options['general']['flush_interval']['number'];
496
- $using = ( $flush_interval_number <= 0 ) ? false : true;
497
- }
498
-
499
- return $using;
500
- }
501
-
502
- /**
503
- * Update the single cache key which holds a list of all the cache keys
504
- * that need to be flushed to the db.
505
- *
506
- * The value of that special cache key is a giant string containing key names separated with the `|` character.
507
- * Each such key name then consists of 3 elements: $id, $type, $period (separated by a `.` character).
508
- * Examples:
509
- * 62053.0.20150327|62053.1.201513|62053.2.201503|62053.3.2015|62053.4.total|62180.0.20150327|62180.1.201513|62180.2.201503|62180.3.2015|62180.4.total
510
- * A single key is `62053.0.20150327` and that key's data is: $id = 62053, $type = 0, $period = 20150327
511
- *
512
- * This data format proved more efficient (avoids the (un)serialization overhead completely + duplicates filtering is a string search now)
513
- *
514
- * @param array $key_names
515
- */
516
- private function update_cached_keys_list_if_needed( $key_names = array() ) {
517
- $existing_list = wp_cache_get( self::NAME_ALLKEYS, self::GROUP );
518
- if ( ! $existing_list )
519
- $existing_list = '';
520
-
521
- $list_modified = false;
522
-
523
- // modify the list contents if/when needed
524
- if ( empty( $existing_list ) ) {
525
- // the simpler case of an empty initial list where we just
526
- // transform the specified key names into a string
527
- $existing_list = implode( '|', $key_names );
528
- $list_modified = true;
529
- } else {
530
- // search each specified key name and append it if it's not found
531
- foreach ( $key_names as $key_name ) {
532
- if ( false === strpos( $existing_list, $key_name ) ) {
533
- $existing_list .= '|' . $key_name;
534
- $list_modified = true;
535
- }
536
- }
537
- }
538
-
539
- // save modified list back in cache
540
- if ( $list_modified ) {
541
- wp_cache_set( self::NAME_ALLKEYS, $existing_list, self::GROUP );
542
- }
543
- }
544
-
545
- /**
546
- * Flush views data stored in the persistent object cache into
547
- * our custom table and clear the object cache keys when done.
548
- *
549
- * @global object $wpdb
550
- * @return bool
551
- */
552
- public function flush_cache_to_db() {
553
- global $wpdb;
554
-
555
- $key_names = wp_cache_get( self::NAME_ALLKEYS, self::GROUP );
556
-
557
- if ( ! $key_names )
558
- $key_names = array();
559
- else {
560
- // create an array out of a string that's stored in the cache
561
- $key_names = explode( '|', $key_names );
562
- }
563
-
564
- foreach ( $key_names as $key_name ) {
565
- // get values stored within the key name itself
566
- list( $id, $type, $period ) = explode( self::CACHE_KEY_SEPARATOR, $key_name );
567
- // get the cached count value
568
- $count = wp_cache_get( $key_name, self::GROUP );
569
-
570
- // store cached value in the db
571
- $this->db_insert( $id, $type, $period, $count );
572
-
573
- // clear the cache key we just flushed
574
- wp_cache_delete( $key_name, self::GROUP );
575
- }
576
-
577
- // delete the key holding the list itself after we've successfully flushed it
578
- if ( ! empty( $key_names ) )
579
- wp_cache_delete( self::NAME_ALLKEYS, self::GROUP );
580
-
581
- return true;
582
- }
583
-
584
- /**
585
- * Insert or update views count.
586
- *
587
- * @global object $wpdb
588
- * @param int $id
589
- * @param string $type
590
- * @param string $period
591
- * @param int $count
592
- * @return bool
593
- */
594
- private function db_insert( $id, $type, $period, $count = 1 ) {
595
- global $wpdb;
596
-
597
- $count = (int) $count;
598
-
599
- if ( ! $count ) {
600
- $count = 1;
601
- }
602
-
603
- return $wpdb->query(
604
- $wpdb->prepare( "
605
- INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count)
606
- VALUES (%d, %d, %s, %d)
607
- ON DUPLICATE KEY UPDATE count = count + %d", $id, $type, $period, $count, $count
608
- )
609
- );
610
- }
611
-
612
- /**
613
- * Check whether user has excluded roles.
614
- *
615
- * @param string $option
616
- * @return bool
617
- */
618
- public function is_user_role_excluded( $user_id, $option ) {
619
- $user = get_user_by( 'id', $user_id );
620
-
621
- if ( empty( $user ) )
622
- return false;
623
-
624
- $roles = (array) $user->roles;
625
-
626
- if ( ! empty( $roles ) ) {
627
- foreach ( $roles as $role ) {
628
- if ( in_array( $role, $option, true ) )
629
- return true;
630
- }
631
- }
632
-
633
- return false;
634
- }
635
-
636
- /**
637
- * Check if IPv4 is in range.
638
- *
639
- * @param string $ip IP address
640
- * @param string $range IP range
641
- * @return boolean Whether IP is in range
642
- */
643
- public function ipv4_in_range( $ip, $range ) {
644
- $start = str_replace( '*', '0', $range );
645
- $end = str_replace( '*', '255', $range );
646
- $ip = (float) sprintf( "%u", ip2long( $ip ) );
647
-
648
- return ( $ip >= (float) sprintf( "%u", ip2long( $start ) ) && $ip <= (float) sprintf( "%u", ip2long( $end ) ) );
649
- }
650
-
651
- /**
652
- * Get user real IP address.
653
- *
654
- * @return string
655
- */
656
- public function get_user_ip() {
657
- foreach ( array( 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR' ) as $key ) {
658
- if ( array_key_exists( $key, $_SERVER ) === true ) {
659
- foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {
660
- // trim for safety measures
661
- $ip = trim( $ip );
662
-
663
- // attempt to validate IP
664
- if ( $this->validate_user_ip( $ip ) )
665
- return $ip;
666
- }
667
- }
668
- }
669
-
670
- return isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
671
- }
672
-
673
- /**
674
- * Ensure an ip address is both a valid IP and does not fall within a private network range.
675
- *
676
- * @param $ip
677
- * @return bool
678
- */
679
- public function validate_user_ip( $ip ) {
680
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) === false )
681
- return false;
682
-
683
- return true;
684
- }
685
-
686
- /**
687
- * Register REST API endpoints.
688
- *
689
- * @return void
690
- */
691
- public function rest_api_init() {
692
- // view post route
693
- register_rest_route( 'post-views-counter', '/view-post/', array(
694
- 'methods' => array( 'GET', 'POST' ),
695
- 'callback' => array( $this, 'check_post_rest_api' ),
696
- 'args' => array(
697
- 'id' => array(
698
- 'default' => 0,
699
- 'sanitize_callback' => 'absint'
700
- )
701
- )
702
- ) );
703
-
704
- // get views route
705
- register_rest_route( 'post-views-counter', '/get-post-views/', array(
706
- 'methods' => array( 'GET', 'POST' ),
707
- 'callback' => array( $this, 'get_post_views_rest_api' ),
708
- 'permission_callback' => array( $this, 'get_post_views_permissions_check' ),
709
- 'args' => array(
710
- 'id' => array(
711
- 'default' => 0,
712
- 'user_id' => get_current_user_id()
713
- )
714
- )
715
- ) );
716
- }
717
-
718
- /**
719
- * Get post views via REST API request.
720
- *
721
- * @param array $request
722
- * @return int
723
- */
724
- public function get_post_views_rest_api( $request ) {
725
- $post_id = is_array( $request['id'] ) ? array_map( 'absint', $request['id'] ) : absint( $request['id'] );
726
-
727
- return pvc_get_post_views( $post_id );
728
- }
729
-
730
- /**
731
- * Check if a given request has access to get views
732
- *
733
- * @param WP_REST_Request $request Full data about the request.
734
- * @return WP_Error|bool
735
- */
736
- public function get_post_views_permissions_check( $request ) {
737
- return (bool) apply_filters( 'pvc_rest_api_get_post_views_check', true, $request );
738
- }
739
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
  }
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Counter class.
8
+ *
9
+ * @class Post_Views_Counter_Counter
10
+ */
11
+ class Post_Views_Counter_Counter {
12
+
13
+ const GROUP = 'pvc';
14
+ const NAME_ALLKEYS = 'cached_key_names';
15
+ const CACHE_KEY_SEPARATOR = '.';
16
+ const MAX_INSERT_STRING_LENGTH = 25000;
17
+
18
+ private $db_insert_values = '';
19
+ private $cookie = array(
20
+ 'exists' => false,
21
+ 'visited_posts' => array(),
22
+ 'expiration' => 0
23
+ );
24
+
25
+ public function __construct() {
26
+ // actions
27
+ add_action( 'plugins_loaded', array( $this, 'check_cookie' ), 1 );
28
+ add_action( 'deleted_post', array( $this, 'delete_post_views' ) );
29
+ add_action( 'wp', array( $this, 'check_post_php' ) );
30
+ add_action( 'wp_ajax_pvc-check-post', array( $this, 'check_post_js' ) );
31
+ add_action( 'wp_ajax_nopriv_pvc-check-post', array( $this, 'check_post_js' ) );
32
+ add_action( 'pvc_ajax_pvc-check-post', array( $this, 'check_post_ajax' ) );
33
+ add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
34
+ }
35
+
36
+ /**
37
+ * Check whether to count visit.
38
+ *
39
+ * @param int $id
40
+ */
41
+ public function check_post( $id = 0 ) {
42
+ // force check post in SHORTINIT mode
43
+ if ( defined( 'SHORTINIT' ) && SHORTINIT )
44
+ $this->check_cookie();
45
+
46
+ // get post id
47
+ $id = (int) ( empty( $id ) ? get_the_ID() : $id );
48
+
49
+ // get user id, from current user or static var in rest api request
50
+ $user_id = get_current_user_id();
51
+
52
+ // get user IP address
53
+ $user_ip = (string) $this->get_user_ip();
54
+
55
+ // empty id?
56
+ if ( empty( $id ) )
57
+ return;
58
+
59
+ do_action( 'pvc_before_check_visit', $id, $user_id, $user_ip );
60
+
61
+ // get ips
62
+ $ips = Post_Views_Counter()->options['general']['exclude_ips'];
63
+
64
+ // whether to count this ip
65
+ if ( ! empty( $ips ) && filter_var( preg_replace( '/[^0-9a-fA-F:., ]/', '', $user_ip ), FILTER_VALIDATE_IP ) ) {
66
+ // check ips
67
+ foreach ( $ips as $ip ) {
68
+ if ( strpos( $ip, '*' ) !== false ) {
69
+ if ( $this->ipv4_in_range( $user_ip, $ip ) )
70
+ return;
71
+ } else {
72
+ if ( $user_ip === $ip )
73
+ return;
74
+ }
75
+ }
76
+ }
77
+
78
+ // get groups to check them faster
79
+ $groups = Post_Views_Counter()->options['general']['exclude']['groups'];
80
+
81
+ // whether to count this user
82
+ if ( ! empty( $user_id ) ) {
83
+ // exclude logged in users?
84
+ if ( in_array( 'users', $groups, true ) )
85
+ return;
86
+ // exclude specific roles?
87
+ elseif ( in_array( 'roles', $groups, true ) && $this->is_user_role_excluded( $user_id, Post_Views_Counter()->options['general']['exclude']['roles'] ) )
88
+ return;
89
+ // exclude guests?
90
+ } elseif ( in_array( 'guests', $groups, true ) )
91
+ return;
92
+
93
+ // whether to count robots
94
+ if ( in_array( 'robots', $groups, true ) && Post_Views_Counter()->crawler_detect->is_crawler() )
95
+ return;
96
+
97
+ $current_time = current_time( 'timestamp', true );
98
+
99
+ // cookie already existed?
100
+ if ( $this->cookie['exists'] ) {
101
+ // post already viewed but not expired?
102
+ if ( in_array( $id, array_keys( $this->cookie['visited_posts'] ), true ) && $current_time < $this->cookie['visited_posts'][$id] ) {
103
+ // update cookie but do not count visit
104
+ $this->save_cookie( $id, $this->cookie, false );
105
+
106
+ return;
107
+ // update cookie
108
+ } else
109
+ $this->save_cookie( $id, $this->cookie );
110
+ } else {
111
+ // set new cookie
112
+ $this->save_cookie( $id );
113
+ }
114
+
115
+ $count_visit = (bool) apply_filters( 'pvc_count_visit', true, $id );
116
+
117
+ // count visit
118
+ if ( $count_visit ) {
119
+ // strict counts?
120
+ if ( Post_Views_Counter()->options['general']['strict_counts'] )
121
+ $this->save_ip( $id );
122
+
123
+ return $this->count_visit( $id );
124
+ } else
125
+ return;
126
+ }
127
+
128
+ /**
129
+ * Check whether to count visit via PHP request.
130
+ */
131
+ public function check_post_php() {
132
+ // do not count admin entries
133
+ if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
134
+ return;
135
+
136
+ // do we use PHP as counter?
137
+ if ( Post_Views_Counter()->options['general']['counter_mode'] !== 'php' )
138
+ return;
139
+
140
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
141
+
142
+ // whether to count this post type
143
+ if ( empty( $post_types ) || ! is_singular( $post_types ) )
144
+ return;
145
+
146
+ $this->check_post( get_the_ID() );
147
+ }
148
+
149
+ /**
150
+ * Check whether to count visit via Javascript(Ajax) request.
151
+ */
152
+ public function check_post_js() {
153
+ if ( isset( $_POST['action'], $_POST['id'], $_POST['pvc_nonce'] ) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int) $_POST['id']) > 0 && wp_verify_nonce( $_POST['pvc_nonce'], 'pvc-check-post' ) !== false ) {
154
+
155
+ // do we use Ajax as counter?
156
+ if ( Post_Views_Counter()->options['general']['counter_mode'] != 'js' )
157
+ exit;
158
+
159
+ // get countable post types
160
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
161
+
162
+ // check if post exists
163
+ $post = get_post( $post_id );
164
+
165
+ // whether to count this post type or not
166
+ if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
167
+ exit;
168
+
169
+ $this->check_post( $post_id );
170
+ }
171
+
172
+ exit;
173
+ }
174
+
175
+ /**
176
+ * Check whether to count visit via Fast AJAX request.
177
+ */
178
+ public function check_post_ajax() {
179
+ if ( isset( $_POST['action'], $_POST['id'], $_POST['pvc_nonce'] ) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int) $_POST['id']) > 0 ) {
180
+
181
+ // do we use Ajax as counter?
182
+ if ( Post_Views_Counter()->options['general']['counter_mode'] != 'ajax' )
183
+ exit;
184
+
185
+ // get countable post types
186
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
187
+
188
+ // check if post exists
189
+ $post = get_post( $post_id );
190
+
191
+ // whether to count this post type or not
192
+ if ( empty( $post_types ) || empty( $post ) || ! in_array( $post->post_type, $post_types, true ) )
193
+ exit;
194
+
195
+ $this->check_post( $post_id );
196
+ }
197
+
198
+ exit;
199
+ }
200
+
201
+ /**
202
+ * Check whether to count visit via REST API request.
203
+ *
204
+ * @param array $request
205
+ * @return int|bool
206
+ */
207
+ public function check_post_rest_api( $request ) {
208
+ $post_id = absint( $request['id'] );
209
+
210
+ // do we use REST API as counter?
211
+ if ( Post_Views_Counter()->options['general']['counter_mode'] != 'rest_api' )
212
+ return new WP_Error( 'pvc_rest_api_disabled', __( 'REST API method is disabled.', 'post-views-counter' ), array( 'status' => 404 ) );
213
+
214
+ // @todo: get current user id in direct api endpoint calls
215
+
216
+ // check if post exists
217
+ $post = get_post( $post_id );
218
+
219
+ if ( ! $post )
220
+ return new WP_Error( 'pvc_post_invalid_id', __( 'Invalid post ID.', 'post-views-counter' ), array( 'status' => 404 ) );
221
+
222
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
223
+
224
+ // whether to count this post type
225
+ if ( empty( $post_types ) || ! in_array( $post->post_type, $post_types ) )
226
+ return new WP_Error( 'pvc_post_type_excluded', __( 'Post type excluded.', 'post-views-counter' ), array( 'status' => 404 ) );
227
+
228
+ return $this->check_post( $post_id );
229
+ }
230
+
231
+ /**
232
+ * Initialize cookie session.
233
+ */
234
+ public function check_cookie() {
235
+ // do not run in admin except for ajax requests
236
+ if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
237
+ return;
238
+
239
+ // assign cookie name
240
+ $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' );
241
+
242
+ // is cookie set?
243
+ if ( isset( $_COOKIE[$cookie_name] ) && ! empty( $_COOKIE[$cookie_name] ) ) {
244
+ $visited_posts = $expirations = array();
245
+
246
+ foreach ( $_COOKIE[$cookie_name] as $content ) {
247
+ // is cookie valid?
248
+ if ( preg_match( '/^(([0-9]+b[0-9]+a?)+)$/', $content ) === 1 ) {
249
+ // get single id with expiration
250
+ $expiration_ids = explode( 'a', $content );
251
+
252
+ // check every expiration => id pair
253
+ foreach ( $expiration_ids as $pair ) {
254
+ $pair = explode( 'b', $pair );
255
+ $expirations[] = (int) $pair[0];
256
+ $visited_posts[(int) $pair[1]] = (int) $pair[0];
257
+ }
258
+ }
259
+ }
260
+
261
+ $this->cookie = array(
262
+ 'exists' => true,
263
+ 'visited_posts' => $visited_posts,
264
+ 'expiration' => max( $expirations )
265
+ );
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Save cookie function.
271
+ *
272
+ * @param int $id
273
+ * @param array $cookie
274
+ * @param bool $expired
275
+ */
276
+ private function save_cookie( $id, $cookie = array(), $expired = true ) {
277
+ $set_cookie = apply_filters( 'pvc_maybe_set_cookie', true );
278
+
279
+ // Cookie Notice compatibility
280
+ if ( function_exists( 'cn_cookies_accepted' ) && ! cn_cookies_accepted() )
281
+ $set_cookie = false;
282
+
283
+ if ( $set_cookie !== true )
284
+ return $id;
285
+
286
+ $expiration = $this->get_timestamp( Post_Views_Counter()->options['general']['time_between_counts']['type'], Post_Views_Counter()->options['general']['time_between_counts']['number'] );
287
+
288
+ // assign cookie name
289
+ $cookie_name = 'pvc_visits' . ( is_multisite() ? '_' . get_current_blog_id() : '' );
290
+
291
+ // is this a new cookie?
292
+ if ( empty( $cookie ) ) {
293
+ // set cookie
294
+ setcookie( $cookie_name . '[0]', $expiration . 'b' . $id, $expiration, COOKIEPATH, COOKIE_DOMAIN, (isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ? true : false ), true );
295
+ } else {
296
+ if ( $expired ) {
297
+ // add new id or change expiration date if id already exists
298
+ $cookie['visited_posts'][$id] = $expiration;
299
+ }
300
+
301
+ // create copy for better foreach performance
302
+ $visited_posts_expirations = $cookie['visited_posts'];
303
+
304
+ // get current gmt time
305
+ $time = current_time( 'timestamp', true );
306
+
307
+ // check whether viewed id has expired - no need to keep it in cookie (less size)
308
+ foreach ( $visited_posts_expirations as $post_id => $post_expiration ) {
309
+ if ( $time > $post_expiration )
310
+ unset( $cookie['visited_posts'][$post_id] );
311
+ }
312
+
313
+ // set new last expiration date if needed
314
+ $cookie['expiration'] = max( $cookie['visited_posts'] );
315
+
316
+ $cookies = $imploded = array();
317
+
318
+ // create pairs
319
+ foreach ( $cookie['visited_posts'] as $id => $exp ) {
320
+ $imploded[] = $exp . 'b' . $id;
321
+ }
322
+
323
+ // split cookie into chunks (4000 bytes to make sure it is safe for every browser)
324
+ $chunks = str_split( implode( 'a', $imploded ), 4000 );
325
+
326
+ // more then one chunk?
327
+ if ( count( $chunks ) > 1 ) {
328
+ $last_id = '';
329
+
330
+ foreach ( $chunks as $chunk_id => $chunk ) {
331
+ // new chunk
332
+ $chunk_c = $last_id . $chunk;
333
+
334
+ // is it full-length chunk?
335
+ if ( strlen( $chunk ) === 4000 ) {
336
+ // get last part
337
+ $last_part = strrchr( $chunk_c, 'a' );
338
+
339
+ // get last id
340
+ $last_id = substr( $last_part, 1 );
341
+
342
+ // add new full-lenght chunk
343
+ $cookies[$chunk_id] = substr( $chunk_c, 0, strlen( $chunk_c ) - strlen( $last_part ) );
344
+ } else {
345
+ // add last chunk
346
+ $cookies[$chunk_id] = $chunk_c;
347
+ }
348
+ }
349
+ } else {
350
+ // only one chunk
351
+ $cookies[] = $chunks[0];
352
+ }
353
+
354
+ foreach ( $cookies as $key => $value ) {
355
+ // set cookie
356
+ setcookie( $cookie_name . '[' . $key . ']', $value, $cookie['expiration'], COOKIEPATH, COOKIE_DOMAIN, (isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ? true : false ), true );
357
+ }
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Save user IP function.
363
+ *
364
+ * @param int $id
365
+ */
366
+ private function save_ip( $id ) {
367
+ $set_cookie = apply_filters( 'pvc_maybe_set_cookie', true );
368
+
369
+ // Cookie Notice compatibility
370
+ if ( function_exists( 'cn_cookies_accepted' ) && ! cn_cookies_accepted() )
371
+ $set_cookie = false;
372
+
373
+ if ( $set_cookie !== true )
374
+ return $id;
375
+
376
+ // get IP cached visits
377
+ $ip_cache = get_transient( 'post_views_counter_ip_cache' );
378
+
379
+ if ( ! $ip_cache )
380
+ $ip_cache = array();
381
+
382
+ // get user IP address
383
+ $user_ip = (string) $this->get_user_ip();
384
+
385
+ // get current time
386
+ $current_time = current_time( 'timestamp', true );
387
+
388
+ // visit exists in transient?
389
+ if ( isset( $ip_cache[$id][$user_ip] ) ) {
390
+ if ( $current_time > $ip_cache[$id][$user_ip] + $this->get_timestamp( Post_Views_Counter()->options['general']['time_between_counts']['type'], Post_Views_Counter()->options['general']['time_between_counts']['number'], false ) )
391
+ $ip_cache[$id][$user_ip] = $current_time;
392
+ else
393
+ return;
394
+ } else
395
+ $ip_cache[$id][$user_ip] = $current_time;
396
+
397
+ // keep it light, only 10 records per post and maximum 100 post records (=> max. 1000 ip entries)
398
+ // also, the data gets deleted after a week if there's no activity during this time...
399
+ if ( count( $ip_cache[$id] ) > 10 )
400
+ $ip_cache[$id] = array_slice( $ip_cache[$id], -10, 10, true );
401
+
402
+ if ( count( $ip_cache ) > 100 )
403
+ $ip_cache = array_slice( $ip_cache, -100, 100, true );
404
+
405
+ set_transient( 'post_views_counter_ip_cache', $ip_cache, WEEK_IN_SECONDS );
406
+ }
407
+
408
+ /**
409
+ * Count visit function.
410
+ *
411
+ * @global object $wpdb
412
+ * @param int $id
413
+ * @return int $id
414
+ */
415
+ private function count_visit( $id ) {
416
+ global $wpdb;
417
+
418
+ $cache_key_names = array();
419
+ $using_object_cache = $this->using_object_cache();
420
+ $increment_amount = (int) apply_filters( 'pvc_views_increment_amount', 1, $id );
421
+
422
+ // get day, week, month and year
423
+ $date = explode( '-', date( 'W-d-m-Y-o', current_time( 'timestamp', true ) ) );
424
+
425
+ foreach ( array(
426
+ 0 => $date[3] . $date[2] . $date[1], // day like 20140324
427
+ 1 => $date[4] . $date[0], // week like 201439
428
+ 2 => $date[3] . $date[2], // month like 201405
429
+ 3 => $date[3], // year like 2014
430
+ 4 => 'total' // total views
431
+ ) as $type => $period ) {
432
+ if ( $using_object_cache ) {
433
+ $cache_key = $id . self::CACHE_KEY_SEPARATOR . $type . self::CACHE_KEY_SEPARATOR . $period;
434
+ wp_cache_add( $cache_key, 0, self::GROUP );
435
+ wp_cache_incr( $cache_key, $increment_amount, self::GROUP );
436
+ $cache_key_names[] = $cache_key;
437
+ } else {
438
+ // hit the db directly
439
+ // @TODO: investigate queueing these queries on the 'shutdown' hook instead of running them instantly?
440
+ $this->db_insert( $id, $type, $period, $increment_amount );
441
+ }
442
+ }
443
+
444
+ // update the list of cache keys to be flushed
445
+ if ( $using_object_cache && ! empty( $cache_key_names ) )
446
+ $this->update_cached_keys_list_if_needed( $cache_key_names );
447
+
448
+ do_action( 'pvc_after_count_visit', $id );
449
+
450
+ return $id;
451
+ }
452
+
453
+ /**
454
+ * Remove post views from database when post is deleted.
455
+ *
456
+ * @global object $wpdb
457
+ * @param int $post_id
458
+ */
459
+ public function delete_post_views( $post_id ) {
460
+ global $wpdb;
461
+
462
+ $wpdb->delete( $wpdb->prefix . 'post_views', array( 'id' => $post_id ), array( '%d' ) );
463
+ }
464
+
465
+ /**
466
+ * Get timestamp convertion.
467
+ *
468
+ * @param string $type
469
+ * @param int $number
470
+ * @param int $timestamp
471
+ * @return string
472
+ */
473
+ public function get_timestamp( $type, $number, $timestamp = true ) {
474
+ $converter = array(
475
+ 'minutes' => 60,
476
+ 'hours' => 3600,
477
+ 'days' => 86400,
478
+ 'weeks' => 604800,
479
+ 'months' => 2592000,
480
+ 'years' => 946080000
481
+ );
482
+
483
+ return (int) ( ( $timestamp ? current_time( 'timestamp', true ) : 0 ) + $number * $converter[$type] );
484
+ }
485
+
486
+ /**
487
+ * Check if object cache is in use.
488
+ *
489
+ * @param bool $using
490
+ * @return bool
491
+ */
492
+ public function using_object_cache( $using = null ) {
493
+ $using = wp_using_ext_object_cache( $using );
494
+
495
+ if ( $using ) {
496
+ // check if explicitly disabled by flush_interval setting/option <= 0
497
+ $flush_interval_number = Post_Views_Counter()->options['general']['flush_interval']['number'];
498
+ $using = ( $flush_interval_number <= 0 ) ? false : true;
499
+ }
500
+
501
+ return $using;
502
+ }
503
+
504
+ /**
505
+ * Update the single cache key which holds a list of all the cache keys
506
+ * that need to be flushed to the db.
507
+ *
508
+ * The value of that special cache key is a giant string containing key names separated with the `|` character.
509
+ * Each such key name then consists of 3 elements: $id, $type, $period (separated by a `.` character).
510
+ * Examples:
511
+ * 62053.0.20150327|62053.1.201513|62053.2.201503|62053.3.2015|62053.4.total|62180.0.20150327|62180.1.201513|62180.2.201503|62180.3.2015|62180.4.total
512
+ * A single key is `62053.0.20150327` and that key's data is: $id = 62053, $type = 0, $period = 20150327
513
+ *
514
+ * This data format proved more efficient (avoids the (un)serialization overhead completely + duplicates filtering is a string search now)
515
+ *
516
+ * @param array $key_names
517
+ */
518
+ private function update_cached_keys_list_if_needed( $key_names = array() ) {
519
+ $existing_list = wp_cache_get( self::NAME_ALLKEYS, self::GROUP );
520
+ if ( ! $existing_list )
521
+ $existing_list = '';
522
+
523
+ $list_modified = false;
524
+
525
+ // modify the list contents if/when needed
526
+ if ( empty( $existing_list ) ) {
527
+ // the simpler case of an empty initial list where we just
528
+ // transform the specified key names into a string
529
+ $existing_list = implode( '|', $key_names );
530
+ $list_modified = true;
531
+ } else {
532
+ // search each specified key name and append it if it's not found
533
+ foreach ( $key_names as $key_name ) {
534
+ if ( false === strpos( $existing_list, $key_name ) ) {
535
+ $existing_list .= '|' . $key_name;
536
+ $list_modified = true;
537
+ }
538
+ }
539
+ }
540
+
541
+ // save modified list back in cache
542
+ if ( $list_modified ) {
543
+ wp_cache_set( self::NAME_ALLKEYS, $existing_list, self::GROUP );
544
+ }
545
+ }
546
+
547
+ /**
548
+ * Flush views data stored in the persistent object cache into
549
+ * our custom table and clear the object cache keys when done.
550
+ *
551
+ * @global object $wpdb
552
+ * @return bool
553
+ */
554
+ public function flush_cache_to_db() {
555
+ global $wpdb;
556
+
557
+ $key_names = wp_cache_get( self::NAME_ALLKEYS, self::GROUP );
558
+
559
+ if ( ! $key_names )
560
+ $key_names = array();
561
+ else {
562
+ // create an array out of a string that's stored in the cache
563
+ $key_names = explode( '|', $key_names );
564
+ }
565
+
566
+ foreach ( $key_names as $key_name ) {
567
+ // get values stored within the key name itself
568
+ list( $id, $type, $period ) = explode( self::CACHE_KEY_SEPARATOR, $key_name );
569
+
570
+ // get the cached count value
571
+ $count = wp_cache_get( $key_name, self::GROUP );
572
+
573
+ // store cached value in the db
574
+ $this->db_prepare_insert( $id, $type, $period, $count );
575
+
576
+ // clear the cache key we just flushed
577
+ wp_cache_delete( $key_name, self::GROUP );
578
+ }
579
+
580
+ // actually flush values to db (if any left)
581
+ $this->db_commit_insert();
582
+
583
+ // remember last flush to db time
584
+ wp_cache_set( 'last-flush', time(), self::GROUP );
585
+
586
+ // delete the key holding the list itself after we've successfully flushed it
587
+ if ( ! empty( $key_names ) )
588
+ wp_cache_delete( self::NAME_ALLKEYS, self::GROUP );
589
+
590
+ return true;
591
+ }
592
+
593
+ /**
594
+ * Insert or update views count.
595
+ *
596
+ * @global object $wpdb
597
+ * @param int $id
598
+ * @param string $type
599
+ * @param string $period
600
+ * @param int $count
601
+ * @return bool
602
+ */
603
+ private function db_insert( $id, $type, $period, $count = 1 ) {
604
+ global $wpdb;
605
+
606
+ $count = (int) $count;
607
+
608
+ if ( ! $count )
609
+ $count = 1;
610
+
611
+ return $wpdb->query(
612
+ $wpdb->prepare( "
613
+ INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count)
614
+ VALUES (%d, %d, %s, %d)
615
+ ON DUPLICATE KEY UPDATE count = count + %d", $id, $type, $period, $count, $count
616
+ )
617
+ );
618
+ }
619
+
620
+ /**
621
+ * Prepare bulk insert or update views count.
622
+ *
623
+ * @param int $id
624
+ * @param string $type
625
+ * @param string $period
626
+ * @param int $count
627
+ * @return void
628
+ */
629
+ private function db_prepare_insert( $id, $type, $period, $count = 1 ) {
630
+ $count = (int) $count;
631
+
632
+ if ( ! $count )
633
+ $count = 1;
634
+
635
+ if ( ! empty( $this->db_insert_values ) )
636
+ $this->db_insert_values .= ', ';
637
+
638
+ $this->db_insert_values .= sprintf( '(%d, %d, "%s", %d)', $id, $type, $period, $count );
639
+
640
+ if ( strlen( $this->db_insert_values ) > self::MAX_INSERT_STRING_LENGTH )
641
+ $this->db_commit_insert();
642
+ }
643
+
644
+ /**
645
+ * Insert accumulated values to database.
646
+ *
647
+ * @global object $wpdb
648
+ * @return bool
649
+ */
650
+ private function db_commit_insert() {
651
+ if ( empty( $this->db_insert_values ) )
652
+ return false;
653
+
654
+ global $wpdb;
655
+
656
+ // $result = $wpdb->query( "
657
+ // INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count)
658
+ // VALUES " . $this->db_insert_values . "
659
+ // ON DUPLICATE KEY UPDATE count = count + VALUES(count)"
660
+ // );
661
+
662
+ $this->db_insert_values = '';
663
+
664
+ // return $result;
665
+ }
666
+
667
+ /**
668
+ * Check whether user has excluded roles.
669
+ *
670
+ * @param string $option
671
+ * @return bool
672
+ */
673
+ public function is_user_role_excluded( $user_id, $option ) {
674
+ $user = get_user_by( 'id', $user_id );
675
+
676
+ if ( empty( $user ) )
677
+ return false;
678
+
679
+ $roles = (array) $user->roles;
680
+
681
+ if ( ! empty( $roles ) ) {
682
+ foreach ( $roles as $role ) {
683
+ if ( in_array( $role, $option, true ) )
684
+ return true;
685
+ }
686
+ }
687
+
688
+ return false;
689
+ }
690
+
691
+ /**
692
+ * Check if IPv4 is in range.
693
+ *
694
+ * @param string $ip IP address
695
+ * @param string $range IP range
696
+ * @return boolean Whether IP is in range
697
+ */
698
+ public function ipv4_in_range( $ip, $range ) {
699
+ $start = str_replace( '*', '0', $range );
700
+ $end = str_replace( '*', '255', $range );
701
+ $ip = (float) sprintf( "%u", ip2long( $ip ) );
702
+
703
+ return ( $ip >= (float) sprintf( "%u", ip2long( $start ) ) && $ip <= (float) sprintf( "%u", ip2long( $end ) ) );
704
+ }
705
+
706
+ /**
707
+ * Get user real IP address.
708
+ *
709
+ * @return string
710
+ */
711
+ public function get_user_ip() {
712
+ foreach ( array( 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR' ) as $key ) {
713
+ if ( array_key_exists( $key, $_SERVER ) === true ) {
714
+ foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {
715
+ // trim for safety measures
716
+ $ip = trim( $ip );
717
+
718
+ // attempt to validate IP
719
+ if ( $this->validate_user_ip( $ip ) )
720
+ return $ip;
721
+ }
722
+ }
723
+ }
724
+
725
+ return isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
726
+ }
727
+
728
+ /**
729
+ * Ensure an ip address is both a valid IP and does not fall within a private network range.
730
+ *
731
+ * @param $ip
732
+ * @return bool
733
+ */
734
+ public function validate_user_ip( $ip ) {
735
+ if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) === false )
736
+ return false;
737
+
738
+ return true;
739
+ }
740
+
741
+ /**
742
+ * Register REST API endpoints.
743
+ *
744
+ * @return void
745
+ */
746
+ public function rest_api_init() {
747
+ // view post route
748
+ register_rest_route( 'post-views-counter', '/view-post/', array(
749
+ 'methods' => array( 'GET', 'POST' ),
750
+ 'callback' => array( $this, 'check_post_rest_api' ),
751
+ 'args' => array(
752
+ 'id' => array(
753
+ 'default' => 0,
754
+ 'sanitize_callback' => 'absint'
755
+ )
756
+ )
757
+ ) );
758
+
759
+ // get views route
760
+ register_rest_route( 'post-views-counter', '/get-post-views/', array(
761
+ 'methods' => array( 'GET', 'POST' ),
762
+ 'callback' => array( $this, 'get_post_views_rest_api' ),
763
+ 'permission_callback' => array( $this, 'get_post_views_permissions_check' ),
764
+ 'args' => array(
765
+ 'id' => array(
766
+ 'default' => 0,
767
+ 'user_id' => get_current_user_id()
768
+ )
769
+ )
770
+ ) );
771
+ }
772
+
773
+ /**
774
+ * Get post views via REST API request.
775
+ *
776
+ * @param array $request
777
+ * @return int
778
+ */
779
+ public function get_post_views_rest_api( $request ) {
780
+ $post_id = is_array( $request['id'] ) ? array_map( 'absint', $request['id'] ) : absint( $request['id'] );
781
+
782
+ return pvc_get_post_views( $post_id );
783
+ }
784
+
785
+ /**
786
+ * Check if a given request has access to get views
787
+ *
788
+ * @param WP_REST_Request $request Full data about the request.
789
+ * @return WP_Error|bool
790
+ */
791
+ public function get_post_views_permissions_check( $request ) {
792
+ return (bool) apply_filters( 'pvc_rest_api_get_post_views_check', true, $request );
793
+ }
794
+
795
  }
includes/crawler-detect.php CHANGED
@@ -5,10 +5,10 @@ if ( ! defined( 'ABSPATH' ) )
5
 
6
  /**
7
  * Post_Views_Counter_Crawler_Detect class.
8
- *
9
  * Based on CrawlerDetect php class adjusted to PHP 5.2
10
  * https://github.com/JayBizzle/Crawler-Detect/blob/master/src/CrawlerDetect.php
11
- *
12
  * @since 1.2.4
13
  * @class Post_Views_Counter_Crawler_Detect
14
  */
5
 
6
  /**
7
  * Post_Views_Counter_Crawler_Detect class.
8
+ *
9
  * Based on CrawlerDetect php class adjusted to PHP 5.2
10
  * https://github.com/JayBizzle/Crawler-Detect/blob/master/src/CrawlerDetect.php
11
+ *
12
  * @since 1.2.4
13
  * @class Post_Views_Counter_Crawler_Detect
14
  */
includes/cron.php CHANGED
@@ -1,108 +1,108 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Cron class.
8
- *
9
- * @class Post_Views_Counter_Cron
10
- */
11
- class Post_Views_Counter_Cron {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'init', array( $this, 'check_cron' ) );
16
- add_action( 'pvc_reset_counts', array( $this, 'reset_counts' ) );
17
- add_action( 'pvc_flush_cached_counts', array( $this, 'flush_cached_counts' ) );
18
-
19
- // filters
20
- add_filter( 'cron_schedules', array( $this, 'cron_time_intervals' ) );
21
- }
22
-
23
- /**
24
- * Reset daily counts.
25
- *
26
- * @global object $wpdb
27
- */
28
- public function reset_counts() {
29
- global $wpdb;
30
-
31
- $counter = array(
32
- 'days' => 1,
33
- 'weeks' => 7,
34
- 'months' => 30,
35
- 'years' => 365
36
- );
37
-
38
- $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'post_views WHERE type = 0 AND CAST( period AS SIGNED ) < CAST( ' . date( 'Ymd', strtotime( '-' . ( (int) ( $counter[Post_Views_Counter()->options['general']['reset_counts']['type']] * Post_Views_Counter()->options['general']['reset_counts']['number'] ) ) . ' days' ) ) . ' AS SIGNED)' );
39
- }
40
-
41
- /**
42
- * Call Post_Views_Counter_Counter::flush_cache_to_db().
43
- * This is (un)scheduled on plugin activation/deactivation.
44
- */
45
- public function flush_cached_counts() {
46
- $counter = Post_Views_Counter()->counter;
47
-
48
- if ( $counter && $counter->using_object_cache() )
49
- $counter->flush_cache_to_db();
50
- }
51
-
52
- /**
53
- * Add new cron interval from settings.
54
- *
55
- * @param array $schedules
56
- * @return array
57
- */
58
- public function cron_time_intervals( $schedules ) {
59
- $schedules['post_views_counter_interval'] = array(
60
- 'interval' => 86400,
61
- 'display' => __( 'Post Views Counter reset daily counts interval', 'post-views-counter' )
62
- );
63
-
64
- $schedules['post_views_counter_flush_interval'] = array(
65
- 'interval' => Post_Views_Counter()->counter->get_timestamp( Post_Views_Counter()->options['general']['flush_interval']['type'], Post_Views_Counter()->options['general']['flush_interval']['number'], false ),
66
- 'display' => __( 'Post Views Counter cache flush interval', 'post-views-counter' )
67
- );
68
-
69
- return $schedules;
70
- }
71
-
72
- /**
73
- * Check whether WP Cron needs to add new task.
74
- */
75
- public function check_cron() {
76
- if ( ! is_admin() )
77
- return;
78
-
79
- // set wp cron task
80
- if ( Post_Views_Counter()->options['general']['cron_run'] ) {
81
-
82
- // not set or need to be updated?
83
- if ( ! wp_next_scheduled( 'pvc_reset_counts' ) || Post_Views_Counter()->options['general']['cron_update'] ) {
84
-
85
- // task is added but need to be updated
86
- if ( Post_Views_Counter()->options['general']['cron_update'] ) {
87
- // remove old schedule
88
- wp_clear_scheduled_hook( 'pvc_reset_counts' );
89
-
90
- // set update to false
91
- $general = Post_Views_Counter()->options['general'];
92
- $general['cron_update'] = false;
93
-
94
- // update settings
95
- update_option( 'post_views_counter_settings_general', $general );
96
- }
97
-
98
- // set schedule
99
- wp_schedule_event( current_time( 'timestamp', true ) + 86400, 'post_views_counter_interval', 'pvc_reset_counts' );
100
- }
101
- } else {
102
- // remove schedule
103
- wp_clear_scheduled_hook( 'pvc_reset_counts' );
104
- remove_action( 'pvc_reset_counts', array( $this, 'reset_counts' ) );
105
- }
106
- }
107
-
108
- }
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Cron class.
8
+ *
9
+ * @class Post_Views_Counter_Cron
10
+ */
11
+ class Post_Views_Counter_Cron {
12
+
13
+ public function __construct() {
14
+ // actions
15
+ add_action( 'init', array( $this, 'check_cron' ) );
16
+ add_action( 'pvc_reset_counts', array( $this, 'reset_counts' ) );
17
+ add_action( 'pvc_flush_cached_counts', array( $this, 'flush_cached_counts' ) );
18
+
19
+ // filters
20
+ add_filter( 'cron_schedules', array( $this, 'cron_time_intervals' ) );
21
+ }
22
+
23
+ /**
24
+ * Reset daily counts.
25
+ *
26
+ * @global object $wpdb
27
+ */
28
+ public function reset_counts() {
29
+ global $wpdb;
30
+
31
+ $counter = array(
32
+ 'days' => 1,
33
+ 'weeks' => 7,
34
+ 'months' => 30,
35
+ 'years' => 365
36
+ );
37
+
38
+ $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'post_views WHERE type = 0 AND CAST( period AS SIGNED ) < CAST( ' . date( 'Ymd', strtotime( '-' . ( (int) ( $counter[Post_Views_Counter()->options['general']['reset_counts']['type']] * Post_Views_Counter()->options['general']['reset_counts']['number'] ) ) . ' days' ) ) . ' AS SIGNED)' );
39
+ }
40
+
41
+ /**
42
+ * Call Post_Views_Counter_Counter::flush_cache_to_db().
43
+ * This is (un)scheduled on plugin activation/deactivation.
44
+ */
45
+ public function flush_cached_counts() {
46
+ $counter = Post_Views_Counter()->counter;
47
+
48
+ if ( $counter && $counter->using_object_cache() )
49
+ $counter->flush_cache_to_db();
50
+ }
51
+
52
+ /**
53
+ * Add new cron interval from settings.
54
+ *
55
+ * @param array $schedules
56
+ * @return array
57
+ */
58
+ public function cron_time_intervals( $schedules ) {
59
+ $schedules['post_views_counter_interval'] = array(
60
+ 'interval' => 86400,
61
+ 'display' => __( 'Post Views Counter reset daily counts interval', 'post-views-counter' )
62
+ );
63
+
64
+ $schedules['post_views_counter_flush_interval'] = array(
65
+ 'interval' => Post_Views_Counter()->counter->get_timestamp( Post_Views_Counter()->options['general']['flush_interval']['type'], Post_Views_Counter()->options['general']['flush_interval']['number'], false ),
66
+ 'display' => __( 'Post Views Counter cache flush interval', 'post-views-counter' )
67
+ );
68
+
69
+ return $schedules;
70
+ }
71
+
72
+ /**
73
+ * Check whether WP Cron needs to add new task.
74
+ */
75
+ public function check_cron() {
76
+ if ( ! is_admin() )
77
+ return;
78
+
79
+ // set wp cron task
80
+ if ( Post_Views_Counter()->options['general']['cron_run'] ) {
81
+
82
+ // not set or need to be updated?
83
+ if ( ! wp_next_scheduled( 'pvc_reset_counts' ) || Post_Views_Counter()->options['general']['cron_update'] ) {
84
+
85
+ // task is added but need to be updated
86
+ if ( Post_Views_Counter()->options['general']['cron_update'] ) {
87
+ // remove old schedule
88
+ wp_clear_scheduled_hook( 'pvc_reset_counts' );
89
+
90
+ // set update to false
91
+ $general = Post_Views_Counter()->options['general'];
92
+ $general['cron_update'] = false;
93
+
94
+ // update settings
95
+ update_option( 'post_views_counter_settings_general', $general );
96
+ }
97
+
98
+ // set schedule
99
+ wp_schedule_event( current_time( 'timestamp', true ) + 86400, 'post_views_counter_interval', 'pvc_reset_counts' );
100
+ }
101
+ } else {
102
+ // remove schedule
103
+ wp_clear_scheduled_hook( 'pvc_reset_counts' );
104
+ remove_action( 'pvc_reset_counts', array( $this, 'reset_counts' ) );
105
+ }
106
+ }
107
+
108
+ }
includes/dashboard.php CHANGED
@@ -1,338 +1,428 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Dashboard class.
8
- *
9
- * @class Post_Views_Counter_Dashboard
10
- */
11
- class Post_Views_Counter_Dashboard {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'wp_dashboard_setup', array( $this, 'wp_dashboard_setup' ) );
16
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts_styles' ) );
17
- add_action( 'wp_ajax_pvc_dashboard_chart', array( $this, 'dashboard_widget_chart' ) );
18
- }
19
-
20
- /**
21
- * Initialize widget.
22
- */
23
- public function wp_dashboard_setup() {
24
- // filter user_can_see_stats
25
- if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) ) {
26
- return;
27
- }
28
-
29
- // add dashboard widget
30
- wp_add_dashboard_widget( 'pvc_dashboard', __( 'Post Views', 'post-views-counter' ), array( $this, 'dashboard_widget' ) /* , array( $this, 'dashboard_widget_control' ) */ );
31
- }
32
-
33
- /**
34
- * Render dashboard widget.
35
- *
36
- * @return mixed
37
- */
38
- public function dashboard_widget() {
39
- ?>
40
- <div id="pvc_dashboard_container">
41
- <canvas id="pvc_chart" height="175"></canvas>
42
- </div>
43
- <?php
44
- }
45
-
46
- /**
47
- * Dashboard widget settings.
48
- *
49
- * @return mixed
50
- */
51
- public function dashboard_widget_control() {
52
-
53
- }
54
-
55
- /**
56
- * Dashboard widget chart data function.
57
- *
58
- * @global $_wp_admin_css_colors
59
- * @return mixed
60
- */
61
- public function dashboard_widget_chart() {
62
-
63
- if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) )
64
- wp_die( _( 'You do not have permission to access this page.', 'post-views-counter' ) );
65
-
66
- if ( ! check_ajax_referer( 'dashboard-chart', 'nonce' ) )
67
- wp_die( __( 'You do not have permission to access this page.', 'post-views-counter' ) );
68
-
69
- // $period = isset( $_REQUEST['period'] ) ? esc_attr( $_REQUEST['period'] ) : 'this_month';
70
-
71
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
72
-
73
- // get stats
74
- $query_args = array(
75
- 'post_type' => $post_types,
76
- 'posts_per_page' => -1,
77
- 'paged' => false,
78
- 'orderby' => 'post_views',
79
- 'suppress_filters' => false,
80
- 'no_found_rows' => true
81
- );
82
-
83
- // set range
84
- $range = 'this_month';
85
-
86
- // $now = getdate( current_time( 'timestamp', get_option( 'gmt_offset' ) ) );
87
- $now = getdate( current_time( 'timestamp', get_option( 'gmt_offset' ) ) - 2592000 );
88
-
89
- // get admin color scheme
90
- global $_wp_admin_css_colors;
91
-
92
- $admin_color = get_user_option( 'admin_color' );
93
- $colors = $_wp_admin_css_colors[$admin_color]->colors;
94
- $color = $this->hex2rgb( $colors[2] );
95
-
96
- // set chart labels
97
- switch ( $range ) {
98
- case 'this_week':
99
- $data = array(
100
- 'text' => array(
101
- 'xAxes' => date_i18n( 'F Y' ),
102
- 'yAxes' => __( 'Post Views', 'post-views-counter' )
103
- )
104
- );
105
-
106
- for ( $day = 0; $day <= 6; $day ++ ) {
107
-
108
- $date = strtotime( $now['mday'] . '-' . $now['mon'] . '-' . $now['year'] . ' + ' . $day . ' days - ' . $now['wday'] . ' days' );
109
- $query = new WP_Query( wp_parse_args( $query_args, array( 'views_query' => array( 'year' => date( 'Y', $date ), 'month' => date( 'n', $date ), 'day' => date( 'd', $date ) ) ) ) );
110
-
111
- $data['data']['labels'][] = date_i18n( 'j', $date );
112
- $data['data']['datasets'][$type_name]['label'] = __( 'Post Views', 'post-views-counter' );
113
- $data['data']['datasets'][0]['data'][] = $query->total_views;
114
- }
115
- break;
116
-
117
- case 'this_year':
118
- $data = array(
119
- 'text' => array(
120
- 'xAxes' => __( 'Year', 'post-views-counter' ) . date( ' Y' ),
121
- 'yAxes' => __( 'Post Views', 'post-views-counter' ),
122
- ),
123
- 'design' => array(
124
- 'fill' => true,
125
- 'backgroundColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 0.2)',
126
- 'borderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
127
- 'borderWidth' => 1.2,
128
- 'borderDash' => array(),
129
- 'pointBorderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
130
- 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
131
- 'pointBorderWidth' => 1.2
132
- )
133
- );
134
-
135
- $data['data']['datasets'][0]['label'] = __( 'Total Views', 'post-views-counter' );
136
-
137
- // get data for specific post types
138
- $empty_post_type_views = array();
139
-
140
- // reindex post types
141
- $post_types = array_combine( range( 1, count( $post_types ) ), array_values( $post_types ) );
142
-
143
- $post_type_data = array();
144
-
145
- foreach ( $post_types as $id => $post_type ) {
146
- $empty_post_type_views[$post_type] = 0;
147
- $post_type_obj = get_post_type_object( $post_type );
148
-
149
- $data['data']['datasets'][$id]['label'] = $post_type_obj->labels->name;
150
- $data['data']['datasets'][$id]['data'] = array();
151
-
152
- // get month views
153
- $post_type_data[$id] = array_values(
154
- pvc_get_views(
155
- array(
156
- 'fields' => 'date=>views',
157
- 'post_type' => $post_type,
158
- 'views_query' => array(
159
- 'year' => date( 'Y' ),
160
- 'month' => '',
161
- 'week' => '',
162
- 'day' => ''
163
- )
164
- )
165
- )
166
- );
167
- }
168
-
169
- $sum = array();
170
-
171
- foreach ( $post_type_data as $post_type_id => $post_views ) {
172
- foreach ( $post_views as $id => $views ) {
173
- // generate chart data for specific post types
174
- $data['data']['datasets'][$post_type_id]['data'][] = $views;
175
-
176
- if ( ! array_key_exists( $id, $sum ) )
177
- $sum[$id] = 0;
178
-
179
- $sum[$id] += $views;
180
- }
181
- }
182
-
183
- // this month all days
184
- for ( $i = 1; $i <= 12; $i ++ ) {
185
- // generate chart data
186
- $data['data']['labels'][] = $i;
187
- $data['data']['dates'][] = date_i18n( 'F Y', strtotime( date( 'Y' ) . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) . '-01' ) );
188
- $data['data']['datasets'][0]['data'][] = $sum[$i - 1];
189
- }
190
- break;
191
-
192
- case 'this_month':
193
- default :
194
- $data = array(
195
- 'text' => array(
196
- 'xAxes' => date_i18n( 'F Y' ),
197
- 'yAxes' => __( 'Post Views', 'post-views-counter' ),
198
- ),
199
- 'design' => array(
200
- 'fill' => true,
201
- 'backgroundColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 0.2)',
202
- 'borderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
203
- 'borderWidth' => 1.2,
204
- 'borderDash' => array(),
205
- 'pointBorderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
206
- 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
207
- 'pointBorderWidth' => 1.2
208
- )
209
- );
210
-
211
- $data['data']['datasets'][0]['label'] = __( 'Total Views', 'post-views-counter' );
212
-
213
- // get data for specific post types
214
- $empty_post_type_views = array();
215
-
216
- // reindex post types
217
- $post_types = array_combine( range( 1, count( $post_types ) ), array_values( $post_types ) );
218
-
219
- $post_type_data = array();
220
-
221
- foreach ( $post_types as $id => $post_type ) {
222
- $empty_post_type_views[$post_type] = 0;
223
- $post_type_obj = get_post_type_object( $post_type );
224
-
225
- $data['data']['datasets'][$id]['label'] = $post_type_obj->labels->name;
226
- $data['data']['datasets'][$id]['data'] = array();
227
-
228
- // get month views
229
- $post_type_data[$id] = array_values(
230
- pvc_get_views(
231
- array(
232
- 'fields' => 'date=>views',
233
- 'post_type' => $post_type,
234
- 'views_query' => array(
235
- 'year' => date( 'Y' ),
236
- 'month' => date( 'm' ),
237
- 'week' => '',
238
- 'day' => ''
239
- )
240
- )
241
- )
242
- );
243
- }
244
-
245
- $sum = array();
246
-
247
- foreach ( $post_type_data as $post_type_id => $post_views ) {
248
- foreach ( $post_views as $id => $views ) {
249
- // generate chart data for specific post types
250
- $data['data']['datasets'][$post_type_id]['data'][] = $views;
251
-
252
- if ( ! array_key_exists( $id, $sum ) )
253
- $sum[$id] = 0;
254
-
255
- $sum[$id] += $views;
256
- }
257
- }
258
-
259
- // this month all days
260
- for ( $i = 1; $i <= date( 't' ); $i ++ ) {
261
- // generate chart data
262
- $data['data']['labels'][] = ( $i % 2 === 0 ? '' : $i );
263
- $data['data']['dates'][] = date_i18n( get_option( 'date_format' ), strtotime( date( 'Y' ) . '-' . date( 'm' ) . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) ) );
264
- $data['data']['datasets'][0]['data'][] = $sum[$i - 1];
265
- }
266
- break;
267
- }
268
-
269
- echo json_encode( $data );
270
-
271
- exit;
272
- }
273
-
274
- /**
275
- * Enqueue admin scripts and styles.
276
- *
277
- * @param string $pagenow
278
- */
279
- public function admin_scripts_styles( $pagenow ) {
280
- if ( $pagenow != 'index.php' )
281
- return;
282
-
283
- // filter user_can_see_stats
284
- if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) ) {
285
- return;
286
- }
287
-
288
- wp_register_style(
289
- 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/css/admin-dashboard.css'
290
- );
291
- wp_enqueue_style( 'pvc-admin-dashboard' );
292
-
293
- wp_register_script(
294
- 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/js/admin-dashboard.js', array( 'jquery', 'pvc-chart' ), Post_Views_Counter()->defaults['version'], true
295
- );
296
-
297
- wp_register_script(
298
- 'pvc-chart', POST_VIEWS_COUNTER_URL . '/js/chart.min.js', array( 'jquery' ), Post_Views_Counter()->defaults['version'], true
299
- );
300
-
301
- // set ajax args
302
- $ajax_args = array(
303
- 'ajaxURL' => admin_url( 'admin-ajax.php' ),
304
- 'nonce' => wp_create_nonce( 'dashboard-chart' )
305
- );
306
-
307
- wp_enqueue_script( 'pvc-admin-dashboard' );
308
- // wp_enqueue_script( 'pvc-chart' );
309
-
310
- wp_localize_script(
311
- 'pvc-admin-dashboard', 'pvcArgs', $ajax_args
312
- );
313
- }
314
-
315
- /**
316
- * Convert hex to rgb color.
317
- *
318
- * @param type $color
319
- * @return boolean
320
- */
321
- public function hex2rgb( $color ) {
322
- if ( $color[0] == '#' ) {
323
- $color = substr( $color, 1 );
324
- }
325
- if ( strlen( $color ) == 6 ) {
326
- list( $r, $g, $b ) = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
327
- } elseif ( strlen( $color ) == 3 ) {
328
- list( $r, $g, $b ) = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
329
- } else {
330
- return false;
331
- }
332
- $r = hexdec( $r );
333
- $g = hexdec( $g );
334
- $b = hexdec( $b );
335
- return array( 'r' => $r, 'g' => $g, 'b' => $b );
336
- }
337
-
338
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Dashboard class.
8
+ *
9
+ * @class Post_Views_Counter_Dashboard
10
+ */
11
+ class Post_Views_Counter_Dashboard {
12
+
13
+ public function __construct() {
14
+ // actions
15
+ add_action( 'wp_dashboard_setup', array( $this, 'wp_dashboard_setup' ) );
16
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts_styles' ) );
17
+ add_action( 'wp_ajax_pvc_dashboard_chart', array( $this, 'dashboard_widget_chart' ) );
18
+ add_action( 'wp_ajax_pvc_dashboard_chart_user_post_types', array( $this, 'dashboard_widget_chart_user_post_types' ) );
19
+ }
20
+
21
+ /**
22
+ * Initialize widget.
23
+ */
24
+ public function wp_dashboard_setup() {
25
+ // filter user_can_see_stats
26
+ if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) ) {
27
+ return;
28
+ }
29
+
30
+ // add dashboard widget
31
+ wp_add_dashboard_widget( 'pvc_dashboard', __( 'Post Views', 'post-views-counter' ), array( $this, 'dashboard_widget' ) );
32
+ }
33
+
34
+ /**
35
+ * Render dashboard widget.
36
+ *
37
+ * @return mixed
38
+ */
39
+ public function dashboard_widget() {
40
+ ?>
41
+ <div id="pvc_dashboard_container">
42
+ <canvas id="pvc_chart" height="175"></canvas>
43
+ <div class="pvc_months">
44
+
45
+ <?php echo $this->generate_months( current_time( 'timestamp', false ) ); ?>
46
+
47
+ </div>
48
+ </div>
49
+ <?php
50
+ }
51
+
52
+ /**
53
+ * Generate months.
54
+ *
55
+ * @param string $timestamp
56
+ * @return string
57
+ */
58
+ public function generate_months( $timestamp ) {
59
+ $dates = array(
60
+ explode( ' ', date( "m F Y", strtotime( "-1 months", $timestamp ) ) ),
61
+ explode( ' ', date( "m F Y", $timestamp ) ),
62
+ explode( ' ', date( "m F Y", strtotime( "+1 months", $timestamp ) ) )
63
+ );
64
+
65
+ $current = date( "Ym", current_time( 'timestamp', false ) );
66
+
67
+ if ( (int) $current <= (int) ( $dates[1][2] . $dates[1][0] ) )
68
+ $next = '<span class="next">' . $dates[2][1] . ' ' . $dates[2][2] . ' ›</span>';
69
+ else
70
+ $next = '<a class="next" href="#" data-date="' . ( $dates[2][0] . '|' . $dates[2][2] ) . '">' . $dates[2][1] . ' ' . $dates[2][2] . ' ›</a>';
71
+
72
+ $dates = array(
73
+ 'prev' => '<a class="prev" href="#" data-date="' . ( $dates[0][0] . '|' . $dates[0][2] ) . '">‹ ' . $dates[0][1] . ' ' . $dates[0][2] . '</a>',
74
+ 'current' => '<span class="current">' . $dates[1][1] . ' ' . $dates[1][2] . '</span>',
75
+ 'next' => $next
76
+ );
77
+
78
+ return $dates['prev'] . $dates['current'] . $dates['next'];
79
+ }
80
+
81
+ /**
82
+ * Dashboard widget chart user post types.
83
+ *
84
+ * @return void
85
+ */
86
+ public function dashboard_widget_chart_user_post_types() {
87
+ if ( ! check_ajax_referer( 'dashboard-chart-user-post-types', 'nonce' ) )
88
+ wp_die( __( 'You do not have permission to access this page.', 'post-views-counter' ) );
89
+
90
+ // get post types
91
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
92
+
93
+ // simulate total views as post type
94
+ $post_types[] = '_pvc_total_views';
95
+
96
+ // valid data?
97
+ if ( isset( $_POST['nonce'], $_POST['hidden'], $_POST['post_type'] ) && ( in_array( $_POST['post_type'], $post_types, true ) ) ) {
98
+ // get user ID
99
+ $user_id = get_current_user_id();
100
+
101
+ // get user dashboard data
102
+ $userdata = get_user_meta( $user_id, 'pvc_dashboard', true );
103
+
104
+ // empty userdata?
105
+ if ( ! is_array( $userdata ) || empty( $userdata ) )
106
+ $userdata = array();
107
+
108
+ // empty post types?
109
+ if ( ! array_key_exists( 'post_types', $userdata ) || ! is_array( $userdata['post_types'] ) )
110
+ $userdata['post_types'] = array();
111
+
112
+ // hide post type?
113
+ if ( $_POST['hidden'] === 'true' ) {
114
+ if ( ! in_array( $_POST['post_type'], $userdata['post_types'], true ) )
115
+ $userdata['post_types'][] = $_POST['post_type'];
116
+ } else {
117
+ if ( ( $key = array_search( $_POST['post_type'], $userdata['post_types'] ) ) !== false )
118
+ unset( $userdata['post_types'][$key] );
119
+ }
120
+
121
+ // update userdata
122
+ update_user_meta( $user_id, 'pvc_dashboard', $userdata );
123
+ }
124
+
125
+ exit;
126
+ }
127
+
128
+ /**
129
+ * Dashboard widget chart data function.
130
+ *
131
+ * @global $_wp_admin_css_colors
132
+ * @return void
133
+ */
134
+ public function dashboard_widget_chart() {
135
+ if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) )
136
+ wp_die( _( 'You do not have permission to access this page.', 'post-views-counter' ) );
137
+
138
+ if ( ! check_ajax_referer( 'dashboard-chart', 'nonce' ) )
139
+ wp_die( __( 'You do not have permission to access this page.', 'post-views-counter' ) );
140
+
141
+ // get period
142
+ $period = isset( $_POST['period'] ) ? esc_attr( $_POST['period'] ) : 'this_month';
143
+
144
+ // get post types
145
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
146
+
147
+ // get stats
148
+ $query_args = array(
149
+ 'post_type' => $post_types,
150
+ 'posts_per_page' => -1,
151
+ 'paged' => false,
152
+ 'orderby' => 'post_views',
153
+ 'suppress_filters' => false,
154
+ 'no_found_rows' => true
155
+ );
156
+
157
+ // $now = getdate( current_time( 'timestamp', get_option( 'gmt_offset' ) ) );
158
+ $now = getdate( current_time( 'timestamp', get_option( 'gmt_offset' ) ) - 2592000 );
159
+
160
+ // get admin color scheme
161
+ global $_wp_admin_css_colors;
162
+
163
+ $admin_color = get_user_option( 'admin_color' );
164
+ $colors = $_wp_admin_css_colors[$admin_color]->colors;
165
+ $color = $this->hex2rgb( $colors[2] );
166
+
167
+ // set chart labels
168
+ switch ( $period ) {
169
+ case 'this_week':
170
+ $data = array(
171
+ 'text' => array(
172
+ 'xAxes' => date_i18n( 'F Y' ),
173
+ 'yAxes' => __( 'Post Views', 'post-views-counter' )
174
+ )
175
+ );
176
+
177
+ for ( $day = 0; $day <= 6; $day ++ ) {
178
+ $date = strtotime( $now['mday'] . '-' . $now['mon'] . '-' . $now['year'] . ' + ' . $day . ' days - ' . $now['wday'] . ' days' );
179
+ $query = new WP_Query( wp_parse_args( $query_args, array( 'views_query' => array( 'year' => date( 'Y', $date ), 'month' => date( 'n', $date ), 'day' => date( 'd', $date ) ) ) ) );
180
+
181
+ $data['data']['labels'][] = date_i18n( 'j', $date );
182
+ $data['data']['datasets'][$type_name]['label'] = __( 'Post Views', 'post-views-counter' );
183
+ $data['data']['datasets'][0]['data'][] = $query->total_views;
184
+ }
185
+ break;
186
+
187
+ case 'this_year':
188
+ $data = array(
189
+ 'text' => array(
190
+ 'xAxes' => __( 'Year', 'post-views-counter' ) . date( ' Y' ),
191
+ 'yAxes' => __( 'Post Views', 'post-views-counter' ),
192
+ ),
193
+ 'design' => array(
194
+ 'fill' => true,
195
+ 'backgroundColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 0.2)',
196
+ 'borderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
197
+ 'borderWidth' => 1.2,
198
+ 'borderDash' => array(),
199
+ 'pointBorderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
200
+ 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
201
+ 'pointBorderWidth' => 1.2
202
+ )
203
+ );
204
+
205
+ $data['data']['datasets'][0]['label'] = __( 'Total Views', 'post-views-counter' );
206
+ $data['data']['datasets'][0]['post_type'] = '_pvc_total_views';
207
+
208
+ // reindex post types
209
+ $post_types = array_combine( range( 1, count( $post_types ) ), array_values( $post_types ) );
210
+
211
+ $post_type_data = array();
212
+
213
+ foreach ( $post_types as $id => $post_type ) {
214
+ $post_type_obj = get_post_type_object( $post_type );
215
+
216
+ $data['data']['datasets'][$id]['label'] = $post_type_obj->labels->name;
217
+ $data['data']['datasets'][$id]['post_type'] = $post_type_obj->name;
218
+ $data['data']['datasets'][$id]['data'] = array();
219
+
220
+ // get month views
221
+ $post_type_data[$id] = array_values(
222
+ pvc_get_views(
223
+ array(
224
+ 'fields' => 'date=>views',
225
+ 'post_type' => $post_type,
226
+ 'views_query' => array(
227
+ 'year' => date( 'Y' ),
228
+ 'month' => '',
229
+ 'week' => '',
230
+ 'day' => ''
231
+ )
232
+ )
233
+ )
234
+ );
235
+ }
236
+
237
+ $sum = array();
238
+
239
+ foreach ( $post_type_data as $post_type_id => $post_views ) {
240
+ foreach ( $post_views as $id => $views ) {
241
+ // generate chart data for specific post types
242
+ $data['data']['datasets'][$post_type_id]['data'][] = $views;
243
+
244
+ if ( ! array_key_exists( $id, $sum ) )
245
+ $sum[$id] = 0;
246
+
247
+ $sum[$id] += $views;
248
+ }
249
+ }
250
+
251
+ // this month all days
252
+ for ( $i = 1; $i <= 12; $i ++ ) {
253
+ // generate chart data
254
+ $data['data']['labels'][] = $i;
255
+ $data['data']['dates'][] = date_i18n( 'F Y', strtotime( date( 'Y' ) . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) . '-01' ) );
256
+ $data['data']['datasets'][0]['data'][] = $sum[$i - 1];
257
+ }
258
+ break;
259
+
260
+ case 'this_month':
261
+ default:
262
+ $userdata = $this->get_dashboard_user_data( get_current_user_id(), 'post_types' );
263
+
264
+ if ( $period !== 'this_month' ) {
265
+ $date = explode( '|', $period, 2 );
266
+ $months = strtotime( (string) $date[1] . '-' . (string) $date[0] . '-13' );
267
+ } else
268
+ $months = current_time( 'timestamp', false );
269
+
270
+ // get date chunks
271
+ $date = explode( ' ', date( "m Y t F", $months ) );
272
+
273
+ $data = array(
274
+ 'months' => $this->generate_months( $months ),
275
+ 'text' => array(
276
+ 'xAxes' => $date[3] . ' ' . $date[1],
277
+ 'yAxes' => __( 'Post Views', 'post-views-counter' ),
278
+ ),
279
+ 'design' => array(
280
+ 'fill' => true,
281
+ 'backgroundColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 0.2)',
282
+ 'borderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
283
+ 'borderWidth' => 1.2,
284
+ 'borderDash' => array(),
285
+ 'pointBorderColor' => 'rgba(' . $color['r'] . ',' . $color['g'] . ',' . $color['b'] . ', 1)',
286
+ 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
287
+ 'pointBorderWidth' => 1.2
288
+ )
289
+ );
290
+
291
+ $data['data']['datasets'][0]['label'] = __( 'Total Views', 'post-views-counter' );
292
+ $data['data']['datasets'][0]['post_type'] = '_pvc_total_views';
293
+ $data['data']['datasets'][0]['hidden'] = in_array( '_pvc_total_views', $userdata, true );
294
+
295
+ // reindex post types
296
+ $post_types = array_combine( range( 1, count( $post_types ) ), array_values( $post_types ) );
297
+
298
+ $post_type_data = array();
299
+
300
+ foreach ( $post_types as $id => $post_type ) {
301
+ $post_type_obj = get_post_type_object( $post_type );
302
+
303
+ $data['data']['datasets'][$id]['label'] = $post_type_obj->labels->name;
304
+ $data['data']['datasets'][$id]['post_type'] = $post_type_obj->name;
305
+ $data['data']['datasets'][$id]['hidden'] = in_array( $post_type_obj->name, $userdata, true );
306
+ $data['data']['datasets'][$id]['data'] = array();
307
+
308
+ // get month views
309
+ $post_type_data[$id] = array_values(
310
+ pvc_get_views(
311
+ array(
312
+ 'fields' => 'date=>views',
313
+ 'post_type' => $post_type,
314
+ 'views_query' => array(
315
+ 'year' => $date[1],
316
+ 'month' => $date[0],
317
+ 'week' => '',
318
+ 'day' => ''
319
+ )
320
+ )
321
+ )
322
+ );
323
+ }
324
+
325
+ $sum = array();
326
+
327
+ foreach ( $post_type_data as $post_type_id => $post_views ) {
328
+ foreach ( $post_views as $id => $views ) {
329
+ // generate chart data for specific post types
330
+ $data['data']['datasets'][$post_type_id]['data'][] = $views;
331
+
332
+ if ( ! array_key_exists( $id, $sum ) )
333
+ $sum[$id] = 0;
334
+
335
+ $sum[$id] += $views;
336
+ }
337
+ }
338
+
339
+ // this month all days
340
+ for ( $i = 1; $i <= $date[2]; $i ++ ) {
341
+ // generate chart data
342
+ $data['data']['labels'][] = ( $i % 2 === 0 ? '' : $i );
343
+ $data['data']['dates'][] = date_i18n( get_option( 'date_format' ), strtotime( $date[1] . '-' . $date[0] . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) ) );
344
+ $data['data']['datasets'][0]['data'][] = $sum[$i - 1];
345
+ }
346
+ break;
347
+ }
348
+
349
+ echo json_encode( $data );
350
+
351
+ exit;
352
+ }
353
+
354
+ /**
355
+ * Get user dashboard data.
356
+ *
357
+ * @param string $data_type
358
+ * @return array
359
+ */
360
+ public function get_dashboard_user_data( $user_id, $data_type ) {
361
+ $userdata = get_user_meta( $user_id, 'pvc_dashboard', true );
362
+
363
+ if ( ! is_array( $userdata ) || empty( $userdata ) )
364
+ $userdata = array();
365
+
366
+ if ( ! array_key_exists( $data_type, $userdata ) || ! is_array( $userdata[$data_type] ) )
367
+ $userdata[$data_type] = array();
368
+
369
+ return $userdata[$data_type];
370
+ }
371
+
372
+ /**
373
+ * Enqueue admin scripts and styles.
374
+ *
375
+ * @param string $pagenow
376
+ */
377
+ public function admin_scripts_styles( $pagenow ) {
378
+ if ( $pagenow != 'index.php' )
379
+ return;
380
+
381
+ // filter user_can_see_stats
382
+ if ( ! apply_filters( 'pvc_user_can_see_stats', current_user_can( 'publish_posts' ) ) )
383
+ return;
384
+
385
+ wp_register_style( 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/css/admin-dashboard.css' );
386
+ wp_enqueue_style( 'pvc-admin-dashboard' );
387
+ wp_enqueue_style( 'pvc-chart-css', POST_VIEWS_COUNTER_URL . '/assets/chartjs/chart.min.css' );
388
+
389
+ wp_register_script( 'pvc-chart', POST_VIEWS_COUNTER_URL . '/assets/chartjs/chart.min.js', array( 'jquery' ), Post_Views_Counter()->defaults['version'], true );
390
+ wp_register_script( 'pvc-admin-dashboard', POST_VIEWS_COUNTER_URL . '/js/admin-dashboard.js', array( 'jquery', 'pvc-chart' ), Post_Views_Counter()->defaults['version'], true );
391
+
392
+ wp_enqueue_script( 'pvc-admin-dashboard' );
393
+
394
+ wp_localize_script(
395
+ 'pvc-admin-dashboard',
396
+ 'pvcArgs',
397
+ array(
398
+ 'ajaxURL' => admin_url( 'admin-ajax.php' ),
399
+ 'nonce' => wp_create_nonce( 'dashboard-chart' ),
400
+ 'nonceUser' => wp_create_nonce( 'dashboard-chart-user-post-types' )
401
+ )
402
+ );
403
+ }
404
+
405
+ /**
406
+ * Convert hex to rgb color.
407
+ *
408
+ * @param type $color
409
+ * @return boolean
410
+ */
411
+ public function hex2rgb( $color ) {
412
+ if ( $color[0] == '#' ) {
413
+ $color = substr( $color, 1 );
414
+ }
415
+ if ( strlen( $color ) == 6 ) {
416
+ list( $r, $g, $b ) = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
417
+ } elseif ( strlen( $color ) == 3 ) {
418
+ list( $r, $g, $b ) = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
419
+ } else {
420
+ return false;
421
+ }
422
+ $r = hexdec( $r );
423
+ $g = hexdec( $g );
424
+ $b = hexdec( $b );
425
+ return array( 'r' => $r, 'g' => $g, 'b' => $b );
426
+ }
427
+
428
+ }
includes/frontend.php CHANGED
@@ -1,203 +1,208 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Frontend class.
8
- *
9
- * @class Post_Views_Counter_Frontend
10
- */
11
- class Post_Views_Counter_Frontend {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'after_setup_theme', array( $this, 'register_shortcode' ) );
16
- add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
17
- add_action( 'wp', array( $this, 'run' ) );
18
- }
19
-
20
- /**
21
- * Register post-views shortcode function.
22
- */
23
- public function register_shortcode() {
24
- add_shortcode( 'post-views', array( $this, 'post_views_shortcode' ) );
25
- }
26
-
27
- /**
28
- * Post views shortcode function.
29
- *
30
- * @param array $args
31
- * @return mixed
32
- */
33
- public function post_views_shortcode( $args ) {
34
- $defaults = array(
35
- 'id' => get_the_ID()
36
- );
37
-
38
- $args = shortcode_atts( $defaults, $args );
39
-
40
- return pvc_post_views( $args['id'], false );
41
- }
42
-
43
- /**
44
- * Set up plugin hooks.
45
- */
46
- public function run() {
47
-
48
- if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
49
- return;
50
-
51
- $filter = apply_filters( 'pvc_shortcode_filter_hook', Post_Views_Counter()->options['display']['position'] );
52
-
53
- if ( ! empty( $filter ) && in_array( $filter, array( 'before', 'after' ) ) ) {
54
- // post content
55
- add_filter( 'the_content', array( $this, 'add_post_views_count' ) );
56
- // add_filter( 'the_excerpt', array( $this, 'add_post_views_count' ) );
57
- // bbpress
58
- add_filter( 'bbp_get_topic_content', array( $this, 'add_post_views_count' ) );
59
- add_filter( 'bbp_get_reply_content', array( $this, 'add_post_views_count' ) );
60
- } else {
61
- // custom
62
- if ( $filter != 'manual' && is_string( $filter ) )
63
- add_filter( $filter, array( $this, 'add_post_views_count' ) );
64
- }
65
- }
66
-
67
- /**
68
- * Add post views counter to content.
69
- *
70
- * @global object $post
71
- * @global string $wp_current_filter
72
- * @param mixed $content
73
- * @return mixed
74
- */
75
- public function add_post_views_count( $content = '' ) {
76
- global $post, $wp_current_filter;
77
-
78
- $display = false;
79
-
80
- // get post types
81
- $post_types = Post_Views_Counter()->options['display']['post_types_display'];
82
-
83
- // get pages
84
- $pages = Post_Views_Counter()->options['display']['page_types_display'];
85
-
86
- // page visibility check
87
- if ( $pages ) {
88
- foreach ( $pages as $page ) {
89
- switch ( $page ) {
90
- case 'singular' :
91
- if ( is_singular( $post_types ) )
92
- $display = true;
93
- break;
94
- case 'archive' :
95
- if ( is_archive() )
96
- $display = true;
97
- break;
98
- case 'search' :
99
- if ( is_search() )
100
- $display = true;
101
- break;
102
- case 'home' :
103
- if ( is_home() || is_front_page() )
104
- $display = true;
105
- break;
106
- }
107
- }
108
- }
109
-
110
- // get groups to check it faster
111
- $groups = Post_Views_Counter()->options['display']['restrict_display']['groups'];
112
-
113
- // whether to display views
114
- if ( is_user_logged_in() ) {
115
- // exclude logged in users?
116
- if ( in_array( 'users', $groups, true ) )
117
- $display = false;
118
- // exclude specific roles?
119
- elseif ( in_array( 'roles', $groups, true ) && Post_Views_Counter()->counter->is_user_role_excluded( get_current_user_id(), Post_Views_Counter()->options['display']['restrict_display']['roles'] ) )
120
- $display = false;
121
- }
122
- // exclude guests?
123
- elseif ( in_array( 'guests', $groups, true ) )
124
- $display = false;
125
-
126
- // we don't want to mess custom loops
127
- if ( ! in_the_loop() )
128
- $display = false;
129
-
130
- if ( apply_filters( 'pvc_display_views_count', $display ) === true ) {
131
-
132
- $filter = apply_filters( 'pvc_shortcode_filter_hook', Post_Views_Counter()->options['display']['position'] );
133
-
134
- switch ( $filter ) {
135
- case 'after':
136
- $content = $content . do_shortcode( '[post-views]' );
137
- break;
138
-
139
- case 'before':
140
- $content = do_shortcode( '[post-views]' ) . $content;
141
- break;
142
-
143
- case 'manual':
144
- default:
145
- break;
146
- }
147
- }
148
-
149
- return $content;
150
- }
151
-
152
- /**
153
- * Enqueue frontend scripts and styles.
154
- */
155
- public function wp_enqueue_scripts() {
156
- $mode = Post_Views_Counter()->options['general']['counter_mode'];
157
- $post_types = Post_Views_Counter()->options['general']['post_types_count'];
158
-
159
- if ( (bool) apply_filters( 'pvc_enqueue_styles', true ) === true ) {
160
- // load dashicons
161
- wp_enqueue_style( 'dashicons' );
162
-
163
- // load style
164
- wp_enqueue_style( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/css/frontend.css', array(), Post_Views_Counter()->defaults['version'] );
165
- }
166
-
167
- if ( in_array( $mode, array( 'js', 'ajax', 'rest_api' ) ) ) {
168
- // whether to count this post type or not
169
- if ( empty( $post_types ) || ! is_singular( $post_types ) )
170
- return;
171
-
172
- wp_register_script(
173
- 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/js/frontend.js', array( 'jquery' ), Post_Views_Counter()->defaults['version'], true
174
- );
175
-
176
- wp_enqueue_script( 'post-views-counter-frontend' );
177
-
178
- $js_args = array(
179
- 'mode' => $mode,
180
- 'requestURL' => esc_url_raw( $mode == 'rest_api' ? rest_url( 'post-views-counter/view-post/') : admin_url( 'admin-ajax.php' ) ),
181
- 'postID' => get_the_ID(),
182
- 'nonce' => ( $mode == 'rest_api' ? wp_create_nonce( 'wp_rest' ) : wp_create_nonce( 'pvc-check-post' ) )
183
- );
184
-
185
- switch ( $mode ) {
186
- case 'rest_api' :
187
- $js_args['requestURL'] = rest_url( 'post-views-counter/view-post/' );
188
- break;
189
- case 'ajax' :
190
- $js_args['requestURL'] = POST_VIEWS_COUNTER_URL . '/includes/ajax.php';
191
- break;
192
- default :
193
- $js_args['requestURL'] = admin_url( 'admin-ajax.php' );
194
- break;
195
- }
196
-
197
- wp_localize_script(
198
- 'post-views-counter-frontend', 'pvcArgsFrontend', apply_filters( 'pvc_frontend_script_args', $js_args )
199
- );
200
- }
201
- }
202
-
203
- }
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Frontend class.
8
+ *
9
+ * @class Post_Views_Counter_Frontend
10
+ */
11
+ class Post_Views_Counter_Frontend {
12
+
13
+ public function __construct() {
14
+ // actions
15
+ add_action( 'after_setup_theme', array( $this, 'register_shortcode' ) );
16
+ add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
17
+ add_action( 'wp', array( $this, 'run' ) );
18
+ }
19
+
20
+ /**
21
+ * Register post-views shortcode function.
22
+ */
23
+ public function register_shortcode() {
24
+ add_shortcode( 'post-views', array( $this, 'post_views_shortcode' ) );
25
+ }
26
+
27
+ /**
28
+ * Post views shortcode function.
29
+ *
30
+ * @param array $args
31
+ * @return mixed
32
+ */
33
+ public function post_views_shortcode( $args ) {
34
+ $defaults = array(
35
+ 'id' => get_the_ID()
36
+ );
37
+
38
+ $args = shortcode_atts( $defaults, $args );
39
+
40
+ return pvc_post_views( $args['id'], false );
41
+ }
42
+
43
+ /**
44
+ * Set up plugin hooks.
45
+ */
46
+ public function run() {
47
+ if ( is_admin() && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
48
+ return;
49
+
50
+ $filter = apply_filters( 'pvc_shortcode_filter_hook', Post_Views_Counter()->options['display']['position'] );
51
+
52
+ if ( ! empty( $filter ) && in_array( $filter, array( 'before', 'after' ) ) ) {
53
+ // post content
54
+ add_filter( 'the_content', array( $this, 'add_post_views_count' ) );
55
+
56
+ // bbpress support
57
+ add_action( 'bbp_template_' . $filter . '_single_topic', array( $this, 'display_bbpress_post_views' ) );
58
+ add_action( 'bbp_template_' . $filter . '_single_forum', array( $this, 'display_bbpress_post_views' ) );
59
+ } else {
60
+ // custom
61
+ if ( $filter != 'manual' && is_string( $filter ) )
62
+ add_filter( $filter, array( $this, 'add_post_views_count' ) );
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Add post views counter to forum/topic of bbPress.
68
+ *
69
+ * @return string
70
+ */
71
+ public function display_bbpress_post_views() {
72
+ $post_id = get_the_ID();
73
+
74
+ // check only for forums and topics
75
+ if ( bbp_is_forum( $post_id ) || bbp_is_topic( $post_id ) )
76
+ echo $this->add_post_views_count( '' );
77
+ }
78
+
79
+ /**
80
+ * Add post views counter to content.
81
+ *
82
+ * @param string $content
83
+ * @return mixed
84
+ */
85
+ public function add_post_views_count( $content = '' ) {
86
+ $display = false;
87
+
88
+ // get post types
89
+ $post_types = Post_Views_Counter()->options['display']['post_types_display'];
90
+
91
+ // get pages
92
+ $pages = Post_Views_Counter()->options['display']['page_types_display'];
93
+
94
+ // page visibility check
95
+ if ( $pages ) {
96
+ foreach ( $pages as $page ) {
97
+ switch ( $page ) {
98
+ case 'singular':
99
+ if ( is_singular( $post_types ) )
100
+ $display = true;
101
+ break;
102
+
103
+ case 'archive':
104
+ if ( is_archive() )
105
+ $display = true;
106
+ break;
107
+
108
+ case 'search':
109
+ if ( is_search() )
110
+ $display = true;
111
+ break;
112
+
113
+ case 'home':
114
+ if ( is_home() || is_front_page() )
115
+ $display = true;
116
+ break;
117
+ }
118
+ }
119
+ }
120
+
121
+ // get groups to check it faster
122
+ $groups = Post_Views_Counter()->options['display']['restrict_display']['groups'];
123
+
124
+ // whether to display views
125
+ if ( is_user_logged_in() ) {
126
+ // exclude logged in users?
127
+ if ( in_array( 'users', $groups, true ) )
128
+ $display = false;
129
+ // exclude specific roles?
130
+ elseif ( in_array( 'roles', $groups, true ) && Post_Views_Counter()->counter->is_user_role_excluded( get_current_user_id(), Post_Views_Counter()->options['display']['restrict_display']['roles'] ) )
131
+ $display = false;
132
+ // exclude guests?
133
+ } elseif ( in_array( 'guests', $groups, true ) )
134
+ $display = false;
135
+
136
+ // we don't want to mess custom loops
137
+ if ( ! in_the_loop() && ! class_exists( 'bbPress' ) )
138
+ $display = false;
139
+
140
+ if ( apply_filters( 'pvc_display_views_count', $display ) === true ) {
141
+ $filter = apply_filters( 'pvc_shortcode_filter_hook', Post_Views_Counter()->options['display']['position'] );
142
+
143
+ switch ( $filter ) {
144
+ case 'after':
145
+ $content = $content . do_shortcode( '[post-views]' );
146
+ break;
147
+
148
+ case 'before':
149
+ $content = do_shortcode( '[post-views]' ) . $content;
150
+ break;
151
+
152
+ case 'manual':
153
+ default:
154
+ break;
155
+ }
156
+ }
157
+
158
+ return $content;
159
+ }
160
+
161
+ /**
162
+ * Enqueue frontend scripts and styles.
163
+ */
164
+ public function wp_enqueue_scripts() {
165
+ $mode = Post_Views_Counter()->options['general']['counter_mode'];
166
+ $post_types = Post_Views_Counter()->options['general']['post_types_count'];
167
+
168
+ if ( (bool) apply_filters( 'pvc_enqueue_styles', true ) === true ) {
169
+ // load dashicons
170
+ wp_enqueue_style( 'dashicons' );
171
+
172
+ // load style
173
+ wp_enqueue_style( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/css/frontend.css', array(), Post_Views_Counter()->defaults['version'] );
174
+ }
175
+
176
+ if ( in_array( $mode, array( 'js', 'ajax', 'rest_api' ) ) ) {
177
+ // whether to count this post type or not
178
+ if ( empty( $post_types ) || ! is_singular( $post_types ) )
179
+ return;
180
+
181
+ wp_register_script( 'post-views-counter-frontend', POST_VIEWS_COUNTER_URL . '/js/frontend.js', array( 'jquery' ), Post_Views_Counter()->defaults['version'], true );
182
+ wp_enqueue_script( 'post-views-counter-frontend' );
183
+
184
+ $js_args = array(
185
+ 'mode' => $mode,
186
+ 'requestURL' => esc_url_raw( $mode == 'rest_api' ? rest_url( 'post-views-counter/view-post/') : admin_url( 'admin-ajax.php' ) ),
187
+ 'postID' => get_the_ID(),
188
+ 'nonce' => ( $mode == 'rest_api' ? wp_create_nonce( 'wp_rest' ) : wp_create_nonce( 'pvc-check-post' ) )
189
+ );
190
+
191
+ switch ( $mode ) {
192
+ case 'rest_api':
193
+ $js_args['requestURL'] = rest_url( 'post-views-counter/view-post/' );
194
+ break;
195
+
196
+ case 'ajax':
197
+ $js_args['requestURL'] = POST_VIEWS_COUNTER_URL . '/includes/ajax.php';
198
+ break;
199
+
200
+ default:
201
+ $js_args['requestURL'] = admin_url( 'admin-ajax.php' );
202
+ break;
203
+ }
204
+
205
+ wp_localize_script( 'post-views-counter-frontend', 'pvcArgsFrontend', apply_filters( 'pvc_frontend_script_args', $js_args ) );
206
+ }
207
+ }
208
+ }
includes/functions.php CHANGED
@@ -1,444 +1,607 @@
1
- <?php
2
- /**
3
- * Post Views Counter pluggable template functions
4
- *
5
- * Override any of those functions by copying it to your theme or replace it via plugin
6
- *
7
- * @author Digital Factory
8
- * @package Post Views Counter
9
- * @since 1.0.0
10
- */
11
- // exit if accessed directly
12
- if ( ! defined( 'ABSPATH' ) )
13
- exit;
14
-
15
- /**
16
- * Get post views for a post or array of posts.
17
- *
18
- * @global $wpdb
19
- * @param int|array $post_id
20
- * @return int
21
- */
22
- if ( ! function_exists( 'pvc_get_post_views' ) ) {
23
-
24
- function pvc_get_post_views( $post_id = 0 ) {
25
- if ( empty( $post_id ) )
26
- $post_id = get_the_ID();
27
-
28
- if ( is_array( $post_id ) )
29
- $post_id = implode( ',', array_map( 'intval', $post_id ) );
30
- else
31
- $post_id = (int) $post_id;
32
-
33
- global $wpdb;
34
-
35
- $query = "SELECT SUM(count) AS views
36
- FROM " . $wpdb->prefix . "post_views
37
- WHERE id IN (" . $post_id . ") AND type = 4";
38
-
39
- // get cached data
40
- $post_views = wp_cache_get( md5( $query ), 'pvc-get_post_views' );
41
-
42
- // cached data not found?
43
- if ( $post_views === false ) {
44
- $post_views = (int) $wpdb->get_var( $query );
45
-
46
- // set the cache expiration, 5 minutes by default
47
- $expire = absint( apply_filters( 'pvc_object_cache_expire', 5 * 60 ) );
48
-
49
- wp_cache_add( md5( $query ), $post_views, 'pvc-get_post_views', $expire );
50
- }
51
-
52
- return apply_filters( 'pvc_get_post_views', $post_views, $post_id );
53
- }
54
-
55
- }
56
-
57
- /**
58
- * Get views query.
59
- *
60
- * @global $wpdb
61
- * @param array $args
62
- * @return int|array
63
- */
64
- if ( ! function_exists( 'pvc_get_views' ) ) {
65
-
66
- function pvc_get_views( $args = array() ) {
67
- $range = array();
68
- $defaults = array(
69
- 'fields' => 'views',
70
- 'post_id' => '',
71
- 'post_type' => '',
72
- 'views_query' => array(
73
- 'year' => '',
74
- 'month' => '',
75
- 'week' => '',
76
- 'day' => ''
77
- )
78
- );
79
-
80
- $args = apply_filters( 'pvc_get_views_args', array_merge( $defaults, $args ) );
81
-
82
- // check post types
83
- if ( is_array( $args['post_type'] ) && ! empty( $args['post_type'] ) ) {
84
- $post_types = array();
85
-
86
- foreach( $args['post_type'] as $post_type ) {
87
- $post_types[] = "'" . $post_type . "'";
88
- }
89
-
90
- $args['post_type'] = implode( ', ', $post_types );
91
- } elseif ( ! is_string( $args['post_type'] ) )
92
- $args['post_type'] = $defaults['post_type'];
93
- else
94
- $args['post_type'] = "'" . $args['post_type'] . "'";
95
-
96
- // check post ids
97
- if ( is_array( $args['post_id'] ) && ! empty( $args['post_id'] ) )
98
- $args['post_id'] = implode( ', ', array_unique( array_map( 'intval', $args['post_id'] ) ) );
99
- else
100
- $args['post_id'] = (int) $args['post_id'];
101
-
102
- // check fields
103
- if ( ! in_array( $args['fields'], array( 'views', 'date=>views' ), true ) )
104
- $args['fields'] = $defaults['fields'];
105
-
106
- // check views query
107
- if ( ! is_array( $args['views_query'] ) )
108
- $args['views_query'] = $defaults['views_query'];
109
-
110
- // check views query year
111
- if ( ! empty( $args['views_query']['year'] ) )
112
- $year = str_pad( (int) $args['views_query']['year'], 4, 0, STR_PAD_LEFT );
113
-
114
- // check views query month
115
- if ( ! empty( $args['views_query']['month'] ) )
116
- $month = str_pad( (int) $args['views_query']['month'], 2, 0, STR_PAD_LEFT );
117
-
118
- // check views query week
119
- if ( ! empty( $args['views_query']['week'] ) )
120
- $week = str_pad( (int) $args['views_query']['week'], 2, 0, STR_PAD_LEFT );
121
-
122
- // check views query day
123
- if ( ! empty( $args['views_query']['day'] ) )
124
- $day = str_pad( (int) $args['views_query']['day'], 2, 0, STR_PAD_LEFT );
125
-
126
- $views_query = '';
127
-
128
- // year
129
- if ( isset( $year ) ) {
130
- // year, week
131
- if ( isset( $week ) ) {
132
- if ( $args['fields'] === 'date=>views' ) {
133
- // create date based on week number
134
- $date = new DateTime( $year . 'W' . $week );
135
-
136
- // get monday
137
- $monday = $date->format( 'd' );
138
-
139
- // get month of monday
140
- $monday_month = $date->format( 'm' );
141
-
142
- // prepare range
143
- for( $i = 1; $i <= 6; $i++ ) {
144
- $range[(string) ( $date->format( 'Y' ) . $date->format( 'm' ) . $date->format( 'd' ) )] = 0;
145
-
146
- $date->modify( '+1days' );
147
- }
148
-
149
- $range[(string) ( $date->format( 'Y' ) . $date->format( 'm' ) . $date->format( 'd' ) )] = 0;
150
-
151
- // get month of sunday
152
- $sunday_month = $date->format( 'm' );
153
-
154
- $views_query = " AND pvc.type = 0 AND pvc.period >= '" . $year . $monday_month . $monday . "' AND pvc.period <= '" . $date->format( 'Y' ) . $sunday_month . $date->format( 'd' ) . "'";
155
- } else
156
- $views_query = " AND pvc.type = 1 AND pvc.period = '" . $year . $week . "'";
157
- // year, month
158
- } elseif ( isset( $month ) ) {
159
- // year, month, day
160
- if ( isset( $day ) ) {
161
- if ( $args['fields'] === 'date=>views' )
162
- // prepare range
163
- $range[(string) ( $year . $month . $day )] = 0;
164
-
165
- $views_query = " AND pvc.type = 0 AND pvc.period = '" . $year . $month . $day . "'";
166
- // year, month
167
- } else {
168
- if ( $args['fields'] === 'date=>views' ) {
169
- // create date
170
- $date = new DateTime( $year . '-' . $month . '-01' );
171
-
172
- // get last day
173
- $last = $date->format( 't' );
174
-
175
- // prepare range
176
- for( $i = 1; $i <= $last; $i++ ) {
177
- $range[(string) ( $year . $month . str_pad( $i, 2, 0, STR_PAD_LEFT ) )] = 0;
178
- }
179
-
180
- $views_query = " AND pvc.type = 0 AND pvc.period >= '" . $year . $month . "01' AND pvc.period <= '" . $year . $month . $last . "'";
181
- } else
182
- $views_query = " AND pvc.type = 2 AND pvc.period = '" . $year . $month . "'";
183
- }
184
- // year
185
- } else {
186
- if ( $args['fields'] === 'date=>views' ) {
187
- // prepare range
188
- for( $i = 1; $i <= 12; $i++ ) {
189
- $range[(string) ( $year . str_pad( $i, 2, 0, STR_PAD_LEFT ) )] = 0;
190
- }
191
-
192
- // create date
193
- $date = new DateTime( $year . '-12-01' );
194
-
195
- $views_query = " AND pvc.type = 2 AND pvc.period >= '" . $year . "01' AND pvc.period <= '" . $year . "12'";
196
- } else
197
- $views_query = " AND pvc.type = 3 AND pvc.period = '" . $year . "'";
198
- }
199
- // month
200
- } elseif ( isset( $month ) ) {
201
- // month, day
202
- if ( isset( $day ) ) {
203
- $views_query = " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) = '" . $month . $day . "'";
204
- // month
205
- } else {
206
- $views_query = " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) = '" . $month . "'";
207
- }
208
- // week
209
- } elseif ( isset( $week ) ) {
210
- $views_query = " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) = '" . $week . "'";
211
- // day
212
- } elseif ( isset( $day ) ) {
213
- $views_query = " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) = '" . $day . "'";
214
- }
215
-
216
- global $wpdb;
217
-
218
- $query = "SELECT " . ( $args['fields'] === 'date=>views' ? 'pvc.period, ' : '' ) . "SUM( IFNULL( pvc.count, 0 ) ) AS post_views
219
- FROM " . $wpdb->prefix . "posts wpp
220
- LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = wpp.ID" . ( $views_query !== '' ? ' ' . $views_query : ' AND pvc.type = 4' ) . ( ! empty( $args['post_id'] ) ? ' AND pvc.id IN (' . $args['post_id'] . ')' : '' ) . "
221
- " . ( $args['post_type'] !== '' ? "WHERE wpp.post_type IN (" . $args['post_type'] . ")" : '' ) . "
222
- " . ( $views_query !== '' ? 'GROUP BY pvc.period' : '' ) . "
223
- HAVING post_views > 0";
224
-
225
- // get cached data
226
- $post_views = wp_cache_get( md5( $query ), 'pvc-get_views' );
227
-
228
- // cached data not found?
229
- if ( $post_views === false ) {
230
- if ( $args['fields'] === 'date=>views' && ! empty( $range ) ) {
231
- $results = $wpdb->get_results( $query );
232
-
233
- if ( ! empty( $results ) ) {
234
- foreach( $results as $row ) {
235
- $range[$row->period] = (int) $row->post_views;
236
- }
237
- }
238
-
239
- $post_views = $range;
240
- } else
241
- $post_views = (int) $wpdb->get_var( $query );
242
-
243
- // set the cache expiration, 5 minutes by default
244
- $expire = absint( apply_filters( 'pvc_object_cache_expire', 5 * 60 ) );
245
-
246
- wp_cache_add( md5( $query ), $post_views, 'pvc-get_views', $expire );
247
- }
248
-
249
- return apply_filters( 'pvc_get_views', $post_views );
250
- }
251
-
252
- }
253
-
254
- /**
255
- * Display post views for a given post.
256
- *
257
- * @param int|array $post_id
258
- * @param bool $display
259
- * @return mixed
260
- */
261
- if ( ! function_exists( 'pvc_post_views' ) ) {
262
-
263
- function pvc_post_views( $post_id = 0, $echo = true ) {
264
-
265
- // get all data
266
- $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id );
267
- $options = Post_Views_Counter()->options['display'];
268
- $views = pvc_get_post_views( $post_id );
269
-
270
- // prepare display
271
- $label = apply_filters( 'pvc_post_views_label', ( function_exists( 'icl_t' ) ? icl_t( 'Post Views Counter', 'Post Views Label', $options['label'] ) : $options['label'] ), $post_id );
272
- // get icon
273
- $icon_class = ( $options['icon_class'] !== '' ? esc_attr( $options['icon_class'] ) : '' );
274
- // add dashicons class if needed
275
- $icon_class = strpos( $icon_class, 'dashicons' ) === 0 ? 'dashicons ' . $icon_class : $icon_class;
276
-
277
- $icon = apply_filters( 'pvc_post_views_icon', '<span class="post-views-icon ' . $icon_class . '"></span>', $post_id );
278
-
279
- $html = apply_filters(
280
- 'pvc_post_views_html', '<div class="post-views post-' . $post_id . ' entry-meta">
281
- ' . ($options['display_style']['icon'] && $icon_class !== '' ? $icon : '') . '
282
- ' . ($options['display_style']['text'] ? '<span class="post-views-label">' . $label . ' </span>' : '') . '
283
- <span class="post-views-count">' . number_format_i18n( $views ) . '</span>
284
- </div>', $post_id, $views, $label, $icon
285
- );
286
-
287
- if ( $echo )
288
- echo $html;
289
- else
290
- return $html;
291
- }
292
-
293
- }
294
-
295
- /**
296
- * Get most viewed posts.
297
- *
298
- * @param array $args
299
- * @return array
300
- */
301
- if ( ! function_exists( 'pvc_get_most_viewed_posts' ) ) {
302
-
303
- function pvc_get_most_viewed_posts( $args = array() ) {
304
- $args = array_merge(
305
- array(
306
- 'posts_per_page' => 10,
307
- 'order' => 'desc',
308
- 'post_type' => 'post'
309
- ), $args
310
- );
311
-
312
- $args = apply_filters( 'pvc_get_most_viewed_posts_args', $args );
313
-
314
- // force to use filters
315
- $args['suppress_filters'] = false;
316
-
317
- // force to use post views as order
318
- $args['orderby'] = 'post_views';
319
-
320
- // force to get all fields
321
- $args['fields'] = '';
322
-
323
- return apply_filters( 'pvc_get_most_viewed_posts', get_posts( $args ), $args );
324
- }
325
-
326
- }
327
-
328
- /**
329
- * Display a list of most viewed posts.
330
- *
331
- * @param array $post_id
332
- * @param bool $display
333
- * @return mixed
334
- */
335
- if ( ! function_exists( 'pvc_most_viewed_posts' ) ) {
336
-
337
- function pvc_most_viewed_posts( $args = array(), $display = true ) {
338
- $defaults = array(
339
- 'number_of_posts' => 5,
340
- 'post_type' => array( 'post' ),
341
- 'order' => 'desc',
342
- 'thumbnail_size' => 'thumbnail',
343
- 'list_type' => 'unordered',
344
- 'show_post_views' => true,
345
- 'show_post_thumbnail' => false,
346
- 'show_post_author' => false,
347
- 'show_post_excerpt' => false,
348
- 'no_posts_message' => __( 'No Posts', 'post-views-counter' ),
349
- 'item_before' => '',
350
- 'item_after' => ''
351
- );
352
-
353
- $args = apply_filters( 'pvc_most_viewed_posts_args', wp_parse_args( $args, $defaults ) );
354
-
355
- $args['show_post_views'] = (bool) $args['show_post_views'];
356
- $args['show_post_thumbnail'] = (bool) $args['show_post_thumbnail'];
357
- $args['show_post_author'] = (bool) $args['show_post_author'];
358
- $args['show_post_excerpt'] = (bool) $args['show_post_excerpt'];
359
-
360
- $posts = pvc_get_most_viewed_posts(
361
- array(
362
- 'posts_per_page' => ( isset( $args['number_of_posts'] ) ? (int) $args['number_of_posts'] : $defaults['number_of_posts'] ),
363
- 'order' => ( isset( $args['order'] ) ? $args['order'] : $defaults['order'] ),
364
- 'post_type' => ( isset( $args['post_type'] ) ? $args['post_type'] : $defaults['post_type'] )
365
- )
366
- );
367
-
368
- if ( ! empty( $posts ) ) {
369
- $html = ( $args['list_type'] === 'unordered' ? '<ul>' : '<ol>' );
370
-
371
- foreach ( $posts as $post ) {
372
- setup_postdata( $post );
373
-
374
- $html .= '
375
- <li>';
376
-
377
- $html .= apply_filters( 'pvc_most_viewed_posts_item_before', $args['item_before'], $post );
378
-
379
- if ( $args['show_post_thumbnail'] && has_post_thumbnail( $post->ID ) ) {
380
- $html .= '
381
- <span class="post-thumbnail">
382
- ' . get_the_post_thumbnail( $post->ID, $args['thumbnail_size'] ) . '
383
- </span>';
384
- }
385
-
386
- $html .= '
387
- <a class="post-title" href="' . get_permalink( $post->ID ) . '">' . get_the_title( $post->ID ) . '</a>' . ( $args['show_post_author'] ? ' <span class="author">(' . get_the_author_meta( 'display_name', $post->post_author ) . ')</span> ' : '' ) . ( $args['show_post_views'] ? ' <span class="count">(' . number_format_i18n( pvc_get_post_views( $post->ID ) ) . ')</span>' : '' );
388
-
389
- $excerpt = '';
390
-
391
- if ( $args['show_post_excerpt'] ) {
392
- if ( empty( $post->post_excerpt ) )
393
- $text = $post->post_content;
394
- else
395
- $text = $post->post_excerpt;
396
-
397
- if ( ! empty( $text ) )
398
- $excerpt = wp_trim_words( str_replace( ']]>', ']]&gt;', strip_shortcodes( $text ) ), apply_filters( 'excerpt_length', 55 ), apply_filters( 'excerpt_more', ' ' . '[&hellip;]' ) );
399
- }
400
-
401
- if ( ! empty( $excerpt ) )
402
- $html .= '
403
-
404
- <div class="post-excerpt">' . esc_html( $excerpt ) . '</div>';
405
-
406
- $html .= apply_filters( 'pvc_most_viewed_posts_item_after', $args['item_after'], $post );
407
-
408
- $html .= '
409
- </li>';
410
- }
411
-
412
- wp_reset_postdata();
413
-
414
- $html .= ( $args['list_type'] === 'unordered' ? '</ul>' : '</ol>' );
415
- } else
416
- $html = $args['no_posts_message'];
417
-
418
- $html = apply_filters( 'pvc_most_viewed_posts_html', $html, $args );
419
-
420
- if ( $display )
421
- echo $html;
422
- else
423
- return $html;
424
- }
425
-
426
- }
427
-
428
- /**
429
- * View post manually function.
430
- *
431
- * @since 1.2.0
432
- * @param int $post_id
433
- * @return bool
434
- */
435
- function pvc_view_post( $post_id = 0 ) {
436
- $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id );
437
-
438
- if ( ! $post_id )
439
- return false;
440
-
441
- Post_Views_Counter()->counter->check_post( $post_id );
442
-
443
- return true;
444
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Post Views Counter pluggable template functions
4
+ *
5
+ * Override any of those functions by copying it to your theme or replace it via plugin
6
+ *
7
+ * @author Digital Factory
8
+ * @package Post Views Counter
9
+ * @since 1.0.0
10
+ */
11
+ // exit if accessed directly
12
+ if ( ! defined( 'ABSPATH' ) )
13
+ exit;
14
+
15
+ /**
16
+ * Get post views for a post or array of posts.
17
+ *
18
+ * @global $wpdb
19
+ * @param int|array $post_id
20
+ * @return int
21
+ */
22
+ if ( ! function_exists( 'pvc_get_post_views' ) ) {
23
+
24
+ function pvc_get_post_views( $post_id = 0 ) {
25
+ if ( empty( $post_id ) )
26
+ $post_id = get_the_ID();
27
+
28
+ if ( is_array( $post_id ) )
29
+ $post_id = implode( ',', array_map( 'intval', $post_id ) );
30
+ else
31
+ $post_id = (int) $post_id;
32
+
33
+ global $wpdb;
34
+
35
+ $query = "SELECT SUM(count) AS views
36
+ FROM " . $wpdb->prefix . "post_views
37
+ WHERE id IN (" . $post_id . ") AND type = 4";
38
+
39
+ // get cached data
40
+ $post_views = wp_cache_get( md5( $query ), 'pvc-get_post_views' );
41
+
42
+ // cached data not found?
43
+ if ( $post_views === false ) {
44
+ $post_views = (int) $wpdb->get_var( $query );
45
+
46
+ // set the cache expiration, 5 minutes by default
47
+ $expire = absint( apply_filters( 'pvc_object_cache_expire', 5 * 60 ) );
48
+
49
+ wp_cache_add( md5( $query ), $post_views, 'pvc-get_post_views', $expire );
50
+ }
51
+
52
+ return apply_filters( 'pvc_get_post_views', $post_views, $post_id );
53
+ }
54
+
55
+ }
56
+
57
+ /**
58
+ * Get views query.
59
+ *
60
+ * @global $wpdb
61
+ * @param array $args
62
+ * @return int|array
63
+ */
64
+ if ( ! function_exists( 'pvc_get_views' ) ) {
65
+
66
+ function pvc_get_views( $args = array() ) {
67
+ $range = array();
68
+ $defaults = array(
69
+ 'fields' => 'views',
70
+ 'post_id' => '',
71
+ 'post_type' => '',
72
+ 'views_query' => array(
73
+ 'year' => '',
74
+ 'month' => '',
75
+ 'week' => '',
76
+ 'day' => '',
77
+ 'after' => '', // string or array
78
+ 'before' => '', // string or array
79
+ 'inclusive' => true
80
+ )
81
+ );
82
+
83
+ // merge default options with new arguments
84
+ $args = array_merge( $defaults, $args );
85
+
86
+ // check views query
87
+ if ( ! is_array( $args['views_query'] ) )
88
+ $args['views_query'] = $defaults['views_query'];
89
+
90
+ // merge views query too
91
+ $args['views_query'] = array_merge( $defaults['views_query'], $args['views_query'] );
92
+
93
+ $args = apply_filters( 'pvc_get_views_args', $args );
94
+
95
+ // check post types
96
+ if ( is_array( $args['post_type'] ) && ! empty( $args['post_type'] ) ) {
97
+ $post_types = array();
98
+
99
+ foreach( $args['post_type'] as $post_type ) {
100
+ $post_types[] = "'" . $post_type . "'";
101
+ }
102
+
103
+ $args['post_type'] = implode( ', ', $post_types );
104
+ } elseif ( ! is_string( $args['post_type'] ) )
105
+ $args['post_type'] = $defaults['post_type'];
106
+ else
107
+ $args['post_type'] = "'" . $args['post_type'] . "'";
108
+
109
+ // check post ids
110
+ if ( is_array( $args['post_id'] ) && ! empty( $args['post_id'] ) )
111
+ $args['post_id'] = implode( ', ', array_unique( array_map( 'intval', $args['post_id'] ) ) );
112
+ else
113
+ $args['post_id'] = (int) $args['post_id'];
114
+
115
+ // check fields
116
+ if ( ! in_array( $args['fields'], array( 'views', 'date=>views' ), true ) )
117
+ $args['fields'] = $defaults['fields'];
118
+
119
+ $query_chunks = array();
120
+ $views_query = '';
121
+
122
+ // views query after/before parameters work only when fields == views
123
+ if ( $args['fields'] === 'views' ) {
124
+ // check views query inclusive
125
+ if ( ! isset( $args['views_query']['inclusive'] ) ) {
126
+ $args['views_query']['inclusive'] = $defaults['views_query']['inclusive'];
127
+ } else
128
+ $args['views_query']['inclusive'] = (bool) $args['views_query']['inclusive'];
129
+
130
+ // check after and before dates
131
+ foreach ( array( 'after' => '>', 'before' => '<' ) as $date => $type ) {
132
+ $year_ = null;
133
+ $month_ = null;
134
+ $week_ = null;
135
+ $day_ = null;
136
+
137
+ // check views query date
138
+ if ( ! empty( $args['views_query'][$date] ) ) {
139
+ // is it a date array?
140
+ if ( is_array( $args['views_query'][$date] ) ) {
141
+ // check views query $date date year
142
+ if ( ! empty( $args['views_query'][$date]['year'] ) )
143
+ $year_ = str_pad( (int) $args['views_query'][$date]['year'], 4, 0, STR_PAD_LEFT );
144
+
145
+ // check views query date month
146
+ if ( ! empty( $args['views_query'][$date]['month'] ) )
147
+ $month_ = str_pad( (int) $args['views_query'][$date]['month'], 2, 0, STR_PAD_LEFT );
148
+
149
+ // check views query date week
150
+ if ( ! empty( $args['views_query'][$date]['week'] ) )
151
+ $week_ = str_pad( (int) $args['views_query'][$date]['week'], 2, 0, STR_PAD_LEFT );
152
+
153
+ // check views query date day
154
+ if ( ! empty( $args['views_query'][$date]['day'] ) )
155
+ $day_ = str_pad( (int) $args['views_query'][$date]['day'], 2, 0, STR_PAD_LEFT );
156
+ // is it a date string?
157
+ } elseif ( is_string( $args['views_query'][$date] ) ) {
158
+ $time_ = strtotime( $args['views_query'][$date] );
159
+
160
+ // valid datetime?
161
+ if ( $time_ !== false ) {
162
+ // week does not exists here, string dates are always treated as year + month + day
163
+ list( $day_, $month_, $year_ ) = explode( ' ', date( "d m Y", $time_ ) );
164
+ }
165
+ }
166
+
167
+ // valid date?
168
+ if ( ! ( $year_ === null && $month_ === null && $week_ === null && $day_ === null ) ) {
169
+ $query_chunks[] = array(
170
+ 'year' => $year_,
171
+ 'month' => $month_,
172
+ 'day' => $day_,
173
+ 'week' => $week_,
174
+ 'type' => $type . ( $args['views_query']['inclusive'] ? '=' : '' )
175
+ );
176
+ }
177
+ }
178
+ }
179
+
180
+ if ( ! empty( $query_chunks ) ) {
181
+ $valid_dates = true;
182
+
183
+ // after and before?
184
+ if ( count( $query_chunks ) === 2 ) {
185
+ // before and after dates should be the same
186
+ foreach ( array( 'year', 'month', 'day', 'week' ) as $date_type ) {
187
+ if ( ! ( ( $query_chunks[0][$date_type] !== null && $query_chunks[1][$date_type] !== null ) || ( $query_chunks[0][$date_type] === null && $query_chunks[1][$date_type] === null ) ) )
188
+ $valid_dates = false;
189
+ }
190
+ }
191
+
192
+ if ( $valid_dates ) {
193
+ foreach ( $query_chunks as $chunk ) {
194
+ // year
195
+ if ( isset( $chunk['year'] ) ) {
196
+ // year, week
197
+ if ( isset( $chunk['week'] ) )
198
+ $views_query .= " AND pvc.type = 1 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['week'] . "'";
199
+ // year, month
200
+ elseif ( isset( $chunk['month'] ) ) {
201
+ // year, month, day
202
+ if ( isset( $chunk['day'] ) )
203
+ $views_query .= " AND pvc.type = 0 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['month'] . $chunk['day'] . "'";
204
+ // year, month
205
+ else
206
+ $views_query .= " AND pvc.type = 2 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['month'] . "'";
207
+ // year
208
+ } else
209
+ $views_query .= " AND pvc.type = 3 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . "'";
210
+ // month
211
+ } elseif ( isset( $chunk['month'] ) ) {
212
+ // month, day
213
+ if ( isset( $chunk['day'] ) ) {
214
+ $views_query .= " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) " . $chunk['type'] . " '" . $chunk['month'] . $chunk['day'] . "'";
215
+ // month
216
+ } else
217
+ $views_query .= " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['month'] . "'";
218
+ // week
219
+ } elseif ( isset( $chunk['week'] ) )
220
+ $views_query .= " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['week'] . "'";
221
+ // day
222
+ elseif ( isset( $chunk['day'] ) )
223
+ $views_query .= " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['day'] . "'";
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ $special_views_query = ( $views_query !== '' );
230
+
231
+ if ( $args['fields'] === 'date=>views' || $views_query === '' ) {
232
+ // check views query year
233
+ if ( ! empty( $args['views_query']['year'] ) )
234
+ $year = str_pad( (int) $args['views_query']['year'], 4, 0, STR_PAD_LEFT );
235
+
236
+ // check views query month
237
+ if ( ! empty( $args['views_query']['month'] ) )
238
+ $month = str_pad( (int) $args['views_query']['month'], 2, 0, STR_PAD_LEFT );
239
+
240
+ // check views query week
241
+ if ( ! empty( $args['views_query']['week'] ) )
242
+ $week = str_pad( (int) $args['views_query']['week'], 2, 0, STR_PAD_LEFT );
243
+
244
+ // check views query day
245
+ if ( ! empty( $args['views_query']['day'] ) )
246
+ $day = str_pad( (int) $args['views_query']['day'], 2, 0, STR_PAD_LEFT );
247
+
248
+ // year
249
+ if ( isset( $year ) ) {
250
+ // year, week
251
+ if ( isset( $week ) ) {
252
+ if ( $args['fields'] === 'date=>views' ) {
253
+ // create date based on week number
254
+ $date = new DateTime( $year . 'W' . $week );
255
+
256
+ // get monday
257
+ $monday = $date->format( 'd' );
258
+
259
+ // get month of monday
260
+ $monday_month = $date->format( 'm' );
261
+
262
+ // prepare range
263
+ for( $i = 1; $i <= 6; $i++ ) {
264
+ $range[(string) ( $date->format( 'Y' ) . $date->format( 'm' ) . $date->format( 'd' ) )] = 0;
265
+
266
+ $date->modify( '+1days' );
267
+ }
268
+
269
+ $range[(string) ( $date->format( 'Y' ) . $date->format( 'm' ) . $date->format( 'd' ) )] = 0;
270
+
271
+ // get month of sunday
272
+ $sunday_month = $date->format( 'm' );
273
+
274
+ $views_query = " AND pvc.type = 0 AND pvc.period >= '" . $year . $monday_month . $monday . "' AND pvc.period <= '" . $date->format( 'Y' ) . $sunday_month . $date->format( 'd' ) . "'";
275
+ } else
276
+ $views_query = " AND pvc.type = 1 AND pvc.period = '" . $year . $week . "'";
277
+ // year, month
278
+ } elseif ( isset( $month ) ) {
279
+ // year, month, day
280
+ if ( isset( $day ) ) {
281
+ if ( $args['fields'] === 'date=>views' )
282
+ // prepare range
283
+ $range[(string) ( $year . $month . $day )] = 0;
284
+
285
+ $views_query = " AND pvc.type = 0 AND pvc.period = '" . $year . $month . $day . "'";
286
+ // year, month
287
+ } else {
288
+ if ( $args['fields'] === 'date=>views' ) {
289
+ // create date
290
+ $date = new DateTime( $year . '-' . $month . '-01' );
291
+
292
+ // get last day
293
+ $last = $date->format( 't' );
294
+
295
+ // prepare range
296
+ for( $i = 1; $i <= $last; $i++ ) {
297
+ $range[(string) ( $year . $month . str_pad( $i, 2, 0, STR_PAD_LEFT ) )] = 0;
298
+ }
299
+
300
+ $views_query = " AND pvc.type = 0 AND pvc.period >= '" . $year . $month . "01' AND pvc.period <= '" . $year . $month . $last . "'";
301
+ } else
302
+ $views_query = " AND pvc.type = 2 AND pvc.period = '" . $year . $month . "'";
303
+ }
304
+ // year
305
+ } else {
306
+ if ( $args['fields'] === 'date=>views' ) {
307
+ // prepare range
308
+ for( $i = 1; $i <= 12; $i++ ) {
309
+ $range[(string) ( $year . str_pad( $i, 2, 0, STR_PAD_LEFT ) )] = 0;
310
+ }
311
+
312
+ // create date
313
+ $date = new DateTime( $year . '-12-01' );
314
+
315
+ $views_query = " AND pvc.type = 2 AND pvc.period >= '" . $year . "01' AND pvc.period <= '" . $year . "12'";
316
+ } else
317
+ $views_query = " AND pvc.type = 3 AND pvc.period = '" . $year . "'";
318
+ }
319
+ // month
320
+ } elseif ( isset( $month ) ) {
321
+ // month, day
322
+ if ( isset( $day ) ) {
323
+ $views_query = " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) = '" . $month . $day . "'";
324
+ // month
325
+ } else {
326
+ $views_query = " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) = '" . $month . "'";
327
+ }
328
+ // week
329
+ } elseif ( isset( $week ) ) {
330
+ $views_query = " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) = '" . $week . "'";
331
+ // day
332
+ } elseif ( isset( $day ) ) {
333
+ $views_query = " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) = '" . $day . "'";
334
+ }
335
+ }
336
+
337
+ global $wpdb;
338
+
339
+ $query = "SELECT " . ( $args['fields'] === 'date=>views' ? 'pvc.period, ' : '' ) . "SUM( IFNULL( pvc.count, 0 ) ) AS post_views
340
+ FROM " . $wpdb->prefix . "posts wpp
341
+ LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = wpp.ID" . ( $views_query !== '' ? ' ' . $views_query : ' AND pvc.type = 4' ) . ( ! empty( $args['post_id'] ) ? ' AND pvc.id IN (' . $args['post_id'] . ')' : '' ) . "
342
+ " . ( $args['post_type'] !== '' ? "WHERE wpp.post_type IN (" . $args['post_type'] . ")" : '' ) . "
343
+ " . ( $views_query !== '' && $special_views_query === false ? 'GROUP BY pvc.period' : '' ) . "
344
+ HAVING post_views > 0";
345
+
346
+ // get cached data
347
+ $post_views = wp_cache_get( md5( $query ), 'pvc-get_views' );
348
+
349
+ // cached data not found?
350
+ if ( $post_views === false ) {
351
+ if ( $args['fields'] === 'date=>views' && ! empty( $range ) ) {
352
+ $results = $wpdb->get_results( $query );
353
+
354
+ if ( ! empty( $results ) ) {
355
+ foreach( $results as $row ) {
356
+ $range[$row->period] = (int) $row->post_views;
357
+ }
358
+ }
359
+
360
+ $post_views = $range;
361
+ } else
362
+ $post_views = (int) $wpdb->get_var( $query );
363
+
364
+ // set the cache expiration, 5 minutes by default
365
+ $expire = absint( apply_filters( 'pvc_object_cache_expire', 300 ) );
366
+
367
+ wp_cache_add( md5( $query ), $post_views, 'pvc-get_views', $expire );
368
+ }
369
+
370
+ return apply_filters( 'pvc_get_views', $post_views );
371
+ }
372
+
373
+ }
374
+
375
+ /**
376
+ * Display post views for a given post.
377
+ *
378
+ * @param int|array $post_id
379
+ * @param bool $display
380
+ * @return mixed
381
+ */
382
+ if ( ! function_exists( 'pvc_post_views' ) ) {
383
+
384
+ function pvc_post_views( $post_id = 0, $echo = true ) {
385
+ // get all data
386
+ $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id );
387
+ $options = Post_Views_Counter()->options['display'];
388
+ $views = pvc_get_post_views( $post_id );
389
+
390
+ // prepare display
391
+ $label = apply_filters( 'pvc_post_views_label', ( function_exists( 'icl_t' ) ? icl_t( 'Post Views Counter', 'Post Views Label', $options['label'] ) : $options['label'] ), $post_id );
392
+
393
+ // get icon class
394
+ $icon_class = ( $options['icon_class'] !== '' ? esc_attr( $options['icon_class'] ) : '' );
395
+
396
+ // add dashicons class if needed
397
+ $icon_class = strpos( $icon_class, 'dashicons' ) === 0 ? 'dashicons ' . $icon_class : $icon_class;
398
+
399
+ // prepare icon output
400
+ $icon = apply_filters( 'pvc_post_views_icon', '<span class="post-views-icon ' . $icon_class . '"></span>', $post_id );
401
+
402
+ $html = apply_filters(
403
+ 'pvc_post_views_html',
404
+ '<div class="post-views post-' . $post_id . ' entry-meta">
405
+ ' . ( $options['display_style']['icon'] && $icon_class !== '' ? $icon : '' ) . '
406
+ ' . ( $options['display_style']['text'] && $label !== '' ? '<span class="post-views-label">' . $label . ' </span>' : '' ) . '
407
+ <span class="post-views-count">' . number_format_i18n( $views ) . '</span>
408
+ </div>',
409
+ $post_id,
410
+ $views,
411
+ $label,
412
+ $icon
413
+ );
414
+
415
+ if ( $echo )
416
+ echo $html;
417
+ else
418
+ return $html;
419
+ }
420
+
421
+ }
422
+
423
+ /**
424
+ * Get most viewed posts.
425
+ *
426
+ * @param array $args
427
+ * @return array
428
+ */
429
+ if ( ! function_exists( 'pvc_get_most_viewed_posts' ) ) {
430
+
431
+ function pvc_get_most_viewed_posts( $args = array() ) {
432
+ $args = array_merge(
433
+ array(
434
+ 'posts_per_page' => 10,
435
+ 'order' => 'desc',
436
+ 'post_type' => 'post'
437
+ ), $args
438
+ );
439
+
440
+ $args = apply_filters( 'pvc_get_most_viewed_posts_args', $args );
441
+
442
+ // force to use filters
443
+ $args['suppress_filters'] = false;
444
+
445
+ // force to use post views as order
446
+ $args['orderby'] = 'post_views';
447
+
448
+ // force to get all fields
449
+ $args['fields'] = '';
450
+
451
+ return apply_filters( 'pvc_get_most_viewed_posts', get_posts( $args ), $args );
452
+ }
453
+
454
+ }
455
+
456
+ /**
457
+ * Display a list of most viewed posts.
458
+ *
459
+ * @param array $post_id
460
+ * @param bool $display
461
+ * @return mixed
462
+ */
463
+ if ( ! function_exists( 'pvc_most_viewed_posts' ) ) {
464
+
465
+ function pvc_most_viewed_posts( $args = array(), $display = true ) {
466
+ $defaults = array(
467
+ 'number_of_posts' => 5,
468
+ 'post_type' => array( 'post' ),
469
+ 'order' => 'desc',
470
+ 'thumbnail_size' => 'thumbnail',
471
+ 'list_type' => 'unordered',
472
+ 'show_post_views' => true,
473
+ 'show_post_thumbnail' => false,
474
+ 'show_post_author' => false,
475
+ 'show_post_excerpt' => false,
476
+ 'no_posts_message' => __( 'No Posts', 'post-views-counter' ),
477
+ 'item_before' => '',
478
+ 'item_after' => ''
479
+ );
480
+
481
+ $args = apply_filters( 'pvc_most_viewed_posts_args', wp_parse_args( $args, $defaults ) );
482
+
483
+ $args['show_post_views'] = (bool) $args['show_post_views'];
484
+ $args['show_post_thumbnail'] = (bool) $args['show_post_thumbnail'];
485
+ $args['show_post_author'] = (bool) $args['show_post_author'];
486
+ $args['show_post_excerpt'] = (bool) $args['show_post_excerpt'];
487
+
488
+ $posts = pvc_get_most_viewed_posts(
489
+ array(
490
+ 'posts_per_page' => ( isset( $args['number_of_posts'] ) ? (int) $args['number_of_posts'] : $defaults['number_of_posts'] ),
491
+ 'order' => ( isset( $args['order'] ) ? $args['order'] : $defaults['order'] ),
492
+ 'post_type' => ( isset( $args['post_type'] ) ? $args['post_type'] : $defaults['post_type'] )
493
+ )
494
+ );
495
+
496
+ if ( ! empty( $posts ) ) {
497
+ $html = ( $args['list_type'] === 'unordered' ? '<ul>' : '<ol>' );
498
+
499
+ foreach ( $posts as $post ) {
500
+ setup_postdata( $post );
501
+
502
+ $html .= '
503
+ <li>';
504
+
505
+ $html .= apply_filters( 'pvc_most_viewed_posts_item_before', $args['item_before'], $post );
506
+
507
+ if ( $args['show_post_thumbnail'] && has_post_thumbnail( $post->ID ) ) {
508
+ $html .= '
509
+ <span class="post-thumbnail">
510
+ ' . get_the_post_thumbnail( $post->ID, $args['thumbnail_size'] ) . '
511
+ </span>';
512
+ }
513
+
514
+ $html .= '
515
+ <a class="post-title" href="' . get_permalink( $post->ID ) . '">' . get_the_title( $post->ID ) . '</a>' . ( $args['show_post_author'] ? ' <span class="author">(' . get_the_author_meta( 'display_name', $post->post_author ) . ')</span> ' : '' ) . ( $args['show_post_views'] ? ' <span class="count">(' . number_format_i18n( pvc_get_post_views( $post->ID ) ) . ')</span>' : '' );
516
+
517
+ $excerpt = '';
518
+
519
+ if ( $args['show_post_excerpt'] ) {
520
+ if ( empty( $post->post_excerpt ) )
521
+ $text = $post->post_content;
522
+ else
523
+ $text = $post->post_excerpt;
524
+
525
+ if ( ! empty( $text ) )
526
+ $excerpt = wp_trim_words( str_replace( ']]>', ']]&gt;', strip_shortcodes( $text ) ), apply_filters( 'excerpt_length', 55 ), apply_filters( 'excerpt_more', ' ' . '[&hellip;]' ) );
527
+ }
528
+
529
+ if ( ! empty( $excerpt ) )
530
+ $html .= '
531
+
532
+ <div class="post-excerpt">' . esc_html( $excerpt ) . '</div>';
533
+
534
+ $html .= apply_filters( 'pvc_most_viewed_posts_item_after', $args['item_after'], $post );
535
+
536
+ $html .= '
537
+ </li>';
538
+ }
539
+
540
+ wp_reset_postdata();
541
+
542
+ $html .= ( $args['list_type'] === 'unordered' ? '</ul>' : '</ol>' );
543
+ } else
544
+ $html = $args['no_posts_message'];
545
+
546
+ $html = apply_filters( 'pvc_most_viewed_posts_html', $html, $args );
547
+
548
+ if ( $display )
549
+ echo $html;
550
+ else
551
+ return $html;
552
+ }
553
+
554
+ }
555
+
556
+ /**
557
+ * Update total number of post views for a post.
558
+ *
559
+ * @global $wpdb
560
+ * @param int $post_id Post ID
561
+ * @param int $post_views Number of post views
562
+ * @return true|string True on success, error string otherwise
563
+ */
564
+ function pvc_update_post_views( $post_id = 0, $post_views = 0 ) {
565
+ // cast post ID
566
+ $post_id = (int) $post_id;
567
+
568
+ // get post
569
+ $post = get_post( $post_id );
570
+
571
+ // check if post exists
572
+ if ( empty( $post ) )
573
+ return false;
574
+
575
+ // cast number of views
576
+ $post_views = (int) $post_views;
577
+ $post_views = $post_views < 0 ? 0 : $post_views;
578
+
579
+ global $wpdb;
580
+
581
+ // chnage post views?
582
+ $post_views = apply_filters( 'pvc_update_post_views_count', $post_views, $post_id );
583
+
584
+ // insert or update db post views count
585
+ $wpdb->query( $wpdb->prepare( "INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count) VALUES (%d, %d, %s, %d) ON DUPLICATE KEY UPDATE count = %d", $post_id, 4, 'total', $post_views, $post_views ) );
586
+
587
+ // query fails only if it returns false
588
+ return apply_filters( 'pvc_update_post_views', $post_id );
589
+ }
590
+
591
+ /**
592
+ * View post manually function.
593
+ *
594
+ * @since 1.2.0
595
+ * @param int $post_id
596
+ * @return bool
597
+ */
598
+ function pvc_view_post( $post_id = 0 ) {
599
+ $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id );
600
+
601
+ if ( ! $post_id )
602
+ return false;
603
+
604
+ Post_Views_Counter()->counter->check_post( $post_id );
605
+
606
+ return true;
607
+ }
includes/query.php CHANGED
@@ -1,258 +1,374 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Query class.
8
- *
9
- * @class Post_Views_Counter_Query
10
- */
11
- class Post_Views_Counter_Query {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'pre_get_posts', array( $this, 'extend_pre_query' ), 1 );
16
-
17
- // filters
18
- add_filter( 'query_vars', array( $this, 'query_vars' ) );
19
- add_filter( 'posts_join', array( $this, 'posts_join' ), 10, 2 );
20
- add_filter( 'posts_groupby', array( $this, 'posts_groupby' ), 10, 2 );
21
- add_filter( 'posts_orderby', array( $this, 'posts_orderby' ), 10, 2 );
22
- add_filter( 'posts_fields', array( $this, 'posts_fields' ), 10, 2 );
23
- add_filter( 'the_posts', array( $this, 'the_posts' ), 10, 2 );
24
- }
25
-
26
- /**
27
- * Register views_query var.
28
- *
29
- * @param array $query_vars
30
- * @return array
31
- */
32
- public function query_vars( $query_vars ) {
33
- $query_vars[] = 'views_query';
34
-
35
- return $query_vars;
36
- }
37
-
38
- /**
39
- * Extend query with post_views orderby parameter.
40
- *
41
- * @param object $query
42
- */
43
- public function extend_pre_query( $query ) {
44
- if ( isset( $query->query_vars['orderby'] ) && $query->query_vars['orderby'] === 'post_views' )
45
- $query->pvc_orderby = true;
46
- }
47
-
48
- /**
49
- * Modify the db query to use post_views parameter.
50
- *
51
- * @global object $wpdb
52
- * @param string $join
53
- * @param object $query
54
- * @return string
55
- */
56
- public function posts_join( $join, $query ) {
57
- $sql = '';
58
-
59
- if ( ! empty( $query->query['views_query'] ) ) {
60
- if ( isset( $query->query['views_query']['year'] ) )
61
- $year = (int) $query->query['views_query']['year'];
62
-
63
- if ( isset( $query->query['views_query']['month'] ) )
64
- $month = (int) $query->query['views_query']['month'];
65
-
66
- if ( isset( $query->query['views_query']['week'] ) )
67
- $week = (int) $query->query['views_query']['week'];
68
-
69
- if ( isset( $query->query['views_query']['day'] ) )
70
- $day = (int) $query->query['views_query']['day'];
71
-
72
- // year
73
- if ( isset( $year ) ) {
74
- // year, week
75
- if ( isset( $week ) && $this->is_valid_date( 'yw', $year, 0, 0, $week ) ) {
76
- $sql = " AND pvc.type = 1 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $week, 2, 0, STR_PAD_LEFT ) . "'";
77
- // year, month
78
- } elseif ( isset( $month ) ) {
79
- // year, month, day
80
- if ( isset( $day ) && $this->is_valid_date( 'ymd', $year, $month, $day ) ) {
81
- $sql = " AND pvc.type = 0 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $month, 2, 0, STR_PAD_LEFT ) . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
82
- // year, month
83
- } elseif ( $this->is_valid_date( 'ym', $year, $month ) ) {
84
- $sql = " AND pvc.type = 2 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $month, 2, 0, STR_PAD_LEFT ) . "'";
85
- }
86
- // year
87
- } elseif ( $this->is_valid_date( 'y', $year ) ) {
88
- $sql = " AND pvc.type = 3 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . "'";
89
- }
90
- // month
91
- } elseif ( isset( $month ) ) {
92
- // month, day
93
- if ( isset( $day ) && $this->is_valid_date( 'md', 0, $month, $day ) ) {
94
- $sql = " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) = '" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
95
- // month
96
- } elseif ( $this->is_valid_date( 'm', 0, $month ) ) {
97
- $sql = " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . "'";
98
- }
99
- // week
100
- } elseif ( isset( $week ) && $this->is_valid_date( 'w', 0, 0, 0, $week ) ) {
101
- $sql = " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $week, 2, 0, STR_PAD_LEFT ) . "'";
102
- // day
103
- } elseif ( isset( $day ) && $this->is_valid_date( 'd', 0, 0, $day ) ) {
104
- $sql = " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
105
- }
106
-
107
- if ( $sql !== '' )
108
- $query->pvc_query = true;
109
- }
110
-
111
- // is it sorted by post views?
112
- if ( ( $sql === '' && isset( $query->pvc_orderby ) && $query->pvc_orderby ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true )
113
- $sql = ' AND pvc.type = 4';
114
-
115
- // add date range
116
- if ( $sql !== '' ) {
117
- global $wpdb;
118
-
119
- $join .= " LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = " . $wpdb->prefix . "posts.ID" . $sql;
120
- }
121
-
122
- return $join;
123
- }
124
-
125
- /**
126
- * Group posts using the post ID.
127
- *
128
- * @global object $wpdb
129
- * @param string $groupby
130
- * @param object $query
131
- * @return string
132
- */
133
- public function posts_groupby( $groupby, $query ) {
134
- // is it sorted by post views or views_query is used?
135
- if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {
136
- global $wpdb;
137
-
138
- $groupby = trim( $groupby );
139
-
140
- if ( strpos( $groupby, $wpdb->prefix . 'posts.ID' ) === false )
141
- $groupby = ( $groupby !== '' ? $groupby . ', ' : '') . $wpdb->prefix . 'posts.ID';
142
-
143
- if ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true )
144
- $groupby .= ' HAVING post_views > 0';
145
- }
146
-
147
- return $groupby;
148
- }
149
-
150
- /**
151
- * Order posts by post views.
152
- *
153
- * @global object $wpdb
154
- * @param string $orderby
155
- * @param object $query
156
- * @return string
157
- */
158
- public function posts_orderby( $orderby, $query ) {
159
- // is it sorted by post views?
160
- if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) ) {
161
- global $wpdb;
162
-
163
- $order = $query->get( 'order' );
164
- $orderby = ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true ? 'post_views' : 'pvc.count' ) . ' ' . $order . ', ' . $wpdb->prefix . 'posts.ID ' . $order;
165
- }
166
-
167
- return $orderby;
168
- }
169
-
170
- /**
171
- * Return post views in queried post objects.
172
- *
173
- * @param string $fields
174
- * @param object $query
175
- * @return string
176
- */
177
- public function posts_fields( $fields, $query ) {
178
- if ( ( ! isset( $query->query['fields'] ) || $query->query['fields'] === '' ) && ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) )
179
- $fields = $fields . ', SUM( IFNULL( pvc.count, 0 ) ) AS post_views';
180
-
181
- return $fields;
182
- }
183
-
184
- /**
185
- * Extend query object with total post views.
186
- *
187
- * @param array $posts
188
- * @param object $query
189
- * @return array
190
- */
191
- public function the_posts( $posts, $query ) {
192
- if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {
193
- $sum = 0;
194
-
195
- // any posts found?
196
- if ( ! empty( $posts ) ) {
197
- foreach ( $posts as $post ) {
198
- if ( ! empty( $post->post_views ) )
199
- $sum += (int) $post->post_views;
200
- }
201
- }
202
-
203
- // pass total views
204
- $query->total_views = $sum;
205
- }
206
-
207
- return $posts;
208
- }
209
-
210
- /**
211
- * Validate date helper function.
212
- *
213
- * @param string $type
214
- * @param int $year
215
- * @param int $month
216
- * @param int $day
217
- * @param int $week
218
- * @return bool
219
- */
220
- private function is_valid_date( $type, $year = 0, $month = 0, $day = 0, $week = 0 ) {
221
- switch ( $type ) {
222
- case 'y':
223
- $bool = ( $year >= 1 && $year <= 32767 );
224
- break;
225
-
226
- case 'yw':
227
- $bool = ( $year >= 1 && $year <= 32767 && $week >= 0 && $week <= 53 );
228
- break;
229
-
230
- case 'ym':
231
- $bool = ( $year >= 1 && $year <= 32767 && $month >= 1 && $month <= 12 );
232
- break;
233
-
234
- case 'ymd':
235
- $bool = checkdate( $month, $day, $year );
236
- break;
237
-
238
- case 'm':
239
- $bool = ( $month >= 1 && $month <= 12 );
240
- break;
241
-
242
- case 'md':
243
- $bool = ( $month >= 1 && $month <= 12 && $day >= 1 && $day <= 31 );
244
- break;
245
-
246
- case 'w':
247
- $bool = ( $week >= 0 && $week <= 53 );
248
- break;
249
-
250
- case 'd':
251
- $bool = ( $day >= 1 && $day <= 31 );
252
- break;
253
- }
254
-
255
- return $bool;
256
- }
257
-
258
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Query class.
8
+ *
9
+ * @class Post_Views_Counter_Query
10
+ */
11
+ class Post_Views_Counter_Query {
12
+
13
+ public function __construct() {
14
+ // actions
15
+ add_action( 'pre_get_posts', array( $this, 'extend_pre_query' ), 1 );
16
+
17
+ // filters
18
+ add_filter( 'query_vars', array( $this, 'query_vars' ) );
19
+ add_filter( 'posts_join', array( $this, 'posts_join' ), 10, 2 );
20
+ add_filter( 'posts_groupby', array( $this, 'posts_groupby' ), 10, 2 );
21
+ add_filter( 'posts_orderby', array( $this, 'posts_orderby' ), 10, 2 );
22
+ add_filter( 'posts_fields', array( $this, 'posts_fields' ), 10, 2 );
23
+ add_filter( 'the_posts', array( $this, 'the_posts' ), 10, 2 );
24
+ }
25
+
26
+ /**
27
+ * Register views_query var.
28
+ *
29
+ * @param array $query_vars
30
+ * @return array
31
+ */
32
+ public function query_vars( $query_vars ) {
33
+ $query_vars[] = 'views_query';
34
+
35
+ return $query_vars;
36
+ }
37
+
38
+ /**
39
+ * Extend query with post_views orderby parameter.
40
+ *
41
+ * @param object $query
42
+ */
43
+ public function extend_pre_query( $query ) {
44
+ if ( isset( $query->query_vars['orderby'] ) && $query->query_vars['orderby'] === 'post_views' )
45
+ $query->pvc_orderby = true;
46
+ }
47
+
48
+ /**
49
+ * Modify the db query to use post_views parameter.
50
+ *
51
+ * @global object $wpdb
52
+ * @param string $join
53
+ * @param object $query
54
+ * @return string
55
+ */
56
+ public function posts_join( $join, $query ) {
57
+ $sql = '';
58
+ $query_chunks = array();
59
+
60
+ // views query?
61
+ if ( ! empty( $query->query['views_query'] ) ) {
62
+ if ( isset( $query->query['views_query']['inclusive'] ) )
63
+ $query->query['views_query']['inclusive'] = (bool) $query->query['views_query']['inclusive'];
64
+ else
65
+ $query->query['views_query']['inclusive'] = true;
66
+
67
+ // check after and before dates
68
+ foreach ( array( 'after' => '>', 'before' => '<' ) as $date => $type ) {
69
+ $year_ = null;
70
+ $month_ = null;
71
+ $week_ = null;
72
+ $day_ = null;
73
+
74
+ // check views query date
75
+ if ( ! empty( $query->query['views_query'][$date] ) ) {
76
+ // is it a date array?
77
+ if ( is_array( $query->query['views_query'][$date] ) ) {
78
+ // check views query $date date year
79
+ if ( ! empty( $query->query['views_query'][$date]['year'] ) )
80
+ $year_ = str_pad( (int) $query->query['views_query'][$date]['year'], 4, 0, STR_PAD_LEFT );
81
+
82
+ // check views query date month
83
+ if ( ! empty( $query->query['views_query'][$date]['month'] ) )
84
+ $month_ = str_pad( (int) $query->query['views_query'][$date]['month'], 2, 0, STR_PAD_LEFT );
85
+
86
+ // check views query date week
87
+ if ( ! empty( $query->query['views_query'][$date]['week'] ) )
88
+ $week_ = str_pad( (int) $query->query['views_query'][$date]['week'], 2, 0, STR_PAD_LEFT );
89
+
90
+ // check views query date day
91
+ if ( ! empty( $query->query['views_query'][$date]['day'] ) )
92
+ $day_ = str_pad( (int) $query->query['views_query'][$date]['day'], 2, 0, STR_PAD_LEFT );
93
+ // is it a date string?
94
+ } elseif ( is_string( $query->query['views_query'][$date] ) ) {
95
+ $time_ = strtotime( $query->query['views_query'][$date] );
96
+
97
+ // valid datetime?
98
+ if ( $time_ !== false ) {
99
+ // week does not exists here, string dates are always treated as year + month + day
100
+ list( $day_, $month_, $year_ ) = explode( ' ', date( "d m Y", $time_ ) );
101
+ }
102
+ }
103
+
104
+ // valid date?
105
+ if ( ! ( $year_ === null && $month_ === null && $week_ === null && $day_ === null ) ) {
106
+ $query_chunks[] = array(
107
+ 'year' => $year_,
108
+ 'month' => $month_,
109
+ 'day' => $day_,
110
+ 'week' => $week_,
111
+ 'type' => $type . ( $query->query['views_query']['inclusive'] ? '=' : '' )
112
+ );
113
+ }
114
+ }
115
+ }
116
+
117
+ // any after, before query chunks?
118
+ if ( ! empty( $query_chunks ) ) {
119
+ $valid_dates = true;
120
+
121
+ // check only if both dates are in query
122
+ if ( count( $query_chunks ) === 2 ) {
123
+ // before and after dates should be the same
124
+ foreach ( array( 'year', 'month', 'day', 'week' ) as $date_type ) {
125
+ if ( ! ( ( $query_chunks[0][$date_type] !== null && $query_chunks[1][$date_type] !== null ) || ( $query_chunks[0][$date_type] === null && $query_chunks[1][$date_type] === null ) ) )
126
+ $valid_dates = false;
127
+ }
128
+ }
129
+
130
+ // after and before dates should be
131
+ if ( $valid_dates ) {
132
+ foreach ( $query_chunks as $chunk ) {
133
+ // year
134
+ if ( isset( $chunk['year'] ) ) {
135
+ // year, week
136
+ if ( isset( $chunk['week'] ) )
137
+ $sql .= " AND pvc.type = 1 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['week'] . "'";
138
+ // year, month
139
+ elseif ( isset( $chunk['month'] ) ) {
140
+ // year, month, day
141
+ if ( isset( $chunk['day'] ) )
142
+ $sql .= " AND pvc.type = 0 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['month'] . $chunk['day'] . "'";
143
+ // year, month
144
+ else
145
+ $sql .= " AND pvc.type = 2 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . $chunk['month'] . "'";
146
+ // year
147
+ } else
148
+ $sql .= " AND pvc.type = 3 AND pvc.period " . $chunk['type'] . " '" . $chunk['year'] . "'";
149
+ // month
150
+ } elseif ( isset( $chunk['month'] ) ) {
151
+ // month, day
152
+ if ( isset( $chunk['day'] ) )
153
+ $sql .= " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) " . $chunk['type'] . " '" . $chunk['month'] . $chunk['day'] . "'";
154
+ // month
155
+ else
156
+ $sql .= " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['month'] . "'";
157
+ // week
158
+ } elseif ( isset( $chunk['week'] ) )
159
+ $sql .= " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['week'] . "'";
160
+ // day
161
+ elseif ( isset( $chunk['day'] ) )
162
+ $sql .= " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) " . $chunk['type'] . " '" . $chunk['day'] . "'";
163
+ }
164
+ }
165
+ }
166
+
167
+ // standard query
168
+ if ( $sql === '' ) {
169
+ // check year
170
+ if ( isset( $query->query['views_query']['year'] ) )
171
+ $year = (int) $query->query['views_query']['year'];
172
+
173
+ // check month
174
+ if ( isset( $query->query['views_query']['month'] ) )
175
+ $month = (int) $query->query['views_query']['month'];
176
+
177
+ // check week
178
+ if ( isset( $query->query['views_query']['week'] ) )
179
+ $week = (int) $query->query['views_query']['week'];
180
+
181
+ // check day
182
+ if ( isset( $query->query['views_query']['day'] ) )
183
+ $day = (int) $query->query['views_query']['day'];
184
+
185
+ // year
186
+ if ( isset( $year ) ) {
187
+ // year, week
188
+ if ( isset( $week ) && $this->is_valid_date( 'yw', $year, 0, 0, $week ) )
189
+ $sql = " AND pvc.type = 1 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $week, 2, 0, STR_PAD_LEFT ) . "'";
190
+ // year, month
191
+ elseif ( isset( $month ) ) {
192
+ // year, month, day
193
+ if ( isset( $day ) && $this->is_valid_date( 'ymd', $year, $month, $day ) )
194
+ $sql = " AND pvc.type = 0 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $month, 2, 0, STR_PAD_LEFT ) . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
195
+ // year, month
196
+ elseif ( $this->is_valid_date( 'ym', $year, $month ) )
197
+ $sql = " AND pvc.type = 2 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . str_pad( $month, 2, 0, STR_PAD_LEFT ) . "'";
198
+ // year
199
+ } elseif ( $this->is_valid_date( 'y', $year ) )
200
+ $sql = " AND pvc.type = 3 AND pvc.period = '" . str_pad( $year, 4, 0, STR_PAD_LEFT ) . "'";
201
+ // month
202
+ } elseif ( isset( $month ) ) {
203
+ // month, day
204
+ if ( isset( $day ) && $this->is_valid_date( 'md', 0, $month, $day ) ) {
205
+ $sql = " AND pvc.type = 0 AND RIGHT( pvc.period, 4 ) = '" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
206
+ // month
207
+ } elseif ( $this->is_valid_date( 'm', 0, $month ) )
208
+ $sql = " AND pvc.type = 2 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . "'";
209
+ // week
210
+ } elseif ( isset( $week ) && $this->is_valid_date( 'w', 0, 0, 0, $week ) )
211
+ $sql = " AND pvc.type = 1 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $week, 2, 0, STR_PAD_LEFT ) . "'";
212
+ // day
213
+ elseif ( isset( $day ) && $this->is_valid_date( 'd', 0, 0, $day ) )
214
+ $sql = " AND pvc.type = 0 AND RIGHT( pvc.period, 2 ) = '" . str_pad( $day, 2, 0, STR_PAD_LEFT ) . "'";
215
+ }
216
+
217
+ if ( $sql !== '' )
218
+ $query->pvc_query = true;
219
+ }
220
+
221
+ // is it sorted by post views?
222
+ if ( ( $sql === '' && isset( $query->pvc_orderby ) && $query->pvc_orderby ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true )
223
+ $sql = ' AND pvc.type = 4';
224
+
225
+ // add date range
226
+ if ( $sql !== '' ) {
227
+ global $wpdb;
228
+
229
+ $join .= " LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = " . $wpdb->prefix . "posts.ID" . $sql;
230
+ }
231
+
232
+ return $join;
233
+ }
234
+
235
+ /**
236
+ * Group posts using the post ID.
237
+ *
238
+ * @global object $wpdb
239
+ * @param string $groupby
240
+ * @param object $query
241
+ * @return string
242
+ */
243
+ public function posts_groupby( $groupby, $query ) {
244
+ // is it sorted by post views or views_query is used?
245
+ if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {
246
+ global $pagenow;
247
+
248
+ // needed only for sorting
249
+ if ( $pagenow === 'upload.php' || $pagenow === 'edit.php' )
250
+ $query->query['views_query']['hide_empty'] = false;
251
+
252
+ global $wpdb;
253
+
254
+ $groupby = trim( $groupby );
255
+
256
+ if ( strpos( $groupby, $wpdb->prefix . 'posts.ID' ) === false )
257
+ $groupby = ( $groupby !== '' ? $groupby . ', ' : '') . $wpdb->prefix . 'posts.ID';
258
+
259
+ if ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true )
260
+ $groupby .= ' HAVING post_views > 0';
261
+ }
262
+
263
+ return $groupby;
264
+ }
265
+
266
+ /**
267
+ * Order posts by post views.
268
+ *
269
+ * @global object $wpdb
270
+ * @param string $orderby
271
+ * @param object $query
272
+ * @return string
273
+ */
274
+ public function posts_orderby( $orderby, $query ) {
275
+ // is it sorted by post views?
276
+ if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) ) {
277
+ global $wpdb;
278
+
279
+ $order = $query->get( 'order' );
280
+ $orderby = ( ! isset( $query->query['views_query']['hide_empty'] ) || $query->query['views_query']['hide_empty'] === true ? 'post_views' : 'pvc.count' ) . ' ' . $order . ', ' . $wpdb->prefix . 'posts.ID ' . $order;
281
+ }
282
+
283
+ return $orderby;
284
+ }
285
+
286
+ /**
287
+ * Return post views in queried post objects.
288
+ *
289
+ * @param string $fields
290
+ * @param object $query
291
+ * @return string
292
+ */
293
+ public function posts_fields( $fields, $query ) {
294
+ if ( ( ! isset( $query->query['fields'] ) || $query->query['fields'] === '' ) && ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) )
295
+ $fields = $fields . ', SUM( IFNULL( pvc.count, 0 ) ) AS post_views';
296
+
297
+ return $fields;
298
+ }
299
+
300
+ /**
301
+ * Extend query object with total post views.
302
+ *
303
+ * @param array $posts
304
+ * @param object $query
305
+ * @return array
306
+ */
307
+ public function the_posts( $posts, $query ) {
308
+ if ( ( isset( $query->pvc_orderby ) && $query->pvc_orderby ) || ( isset( $query->pvc_query ) && $query->pvc_query ) || apply_filters( 'pvc_extend_post_object', false, $query ) === true ) {
309
+ $sum = 0;
310
+
311
+ // any posts found?
312
+ if ( ! empty( $posts ) ) {
313
+ foreach ( $posts as $post ) {
314
+ if ( ! empty( $post->post_views ) )
315
+ $sum += (int) $post->post_views;
316
+ }
317
+ }
318
+
319
+ // pass total views
320
+ $query->total_views = $sum;
321
+ }
322
+
323
+ return $posts;
324
+ }
325
+
326
+ /**
327
+ * Validate date helper function.
328
+ *
329
+ * @param string $type
330
+ * @param int $year
331
+ * @param int $month
332
+ * @param int $day
333
+ * @param int $week
334
+ * @return bool
335
+ */
336
+ private function is_valid_date( $type, $year = 0, $month = 0, $day = 0, $week = 0 ) {
337
+ switch ( $type ) {
338
+ case 'y':
339
+ $bool = ( $year >= 1 && $year <= 32767 );
340
+ break;
341
+
342
+ case 'yw':
343
+ $bool = ( $year >= 1 && $year <= 32767 && $week >= 0 && $week <= 53 );
344
+ break;
345
+
346
+ case 'ym':
347
+ $bool = ( $year >= 1 && $year <= 32767 && $month >= 1 && $month <= 12 );
348
+ break;
349
+
350
+ case 'ymd':
351
+ $bool = checkdate( $month, $day, $year );
352
+ break;
353
+
354
+ case 'm':
355
+ $bool = ( $month >= 1 && $month <= 12 );
356
+ break;
357
+
358
+ case 'md':
359
+ $bool = ( $month >= 1 && $month <= 12 && $day >= 1 && $day <= 31 );
360
+ break;
361
+
362
+ case 'w':
363
+ $bool = ( $week >= 0 && $week <= 53 );
364
+ break;
365
+
366
+ case 'd':
367
+ $bool = ( $day >= 1 && $day <= 31 );
368
+ break;
369
+ }
370
+
371
+ return $bool;
372
+ }
373
+
374
+ }
includes/settings.php CHANGED
@@ -1,804 +1,816 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Settings class.
8
- *
9
- * @class Post_Views_Counter_Settings
10
- */
11
- class Post_Views_Counter_Settings {
12
-
13
- private $tabs;
14
- private $choices;
15
- private $modes;
16
- private $time_types;
17
- private $groups;
18
- private $user_roles;
19
- private $positions;
20
- private $display_styles;
21
- public $post_types;
22
- public $page_types;
23
-
24
- public function __construct() {
25
- // actions
26
- add_action( 'admin_init', array( $this, 'register_settings' ) );
27
- add_action( 'admin_menu', array( $this, 'admin_menu_options' ) );
28
- add_action( 'after_setup_theme', array( $this, 'load_defaults' ) );
29
- add_action( 'wp_loaded', array( $this, 'load_post_types' ) );
30
- }
31
-
32
- /**
33
- * Load default settings.
34
- */
35
- public function load_defaults() {
36
-
37
- if ( ! is_admin() )
38
- return;
39
-
40
- $this->modes = array(
41
- 'php' => __( 'PHP', 'post-views-counter' ),
42
- 'js' => __( 'JavaScript', 'post-views-counter' ),
43
- 'ajax' => __( 'Fast AJAX', 'post-views-counter' )
44
- );
45
-
46
- if ( function_exists( 'register_rest_route' ) ) {
47
- $this->modes['rest_api'] = __( 'REST API', 'post-views-counter' );
48
- }
49
-
50
- $this->time_types = array(
51
- 'minutes' => __( 'minutes', 'post-views-counter' ),
52
- 'hours' => __( 'hours', 'post-views-counter' ),
53
- 'days' => __( 'days', 'post-views-counter' ),
54
- 'weeks' => __( 'weeks', 'post-views-counter' ),
55
- 'months' => __( 'months', 'post-views-counter' ),
56
- 'years' => __( 'years', 'post-views-counter' )
57
- );
58
-
59
- $this->groups = array(
60
- 'robots' => __( 'robots', 'post-views-counter' ),
61
- 'users' => __( 'logged in users', 'post-views-counter' ),
62
- 'guests' => __( 'guests', 'post-views-counter' ),
63
- 'roles' => __( 'selected user roles', 'post-views-counter' )
64
- );
65
-
66
- $this->positions = array(
67
- 'before' => __( 'before the content', 'post-views-counter' ),
68
- 'after' => __( 'after the content', 'post-views-counter' ),
69
- 'manual' => __( 'manual', 'post-views-counter' )
70
- );
71
-
72
- $this->display_styles = array(
73
- 'icon' => __( 'icon', 'post-views-counter' ),
74
- 'text' => __( 'label', 'post-views-counter' )
75
- );
76
-
77
- $this->tabs = array(
78
- 'general' => array(
79
- 'name' => __( 'General', 'post-views-counter' ),
80
- 'key' => 'post_views_counter_settings_general',
81
- 'submit' => 'save_pvc_general',
82
- 'reset' => 'reset_pvc_general'
83
- ),
84
- 'display' => array(
85
- 'name' => __( 'Display', 'post-views-counter' ),
86
- 'key' => 'post_views_counter_settings_display',
87
- 'submit' => 'save_pvc_display',
88
- 'reset' => 'reset_pvc_display'
89
- )
90
- );
91
-
92
- $this->user_roles = $this->get_user_roles();
93
-
94
- $this->page_types = apply_filters( 'pvc_page_types_display_options', array(
95
- 'home' => __( 'Home', 'post-views-counter' ),
96
- 'archive' => __( 'Archives', 'post-views-counter' ),
97
- 'singular' => __( 'Single pages', 'post-views-counter' ),
98
- 'search' => __( 'Search results', 'post-views-counter' ),
99
- ) );
100
- }
101
-
102
- /**
103
- * Get post types avaiable for counting.
104
- */
105
- public function load_post_types() {
106
-
107
- if ( ! is_admin() )
108
- return;
109
-
110
- $post_types = array();
111
-
112
- // built in public post types
113
- foreach ( get_post_types( array( '_builtin' => true, 'public' => true ), 'objects', 'and' ) as $key => $post_type ) {
114
- if ( $key !== 'attachment' )
115
- $post_types[$key] = $post_type->labels->name;
116
- }
117
-
118
- // public custom post types
119
- foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects', 'and' ) as $key => $post_type ) {
120
- $post_types[$key] = $post_type->labels->name;
121
- }
122
-
123
- // sort post types alphabetically with their keys
124
- asort( $post_types, SORT_STRING );
125
-
126
- $this->post_types = $post_types;
127
- }
128
-
129
- /**
130
- * Get all user roles.
131
- *
132
- * @global object $wp_roles
133
- */
134
- public function get_user_roles() {
135
- global $wp_roles;
136
-
137
- $roles = array();
138
-
139
- foreach ( apply_filters( 'editable_roles', $wp_roles->roles ) as $role => $details ) {
140
- $roles[$role] = translate_user_role( $details['name'] );
141
- }
142
-
143
- asort( $roles, SORT_STRING );
144
-
145
- return $roles;
146
- }
147
-
148
- /**
149
- * Add options page.
150
- */
151
- public function admin_menu_options() {
152
- add_options_page(
153
- __( 'Post Views Counter', 'post-views-counter' ), __( 'Post Views Counter', 'post-views-counter' ), 'manage_options', 'post-views-counter', array( $this, 'options_page' )
154
- );
155
- }
156
-
157
- /**
158
- * Options page callback.
159
- *
160
- * @return mixed
161
- */
162
- public function options_page() {
163
- $tab_key = (isset( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'general');
164
-
165
- echo '
166
- <div class="wrap">
167
- <h2>' . __( 'Post Views Counter', 'post-views-counter' ) . '</h2>
168
- <h2 class="nav-tab-wrapper">';
169
-
170
- foreach ( $this->tabs as $key => $name ) {
171
- echo '
172
- <a class="nav-tab ' . ($tab_key == $key ? 'nav-tab-active' : '') . '" href="' . esc_url( admin_url( 'options-general.php?page=post-views-counter&tab=' . $key ) ) . '">' . $name['name'] . '</a>';
173
- }
174
-
175
- echo '
176
- </h2>
177
- <div class="post-views-counter-settings">
178
- <div class="df-credits">
179
- <h3 class="hndle">' . __( 'Post Views Counter', 'post-views-counter' ) . ' ' . Post_Views_Counter()->defaults['version'] . '</h3>
180
- <div class="inside">
181
- <h4 class="inner">' . __( 'Need support?', 'post-views-counter' ) . '</h4>
182
- <p class="inner">' . sprintf( __( 'If you are having problems with this plugin, please browse it\'s <a href="%s" target="_blank">Documentation</a> or talk about them in the <a href="%s" target="_blank">Support forum</a>', 'post-views-counter' ), 'https://www.dfactory.eu/docs/post-views-counter/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=docs', 'https://www.dfactory.eu/support/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=support' ) . '</p>
183
- <hr />
184
- <h4 class="inner">' . __( 'Do you like this plugin?', 'post-views-counter' ) . '</h4>
185
- <p class="inner">' . sprintf( __( '<a href="%s" target="_blank">Rate it 5</a> on WordPress.org', 'post-views-counter' ), 'https://wordpress.org/support/plugin/post-views-counter/reviews/?filter=5' ) . '<br />' .
186
- sprintf( __( 'Blog about it & link to the <a href="%s" target="_blank">plugin page</a>.', 'post-views-counter' ), 'https://dfactory.eu/plugins/post-views-counter/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=blog-about' ) . '<br />' .
187
- sprintf( __( 'Check out our other <a href="%s" target="_blank">WordPress plugins</a>.', 'post-views-counter' ), 'https://dfactory.eu/plugins/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=other-plugins' ) . '
188
- </p>
189
- <hr />
190
- <p class="df-link inner">' . __( 'Created by', 'post-views-counter' ) . ' <a href="http://www.dfactory.eu/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=created-by" target="_blank" title="dFactory - Quality plugins for WordPress"><img src="' . POST_VIEWS_COUNTER_URL . '/images/logo-dfactory.png' . '" title="dFactory - Quality plugins for WordPress" alt="dFactory - Quality plugins for WordPress" /></a></p>
191
- </div>
192
- </div>
193
- <form action="options.php" method="post">';
194
-
195
- wp_nonce_field( 'update-options' );
196
- settings_fields( $this->tabs[$tab_key]['key'] );
197
- do_settings_sections( $this->tabs[$tab_key]['key'] );
198
-
199
- echo '
200
- <p class="submit">';
201
-
202
- submit_button( '', 'primary', $this->tabs[$tab_key]['submit'], false );
203
-
204
- echo ' ';
205
-
206
- submit_button( __( 'Reset to defaults', 'post-views-counter' ), 'secondary reset_pvc_settings', $this->tabs[$tab_key]['reset'], false );
207
-
208
- echo '
209
- </p>
210
- </form>
211
- </div>
212
- <div class="clear"></div>
213
- </div>';
214
- }
215
-
216
- /**
217
- * Register settings callback.
218
- */
219
- public function register_settings() {
220
- // general options
221
- register_setting( 'post_views_counter_settings_general', 'post_views_counter_settings_general', array( $this, 'validate_settings' ) );
222
- add_settings_section( 'post_views_counter_settings_general', __( 'General settings', 'post-views-counter' ), '', 'post_views_counter_settings_general' );
223
- add_settings_field( 'pvc_post_types_count', __( 'Post Types Count', 'post-views-counter' ), array( $this, 'post_types_count' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
224
- add_settings_field( 'pvc_counter_mode', __( 'Counter Mode', 'post-views-counter' ), array( $this, 'counter_mode' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
225
- add_settings_field( 'pvc_post_views_column', __( 'Post Views Column', 'post-views-counter' ), array( $this, 'post_views_column' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
226
- add_settings_field( 'pvc_restrict_edit_views', __( 'Restrict Edit', 'post-views-counter' ), array( $this, 'restrict_edit_views' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
227
- add_settings_field( 'pvc_time_between_counts', __( 'Count Interval', 'post-views-counter' ), array( $this, 'time_between_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
228
- add_settings_field( 'pvc_reset_counts', __( 'Reset Data Interval', 'post-views-counter' ), array( $this, 'reset_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
229
- add_settings_field( 'pvc_flush_interval', __( 'Flush Object Cache Interval', 'post-views-counter' ), array( $this, 'flush_interval' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
230
- add_settings_field( 'pvc_exclude', __( 'Exclude Visitors', 'post-views-counter' ), array( $this, 'exclude' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
231
- add_settings_field( 'pvc_exclude_ips', __( 'Exclude IPs', 'post-views-counter' ), array( $this, 'exclude_ips' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
232
- add_settings_field( 'pvc_strict_counts', __( 'Strict counts', 'post-views-counter' ), array( $this, 'strict_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
233
- add_settings_field( 'pvc_wp_postviews', __( 'Tools', 'post-views-counter' ), array( $this, 'wp_postviews' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
234
- add_settings_field( 'pvc_deactivation_delete', __( 'Deactivation', 'post-views-counter' ), array( $this, 'deactivation_delete' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
235
-
236
- // display options
237
- register_setting( 'post_views_counter_settings_display', 'post_views_counter_settings_display', array( $this, 'validate_settings' ) );
238
- add_settings_section( 'post_views_counter_settings_display', __( 'Display settings', 'post-views-counter' ), '', 'post_views_counter_settings_display' );
239
- add_settings_field( 'pvc_post_views_label', __( 'Post Views Label', 'post-views-counter' ), array( $this, 'post_views_label' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
240
- add_settings_field( 'pvc_post_types_display', __( 'Post Type', 'post-views-counter' ), array( $this, 'post_types_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
241
- add_settings_field( 'pvc_page_types_display', __( 'Page Type', 'post-views-counter' ), array( $this, 'page_types_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
242
- add_settings_field( 'pvc_restrict_display', __( 'User Type', 'post-views-counter' ), array( $this, 'restrict_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
243
- add_settings_field( 'pvc_position', __( 'Position', 'post-views-counter' ), array( $this, 'position' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
244
- add_settings_field( 'pvc_display_style', __( 'Display Style', 'post-views-counter' ), array( $this, 'display_style' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
245
- add_settings_field( 'pvc_icon_class', __( 'Icon Class', 'post-views-counter' ), array( $this, 'icon_class' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
246
- }
247
-
248
- /**
249
- * Post views label option.
250
- */
251
- public function post_views_label() {
252
- echo '
253
- <div id="pvc_post_views_label">
254
- <fieldset>
255
- <input type="text" class="large-text" name="post_views_counter_settings_display[label]" value="' . esc_attr( Post_Views_Counter()->options['display']['label'] ) . '" />
256
- <p class="description">' . __( 'Enter the label for the post views counter field.', 'post-views-counter' ) . '</p>
257
- </fieldset>
258
- </div>';
259
- }
260
-
261
- /**
262
- * Post types to count option.
263
- */
264
- public function post_types_count() {
265
- echo '
266
- <div id="pvc_post_types_count">';
267
-
268
- foreach ( $this->post_types as $post_type => $post_type_name ) {
269
- echo '
270
- <label class="cb-checkbox"><input id="pvc_post_types_count-' . esc_attr( $post_type ) . '" type="checkbox" name="post_views_counter_settings_general[post_types_count][' . esc_attr( $post_type ) . ']" value="1" ' . checked( in_array( $post_type, Post_Views_Counter()->options['general']['post_types_count'], true ), true, false ) . ' />' . esc_html( $post_type_name ) . ' </label>';
271
- }
272
-
273
- echo '
274
- <p class="description">' . __( 'Select post types for which post views will be counted.', 'post-views-counter' ) . '</p>
275
- </div>';
276
- }
277
-
278
- /**
279
- * Post types to display option.
280
- */
281
- public function post_types_display() {
282
- echo '
283
- <div id="pvc_post_types_display">';
284
-
285
- foreach ( $this->post_types as $post_type => $post_type_name ) {
286
- echo '
287
- <label class="cb-checkbox"><input id="pvc_post_types_display-' . esc_attr( $post_type ) . '" type="checkbox" name="post_views_counter_settings_display[post_types_display][' . esc_attr( $post_type ) . ']" value="1" ' . checked( in_array( $post_type, Post_Views_Counter()->options['display']['post_types_display'], true ), true, false ) . ' />' . esc_html( $post_type_name ) . '</label>';
288
- }
289
-
290
- echo '
291
- <p class="description">' . __( 'Select post types for which the views count will be displayed.', 'post-views-counter' ) . '</p>
292
- </div>';
293
- }
294
-
295
- /**
296
- * Counter mode option.
297
- */
298
- public function counter_mode() {
299
- echo '
300
- <div id="pvc_counter_mode">';
301
-
302
- foreach ( $this->modes as $key => $value ) {
303
- $key = esc_attr( $key );
304
-
305
- echo '
306
- <label class="cb-radio"><input type="radio" name="post_views_counter_settings_general[counter_mode]" value="' . $key . '" ' . checked( $key, Post_Views_Counter()->options['general']['counter_mode'], false ) . ' />' . esc_html( $value ) . '</label>';
307
- }
308
-
309
- echo '
310
- <p class="description">' . __( 'Select the method of collecting post views data. If you are using any of the caching plugins select Javascript or REST API (if available).', 'post-views-counter' ) . '<br />' . __( 'Optionally try the Fast AJAX experimental method, usually 10+ times faster than Javascript or REST API.', 'post-views-counter' ) . '</p>
311
- </div>';
312
- }
313
-
314
- /**
315
- * Post views column option.
316
- */
317
- public function post_views_column() {
318
- echo '
319
- <div id="pvc_post_views_column">
320
- <label class="cb-checkbox"><input id="pvc-post-views-column-enable" type="checkbox" name="post_views_counter_settings_general[post_views_column]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['post_views_column'], false ) . ' />' . __( 'Enable to display post views count column for each of the selected post types.', 'post-views-counter' ) . '</label>
321
- </div>';
322
- }
323
-
324
- /**
325
- * Time between counts option.
326
- */
327
- public function time_between_counts() {
328
- echo '
329
- <div id="pvc_time_between_counts">
330
- <input size="4" type="text" name="post_views_counter_settings_general[time_between_counts][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['time_between_counts']['number'] ) . '" />
331
- <select class="pvc-chosen-short" name="post_views_counter_settings_general[time_between_counts][type]">';
332
-
333
- foreach ( $this->time_types as $type => $type_name ) {
334
- echo '
335
- <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['time_between_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
336
- }
337
-
338
- echo '
339
- </select>
340
- <p class="description">' . __( 'Enter the time between single user visit count.', 'post-views-counter' ) . '</p>
341
- </div>';
342
- }
343
-
344
- /**
345
- * Reset counts option.
346
- */
347
- public function reset_counts() {
348
- echo '
349
- <div id="pvc_reset_counts">
350
- <input size="4" type="text" name="post_views_counter_settings_general[reset_counts][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['reset_counts']['number'] ) . '" />
351
- <select class="pvc-chosen-short" name="post_views_counter_settings_general[reset_counts][type]">';
352
-
353
- foreach ( array_slice( $this->time_types, 2, null, true ) as $type => $type_name ) {
354
- echo '
355
- <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['reset_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
356
- }
357
-
358
- echo '
359
- </select>
360
- <p class="description">' . __( 'Delete single day post views data older than specified above. Enter 0 (number zero) if you want to preserve your data regardless of its age.', 'post-views-counter' ) . '</p>
361
- </div>';
362
- }
363
-
364
- /**
365
- * Flush interval option.
366
- */
367
- public function flush_interval() {
368
- echo '
369
- <div id="pvc_flush_interval">
370
- <input size="4" type="text" name="post_views_counter_settings_general[flush_interval][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['flush_interval']['number'] ) . '" />
371
- <select class="pvc-chosen-short" name="post_views_counter_settings_general[flush_interval][type]">';
372
-
373
- foreach ( $this->time_types as $type => $type_name ) {
374
- echo '
375
- <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['flush_interval']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
376
- }
377
-
378
- echo '
379
- </select>
380
- <p class="description">' . __( 'How often to flush cached view counts from the object cache into the database. This feature is used only if a persistent object cache is detected and the interval is greater than 0 (number zero)). When used, view counts will be collected and stored in the object cache instead of the database and will then be asynchronously flushed to the database according to the specified interval.<br /><strong>Notice:</strong> Potential data loss may occur if the object cache is cleared/unavailable for the duration of the interval.', 'post-views-counter' ) . '</p>
381
- </div>';
382
- }
383
-
384
- /**
385
- * Exlude user groups option.
386
- */
387
- public function exclude() {
388
- echo '
389
- <div id="pvc_exclude">
390
- <fieldset>';
391
-
392
- foreach ( $this->groups as $type => $type_name ) {
393
- echo '
394
- <label class="cb-checkbox"><input id="pvc_exclude-' . $type . '" type="checkbox" name="post_views_counter_settings_general[exclude][groups][' . $type . ']" value="1" ' . checked( in_array( $type, Post_Views_Counter()->options['general']['exclude']['groups'], true ), true, false ) . ' />' . esc_html( $type_name ) . '</label>';
395
- }
396
-
397
- echo '
398
- <p class="description">' . __( 'Use it to hide the post views counter from selected type of visitors.', 'post-views-counter' ) . '</p>
399
- <div class="pvc_user_roles"' . (in_array( 'roles', Post_Views_Counter()->options['general']['exclude']['groups'], true ) ? '' : ' style="display: none;"') . '>';
400
-
401
- foreach ( $this->user_roles as $role => $role_name ) {
402
- echo '
403
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[exclude][roles][' . $role . ']" value="1" ' . checked( in_array( $role, Post_Views_Counter()->options['general']['exclude']['roles'], true ), true, false ) . '>' . esc_html( $role_name ) . '</label>';
404
- }
405
-
406
- echo ' <p class="description">' . __( 'Use it to hide the post views counter from selected user roles.', 'post-views-counter' ) . '</p>
407
- </div>
408
- </fieldset>
409
- </div>';
410
- }
411
-
412
- /**
413
- * Exclude IPs option.
414
- */
415
- public function exclude_ips() {
416
- // lovely php 5.2 limitations
417
- $ips = Post_Views_Counter()->options['general']['exclude_ips'];
418
-
419
- echo '
420
- <div id="pvc_exclude_ips">';
421
-
422
- if ( ! empty( $ips ) ) {
423
- foreach ( $ips as $key => $ip ) {
424
- echo '
425
- <div class="ip-box">
426
- <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="' . esc_attr( $ip ) . '" /> <a href="#" class="remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_attr__( 'Remove', 'post-views-counter' ) . '</a>
427
- </div>';
428
- }
429
- } else {
430
- echo '
431
- <div class="ip-box">
432
- <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="" /> <a href="#" class="remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_attr__( 'Remove', 'post-views-counter' ) . '</a>
433
- </div>';
434
- }
435
-
436
- echo '
437
- <p><input type="button" class="button button-secondary add-exclude-ip" value="' . esc_attr__( 'Add new', 'post-views-counter' ) . '" /> <input type="button" class="button button-secondary add-current-ip" value="' . esc_attr__( 'Add my current IP', 'post-views-counter' ) . '" data-rel="' . esc_attr( $_SERVER['REMOTE_ADDR'] ) . '" /></p>
438
- <p class="description">' . __( 'Enter the IP addresses to be excluded from post views count.', 'post-views-counter' ) . '</p>
439
- </div>';
440
- }
441
-
442
- /**
443
- * Strict counts option.
444
- */
445
- public function strict_counts() {
446
- echo '
447
- <div id="pvc_strict_counts">
448
- <label class="cb-checkbox"><input id="pvc-strict-counts" type="checkbox" name="post_views_counter_settings_general[strict_counts]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['strict_counts'], false ) . ' />' . __( 'Enable to prevent bypassing the counts interval (for e.g. using incognito browser window or by clearing cookies).', 'post-views-counter' ) . '</label>
449
- </div>';
450
- }
451
-
452
- /**
453
- * WP-PostViews import option.
454
- */
455
- public function wp_postviews() {
456
- echo '
457
- <div id="pvc_wp_postviews">
458
- <fieldset>
459
- <input type="submit" class="button button-secondary" name="post_views_counter_import_wp_postviews" value="' . __( 'Import views', 'post-views-counter' ) . '"/> <label class="cb-checkbox"><input id="pvc-wp-postviews" type="checkbox" name="post_views_counter_import_wp_postviews_override" value="1" />' . __( 'Override existing views data.', 'post-views-counter' ) . '</label>
460
- <p class="description">' . __( 'Import post views data from WP-PostViews plugin.', 'post-views-counter' ) . '</p>
461
- <input type="submit" class="button button-secondary" name="post_views_counter_reset_views" value="' . __( 'Delete views', 'post-views-counter' ) . '"/>
462
- <p class="description">' . __( 'Delete ALL the existing post views data.', 'post-views-counter' ) . '</p>
463
- </fieldset>
464
- </div>';
465
- }
466
-
467
- /**
468
- * Limit views edit to admins.
469
- */
470
- public function restrict_edit_views() {
471
- echo '
472
- <div id="pvc_restrict_edit_views">
473
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[restrict_edit_views]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['restrict_edit_views'], false ) . ' />' . __( 'Enable to restrict post views editing to admins only.', 'post-views-counter' ) . '</label>
474
- </div>';
475
- }
476
-
477
- /**
478
- * Plugin deactivation option.
479
- */
480
- public function deactivation_delete() {
481
- echo '
482
- <div id="pvc_deactivation_delete">
483
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[deactivation_delete]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['deactivation_delete'], false ) . ' />' . __( 'Enable to delete all plugin data on deactivation.', 'post-views-counter' ) . '</label>
484
- </div>';
485
- }
486
-
487
- /**
488
- * Visibility option.
489
- */
490
- public function page_types_display() {
491
- echo '
492
- <div id="pvc_post_types_display">';
493
-
494
- foreach ( $this->page_types as $key => $label ) {
495
- echo '
496
- <label class="cb-checkbox"><input id="pvc_page_types_display-' . esc_attr( $key ) . '" type="checkbox" name="post_views_counter_settings_display[page_types_display][' . esc_attr( $key ) . ']" value="1" ' . checked( in_array( $key, Post_Views_Counter()->options['display']['page_types_display'], true ), true, false ) . ' />' . esc_html( $label ) . '</label>';
497
- }
498
-
499
- echo '
500
- <p class="description">' . __( 'Select page types where the views count will be displayed.', 'post-views-counter' ) . '</p>
501
- </div>';
502
- }
503
-
504
- /**
505
- * Counter position option.
506
- */
507
- public function position() {
508
- echo '
509
- <div id="pvc_position">
510
- <select class="pvc-chosen-short" name="post_views_counter_settings_display[position]">';
511
-
512
- foreach ( $this->positions as $position => $position_name ) {
513
- echo '
514
- <option value="' . esc_attr( $position ) . '" ' . selected( $position, Post_Views_Counter()->options['display']['position'], false ) . '>' . esc_html( $position_name ) . '</option>';
515
- }
516
-
517
- echo '
518
- </select>
519
- <p class="description">' . __( 'Select where would you like to display the post views counter. Use [post-views] shortcode for manual display.', 'post-views-counter' ) . '</p>
520
- </div>';
521
- }
522
-
523
- /**
524
- * Counter style option.
525
- */
526
- public function display_style() {
527
- echo '
528
- <div id="pvc_display_style">';
529
-
530
- foreach ( $this->display_styles as $display => $style ) {
531
- $display = esc_attr( $display );
532
-
533
- echo '
534
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_display[display_style][' . $display . ']" value="1" ' . checked( true, Post_Views_Counter()->options['display']['display_style'][$display], false ) . ' />' . esc_html( $style ) . '</label>';
535
- }
536
-
537
- echo '
538
- <p class="description">' . __( 'Choose how to display the post views counter.', 'post-views-counter' ) . '</p>
539
- </div>';
540
- }
541
-
542
- /**
543
- * Counter icon class option.
544
- */
545
- public function icon_class() {
546
- echo '
547
- <div id="pvc_icon_class">
548
- <input type="text" name="post_views_counter_settings_display[icon_class]" class="large-text" value="' . esc_attr( Post_Views_Counter()->options['display']['icon_class'] ) . '" />
549
- <p class="description">' . sprintf( __( 'Enter the post views icon class. Any of the <a href="%s" target="_blank">Dashicons</a> classes are available.', 'post-views-counter' ), 'https://developer.wordpress.org/resource/dashicons/' ) . '</p>
550
- </div>';
551
- }
552
-
553
- /**
554
- * Restrict display option.
555
- */
556
- public function restrict_display() {
557
- echo '
558
- <div id="pvc_restrict_display">
559
- <fieldset>';
560
-
561
- foreach ( $this->groups as $type => $type_name ) {
562
-
563
- if ( $type === 'robots' )
564
- continue;
565
-
566
- echo '
567
- <label class="cb-checkbox"><input id="pvc_restrict_display-' . $type . '" type="checkbox" name="post_views_counter_settings_display[restrict_display][groups][' . esc_html( $type ) . ']" value="1" ' . checked( in_array( $type, Post_Views_Counter()->options['display']['restrict_display']['groups'], true ), true, false ) . ' />' . esc_html( $type_name ) . '</label>';
568
- }
569
-
570
- echo '
571
- <p class="description">' . __( 'Use it to hide the post views counter from selected type of visitors.', 'post-views-counter' ) . '</p>
572
- <div class="pvc_user_roles"' . (in_array( 'roles', Post_Views_Counter()->options['display']['restrict_display']['groups'], true ) ? '' : ' style="display: none;"') . '>';
573
-
574
- foreach ( $this->user_roles as $role => $role_name ) {
575
- echo '
576
- <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_display[restrict_display][roles][' . $role . ']" value="1" ' . checked( in_array( $role, Post_Views_Counter()->options['display']['restrict_display']['roles'], true ), true, false ) . ' />' . esc_html( $role_name ) . '</label>';
577
- }
578
-
579
- echo '
580
- <p class="description">' . __( 'Use it to hide the post views counter from selected user roles.', 'post-views-counter' ) . '</p>
581
- </div>
582
- </fieldset>
583
- </div>';
584
- }
585
-
586
- /**
587
- * Validate general settings.
588
- */
589
- public function validate_settings( $input ) {
590
- if ( isset( $_POST['post_views_counter_import_wp_postviews'] ) ) {
591
- global $wpdb;
592
-
593
- $meta_key = esc_attr( apply_filters( 'pvc_import_meta_key', 'views' ) );
594
-
595
- $views = $wpdb->get_results( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = '" . $meta_key . "'", ARRAY_A, 0 );
596
-
597
- if ( ! empty( $views ) ) {
598
- $input = Post_Views_Counter()->defaults['general'];
599
- $input['wp_postviews_import'] = true;
600
-
601
- $sql = array();
602
-
603
- foreach ( $views as $view ) {
604
- $sql[] = "(" . $view['post_id'] . ", 4, 'total', " . $view['meta_value'] . ")";
605
- }
606
-
607
- $wpdb->query( "INSERT INTO " . $wpdb->prefix . "post_views(id, type, period, count) VALUES " . implode( ',', $sql ) . " ON DUPLICATE KEY UPDATE count = " . (isset( $_POST['post_views_counter_import_wp_postviews_override'] ) ? '' : 'count + ') . "VALUES(count)" );
608
-
609
- add_settings_error( 'wp_postviews_import', 'wp_postviews_import', __( 'Post views data imported succesfully.', 'post-views-counter' ), 'updated' );
610
- } else {
611
- add_settings_error( 'wp_postviews_import', 'wp_postviews_import', __( 'There was no post views data to import.', 'post-views-counter' ), 'updated' );
612
- }
613
- } elseif ( isset( $_POST['post_views_counter_reset_views'] ) ) {
614
- global $wpdb;
615
-
616
- if ( $wpdb->query( 'TRUNCATE TABLE ' . $wpdb->prefix . 'post_views' ) )
617
- add_settings_error( 'reset_post_views', 'reset_post_views', __( 'All existing data deleted succesfully.', 'post-views-counter' ), 'updated' );
618
- else
619
- add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Error occurred. All existing data were not deleted.', 'post-views-counter' ), 'error' );
620
- } elseif ( isset( $_POST['save_pvc_general'] ) ) {
621
- // post types count
622
- if ( isset( $input['post_types_count'] ) ) {
623
- $post_types = array();
624
-
625
- foreach ( $input['post_types_count'] as $post_type => $set ) {
626
- if ( isset( $this->post_types[$post_type] ) )
627
- $post_types[] = $post_type;
628
- }
629
-
630
- $input['post_types_count'] = array_unique( $post_types );
631
- } else
632
- $input['post_types_count'] = array();
633
-
634
- // counter mode
635
- $input['counter_mode'] = isset( $input['counter_mode'], $this->modes[$input['counter_mode']] ) ? $input['counter_mode'] : Post_Views_Counter()->defaults['general']['counter_mode'];
636
-
637
- // post views column
638
- $input['post_views_column'] = isset( $input['post_views_column'] );
639
-
640
- // time between counts
641
- $input['time_between_counts']['number'] = (int) ( isset( $input['time_between_counts']['number'] ) ? $input['time_between_counts']['number'] : Post_Views_Counter()->defaults['general']['time_between_counts']['number'] );
642
- $input['time_between_counts']['type'] = isset( $input['time_between_counts']['type'], $this->time_types[$input['time_between_counts']['type']] ) ? $input['time_between_counts']['type'] : Post_Views_Counter()->defaults['general']['time_between_counts']['type'];
643
-
644
- // flush interval
645
- $input['flush_interval']['number'] = (int) ( isset( $input['flush_interval']['number'] ) ? $input['flush_interval']['number'] : Post_Views_Counter()->defaults['general']['flush_interval']['number'] );
646
- $input['flush_interval']['type'] = isset( $input['flush_interval']['type'], $this->time_types[$input['flush_interval']['type']] ) ? $input['flush_interval']['type'] : Post_Views_Counter()->defaults['general']['flush_interval']['type'];
647
-
648
- // Since the settings are about to be saved and cache flush interval could've changed,
649
- // we want to make sure that any changes done on the settings page are in effect immediately
650
- // (instead of having to wait for the previous schedule to occur).
651
- // We achieve that by making sure to clear any previous cache flush schedules and
652
- // schedule the new one if the specified interval is > 0
653
- Post_Views_Counter()->remove_cache_flush();
654
-
655
- if ( $input['flush_interval']['number'] > 0 ) {
656
- Post_Views_Counter()->schedule_cache_flush();
657
- }
658
-
659
- // reset counts
660
- $input['reset_counts']['number'] = (int) ( isset( $input['reset_counts']['number'] ) ? $input['reset_counts']['number'] : Post_Views_Counter()->defaults['general']['reset_counts']['number'] );
661
- $input['reset_counts']['type'] = isset( $input['reset_counts']['type'], $this->time_types[$input['reset_counts']['type']] ) ? $input['reset_counts']['type'] : Post_Views_Counter()->defaults['general']['reset_counts']['type'];
662
-
663
- // run cron on next visit?
664
- $input['cron_run'] = ($input['reset_counts']['number'] > 0 ? true : false);
665
- $input['cron_update'] = ($input['cron_run'] && (Post_Views_Counter()->options['general']['reset_counts']['number'] !== $input['reset_counts']['number'] || Post_Views_Counter()->options['general']['reset_counts']['type'] !== $input['reset_counts']['type']) ? true : false);
666
-
667
- // exclude
668
- if ( isset( $input['exclude']['groups'] ) ) {
669
- $groups = array();
670
-
671
- foreach ( $input['exclude']['groups'] as $group => $set ) {
672
- if ( isset( $this->groups[$group] ) )
673
- $groups[] = $group;
674
- }
675
-
676
- $input['exclude']['groups'] = array_unique( $groups );
677
- } else {
678
- $input['exclude']['groups'] = array();
679
- }
680
-
681
- if ( in_array( 'roles', $input['exclude']['groups'], true ) && isset( $input['exclude']['roles'] ) ) {
682
- $roles = array();
683
-
684
- foreach ( $input['exclude']['roles'] as $role => $set ) {
685
- if ( isset( $this->user_roles[$role] ) )
686
- $roles[] = $role;
687
- }
688
-
689
- $input['exclude']['roles'] = array_unique( $roles );
690
- } else
691
- $input['exclude']['roles'] = array();
692
-
693
- // exclude ips
694
- if ( isset( $input['exclude_ips'] ) ) {
695
- $ips = array();
696
-
697
- foreach ( $input['exclude_ips'] as $ip ) {
698
- if ( strpos( $ip, '*' ) !== false ) {
699
- $new_ip = str_replace( '*', '0', $ip );
700
-
701
- if ( filter_var( $new_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) )
702
- $ips[] = $ip;
703
- } elseif ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) )
704
- $ips[] = $ip;
705
- }
706
-
707
- $input['exclude_ips'] = array_unique( $ips );
708
- }
709
-
710
- // restrict edit views
711
- $input['restrict_edit_views'] = isset( $input['restrict_edit_views'] );
712
-
713
- // strict counts
714
- $input['strict_counts'] = isset( $input['strict_counts'] );
715
-
716
- // deactivation delete
717
- $input['deactivation_delete'] = isset( $input['deactivation_delete'] );
718
- } elseif ( isset( $_POST['save_pvc_display'] ) ) {
719
-
720
- // post views label
721
- $input['label'] = isset( $input['label'] ) ? $input['label'] : Post_Views_Counter()->defaults['general']['label'];
722
-
723
- if ( function_exists( 'icl_register_string' ) )
724
- icl_register_string( 'Post Views Counter', 'Post Views Label', $input['label'] );
725
-
726
- // position
727
- $input['position'] = isset( $input['position'], $this->positions[$input['position']] ) ? $input['position'] : Post_Views_Counter()->defaults['general']['position'];
728
-
729
- // display style
730
- $input['display_style']['icon'] = isset( $input['display_style']['icon'] );
731
- $input['display_style']['text'] = isset( $input['display_style']['text'] );
732
-
733
- // link to post
734
- $input['link_to_post'] = isset( $input['link_to_post'] ) ? $input['link_to_post'] : Post_Views_Counter()->defaults['display']['link_to_post'];
735
-
736
- // icon class
737
- $input['icon_class'] = isset( $input['icon_class'] ) ? trim( $input['icon_class'] ) : Post_Views_Counter()->defaults['general']['icon_class'];
738
-
739
- // post types display
740
- if ( isset( $input['post_types_display'] ) ) {
741
- $post_types = array();
742
-
743
- foreach ( $input['post_types_display'] as $post_type => $set ) {
744
- if ( isset( $this->post_types[$post_type] ) )
745
- $post_types[] = $post_type;
746
- }
747
-
748
- $input['post_types_display'] = array_unique( $post_types );
749
- } else
750
- $input['post_types_display'] = array();
751
-
752
- // page types display
753
- if ( isset( $input['page_types_display'] ) ) {
754
- $page_types = array();
755
-
756
- foreach ( $input['page_types_display'] as $page_type => $set ) {
757
- if ( isset( $this->page_types[$page_type] ) )
758
- $page_types[] = $page_type;
759
- }
760
-
761
- $input['page_types_display'] = array_unique( $page_types );
762
- } else
763
- $input['page_types_display'] = array();
764
-
765
- // restrict display
766
- if ( isset( $input['restrict_display']['groups'] ) ) {
767
- $groups = array();
768
-
769
- foreach ( $input['restrict_display']['groups'] as $group => $set ) {
770
- if ( $group === 'robots' )
771
- continue;
772
-
773
- if ( isset( $this->groups[$group] ) )
774
- $groups[] = $group;
775
- }
776
-
777
- $input['restrict_display']['groups'] = array_unique( $groups );
778
- } else
779
- $input['restrict_display']['groups'] = array();
780
-
781
- if ( in_array( 'roles', $input['restrict_display']['groups'], true ) && isset( $input['restrict_display']['roles'] ) ) {
782
- $roles = array();
783
-
784
- foreach ( $input['restrict_display']['roles'] as $role => $set ) {
785
- if ( isset( $this->user_roles[$role] ) )
786
- $roles[] = $role;
787
- }
788
-
789
- $input['restrict_display']['roles'] = array_unique( $roles );
790
- } else
791
- $input['restrict_display']['roles'] = array();
792
- } elseif ( isset( $_POST['reset_pvc_general'] ) ) {
793
- $input = Post_Views_Counter()->defaults['general'];
794
-
795
- add_settings_error( 'reset_general_settings', 'settings_reset', __( 'General settings restored to defaults.', 'post-views-counter' ), 'updated' );
796
- } elseif ( isset( $_POST['reset_pvc_display'] ) ) {
797
- $input = Post_Views_Counter()->defaults['display'];
798
-
799
- add_settings_error( 'reset_general_settings', 'settings_reset', __( 'Display settings restored to defaults.', 'post-views-counter' ), 'updated' );
800
- }
801
-
802
- return $input;
803
- }
 
 
 
 
 
 
 
 
 
 
 
 
804
  }
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Settings class.
8
+ *
9
+ * @class Post_Views_Counter_Settings
10
+ */
11
+ class Post_Views_Counter_Settings {
12
+
13
+ private $tabs;
14
+ private $choices;
15
+ private $modes;
16
+ private $time_types;
17
+ private $groups;
18
+ private $user_roles;
19
+ private $positions;
20
+ private $display_styles;
21
+ public $post_types;
22
+ public $page_types;
23
+
24
+ public function __construct() {
25
+ // actions
26
+ add_action( 'admin_init', array( $this, 'register_settings' ) );
27
+ add_action( 'admin_menu', array( $this, 'admin_menu_options' ) );
28
+ add_action( 'after_setup_theme', array( $this, 'load_defaults' ) );
29
+ add_action( 'wp_loaded', array( $this, 'load_post_types' ) );
30
+ }
31
+
32
+ /**
33
+ * Load default settings.
34
+ */
35
+ public function load_defaults() {
36
+ if ( ! is_admin() )
37
+ return;
38
+
39
+ $this->modes = array(
40
+ 'php' => __( 'PHP', 'post-views-counter' ),
41
+ 'js' => __( 'JavaScript', 'post-views-counter' ),
42
+ 'ajax' => __( 'Fast AJAX', 'post-views-counter' )
43
+ );
44
+
45
+ if ( function_exists( 'register_rest_route' ) )
46
+ $this->modes['rest_api'] = __( 'REST API', 'post-views-counter' );
47
+
48
+ $this->time_types = array(
49
+ 'minutes' => __( 'minutes', 'post-views-counter' ),
50
+ 'hours' => __( 'hours', 'post-views-counter' ),
51
+ 'days' => __( 'days', 'post-views-counter' ),
52
+ 'weeks' => __( 'weeks', 'post-views-counter' ),
53
+ 'months' => __( 'months', 'post-views-counter' ),
54
+ 'years' => __( 'years', 'post-views-counter' )
55
+ );
56
+
57
+ $this->groups = array(
58
+ 'robots' => __( 'robots', 'post-views-counter' ),
59
+ 'users' => __( 'logged in users', 'post-views-counter' ),
60
+ 'guests' => __( 'guests', 'post-views-counter' ),
61
+ 'roles' => __( 'selected user roles', 'post-views-counter' )
62
+ );
63
+
64
+ $this->positions = array(
65
+ 'before' => __( 'before the content', 'post-views-counter' ),
66
+ 'after' => __( 'after the content', 'post-views-counter' ),
67
+ 'manual' => __( 'manual', 'post-views-counter' )
68
+ );
69
+
70
+ $this->display_styles = array(
71
+ 'icon' => __( 'icon', 'post-views-counter' ),
72
+ 'text' => __( 'label', 'post-views-counter' )
73
+ );
74
+
75
+ $this->tabs = array(
76
+ 'general' => array(
77
+ 'name' => __( 'General', 'post-views-counter' ),
78
+ 'key' => 'post_views_counter_settings_general',
79
+ 'submit' => 'save_pvc_general',
80
+ 'reset' => 'reset_pvc_general'
81
+ ),
82
+ 'display' => array(
83
+ 'name' => __( 'Display', 'post-views-counter' ),
84
+ 'key' => 'post_views_counter_settings_display',
85
+ 'submit' => 'save_pvc_display',
86
+ 'reset' => 'reset_pvc_display'
87
+ )
88
+ );
89
+
90
+ $this->user_roles = $this->get_user_roles();
91
+
92
+ $this->page_types = apply_filters(
93
+ 'pvc_page_types_display_options',
94
+ array(
95
+ 'home' => __( 'Home', 'post-views-counter' ),
96
+ 'archive' => __( 'Archives', 'post-views-counter' ),
97
+ 'singular' => __( 'Single pages', 'post-views-counter' ),
98
+ 'search' => __( 'Search results', 'post-views-counter' ),
99
+ )
100
+ );
101
+ }
102
+
103
+ /**
104
+ * Get post types avaiable for counting.
105
+ */
106
+ public function load_post_types() {
107
+ if ( ! is_admin() )
108
+ return;
109
+
110
+ $post_types = array();
111
+
112
+ // built in public post types
113
+ foreach ( get_post_types( array( '_builtin' => true, 'public' => true ), 'objects', 'and' ) as $key => $post_type ) {
114
+ $post_types[$key] = $post_type->labels->name;
115
+ }
116
+
117
+ // public custom post types
118
+ foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects', 'and' ) as $key => $post_type ) {
119
+ $post_types[$key] = $post_type->labels->name;
120
+ }
121
+
122
+ // remove bbPress replies
123
+ if ( class_exists( 'bbPress' ) && isset( $post_types['reply'] ) )
124
+ unset( $post_types['reply'] );
125
+
126
+ $post_types = apply_filters( 'pvc_available_post_types', $post_types );
127
+
128
+ // sort post types alphabetically with their keys
129
+ asort( $post_types, SORT_STRING );
130
+
131
+ $this->post_types = $post_types;
132
+ }
133
+
134
+ /**
135
+ * Get all user roles.
136
+ *
137
+ * @global object $wp_roles
138
+ * @return array
139
+ */
140
+ public function get_user_roles() {
141
+ global $wp_roles;
142
+
143
+ $roles = array();
144
+
145
+ foreach ( apply_filters( 'editable_roles', $wp_roles->roles ) as $role => $details ) {
146
+ $roles[$role] = translate_user_role( $details['name'] );
147
+ }
148
+
149
+ asort( $roles, SORT_STRING );
150
+
151
+ return $roles;
152
+ }
153
+
154
+ /**
155
+ * Add options page.
156
+ *
157
+ * @return void
158
+ */
159
+ public function admin_menu_options() {
160
+ add_options_page( __( 'Post Views Counter', 'post-views-counter' ), __( 'Post Views Counter', 'post-views-counter' ), 'manage_options', 'post-views-counter', array( $this, 'options_page' ) );
161
+ }
162
+
163
+ /**
164
+ * Options page callback.
165
+ *
166
+ * @return void
167
+ */
168
+ public function options_page() {
169
+ $tab_key = (isset( $_GET['tab'] ) ? esc_attr( $_GET['tab'] ) : 'general');
170
+
171
+ echo '
172
+ <div class="wrap">
173
+ <h2>' . __( 'Post Views Counter', 'post-views-counter' ) . '</h2>
174
+ <h2 class="nav-tab-wrapper">';
175
+
176
+ foreach ( $this->tabs as $key => $name ) {
177
+ echo '
178
+ <a class="nav-tab ' . ($tab_key == $key ? 'nav-tab-active' : '') . '" href="' . esc_url( admin_url( 'options-general.php?page=post-views-counter&tab=' . $key ) ) . '">' . $name['name'] . '</a>';
179
+ }
180
+
181
+ echo '
182
+ </h2>
183
+ <div class="post-views-counter-settings">
184
+ <div class="df-credits">
185
+ <h3 class="hndle">' . __( 'Post Views Counter', 'post-views-counter' ) . ' ' . Post_Views_Counter()->defaults['version'] . '</h3>
186
+ <div class="inside">
187
+ <h4 class="inner">' . __( 'Need support?', 'post-views-counter' ) . '</h4>
188
+ <p class="inner">' . sprintf( __( 'If you are having problems with this plugin, please browse it\'s <a href="%s" target="_blank">Documentation</a> or talk about them in the <a href="%s" target="_blank">Support forum</a>', 'post-views-counter' ), 'https://www.dfactory.eu/docs/post-views-counter/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=docs', 'https://www.dfactory.eu/support/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=support' ) . '</p>
189
+ <hr />
190
+ <h4 class="inner">' . __( 'Do you like this plugin?', 'post-views-counter' ) . '</h4>
191
+ <p class="inner">' . sprintf( __( '<a href="%s" target="_blank">Rate it 5</a> on WordPress.org', 'post-views-counter' ), 'https://wordpress.org/support/plugin/post-views-counter/reviews/?filter=5' ) . '<br />' .
192
+ sprintf( __( 'Blog about it & link to the <a href="%s" target="_blank">plugin page</a>.', 'post-views-counter' ), 'https://dfactory.eu/plugins/post-views-counter/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=blog-about' ) . '<br />' .
193
+ sprintf( __( 'Check out our other <a href="%s" target="_blank">WordPress plugins</a>.', 'post-views-counter' ), 'https://dfactory.eu/plugins/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=other-plugins' ) . '
194
+ </p>
195
+ <hr />
196
+ <p class="df-link inner"><a href="http://www.dfactory.eu/?utm_source=post-views-counter-settings&utm_medium=link&utm_campaign=created-by" target="_blank" title="Digital Factory"><img src="//pvc-53eb.kxcdn.com/df-black-sm.png' . '" alt="Digital Factory" /></a></p>
197
+ </div>
198
+ </div>
199
+ <form action="options.php" method="post">';
200
+
201
+ wp_nonce_field( 'update-options' );
202
+ settings_fields( $this->tabs[$tab_key]['key'] );
203
+ do_settings_sections( $this->tabs[$tab_key]['key'] );
204
+
205
+ echo '
206
+ <p class="submit">';
207
+
208
+ submit_button( '', 'primary', $this->tabs[$tab_key]['submit'], false );
209
+
210
+ echo ' ';
211
+
212
+ submit_button( __( 'Reset to defaults', 'post-views-counter' ), 'secondary reset_pvc_settings', $this->tabs[$tab_key]['reset'], false );
213
+
214
+ echo '
215
+ </p>
216
+ </form>
217
+ </div>
218
+ <div class="clear"></div>
219
+ </div>';
220
+ }
221
+
222
+ /**
223
+ * Register settings callback.
224
+ */
225
+ public function register_settings() {
226
+ // general options
227
+ register_setting( 'post_views_counter_settings_general', 'post_views_counter_settings_general', array( $this, 'validate_settings' ) );
228
+ add_settings_section( 'post_views_counter_settings_general', __( 'General settings', 'post-views-counter' ), '', 'post_views_counter_settings_general' );
229
+ add_settings_field( 'pvc_post_types_count', __( 'Post Types Count', 'post-views-counter' ), array( $this, 'post_types_count' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
230
+ add_settings_field( 'pvc_counter_mode', __( 'Counter Mode', 'post-views-counter' ), array( $this, 'counter_mode' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
231
+ add_settings_field( 'pvc_post_views_column', __( 'Post Views Column', 'post-views-counter' ), array( $this, 'post_views_column' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
232
+ add_settings_field( 'pvc_restrict_edit_views', __( 'Restrict Edit', 'post-views-counter' ), array( $this, 'restrict_edit_views' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
233
+ add_settings_field( 'pvc_time_between_counts', __( 'Count Interval', 'post-views-counter' ), array( $this, 'time_between_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
234
+ add_settings_field( 'pvc_reset_counts', __( 'Reset Data Interval', 'post-views-counter' ), array( $this, 'reset_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
235
+ add_settings_field( 'pvc_flush_interval', __( 'Flush Object Cache Interval', 'post-views-counter' ), array( $this, 'flush_interval' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
236
+ add_settings_field( 'pvc_exclude', __( 'Exclude Visitors', 'post-views-counter' ), array( $this, 'exclude' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
237
+ add_settings_field( 'pvc_exclude_ips', __( 'Exclude IPs', 'post-views-counter' ), array( $this, 'exclude_ips' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
238
+ add_settings_field( 'pvc_strict_counts', __( 'Strict counts', 'post-views-counter' ), array( $this, 'strict_counts' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
239
+ add_settings_field( 'pvc_wp_postviews', __( 'Tools', 'post-views-counter' ), array( $this, 'wp_postviews' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
240
+ add_settings_field( 'pvc_deactivation_delete', __( 'Deactivation', 'post-views-counter' ), array( $this, 'deactivation_delete' ), 'post_views_counter_settings_general', 'post_views_counter_settings_general' );
241
+
242
+ // display options
243
+ register_setting( 'post_views_counter_settings_display', 'post_views_counter_settings_display', array( $this, 'validate_settings' ) );
244
+ add_settings_section( 'post_views_counter_settings_display', __( 'Display settings', 'post-views-counter' ), '', 'post_views_counter_settings_display' );
245
+ add_settings_field( 'pvc_post_views_label', __( 'Post Views Label', 'post-views-counter' ), array( $this, 'post_views_label' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
246
+ add_settings_field( 'pvc_post_types_display', __( 'Post Type', 'post-views-counter' ), array( $this, 'post_types_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
247
+ add_settings_field( 'pvc_page_types_display', __( 'Page Type', 'post-views-counter' ), array( $this, 'page_types_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
248
+ add_settings_field( 'pvc_restrict_display', __( 'User Type', 'post-views-counter' ), array( $this, 'restrict_display' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
249
+ add_settings_field( 'pvc_position', __( 'Position', 'post-views-counter' ), array( $this, 'position' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
250
+ add_settings_field( 'pvc_display_style', __( 'Display Style', 'post-views-counter' ), array( $this, 'display_style' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
251
+ add_settings_field( 'pvc_icon_class', __( 'Icon Class', 'post-views-counter' ), array( $this, 'icon_class' ), 'post_views_counter_settings_display', 'post_views_counter_settings_display' );
252
+ }
253
+
254
+ /**
255
+ * Post views label option.
256
+ */
257
+ public function post_views_label() {
258
+ echo '
259
+ <div id="pvc_post_views_label">
260
+ <fieldset>
261
+ <input type="text" class="large-text" name="post_views_counter_settings_display[label]" value="' . esc_attr( Post_Views_Counter()->options['display']['label'] ) . '" />
262
+ <p class="description">' . __( 'Enter the label for the post views counter field.', 'post-views-counter' ) . '</p>
263
+ </fieldset>
264
+ </div>';
265
+ }
266
+
267
+ /**
268
+ * Post types to count option.
269
+ */
270
+ public function post_types_count() {
271
+ echo '
272
+ <div id="pvc_post_types_count">';
273
+
274
+ foreach ( $this->post_types as $post_type => $post_type_name ) {
275
+ echo '
276
+ <label class="cb-checkbox"><input id="pvc_post_types_count-' . esc_attr( $post_type ) . '" type="checkbox" name="post_views_counter_settings_general[post_types_count][' . esc_attr( $post_type ) . ']" value="1" ' . checked( in_array( $post_type, Post_Views_Counter()->options['general']['post_types_count'], true ), true, false ) . ' />' . esc_html( $post_type_name ) . ' </label>';
277
+ }
278
+
279
+ echo '
280
+ <p class="description">' . __( 'Select post types for which post views will be counted.', 'post-views-counter' ) . '</p>
281
+ </div>';
282
+ }
283
+
284
+ /**
285
+ * Post types to display option.
286
+ */
287
+ public function post_types_display() {
288
+ echo '
289
+ <div id="pvc_post_types_display">';
290
+
291
+ foreach ( $this->post_types as $post_type => $post_type_name ) {
292
+ echo '
293
+ <label class="cb-checkbox"><input id="pvc_post_types_display-' . esc_attr( $post_type ) . '" type="checkbox" name="post_views_counter_settings_display[post_types_display][' . esc_attr( $post_type ) . ']" value="1" ' . checked( in_array( $post_type, Post_Views_Counter()->options['display']['post_types_display'], true ), true, false ) . ' />' . esc_html( $post_type_name ) . '</label>';
294
+ }
295
+
296
+ echo '
297
+ <p class="description">' . __( 'Select post types for which the views count will be displayed.', 'post-views-counter' ) . '</p>
298
+ </div>';
299
+ }
300
+
301
+ /**
302
+ * Counter mode option.
303
+ */
304
+ public function counter_mode() {
305
+ echo '
306
+ <div id="pvc_counter_mode">';
307
+
308
+ foreach ( $this->modes as $key => $value ) {
309
+ $key = esc_attr( $key );
310
+
311
+ echo '
312
+ <label class="cb-radio"><input type="radio" name="post_views_counter_settings_general[counter_mode]" value="' . $key . '" ' . checked( $key, Post_Views_Counter()->options['general']['counter_mode'], false ) . ' />' . esc_html( $value ) . '</label>';
313
+ }
314
+
315
+ echo '
316
+ <p class="description">' . __( 'Select the method of collecting post views data. If you are using any of the caching plugins select Javascript or REST API (if available).', 'post-views-counter' ) . '<br />' . __( 'Optionally try the Fast AJAX experimental method, usually 10+ times faster than Javascript or REST API.', 'post-views-counter' ) . '</p>
317
+ </div>';
318
+ }
319
+
320
+ /**
321
+ * Post views column option.
322
+ */
323
+ public function post_views_column() {
324
+ echo '
325
+ <div id="pvc_post_views_column">
326
+ <label class="cb-checkbox"><input id="pvc-post-views-column-enable" type="checkbox" name="post_views_counter_settings_general[post_views_column]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['post_views_column'], false ) . ' />' . __( 'Enable to display post views count column for each of the selected post types.', 'post-views-counter' ) . '</label>
327
+ </div>';
328
+ }
329
+
330
+ /**
331
+ * Time between counts option.
332
+ */
333
+ public function time_between_counts() {
334
+ echo '
335
+ <div id="pvc_time_between_counts">
336
+ <input size="4" type="text" name="post_views_counter_settings_general[time_between_counts][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['time_between_counts']['number'] ) . '" />
337
+ <select class="pvc-chosen-short" name="post_views_counter_settings_general[time_between_counts][type]">';
338
+
339
+ foreach ( $this->time_types as $type => $type_name ) {
340
+ echo '
341
+ <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['time_between_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
342
+ }
343
+
344
+ echo '
345
+ </select>
346
+ <p class="description">' . __( 'Enter the time between single user visit count.', 'post-views-counter' ) . '</p>
347
+ </div>';
348
+ }
349
+
350
+ /**
351
+ * Reset counts option.
352
+ */
353
+ public function reset_counts() {
354
+ echo '
355
+ <div id="pvc_reset_counts">
356
+ <input size="4" type="text" name="post_views_counter_settings_general[reset_counts][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['reset_counts']['number'] ) . '" />
357
+ <select class="pvc-chosen-short" name="post_views_counter_settings_general[reset_counts][type]">';
358
+
359
+ foreach ( array_slice( $this->time_types, 2, null, true ) as $type => $type_name ) {
360
+ echo '
361
+ <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['reset_counts']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
362
+ }
363
+
364
+ echo '
365
+ </select>
366
+ <p class="description">' . __( 'Delete single day post views data older than specified above. Enter 0 (number zero) if you want to preserve your data regardless of its age.', 'post-views-counter' ) . '</p>
367
+ </div>';
368
+ }
369
+
370
+ /**
371
+ * Flush interval option.
372
+ */
373
+ public function flush_interval() {
374
+ echo '
375
+ <div id="pvc_flush_interval">
376
+ <input size="4" type="text" name="post_views_counter_settings_general[flush_interval][number]" value="' . esc_attr( Post_Views_Counter()->options['general']['flush_interval']['number'] ) . '" />
377
+ <select class="pvc-chosen-short" name="post_views_counter_settings_general[flush_interval][type]">';
378
+
379
+ foreach ( $this->time_types as $type => $type_name ) {
380
+ echo '
381
+ <option value="' . esc_attr( $type ) . '" ' . selected( $type, Post_Views_Counter()->options['general']['flush_interval']['type'], false ) . '>' . esc_html( $type_name ) . '</option>';
382
+ }
383
+
384
+ echo '
385
+ </select>
386
+ <p class="description">' . __( 'How often to flush cached view counts from the object cache into the database. This feature is used only if a persistent object cache is detected and the interval is greater than 0 (number zero). When used, view counts will be collected and stored in the object cache instead of the database and will then be asynchronously flushed to the database according to the specified interval.<br /><strong>Notice:</strong> Potential data loss may occur if the object cache is cleared/unavailable for the duration of the interval.', 'post-views-counter' ) . '</p>
387
+ </div>';
388
+ }
389
+
390
+ /**
391
+ * Exlude user groups option.
392
+ */
393
+ public function exclude() {
394
+ echo '
395
+ <div id="pvc_exclude">
396
+ <fieldset>';
397
+
398
+ foreach ( $this->groups as $type => $type_name ) {
399
+ echo '
400
+ <label class="cb-checkbox"><input id="pvc_exclude-' . $type . '" type="checkbox" name="post_views_counter_settings_general[exclude][groups][' . $type . ']" value="1" ' . checked( in_array( $type, Post_Views_Counter()->options['general']['exclude']['groups'], true ), true, false ) . ' />' . esc_html( $type_name ) . '</label>';
401
+ }
402
+
403
+ echo '
404
+ <p class="description">' . __( 'Use it to hide the post views counter from selected type of visitors.', 'post-views-counter' ) . '</p>
405
+ <div class="pvc_user_roles"' . (in_array( 'roles', Post_Views_Counter()->options['general']['exclude']['groups'], true ) ? '' : ' style="display: none;"') . '>';
406
+
407
+ foreach ( $this->user_roles as $role => $role_name ) {
408
+ echo '
409
+ <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[exclude][roles][' . $role . ']" value="1" ' . checked( in_array( $role, Post_Views_Counter()->options['general']['exclude']['roles'], true ), true, false ) . '>' . esc_html( $role_name ) . '</label>';
410
+ }
411
+
412
+ echo ' <p class="description">' . __( 'Use it to hide the post views counter from selected user roles.', 'post-views-counter' ) . '</p>
413
+ </div>
414
+ </fieldset>
415
+ </div>';
416
+ }
417
+
418
+ /**
419
+ * Exclude IPs option.
420
+ */
421
+ public function exclude_ips() {
422
+ // lovely php 5.2 limitations
423
+ $ips = Post_Views_Counter()->options['general']['exclude_ips'];
424
+
425
+ echo '
426
+ <div id="pvc_exclude_ips">';
427
+
428
+ if ( ! empty( $ips ) ) {
429
+ foreach ( $ips as $key => $ip ) {
430
+ echo '
431
+ <div class="ip-box">
432
+ <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="' . esc_attr( $ip ) . '" /> <a href="#" class="remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_attr__( 'Remove', 'post-views-counter' ) . '</a>
433
+ </div>';
434
+ }
435
+ } else {
436
+ echo '
437
+ <div class="ip-box">
438
+ <input type="text" name="post_views_counter_settings_general[exclude_ips][]" value="" /> <a href="#" class="remove-exclude-ip" title="' . esc_attr__( 'Remove', 'post-views-counter' ) . '">' . esc_attr__( 'Remove', 'post-views-counter' ) . '</a>
439
+ </div>';
440
+ }
441
+
442
+ echo '
443
+ <p><input type="button" class="button button-secondary add-exclude-ip" value="' . esc_attr__( 'Add new', 'post-views-counter' ) . '" /> <input type="button" class="button button-secondary add-current-ip" value="' . esc_attr__( 'Add my current IP', 'post-views-counter' ) . '" data-rel="' . esc_attr( $_SERVER['REMOTE_ADDR'] ) . '" /></p>
444
+ <p class="description">' . __( 'Enter the IP addresses to be excluded from post views count.', 'post-views-counter' ) . '</p>
445
+ </div>';
446
+ }
447
+
448
+ /**
449
+ * Strict counts option.
450
+ */
451
+ public function strict_counts() {
452
+ echo '
453
+ <div id="pvc_strict_counts">
454
+ <label class="cb-checkbox"><input id="pvc-strict-counts" type="checkbox" name="post_views_counter_settings_general[strict_counts]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['strict_counts'], false ) . ' />' . __( 'Enable to prevent bypassing the counts interval (for e.g. using incognito browser window or by clearing cookies).', 'post-views-counter' ) . '</label>
455
+ </div>';
456
+ }
457
+
458
+ /**
459
+ * WP-PostViews import option.
460
+ */
461
+ public function wp_postviews() {
462
+ echo '
463
+ <div id="pvc_wp_postviews">
464
+ <fieldset>
465
+ <input type="submit" class="button button-secondary" name="post_views_counter_import_wp_postviews" value="' . __( 'Import views', 'post-views-counter' ) . '"/> <label class="cb-checkbox"><input id="pvc-wp-postviews" type="checkbox" name="post_views_counter_import_wp_postviews_override" value="1" />' . __( 'Override existing views data.', 'post-views-counter' ) . '</label>
466
+ <p class="description">' . __( 'Import post views data from WP-PostViews plugin.', 'post-views-counter' ) . '</p>
467
+ <input type="submit" class="button button-secondary" name="post_views_counter_reset_views" value="' . __( 'Delete views', 'post-views-counter' ) . '"/>
468
+ <p class="description">' . __( 'Delete ALL the existing post views data.', 'post-views-counter' ) . '</p>
469
+ </fieldset>
470
+ </div>';
471
+ }
472
+
473
+ /**
474
+ * Limit views edit to admins.
475
+ */
476
+ public function restrict_edit_views() {
477
+ echo '
478
+ <div id="pvc_restrict_edit_views">
479
+ <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[restrict_edit_views]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['restrict_edit_views'], false ) . ' />' . __( 'Enable to restrict post views editing to admins only.', 'post-views-counter' ) . '</label>
480
+ </div>';
481
+ }
482
+
483
+ /**
484
+ * Plugin deactivation option.
485
+ */
486
+ public function deactivation_delete() {
487
+ echo '
488
+ <div id="pvc_deactivation_delete">
489
+ <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_general[deactivation_delete]" value="1" ' . checked( true, Post_Views_Counter()->options['general']['deactivation_delete'], false ) . ' />' . __( 'Enable to delete all plugin data on deactivation.', 'post-views-counter' ) . '</label>
490
+ </div>';
491
+ }
492
+
493
+ /**
494
+ * Visibility option.
495
+ */
496
+ public function page_types_display() {
497
+ echo '
498
+ <div id="pvc_post_types_display">';
499
+
500
+ foreach ( $this->page_types as $key => $label ) {
501
+ echo '
502
+ <label class="cb-checkbox"><input id="pvc_page_types_display-' . esc_attr( $key ) . '" type="checkbox" name="post_views_counter_settings_display[page_types_display][' . esc_attr( $key ) . ']" value="1" ' . checked( in_array( $key, Post_Views_Counter()->options['display']['page_types_display'], true ), true, false ) . ' />' . esc_html( $label ) . '</label>';
503
+ }
504
+
505
+ echo '
506
+ <p class="description">' . __( 'Select page types where the views count will be displayed.', 'post-views-counter' ) . '</p>
507
+ </div>';
508
+ }
509
+
510
+ /**
511
+ * Counter position option.
512
+ */
513
+ public function position() {
514
+ echo '
515
+ <div id="pvc_position">
516
+ <select class="pvc-chosen-short" name="post_views_counter_settings_display[position]">';
517
+
518
+ foreach ( $this->positions as $position => $position_name ) {
519
+ echo '
520
+ <option value="' . esc_attr( $position ) . '" ' . selected( $position, Post_Views_Counter()->options['display']['position'], false ) . '>' . esc_html( $position_name ) . '</option>';
521
+ }
522
+
523
+ echo '
524
+ </select>
525
+ <p class="description">' . __( 'Select where would you like to display the post views counter. Use [post-views] shortcode for manual display.', 'post-views-counter' ) . '</p>
526
+ </div>';
527
+ }
528
+
529
+ /**
530
+ * Counter style option.
531
+ */
532
+ public function display_style() {
533
+ echo '
534
+ <div id="pvc_display_style">';
535
+
536
+ foreach ( $this->display_styles as $display => $style ) {
537
+ $display = esc_attr( $display );
538
+
539
+ echo '
540
+ <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_display[display_style][' . $display . ']" value="1" ' . checked( true, Post_Views_Counter()->options['display']['display_style'][$display], false ) . ' />' . esc_html( $style ) . '</label>';
541
+ }
542
+
543
+ echo '
544
+ <p class="description">' . __( 'Choose how to display the post views counter.', 'post-views-counter' ) . '</p>
545
+ </div>';
546
+ }
547
+
548
+ /**
549
+ * Counter icon class option.
550
+ */
551
+ public function icon_class() {
552
+ echo '
553
+ <div id="pvc_icon_class">
554
+ <input type="text" name="post_views_counter_settings_display[icon_class]" class="large-text" value="' . esc_attr( Post_Views_Counter()->options['display']['icon_class'] ) . '" />
555
+ <p class="description">' . sprintf( __( 'Enter the post views icon class. Any of the <a href="%s" target="_blank">Dashicons</a> classes are available.', 'post-views-counter' ), 'https://developer.wordpress.org/resource/dashicons/' ) . '</p>
556
+ </div>';
557
+ }
558
+
559
+ /**
560
+ * Restrict display option.
561
+ */
562
+ public function restrict_display() {
563
+ echo '
564
+ <div id="pvc_restrict_display">
565
+ <fieldset>';
566
+
567
+ foreach ( $this->groups as $type => $type_name ) {
568
+
569
+ if ( $type === 'robots' )
570
+ continue;
571
+
572
+ echo '
573
+ <label class="cb-checkbox"><input id="pvc_restrict_display-' . $type . '" type="checkbox" name="post_views_counter_settings_display[restrict_display][groups][' . esc_html( $type ) . ']" value="1" ' . checked( in_array( $type, Post_Views_Counter()->options['display']['restrict_display']['groups'], true ), true, false ) . ' />' . esc_html( $type_name ) . '</label>';
574
+ }
575
+
576
+ echo '
577
+ <p class="description">' . __( 'Use it to hide the post views counter from selected type of visitors.', 'post-views-counter' ) . '</p>
578
+ <div class="pvc_user_roles"' . (in_array( 'roles', Post_Views_Counter()->options['display']['restrict_display']['groups'], true ) ? '' : ' style="display: none;"') . '>';
579
+
580
+ foreach ( $this->user_roles as $role => $role_name ) {
581
+ echo '
582
+ <label class="cb-checkbox"><input type="checkbox" name="post_views_counter_settings_display[restrict_display][roles][' . $role . ']" value="1" ' . checked( in_array( $role, Post_Views_Counter()->options['display']['restrict_display']['roles'], true ), true, false ) . ' />' . esc_html( $role_name ) . '</label>';
583
+ }
584
+
585
+ echo '
586
+ <p class="description">' . __( 'Use it to hide the post views counter from selected user roles.', 'post-views-counter' ) . '</p>
587
+ </div>
588
+ </fieldset>
589
+ </div>';
590
+ }
591
+
592
+ /**
593
+ * Validate general settings.
594
+ */
595
+ public function validate_settings( $input ) {
596
+ // get main instance
597
+ $pvc = Post_Views_Counter();
598
+
599
+ if ( isset( $_POST['post_views_counter_import_wp_postviews'] ) ) {
600
+ global $wpdb;
601
+
602
+ $meta_key = esc_attr( apply_filters( 'pvc_import_meta_key', 'views' ) );
603
+
604
+ $views = $wpdb->get_results( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = '" . $meta_key . "'", ARRAY_A, 0 );
605
+
606
+ if ( ! empty( $views ) ) {
607
+ $input = $pvc->defaults['general'];
608
+ $input['wp_postviews_import'] = true;
609
+
610
+ $sql = array();
611
+
612
+ foreach ( $views as $view ) {
613
+ $sql[] = "(" . $view['post_id'] . ", 4, 'total', " . $view['meta_value'] . ")";
614
+ }
615
+
616
+ $wpdb->query( "INSERT INTO " . $wpdb->prefix . "post_views(id, type, period, count) VALUES " . implode( ',', $sql ) . " ON DUPLICATE KEY UPDATE count = " . (isset( $_POST['post_views_counter_import_wp_postviews_override'] ) ? '' : 'count + ') . "VALUES(count)" );
617
+
618
+ add_settings_error( 'wp_postviews_import', 'wp_postviews_import', __( 'Post views data imported succesfully.', 'post-views-counter' ), 'updated' );
619
+ } else {
620
+ add_settings_error( 'wp_postviews_import', 'wp_postviews_import', __( 'There was no post views data to import.', 'post-views-counter' ), 'updated' );
621
+ }
622
+ } elseif ( isset( $_POST['post_views_counter_reset_views'] ) ) {
623
+ global $wpdb;
624
+
625
+ if ( $wpdb->query( 'TRUNCATE TABLE ' . $wpdb->prefix . 'post_views' ) )
626
+ add_settings_error( 'reset_post_views', 'reset_post_views', __( 'All existing data deleted succesfully.', 'post-views-counter' ), 'updated' );
627
+ else
628
+ add_settings_error( 'reset_post_views', 'reset_post_views', __( 'Error occurred. All existing data were not deleted.', 'post-views-counter' ), 'error' );
629
+ } elseif ( isset( $_POST['save_pvc_general'] ) ) {
630
+ // post types count
631
+ if ( isset( $input['post_types_count'] ) ) {
632
+ $post_types = array();
633
+
634
+ foreach ( $input['post_types_count'] as $post_type => $set ) {
635
+ if ( isset( $this->post_types[$post_type] ) )
636
+ $post_types[] = $post_type;
637
+ }
638
+
639
+ $input['post_types_count'] = array_unique( $post_types );
640
+ } else
641
+ $input['post_types_count'] = array();
642
+
643
+ // counter mode
644
+ $input['counter_mode'] = isset( $input['counter_mode'], $this->modes[$input['counter_mode']] ) ? $input['counter_mode'] : $pvc->defaults['general']['counter_mode'];
645
+
646
+ // post views column
647
+ $input['post_views_column'] = isset( $input['post_views_column'] );
648
+
649
+ // time between counts
650
+ $input['time_between_counts']['number'] = (int) ( isset( $input['time_between_counts']['number'] ) ? $input['time_between_counts']['number'] : $pvc->defaults['general']['time_between_counts']['number'] );
651
+ $input['time_between_counts']['type'] = isset( $input['time_between_counts']['type'], $this->time_types[$input['time_between_counts']['type']] ) ? $input['time_between_counts']['type'] : $pvc->defaults['general']['time_between_counts']['type'];
652
+
653
+ // flush interval
654
+ $input['flush_interval']['number'] = (int) ( isset( $input['flush_interval']['number'] ) ? $input['flush_interval']['number'] : $pvc->defaults['general']['flush_interval']['number'] );
655
+ $input['flush_interval']['type'] = isset( $input['flush_interval']['type'], $this->time_types[$input['flush_interval']['type']] ) ? $input['flush_interval']['type'] : $pvc->defaults['general']['flush_interval']['type'];
656
+
657
+ // Since the settings are about to be saved and cache flush interval could've changed,
658
+ // we want to make sure that any changes done on the settings page are in effect immediately
659
+ // (instead of having to wait for the previous schedule to occur).
660
+ // We achieve that by making sure to clear any previous cache flush schedules and
661
+ // schedule the new one if the specified interval is > 0
662
+ $pvc->remove_cache_flush();
663
+
664
+ if ( $input['flush_interval']['number'] > 0 ) {
665
+ $pvc->schedule_cache_flush();
666
+ }
667
+
668
+ // reset counts
669
+ $input['reset_counts']['number'] = (int) ( isset( $input['reset_counts']['number'] ) ? $input['reset_counts']['number'] : $pvc->defaults['general']['reset_counts']['number'] );
670
+ $input['reset_counts']['type'] = isset( $input['reset_counts']['type'], $this->time_types[$input['reset_counts']['type']] ) ? $input['reset_counts']['type'] : $pvc->defaults['general']['reset_counts']['type'];
671
+
672
+ // run cron on next visit?
673
+ $input['cron_run'] = ($input['reset_counts']['number'] > 0 ? true : false);
674
+ $input['cron_update'] = ($input['cron_run'] && ( $pvc->options['general']['reset_counts']['number'] !== $input['reset_counts']['number'] || $pvc->options['general']['reset_counts']['type'] !== $input['reset_counts']['type'] ) ? true : false);
675
+
676
+ // exclude
677
+ if ( isset( $input['exclude']['groups'] ) ) {
678
+ $groups = array();
679
+
680
+ foreach ( $input['exclude']['groups'] as $group => $set ) {
681
+ if ( isset( $this->groups[$group] ) )
682
+ $groups[] = $group;
683
+ }
684
+
685
+ $input['exclude']['groups'] = array_unique( $groups );
686
+ } else {
687
+ $input['exclude']['groups'] = array();
688
+ }
689
+
690
+ if ( in_array( 'roles', $input['exclude']['groups'], true ) && isset( $input['exclude']['roles'] ) ) {
691
+ $roles = array();
692
+
693
+ foreach ( $input['exclude']['roles'] as $role => $set ) {
694
+ if ( isset( $this->user_roles[$role] ) )
695
+ $roles[] = $role;
696
+ }
697
+
698
+ $input['exclude']['roles'] = array_unique( $roles );
699
+ } else
700
+ $input['exclude']['roles'] = array();
701
+
702
+ // exclude ips
703
+ if ( isset( $input['exclude_ips'] ) ) {
704
+ $ips = array();
705
+
706
+ foreach ( $input['exclude_ips'] as $ip ) {
707
+ if ( strpos( $ip, '*' ) !== false ) {
708
+ $new_ip = str_replace( '*', '0', $ip );
709
+
710
+ if ( filter_var( $new_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) )
711
+ $ips[] = $ip;
712
+ } elseif ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) )
713
+ $ips[] = $ip;
714
+ }
715
+
716
+ $input['exclude_ips'] = array_unique( $ips );
717
+ }
718
+
719
+ // restrict edit views
720
+ $input['restrict_edit_views'] = isset( $input['restrict_edit_views'] );
721
+
722
+ // strict counts
723
+ $input['strict_counts'] = isset( $input['strict_counts'] );
724
+
725
+ // deactivation delete
726
+ $input['deactivation_delete'] = isset( $input['deactivation_delete'] );
727
+
728
+ $input['update_version'] = $pvc->options['general']['update_version'];
729
+ $input['update_notice'] = $pvc->options['general']['update_notice'];
730
+ } elseif ( isset( $_POST['save_pvc_display'] ) ) {
731
+
732
+ // post views label
733
+ $input['label'] = isset( $input['label'] ) ? $input['label'] : $pvc->defaults['general']['label'];
734
+
735
+ if ( function_exists( 'icl_register_string' ) )
736
+ icl_register_string( 'Post Views Counter', 'Post Views Label', $input['label'] );
737
+
738
+ // position
739
+ $input['position'] = isset( $input['position'], $this->positions[$input['position']] ) ? $input['position'] : $pvc->defaults['general']['position'];
740
+
741
+ // display style
742
+ $input['display_style']['icon'] = isset( $input['display_style']['icon'] );
743
+ $input['display_style']['text'] = isset( $input['display_style']['text'] );
744
+
745
+ // link to post
746
+ $input['link_to_post'] = isset( $input['link_to_post'] ) ? $input['link_to_post'] : $pvc->defaults['display']['link_to_post'];
747
+
748
+ // icon class
749
+ $input['icon_class'] = isset( $input['icon_class'] ) ? trim( $input['icon_class'] ) : $pvc->defaults['general']['icon_class'];
750
+
751
+ // post types display
752
+ if ( isset( $input['post_types_display'] ) ) {
753
+ $post_types = array();
754
+
755
+ foreach ( $input['post_types_display'] as $post_type => $set ) {
756
+ if ( isset( $this->post_types[$post_type] ) )
757
+ $post_types[] = $post_type;
758
+ }
759
+
760
+ $input['post_types_display'] = array_unique( $post_types );
761
+ } else
762
+ $input['post_types_display'] = array();
763
+
764
+ // page types display
765
+ if ( isset( $input['page_types_display'] ) ) {
766
+ $page_types = array();
767
+
768
+ foreach ( $input['page_types_display'] as $page_type => $set ) {
769
+ if ( isset( $this->page_types[$page_type] ) )
770
+ $page_types[] = $page_type;
771
+ }
772
+
773
+ $input['page_types_display'] = array_unique( $page_types );
774
+ } else
775
+ $input['page_types_display'] = array();
776
+
777
+ // restrict display
778
+ if ( isset( $input['restrict_display']['groups'] ) ) {
779
+ $groups = array();
780
+
781
+ foreach ( $input['restrict_display']['groups'] as $group => $set ) {
782
+ if ( $group === 'robots' )
783
+ continue;
784
+
785
+ if ( isset( $this->groups[$group] ) )
786
+ $groups[] = $group;
787
+ }
788
+
789
+ $input['restrict_display']['groups'] = array_unique( $groups );
790
+ } else
791
+ $input['restrict_display']['groups'] = array();
792
+
793
+ if ( in_array( 'roles', $input['restrict_display']['groups'], true ) && isset( $input['restrict_display']['roles'] ) ) {
794
+ $roles = array();
795
+
796
+ foreach ( $input['restrict_display']['roles'] as $role => $set ) {
797
+ if ( isset( $this->user_roles[$role] ) )
798
+ $roles[] = $role;
799
+ }
800
+
801
+ $input['restrict_display']['roles'] = array_unique( $roles );
802
+ } else
803
+ $input['restrict_display']['roles'] = array();
804
+ } elseif ( isset( $_POST['reset_pvc_general'] ) ) {
805
+ $input = $pvc->defaults['general'];
806
+
807
+ add_settings_error( 'reset_general_settings', 'settings_reset', __( 'General settings restored to defaults.', 'post-views-counter' ), 'updated' );
808
+ } elseif ( isset( $_POST['reset_pvc_display'] ) ) {
809
+ $input = $pvc->defaults['display'];
810
+
811
+ add_settings_error( 'reset_general_settings', 'settings_reset', __( 'Display settings restored to defaults.', 'post-views-counter' ), 'updated' );
812
+ }
813
+
814
+ return $input;
815
+ }
816
  }
includes/update.php CHANGED
@@ -1,119 +1,119 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Update class.
8
- *
9
- * @class Post_Views_Counter_Update
10
- */
11
- class Post_Views_Counter_Update {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'init', array( $this, 'check_update' ) );
16
- }
17
-
18
- /**
19
- * Check if there's a db update required
20
- */
21
- public function check_update() {
22
- if ( ! current_user_can( 'manage_options' ) )
23
- return;
24
-
25
- // get current database version
26
- $current_db_version = get_option( 'post_views_counter_version', '1.0.0' );
27
-
28
- // update 1.2.4+
29
- if ( version_compare( $current_db_version, '1.2.4', '<=' ) ) {
30
- $general = Post_Views_Counter()->options['general'];
31
-
32
- if ( $general['reset_counts']['number'] > 0 ) {
33
- // unsupported data reset in minutes/hours
34
- if ( in_array( $general['reset_counts']['type'], array( 'minutes', 'hours' ), true ) ) {
35
- // set type to date
36
- $general['reset_counts']['type'] = 'days';
37
-
38
- // new number of days
39
- if ( $general['reset_counts']['type'] === 'minutes' )
40
- $general['reset_counts']['number'] = $general['reset_counts']['number'] * 60;
41
- else
42
- $general['reset_counts']['number'] = $general['reset_counts']['number'] * 3600;
43
-
44
- // how many days?
45
- $general['reset_counts']['number'] = (int) round( ceil( $general['reset_counts']['number'] / 86400 ) );
46
-
47
- // force cron to update
48
- $general['cron_run'] = true;
49
- $general['cron_update'] = true;
50
-
51
- // update settings
52
- update_option( 'post_views_counter_settings_general', $general );
53
-
54
- // update general options
55
- Post_Views_Counter()->options['general'] = $general;
56
- }
57
-
58
- // update cron job for all users
59
- Post_Views_Counter()->cron->check_cron();
60
- }
61
- }
62
-
63
- if ( isset( $_POST['post_view_counter_update'], $_POST['post_view_counter_number'] ) ) {
64
- if ( $_POST['post_view_counter_number'] === 'update_1' ) {
65
- $this->update_1();
66
-
67
- // update plugin version
68
- update_option( 'post_views_counter_version', Post_Views_Counter()->defaults['version'], false );
69
- }
70
- }
71
-
72
- $update_1_html = '
73
- <form action="" method="post">
74
- <input type="hidden" name="post_view_counter_number" value="update_1"/>
75
- <p>' . __( '<strong>Post Views Counter</strong> - this version requires a database update. Make sure to back up your database first.', 'post-views-counter' ) . '</p>
76
- <p><input type="submit" class="button button-primary" name="post_view_counter_update" value="' . __( 'Run the Update', 'post-views-counter' ) . '"/></p>
77
- </form>';
78
-
79
- // get current database version
80
- $current_db_version = get_option( 'post_views_counter_version', '1.0.0' );
81
-
82
- // new version?
83
- if ( version_compare( $current_db_version, Post_Views_Counter()->defaults['version'], '<' ) ) {
84
- // is update 1 required?
85
- if ( version_compare( $current_db_version, '1.2.4', '<=' ) )
86
- Post_Views_Counter()->add_notice( $update_1_html, 'notice notice-info' );
87
- else
88
- // update plugin version
89
- update_option( 'post_views_counter_version', Post_Views_Counter()->defaults['version'], false );
90
- }
91
- }
92
-
93
- /**
94
- * Database update for 1.2.4 and below.
95
- */
96
- public function update_1() {
97
- global $wpdb;
98
-
99
- // get index
100
- $old_index = $wpdb->query( "SHOW INDEX FROM `" . $wpdb->prefix . "post_views` WHERE Key_name = 'id_period'" );
101
-
102
- // check whether index already exists
103
- if ( $old_index > 0 ) {
104
- // drop unwanted index which prevented saving views with indentical weeks and months
105
- $wpdb->query( "ALTER TABLE `" . $wpdb->prefix . "post_views` DROP INDEX id_period" );
106
- }
107
-
108
- // get index
109
- $new_index = $wpdb->query( "SHOW INDEX FROM `" . $wpdb->prefix . "post_views` WHERE Key_name = 'id_type_period_count'" );
110
-
111
- // check whether index already exists
112
- if ( $new_index === 0 ) {
113
- // create new index for better performance of SQL queries
114
- $wpdb->query( 'ALTER TABLE `' . $wpdb->prefix . 'post_views` ADD UNIQUE INDEX `id_type_period_count` (`id`, `type`, `period`, `count`) USING BTREE' );
115
- }
116
-
117
- Post_Views_Counter()->add_notice( __( 'Thank you! Datebase was succesfully updated.', 'post-views-counter' ), 'updated', true );
118
- }
119
  }
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Update class.
8
+ *
9
+ * @class Post_Views_Counter_Update
10
+ */
11
+ class Post_Views_Counter_Update {
12
+
13
+ public function __construct() {
14
+ // actions
15
+ add_action( 'init', array( $this, 'check_update' ) );
16
+ }
17
+
18
+ /**
19
+ * Check if there's a db update required
20
+ */
21
+ public function check_update() {
22
+ if ( ! current_user_can( 'manage_options' ) )
23
+ return;
24
+
25
+ // get current database version
26
+ $current_db_version = get_option( 'post_views_counter_version', '1.0.0' );
27
+
28
+ // update 1.2.4+
29
+ if ( version_compare( $current_db_version, '1.2.4', '<=' ) ) {
30
+ $general = Post_Views_Counter()->options['general'];
31
+
32
+ if ( $general['reset_counts']['number'] > 0 ) {
33
+ // unsupported data reset in minutes/hours
34
+ if ( in_array( $general['reset_counts']['type'], array( 'minutes', 'hours' ), true ) ) {
35
+ // set type to date
36
+ $general['reset_counts']['type'] = 'days';
37
+
38
+ // new number of days
39
+ if ( $general['reset_counts']['type'] === 'minutes' )
40
+ $general['reset_counts']['number'] = $general['reset_counts']['number'] * 60;
41
+ else
42
+ $general['reset_counts']['number'] = $general['reset_counts']['number'] * 3600;
43
+
44
+ // how many days?
45
+ $general['reset_counts']['number'] = (int) round( ceil( $general['reset_counts']['number'] / 86400 ) );
46
+
47
+ // force cron to update
48
+ $general['cron_run'] = true;
49
+ $general['cron_update'] = true;
50
+
51
+ // update settings
52
+ update_option( 'post_views_counter_settings_general', $general );
53
+
54
+ // update general options
55
+ Post_Views_Counter()->options['general'] = $general;
56
+ }
57
+
58
+ // update cron job for all users
59
+ Post_Views_Counter()->cron->check_cron();
60
+ }
61
+ }
62
+
63
+ if ( isset( $_POST['post_view_counter_update'], $_POST['post_view_counter_number'] ) ) {
64
+ if ( $_POST['post_view_counter_number'] === 'update_1' ) {
65
+ $this->update_1();
66
+
67
+ // update plugin version
68
+ update_option( 'post_views_counter_version', Post_Views_Counter()->defaults['version'], false );
69
+ }
70
+ }
71
+
72
+ $update_1_html = '
73
+ <form action="" method="post">
74
+ <input type="hidden" name="post_view_counter_number" value="update_1"/>
75
+ <p>' . __( '<strong>Post Views Counter</strong> - this version requires a database update. Make sure to back up your database first.', 'post-views-counter' ) . '</p>
76
+ <p><input type="submit" class="button button-primary" name="post_view_counter_update" value="' . __( 'Run the Update', 'post-views-counter' ) . '"/></p>
77
+ </form>';
78
+
79
+ // get current database version
80
+ $current_db_version = get_option( 'post_views_counter_version', '1.0.0' );
81
+
82
+ // new version?
83
+ if ( version_compare( $current_db_version, Post_Views_Counter()->defaults['version'], '<' ) ) {
84
+ // is update 1 required?
85
+ if ( version_compare( $current_db_version, '1.2.4', '<=' ) )
86
+ Post_Views_Counter()->add_notice( $update_1_html, 'notice notice-info' );
87
+ else
88
+ // update plugin version
89
+ update_option( 'post_views_counter_version', Post_Views_Counter()->defaults['version'], false );
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Database update for 1.2.4 and below.
95
+ */
96
+ public function update_1() {
97
+ global $wpdb;
98
+
99
+ // get index
100
+ $old_index = $wpdb->query( "SHOW INDEX FROM `" . $wpdb->prefix . "post_views` WHERE Key_name = 'id_period'" );
101
+
102
+ // check whether index already exists
103
+ if ( $old_index > 0 ) {
104
+ // drop unwanted index which prevented saving views with indentical weeks and months
105
+ $wpdb->query( "ALTER TABLE `" . $wpdb->prefix . "post_views` DROP INDEX id_period" );
106
+ }
107
+
108
+ // get index
109
+ $new_index = $wpdb->query( "SHOW INDEX FROM `" . $wpdb->prefix . "post_views` WHERE Key_name = 'id_type_period_count'" );
110
+
111
+ // check whether index already exists
112
+ if ( $new_index === 0 ) {
113
+ // create new index for better performance of SQL queries
114
+ $wpdb->query( 'ALTER TABLE `' . $wpdb->prefix . 'post_views` ADD UNIQUE INDEX `id_type_period_count` (`id`, `type`, `period`, `count`) USING BTREE' );
115
+ }
116
+
117
+ Post_Views_Counter()->add_notice( __( 'Thank you! Datebase was succesfully updated.', 'post-views-counter' ), 'updated', true );
118
+ }
119
  }
includes/widgets.php CHANGED
@@ -1,234 +1,234 @@
1
- <?php
2
- // exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
5
-
6
- /**
7
- * Post_Views_Counter_Widgets class.
8
- *
9
- * @class Post_Views_Counter_Widgets
10
- */
11
- class Post_Views_Counter_Widgets {
12
-
13
- public function __construct() {
14
- // actions
15
- add_action( 'widgets_init', array( $this, 'register_widgets' ) );
16
- }
17
-
18
- /**
19
- * Register widgets.
20
- */
21
- public function register_widgets() {
22
- register_widget( 'Post_Views_Counter_List_Widget' );
23
- }
24
-
25
- }
26
-
27
- /**
28
- * Post_Views_Counter_List_Widget class.
29
- *
30
- * @class Post_Views_Counter_List_Widget
31
- */
32
- class Post_Views_Counter_List_Widget extends WP_Widget {
33
-
34
- private $pvc_defaults;
35
- private $pvc_post_types;
36
- private $pvc_order_types;
37
- private $pvc_list_types;
38
- private $pvc_image_sizes;
39
-
40
- public function __construct() {
41
- parent::__construct(
42
- 'Post_Views_Counter_List_Widget', __( 'Most Viewed Posts', 'post-views-counter' ), array(
43
- 'description' => __( 'Displays a list of the most viewed posts', 'post-views-counter' )
44
- )
45
- );
46
-
47
- $this->pvc_defaults = array(
48
- 'title' => __( 'Most Viewed Posts', 'post-views-counter' ),
49
- 'number_of_posts' => 5,
50
- 'thumbnail_size' => 'thumbnail',
51
- 'post_type' => array(),
52
- 'order' => 'desc',
53
- 'list_type' => 'unordered',
54
- 'show_post_views' => true,
55
- 'show_post_thumbnail' => false,
56
- 'show_post_excerpt' => false,
57
- 'show_post_author' => false,
58
- 'no_posts_message' => __( 'No Posts found', 'post-views-counter' )
59
- );
60
-
61
- $this->pvc_order_types = array(
62
- 'asc' => __( 'Ascending', 'post-views-counter' ),
63
- 'desc' => __( 'Descending', 'post-views-counter' )
64
- );
65
-
66
- $this->pvc_list_types = array(
67
- 'unordered' => __( 'Unordered list', 'post-views-counter' ),
68
- 'ordered' => __( 'Ordered list', 'post-views-counter' )
69
- );
70
-
71
- $this->pvc_image_sizes = array_merge( array( 'full' ), get_intermediate_image_sizes() );
72
-
73
- // sort image sizes by name, ascending
74
- sort( $this->pvc_image_sizes, SORT_STRING );
75
-
76
- add_action( 'wp_loaded', array( $this, 'load_post_types' ) );
77
- }
78
-
79
- /**
80
- * Get selected post types.
81
- */
82
- public function load_post_types() {
83
-
84
- if ( ! is_admin() )
85
- return;
86
-
87
- $this->pvc_post_types = Post_Views_Counter()->settings->post_types;
88
- }
89
-
90
- /**
91
- * Display widget.
92
- *
93
- * @param array $args
94
- * @param object $instance
95
- */
96
- public function widget( $args, $instance ) {
97
- $instance['title'] = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
98
-
99
- $html = $args['before_widget'] . ( ! empty( $instance['title'] ) ? $args['before_title'] . $instance['title'] . $args['after_title'] : '');
100
- $html .= pvc_most_viewed_posts( $instance, false );
101
- $html .= $args['after_widget'];
102
-
103
- echo $html;
104
- }
105
-
106
- /** Render widget form.
107
- *
108
- * @param object $instance
109
- * @return mixed
110
- */
111
- public function form( $instance ) {
112
- $html = '
113
- <p>
114
- <label for="' . $this->get_field_id( 'title' ) . '">' . __( 'Title', 'post-views-counter' ) . ':</label>
115
- <input id="' . $this->get_field_id( 'title' ) . '" class="widefat" name="' . $this->get_field_name( 'title' ) . '" type="text" value="' . esc_attr( isset( $instance['title'] ) ? $instance['title'] : $this->pvc_defaults['title'] ) . '" />
116
- </p>
117
- <p>
118
- <label>' . __( 'Post Types', 'post-views-counter' ) . ':</label><br />';
119
-
120
- foreach ( $this->pvc_post_types as $post_type => $post_type_name ) {
121
- $html .= '
122
- <input id="' . $this->get_field_id( 'post_type' ) . '-' . $post_type . '" type="checkbox" name="' . $this->get_field_name( 'post_type' ) . '[]" value="' . $post_type . '" ' . checked( ( ! isset( $instance['post_type'] ) ? true : in_array( $post_type, $instance['post_type'], true ) ), true, false ) . '><label for="' . $this->get_field_id( 'post_type' ) . '-' . $post_type . '">' . esc_html( $post_type_name ) . '</label>';
123
- }
124
-
125
- $show_post_thumbnail = isset( $instance['show_post_thumbnail'] ) ? $instance['show_post_thumbnail'] : $this->pvc_defaults['show_post_thumbnail'];
126
-
127
- $html .= '
128
- </p>
129
- <p>
130
- <label for="' . $this->get_field_id( 'number_of_posts' ) . '">' . __( 'Number of posts to show', 'post-views-counter' ) . ':</label>
131
- <input id="' . $this->get_field_id( 'number_of_posts' ) . '" name="' . $this->get_field_name( 'number_of_posts' ) . '" type="text" size="3" value="' . esc_attr( isset( $instance['number_of_posts'] ) ? $instance['number_of_posts'] : $this->pvc_defaults['number_of_posts'] ) . '" />
132
- </p>
133
- <p>
134
- <label for="' . $this->get_field_id( 'no_posts_message' ) . '">' . __( 'No posts message', 'post-views-counter' ) . ':</label>
135
- <input id="' . $this->get_field_id( 'no_posts_message' ) . '" class="widefat" type="text" name="' . $this->get_field_name( 'no_posts_message' ) . '" value="' . esc_attr( isset( $instance['no_posts_message'] ) ? $instance['no_posts_message'] : $this->pvc_defaults['no_posts_message'] ) . '" />
136
- </p>
137
- <p>
138
- <label for="' . $this->get_field_id( 'order' ) . '">' . __( 'Order', 'post-views-counter' ) . ':</label>
139
- <select id="' . $this->get_field_id( 'order' ) . '" name="' . $this->get_field_name( 'order' ) . '">';
140
-
141
- foreach ( $this->pvc_order_types as $id => $order ) {
142
- $html .= '
143
- <option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['order'] ) ? $instance['order'] : $this->pvc_defaults['order'] ), false ) . '>' . $order . '</option>';
144
- }
145
-
146
- $html .= '
147
- </select>
148
- </p>
149
- <p>
150
- <label for="' . $this->get_field_id( 'list_type' ) . '">' . __( 'Display Style', 'post-views-counter' ) . ':</label>
151
- <select id="' . $this->get_field_id( 'list_type' ) . '" name="' . $this->get_field_name( 'list_type' ) . '">';
152
-
153
- foreach ( $this->pvc_list_types as $id => $list_type ) {
154
- $html .= '
155
- <option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['list_type'] ) ? $instance['list_type'] : $this->pvc_defaults['list_type'] ), false ) . '>' . $list_type . '</option>';
156
- }
157
-
158
- $html .= '
159
- </select>
160
- </p>
161
- <p>
162
- <input id="' . $this->get_field_id( 'show_post_views' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_views' ) . '" ' . checked( true, (isset( $instance['show_post_views'] ) ? $instance['show_post_views'] : $this->pvc_defaults['show_post_views'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_views' ) . '">' . __( 'Display post views?', 'post-views-counter' ) . '</label>
163
- <br />
164
- <input id="' . $this->get_field_id( 'show_post_excerpt' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_excerpt' ) . '" ' . checked( true, (isset( $instance['show_post_excerpt'] ) ? $instance['show_post_excerpt'] : $this->pvc_defaults['show_post_excerpt'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_excerpt' ) . '">' . __( 'Display post excerpt?', 'post-views-counter' ) . '</label>
165
- <br />
166
- <input id="' . $this->get_field_id( 'show_post_author' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_author' ) . '" ' . checked( true, (isset( $instance['show_post_author'] ) ? $instance['show_post_author'] : $this->pvc_defaults['show_post_author'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_author' ) . '">' . __( 'Display post author?', 'post-views-counter' ) . '</label>
167
- <br />
168
- <input id="' . $this->get_field_id( 'show_post_thumbnail' ) . '" class="pvc-show-post-thumbnail" type="checkbox" name="' . $this->get_field_name( 'show_post_thumbnail' ) . '" ' . checked( true, $show_post_thumbnail, false ) . ' /> <label for="' . $this->get_field_id( 'show_post_thumbnail' ) . '">' . __( 'Display post thumbnail?', 'post-views-counter' ) . '</label>
169
- </p>
170
- <p class="pvc-post-thumbnail-size"' . ( $show_post_thumbnail ? '' : ' style="display: none;"' ) . '>
171
- <label for="' . $this->get_field_id( 'thumbnail_size' ) . '">' . __( 'Thumbnail size', 'post-views-counter' ) . ':</label>
172
- <select id="' . $this->get_field_id( 'thumbnail_size' ) . '" name="' . $this->get_field_name( 'thumbnail_size' ) . '">';
173
-
174
- $size_type = isset( $instance['thumbnail_size'] ) ? $instance['thumbnail_size'] : $this->pvc_defaults['thumbnail_size'];
175
-
176
- foreach ( $this->pvc_image_sizes as $size ) {
177
- $html .= '
178
- <option value="' . esc_attr( $size ) . '" ' . selected( $size, $size_type, false ) . '>' . $size . '</option>';
179
- }
180
-
181
- $html .= '
182
- </select>
183
- </p>';
184
-
185
- echo $html;
186
- }
187
-
188
- /**
189
- * Save widget form.
190
- *
191
- * @param array $new_instance
192
- * @param array $old_instance
193
- * @return array
194
- */
195
- public function update( $new_instance, $old_instance ) {
196
- // number of posts
197
- $old_instance['number_of_posts'] = (int) (isset( $new_instance['number_of_posts'] ) ? $new_instance['number_of_posts'] : $this->pvc_defaults['number_of_posts']);
198
-
199
- // order
200
- $old_instance['order'] = isset( $new_instance['order'] ) && in_array( $new_instance['order'], array_keys( $this->pvc_order_types ), true ) ? $new_instance['order'] : $this->pvc_defaults['order'];
201
-
202
- // list type
203
- $old_instance['list_type'] = isset( $new_instance['list_type'] ) && in_array( $new_instance['list_type'], array_keys( $this->pvc_list_types ), true ) ? $new_instance['list_type'] : $this->pvc_defaults['list_type'];
204
-
205
- // thumbnail size
206
- $old_instance['thumbnail_size'] = isset( $new_instance['thumbnail_size'] ) && in_array( $new_instance['thumbnail_size'], $this->pvc_image_sizes, true ) ? $new_instance['thumbnail_size'] : $this->pvc_defaults['thumbnail_size'];
207
-
208
- // booleans
209
- $old_instance['show_post_views'] = isset( $new_instance['show_post_views'] );
210
- $old_instance['show_post_thumbnail'] = isset( $new_instance['show_post_thumbnail'] );
211
- $old_instance['show_post_excerpt'] = isset( $new_instance['show_post_excerpt'] );
212
- $old_instance['show_post_author'] = isset( $new_instance['show_post_author'] );
213
-
214
- // texts
215
- $old_instance['title'] = sanitize_text_field( isset( $new_instance['title'] ) ? $new_instance['title'] : $this->pvc_defaults['title'] );
216
- $old_instance['no_posts_message'] = sanitize_text_field( isset( $new_instance['no_posts_message'] ) ? $new_instance['no_posts_message'] : $this->pvc_defaults['no_posts_message'] );
217
-
218
- // post types
219
- if ( isset( $new_instance['post_type'] ) ) {
220
- $post_types = array();
221
-
222
- foreach ( $new_instance['post_type'] as $post_type ) {
223
- if ( isset( $this->pvc_post_types[$post_type] ) )
224
- $post_types[] = $post_type;
225
- }
226
-
227
- $old_instance['post_type'] = array_unique( $post_types );
228
- } else
229
- $old_instance['post_type'] = array( 'post' );
230
-
231
- return $old_instance;
232
- }
233
-
234
- }
1
+ <?php
2
+ // exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) )
4
+ exit;
5
+
6
+ /**
7
+ * Post_Views_Counter_Widgets class.
8
+ *
9
+ * @class Post_Views_Counter_Widgets
10
+ */
11
+ class Post_Views_Counter_Widgets {
12
+
13
+ public function __construct() {
14
+ // actions
15
+ add_action( 'widgets_init', array( $this, 'register_widgets' ) );
16
+ }
17
+
18
+ /**
19
+ * Register widgets.
20
+ */
21
+ public function register_widgets() {
22
+ register_widget( 'Post_Views_Counter_List_Widget' );
23
+ }
24
+
25
+ }
26
+
27
+ /**
28
+ * Post_Views_Counter_List_Widget class.
29
+ *
30
+ * @class Post_Views_Counter_List_Widget
31
+ */
32
+ class Post_Views_Counter_List_Widget extends WP_Widget {
33
+
34
+ private $pvc_defaults;
35
+ private $pvc_post_types;
36
+ private $pvc_order_types;
37
+ private $pvc_list_types;
38
+ private $pvc_image_sizes;
39
+
40
+ public function __construct() {
41
+ parent::__construct(
42
+ 'Post_Views_Counter_List_Widget', __( 'Most Viewed Posts', 'post-views-counter' ), array(
43
+ 'description' => __( 'Displays a list of the most viewed posts', 'post-views-counter' )
44
+ )
45
+ );
46
+
47
+ $this->pvc_defaults = array(
48
+ 'title' => __( 'Most Viewed Posts', 'post-views-counter' ),
49
+ 'number_of_posts' => 5,
50
+ 'thumbnail_size' => 'thumbnail',
51
+ 'post_type' => array(),
52
+ 'order' => 'desc',
53
+ 'list_type' => 'unordered',
54
+ 'show_post_views' => true,
55
+ 'show_post_thumbnail' => false,
56
+ 'show_post_excerpt' => false,
57
+ 'show_post_author' => false,
58
+ 'no_posts_message' => __( 'No Posts found', 'post-views-counter' )
59
+ );
60
+
61
+ $this->pvc_order_types = array(
62
+ 'asc' => __( 'Ascending', 'post-views-counter' ),
63
+ 'desc' => __( 'Descending', 'post-views-counter' )
64
+ );
65
+
66
+ $this->pvc_list_types = array(
67
+ 'unordered' => __( 'Unordered list', 'post-views-counter' ),
68
+ 'ordered' => __( 'Ordered list', 'post-views-counter' )
69
+ );
70
+
71
+ $this->pvc_image_sizes = array_merge( array( 'full' ), get_intermediate_image_sizes() );
72
+
73
+ // sort image sizes by name, ascending
74
+ sort( $this->pvc_image_sizes, SORT_STRING );
75
+
76
+ add_action( 'wp_loaded', array( $this, 'load_post_types' ) );
77
+ }
78
+
79
+ /**
80
+ * Get selected post types.
81
+ */
82
+ public function load_post_types() {
83
+
84
+ if ( ! is_admin() )
85
+ return;
86
+
87
+ $this->pvc_post_types = Post_Views_Counter()->settings->post_types;
88
+ }
89
+
90
+ /**
91
+ * Display widget.
92
+ *
93
+ * @param array $args
94
+ * @param object $instance
95
+ */
96
+ public function widget( $args, $instance ) {
97
+ $instance['title'] = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
98
+
99
+ $html = $args['before_widget'] . ( ! empty( $instance['title'] ) ? $args['before_title'] . $instance['title'] . $args['after_title'] : '');
100
+ $html .= pvc_most_viewed_posts( $instance, false );
101
+ $html .= $args['after_widget'];
102
+
103
+ echo $html;
104
+ }
105
+
106
+ /** Render widget form.
107
+ *
108
+ * @param object $instance
109
+ * @return mixed
110
+ */
111
+ public function form( $instance ) {
112
+ $html = '
113
+ <p>
114
+ <label for="' . $this->get_field_id( 'title' ) . '">' . __( 'Title', 'post-views-counter' ) . ':</label>
115
+ <input id="' . $this->get_field_id( 'title' ) . '" class="widefat" name="' . $this->get_field_name( 'title' ) . '" type="text" value="' . esc_attr( isset( $instance['title'] ) ? $instance['title'] : $this->pvc_defaults['title'] ) . '" />
116
+ </p>
117
+ <p>
118
+ <label>' . __( 'Post Types', 'post-views-counter' ) . ':</label><br />';
119
+
120
+ foreach ( $this->pvc_post_types as $post_type => $post_type_name ) {
121
+ $html .= '
122
+ <input id="' . $this->get_field_id( 'post_type' ) . '-' . $post_type . '" type="checkbox" name="' . $this->get_field_name( 'post_type' ) . '[]" value="' . $post_type . '" ' . checked( ( ! isset( $instance['post_type'] ) ? true : in_array( $post_type, $instance['post_type'], true ) ), true, false ) . '><label for="' . $this->get_field_id( 'post_type' ) . '-' . $post_type . '">' . esc_html( $post_type_name ) . '</label>';
123
+ }
124
+
125
+ $show_post_thumbnail = isset( $instance['show_post_thumbnail'] ) ? $instance['show_post_thumbnail'] : $this->pvc_defaults['show_post_thumbnail'];
126
+
127
+ $html .= '
128
+ </p>
129
+ <p>
130
+ <label for="' . $this->get_field_id( 'number_of_posts' ) . '">' . __( 'Number of posts to show', 'post-views-counter' ) . ':</label>
131
+ <input id="' . $this->get_field_id( 'number_of_posts' ) . '" name="' . $this->get_field_name( 'number_of_posts' ) . '" type="text" size="3" value="' . esc_attr( isset( $instance['number_of_posts'] ) ? $instance['number_of_posts'] : $this->pvc_defaults['number_of_posts'] ) . '" />
132
+ </p>
133
+ <p>
134
+ <label for="' . $this->get_field_id( 'no_posts_message' ) . '">' . __( 'No posts message', 'post-views-counter' ) . ':</label>
135
+ <input id="' . $this->get_field_id( 'no_posts_message' ) . '" class="widefat" type="text" name="' . $this->get_field_name( 'no_posts_message' ) . '" value="' . esc_attr( isset( $instance['no_posts_message'] ) ? $instance['no_posts_message'] : $this->pvc_defaults['no_posts_message'] ) . '" />
136
+ </p>
137
+ <p>
138
+ <label for="' . $this->get_field_id( 'order' ) . '">' . __( 'Order', 'post-views-counter' ) . ':</label>
139
+ <select id="' . $this->get_field_id( 'order' ) . '" name="' . $this->get_field_name( 'order' ) . '">';
140
+
141
+ foreach ( $this->pvc_order_types as $id => $order ) {
142
+ $html .= '
143
+ <option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['order'] ) ? $instance['order'] : $this->pvc_defaults['order'] ), false ) . '>' . $order . '</option>';
144
+ }
145
+
146
+ $html .= '
147
+ </select>
148
+ </p>
149
+ <p>
150
+ <label for="' . $this->get_field_id( 'list_type' ) . '">' . __( 'Display Style', 'post-views-counter' ) . ':</label>
151
+ <select id="' . $this->get_field_id( 'list_type' ) . '" name="' . $this->get_field_name( 'list_type' ) . '">';
152
+
153
+ foreach ( $this->pvc_list_types as $id => $list_type ) {
154
+ $html .= '
155
+ <option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['list_type'] ) ? $instance['list_type'] : $this->pvc_defaults['list_type'] ), false ) . '>' . $list_type . '</option>';
156
+ }
157
+
158
+ $html .= '
159
+ </select>
160
+ </p>
161
+ <p>
162
+ <input id="' . $this->get_field_id( 'show_post_views' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_views' ) . '" ' . checked( true, (isset( $instance['show_post_views'] ) ? $instance['show_post_views'] : $this->pvc_defaults['show_post_views'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_views' ) . '">' . __( 'Display post views?', 'post-views-counter' ) . '</label>
163
+ <br />
164
+ <input id="' . $this->get_field_id( 'show_post_excerpt' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_excerpt' ) . '" ' . checked( true, (isset( $instance['show_post_excerpt'] ) ? $instance['show_post_excerpt'] : $this->pvc_defaults['show_post_excerpt'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_excerpt' ) . '">' . __( 'Display post excerpt?', 'post-views-counter' ) . '</label>
165
+ <br />
166
+ <input id="' . $this->get_field_id( 'show_post_author' ) . '" type="checkbox" name="' . $this->get_field_name( 'show_post_author' ) . '" ' . checked( true, (isset( $instance['show_post_author'] ) ? $instance['show_post_author'] : $this->pvc_defaults['show_post_author'] ), false ) . ' /> <label for="' . $this->get_field_id( 'show_post_author' ) . '">' . __( 'Display post author?', 'post-views-counter' ) . '</label>
167
+ <br />
168
+ <input id="' . $this->get_field_id( 'show_post_thumbnail' ) . '" class="pvc-show-post-thumbnail" type="checkbox" name="' . $this->get_field_name( 'show_post_thumbnail' ) . '" ' . checked( true, $show_post_thumbnail, false ) . ' /> <label for="' . $this->get_field_id( 'show_post_thumbnail' ) . '">' . __( 'Display post thumbnail?', 'post-views-counter' ) . '</label>
169
+ </p>
170
+ <p class="pvc-post-thumbnail-size"' . ( $show_post_thumbnail ? '' : ' style="display: none;"' ) . '>
171
+ <label for="' . $this->get_field_id( 'thumbnail_size' ) . '">' . __( 'Thumbnail size', 'post-views-counter' ) . ':</label>
172
+ <select id="' . $this->get_field_id( 'thumbnail_size' ) . '" name="' . $this->get_field_name( 'thumbnail_size' ) . '">';
173
+
174
+ $size_type = isset( $instance['thumbnail_size'] ) ? $instance['thumbnail_size'] : $this->pvc_defaults['thumbnail_size'];
175
+
176
+ foreach ( $this->pvc_image_sizes as $size ) {
177
+ $html .= '
178
+ <option value="' . esc_attr( $size ) . '" ' . selected( $size, $size_type, false ) . '>' . $size . '</option>';
179
+ }
180
+
181
+ $html .= '
182
+ </select>
183
+ </p>';
184
+
185
+ echo $html;
186
+ }
187
+
188
+ /**
189
+ * Save widget form.
190
+ *
191
+ * @param array $new_instance
192
+ * @param array $old_instance
193
+ * @return array
194
+ */
195
+ public function update( $new_instance, $old_instance ) {
196
+ // number of posts
197
+ $old_instance['number_of_posts'] = (int) (isset( $new_instance['number_of_posts'] ) ? $new_instance['number_of_posts'] : $this->pvc_defaults['number_of_posts']);
198
+
199
+ // order
200
+ $old_instance['order'] = isset( $new_instance['order'] ) && in_array( $new_instance['order'], array_keys( $this->pvc_order_types ), true ) ? $new_instance['order'] : $this->pvc_defaults['order'];
201
+
202
+ // list type
203
+ $old_instance['list_type'] = isset( $new_instance['list_type'] ) && in_array( $new_instance['list_type'], array_keys( $this->pvc_list_types ), true ) ? $new_instance['list_type'] : $this->pvc_defaults['list_type'];
204
+
205
+ // thumbnail size
206
+ $old_instance['thumbnail_size'] = isset( $new_instance['thumbnail_size'] ) && in_array( $new_instance['thumbnail_size'], $this->pvc_image_sizes, true ) ? $new_instance['thumbnail_size'] : $this->pvc_defaults['thumbnail_size'];
207
+
208
+ // booleans
209
+ $old_instance['show_post_views'] = isset( $new_instance['show_post_views'] );
210
+ $old_instance['show_post_thumbnail'] = isset( $new_instance['show_post_thumbnail'] );
211
+ $old_instance['show_post_excerpt'] = isset( $new_instance['show_post_excerpt'] );
212
+ $old_instance['show_post_author'] = isset( $new_instance['show_post_author'] );
213
+
214
+ // texts
215
+ $old_instance['title'] = sanitize_text_field( isset( $new_instance['title'] ) ? $new_instance['title'] : $this->pvc_defaults['title'] );
216
+ $old_instance['no_posts_message'] = sanitize_text_field( isset( $new_instance['no_posts_message'] ) ? $new_instance['no_posts_message'] : $this->pvc_defaults['no_posts_message'] );
217
+
218
+ // post types
219
+ if ( isset( $new_instance['post_type'] ) ) {
220
+ $post_types = array();
221
+
222
+ foreach ( $new_instance['post_type'] as $post_type ) {
223
+ if ( isset( $this->pvc_post_types[$post_type] ) )
224
+ $post_types[] = $post_type;
225
+ }
226
+
227
+ $old_instance['post_type'] = array_unique( $post_types );
228
+ } else
229
+ $old_instance['post_type'] = array( 'post' );
230
+
231
+ return $old_instance;
232
+ }
233
+
234
+ }
index.php CHANGED
@@ -1,3 +1,3 @@
1
- <?php
2
- // Silence is golden.
3
  ?>
1
+ <?php
2
+ // Silence is golden.
3
  ?>
js/admin-dashboard.js CHANGED
@@ -1,99 +1,167 @@
1
- ( function ( $ ) {
2
-
3
- // set global options
4
- // Chart.defaults.global.tooltips.titleMarginBottom = 0;
5
- // Chart.defaults.global.tooltips.footerMarginTop = 4;
6
-
7
- window.onload = function () {
8
- updateChart( 'this_month' );
9
- };
10
-
11
- function updateChart( period ) {
12
-
13
- var container = document.getElementById( 'pvc_dashboard_container' );
14
-
15
- if ( $( container ).length > 0 ) {
16
-
17
- $( container ).addClass( 'loading' ).append( '<span class="spinner is-active"></span>' );
18
-
19
- $.ajax( {
20
- url: pvcArgs.ajaxURL,
21
- type: 'POST',
22
- dataType: 'json',
23
- data: ( {
24
- action: 'pvc_dashboard_chart',
25
- nonce: pvcArgs.nonce,
26
- period: period
27
- } ),
28
- success: function ( args ) {
29
- $( container ).removeClass( 'loading' );
30
- $( container ).find( '.spinner' ).removeClass( 'is-active' );
31
-
32
- var config = {
33
- type: 'line',
34
- data: args.data,
35
- options: {
36
- responsive: true,
37
- legend: {
38
- display: false,
39
- position: 'bottom',
40
- },
41
- scales: {
42
- xAxes: [ {
43
- display: true,
44
- scaleLabel: {
45
- display: true,
46
- labelString: args.text.xAxes,
47
- fontSize: 14,
48
- fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif'
49
- }
50
- } ],
51
- yAxes: [ {
52
- display: true,
53
- scaleLabel: {
54
- display: false,
55
- labelString: args.text.yAxes
56
- }
57
- } ]
58
- },
59
- hover: {
60
- mode: 'label'
61
- },
62
- tooltips: {
63
- custom: function ( tooltip ) {
64
- // console.log( tooltip );
65
- },
66
- callbacks: {
67
- title: function ( tooltip ) {
68
- return args.data.dates[tooltip[0].index];
69
- }
70
- }
71
- }
72
- }
73
- };
74
-
75
- $.each( config.data.datasets, function ( i, dataset ) {
76
- dataset.fill = args.design.fill;
77
- dataset.borderColor = args.design.borderColor;
78
- dataset.backgroundColor = args.design.backgroundColor;
79
- dataset.borderWidth = args.design.borderWidth;
80
- dataset.borderDash = args.design.borderDash;
81
- dataset.pointBorderColor = args.design.pointBorderColor;
82
- dataset.pointBackgroundColor = args.design.pointBackgroundColor;
83
- dataset.pointBorderWidth = args.design.pointBorderWidth;
84
- } );
85
-
86
- window.chartPVC = new Chart( document.getElementById( 'pvc_chart' ).getContext( '2d' ), config );
87
- }
88
- } );
89
-
90
- }
91
- }
92
-
93
- function updateLegend() {
94
- $legendContainer = $( '#legendContainer' );
95
- $legendContainer.empty();
96
- $legendContainer.append( window.chartPVC.generateLegend() );
97
- }
98
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  } )( jQuery );
1
+ ( function ( $ ) {
2
+
3
+ window.onload = function () {
4
+ updateChart( 'this_month' );
5
+ };
6
+
7
+ function ajaxGetChartData( init, period, container ) {
8
+ $.ajax( {
9
+ url: pvcArgs.ajaxURL,
10
+ type: 'POST',
11
+ dataType: 'json',
12
+ data: {
13
+ action: 'pvc_dashboard_chart',
14
+ nonce: pvcArgs.nonce,
15
+ period: period
16
+ },
17
+ success: function ( args ) {
18
+ // first call?
19
+ if ( init ) {
20
+ container.removeClass( 'loading' );
21
+ container.find( '.spinner' ).removeClass( 'is-active' );
22
+
23
+ var config = {
24
+ type: 'line',
25
+ options: {
26
+ responsive: true,
27
+ legend: {
28
+ display: true,
29
+ position: 'bottom',
30
+ onClick: function( e, element ) {
31
+ var index = element.datasetIndex,
32
+ ci = this.chart,
33
+ meta = ci.getDatasetMeta( index );
34
+
35
+ // set new hidden value
36
+ meta.hidden = ( meta.hidden === null ? ! ci.data.datasets[index].hidden : null );
37
+
38
+ // rerender the chart
39
+ ci.update();
40
+
41
+ ajaxUpdateChartPostTypes( ci.data.datasets[index].post_type, meta.hidden === null ? false : meta.hidden );
42
+ },
43
+ labels: {
44
+ boxWidth: 0,
45
+ fontSize: 12,
46
+ padding: 10,
47
+ usePointStyle: false
48
+ }
49
+ },
50
+ scales: {
51
+ xAxes: [ {
52
+ display: true,
53
+ scaleLabel: {
54
+ display: false,
55
+ labelString: args.text.xAxes
56
+ }
57
+ } ],
58
+ yAxes: [ {
59
+ display: true,
60
+ scaleLabel: {
61
+ display: false,
62
+ labelString: args.text.yAxes
63
+ }
64
+ } ]
65
+ },
66
+ hover: {
67
+ mode: 'label'
68
+ }
69
+ }
70
+ };
71
+
72
+ config = updateConfig( config, args );
73
+
74
+ window.chartPVC = new Chart( document.getElementById( 'pvc_chart' ).getContext( '2d' ), config );
75
+ } else {
76
+ bindMonthEvents( args.months );
77
+
78
+ window.chartPVC.config = updateConfig( window.chartPVC.config, args );
79
+ window.chartPVC.update();
80
+ }
81
+ }
82
+ } );
83
+ }
84
+
85
+ function ajaxUpdateChartPostTypes( post_type, hidden ) {
86
+ $.ajax( {
87
+ url: pvcArgs.ajaxURL,
88
+ type: 'POST',
89
+ dataType: 'json',
90
+ data: {
91
+ action: 'pvc_dashboard_chart_user_post_types',
92
+ nonce: pvcArgs.nonceUser,
93
+ post_type: post_type,
94
+ hidden: hidden
95
+ },
96
+ success: function ( ) {}
97
+ } );
98
+ }
99
+
100
+ function updateConfig( config, args ) {
101
+ // update datasets
102
+ config.data = args.data;
103
+
104
+ // update tooltips with new dates
105
+ config.options.tooltips = {
106
+ callbacks: {
107
+ title: function ( tooltip ) {
108
+ return args.data.dates[tooltip[0].index];
109
+ }
110
+ }
111
+ };
112
+
113
+ // update labels
114
+ config.options.scales.xAxes[0].scaleLabel.labelString = args.text.xAxes;
115
+ config.options.scales.yAxes[0].scaleLabel.labelString = args.text.yAxes;
116
+
117
+ // update colors
118
+ $.each( config.data.datasets, function ( i, dataset ) {
119
+ dataset.fill = args.design.fill;
120
+ dataset.borderColor = args.design.borderColor;
121
+ dataset.backgroundColor = args.design.backgroundColor;
122
+ dataset.borderWidth = args.design.borderWidth;
123
+ dataset.borderDash = args.design.borderDash;
124
+ dataset.pointBorderColor = args.design.pointBorderColor;
125
+ dataset.pointBackgroundColor = args.design.pointBackgroundColor;
126
+ dataset.pointBorderWidth = args.design.pointBorderWidth;
127
+ } );
128
+
129
+ return config;
130
+ }
131
+
132
+ function updateChart( period ) {
133
+ var container = document.getElementById( 'pvc_dashboard_container' );
134
+
135
+ if ( $( container ).length > 0 ) {
136
+ bindMonthEvents( false );
137
+
138
+ $( container ).addClass( 'loading' ).append( '<span class="spinner is-active"></span>' );
139
+
140
+ ajaxGetChartData( true, period, $( container ) );
141
+ }
142
+ }
143
+
144
+ function bindMonthEvents( newMonths ) {
145
+ var months = document.getElementsByClassName( 'pvc_months' );
146
+
147
+ // replace months?
148
+ if ( newMonths !== false )
149
+ months[0].innerHTML = newMonths;
150
+
151
+ var prev = months[0].getElementsByClassName( 'prev' );
152
+ var next = months[0].getElementsByClassName( 'next' );
153
+
154
+ prev[0].addEventListener( 'click', loadChartData );
155
+
156
+ // skip span
157
+ if ( next[0].tagName === 'A' )
158
+ next[0].addEventListener( 'click', loadChartData );
159
+ }
160
+
161
+ function loadChartData( e ) {
162
+ e.preventDefault();
163
+
164
+ ajaxGetChartData( false, e.target.dataset.date );
165
+ }
166
+
167
  } )( jQuery );
js/admin-post.js CHANGED
@@ -1,46 +1,46 @@
1
- ( function( $ ) {
2
-
3
- $( document ).ready( function() {
4
- // post views input
5
- $( '#post-views .edit-post-views' ).click( function() {
6
- if ( $( '#post-views-input-container' ).is( ":hidden" ) ) {
7
- $( '#post-views-input-container' ).slideDown( 'fast' );
8
- $( this ).hide();
9
- }
10
-
11
- return false;
12
- } );
13
-
14
- // save post views
15
- $( '#post-views .save-post-views' ).click( function() {
16
- var views = $.trim( $( '#post-views-display b' ).text() );
17
-
18
- $( '#post-views-input-container' ).slideUp( 'fast' );
19
- $( '#post-views .edit-post-views' ).show();
20
-
21
- views = parseInt( $( '#post-views-input' ).val() );
22
- // reassign value as integer
23
- $( '#post-views-input' ).val( views );
24
-
25
- $( '#post-views-display b' ).text( views );
26
-
27
- return false;
28
- } );
29
-
30
- // cancel post views
31
- $( '#post-views .cancel-post-views' ).click( function() {
32
- var views = $.trim( $( '#post-views-display b' ).text() );
33
-
34
- $( '#post-views-input-container' ).slideUp( 'fast' );
35
- $( '#post-views .edit-post-views' ).show();
36
-
37
- views = parseInt( $( '#post-views-current' ).val() );
38
-
39
- $( '#post-views-display b' ).text( views );
40
- $( '#post-views-input' ).val( views );
41
-
42
- return false;
43
- } );
44
- } );
45
-
46
  } )( jQuery );
1
+ ( function( $ ) {
2
+
3
+ $( document ).ready( function() {
4
+ // post views input
5
+ $( '#post-views .edit-post-views' ).click( function() {
6
+ if ( $( '#post-views-input-container' ).is( ":hidden" ) ) {
7
+ $( '#post-views-input-container' ).slideDown( 'fast' );
8
+ $( this ).hide();
9
+ }
10
+
11
+ return false;
12
+ } );
13
+
14
+ // save post views
15
+ $( '#post-views .save-post-views' ).click( function() {
16
+ var views = $.trim( $( '#post-views-display b' ).text() );
17
+
18
+ $( '#post-views-input-container' ).slideUp( 'fast' );
19
+ $( '#post-views .edit-post-views' ).show();
20
+
21
+ views = parseInt( $( '#post-views-input' ).val() );
22
+ // reassign value as integer
23
+ $( '#post-views-input' ).val( views );
24
+
25
+ $( '#post-views-display b' ).text( views );
26
+
27
+ return false;
28
+ } );
29
+
30
+ // cancel post views
31
+ $( '#post-views .cancel-post-views' ).click( function() {
32
+ var views = $.trim( $( '#post-views-display b' ).text() );
33
+
34
+ $( '#post-views-input-container' ).slideUp( 'fast' );
35
+ $( '#post-views .edit-post-views' ).show();
36
+
37
+ views = parseInt( $( '#post-views-current' ).val() );
38
+
39
+ $( '#post-views-display b' ).text( views );
40
+ $( '#post-views-input' ).val( views );
41
+
42
+ return false;
43
+ } );
44
+ } );
45
+
46
  } )( jQuery );
js/admin-quick-edit.js CHANGED
@@ -1,65 +1,65 @@
1
- ( function( $ ) {
2
-
3
- // we create a copy of the WP inline edit post function
4
- var $wp_inline_edit = inlineEditPost.edit;
5
-
6
- // and then we overwrite the function with our own code
7
- inlineEditPost.edit = function( id ) {
8
- console.log( 'edit' );
9
- // call the original WP edit function
10
- // we don't want to leave WordPress hanging
11
- $wp_inline_edit.apply( this, arguments );
12
-
13
- // get the post ID
14
- var $post_id = 0;
15
-
16
- if ( typeof ( id ) == 'object' )
17
- $post_id = parseInt( this.getId( id ) );
18
-
19
- if ( $post_id > 0 ) {
20
- // define the edit row
21
- var $edit_row = $( '#edit-' + $post_id ),
22
- $post_row = $( '#post-' + $post_id );
23
-
24
- // get the data
25
- var $post_views = $( '.column-post_views', $post_row ).text();
26
-
27
- // populate the data
28
- $( ':input[name="post_views"]', $edit_row ).val( $post_views );
29
- $( ':input[name="current_post_views"]', $edit_row ).val( $post_views );
30
- }
31
-
32
- return false;
33
- };
34
-
35
- $( document ).on( 'click', '#bulk_edit', function() {
36
- console.log( 'bulk edit' );
37
- // define the bulk edit row
38
- var $bulk_row = $( '#bulk-edit' );
39
-
40
- // get the selected post ids that are being edited
41
- var $post_ids = new Array();
42
-
43
- $bulk_row.find( '#bulk-titles' ).children().each( function() {
44
- $post_ids.push( $( this ).attr( 'id' ).replace( /^(ttle)/i, '' ) );
45
- } );
46
-
47
- // get the data
48
- var $post_views = $bulk_row.find( 'input[name="post_views"]' ).val();
49
-
50
- // save the data
51
- $.ajax( {
52
- url: ajaxurl, // this is a variable that WordPress has already defined for us
53
- type: 'post',
54
- async: false,
55
- cache: false,
56
- data: {
57
- action: 'save_bulk_post_views', // this is the name of our WP AJAX function that we'll set up next
58
- post_ids: $post_ids, // and these are the 2 parameters we're passing to our function
59
- post_views: $post_views,
60
- current_post_views: $post_views,
61
- }
62
- } );
63
- } );
64
-
65
  } )( jQuery );
1
+ ( function( $ ) {
2
+
3
+ // we create a copy of the WP inline edit post function
4
+ var $wp_inline_edit = inlineEditPost.edit;
5
+
6
+ // and then we overwrite the function with our own code
7
+ inlineEditPost.edit = function( id ) {
8
+ console.log( 'edit' );
9
+ // call the original WP edit function
10
+ // we don't want to leave WordPress hanging
11
+ $wp_inline_edit.apply( this, arguments );
12
+
13
+ // get the post ID
14
+ var $post_id = 0;
15
+
16
+ if ( typeof ( id ) == 'object' )
17
+ $post_id = parseInt( this.getId( id ) );
18
+
19
+ if ( $post_id > 0 ) {
20
+ // define the edit row
21
+ var $edit_row = $( '#edit-' + $post_id ),
22
+ $post_row = $( '#post-' + $post_id );
23
+
24
+ // get the data
25
+ var $post_views = $( '.column-post_views', $post_row ).text();
26
+
27
+ // populate the data
28
+ $( ':input[name="post_views"]', $edit_row ).val( $post_views );
29
+ $( ':input[name="current_post_views"]', $edit_row ).val( $post_views );
30
+ }
31
+
32
+ return false;
33
+ };
34
+
35
+ $( document ).on( 'click', '#bulk_edit', function() {
36
+ console.log( 'bulk edit' );
37
+ // define the bulk edit row
38
+ var $bulk_row = $( '#bulk-edit' );
39
+
40
+ // get the selected post ids that are being edited
41
+ var $post_ids = new Array();
42
+
43
+ $bulk_row.find( '#bulk-titles' ).children().each( function() {
44
+ $post_ids.push( $( this ).attr( 'id' ).replace( /^(ttle)/i, '' ) );
45
+ } );
46
+
47
+ // get the data
48
+ var $post_views = $bulk_row.find( 'input[name="post_views"]' ).val();
49
+
50
+ // save the data
51
+ $.ajax( {
52
+ url: ajaxurl, // this is a variable that WordPress has already defined for us
53
+ type: 'post',
54
+ async: false,
55
+ cache: false,
56
+ data: {
57
+ action: 'save_bulk_post_views', // this is the name of our WP AJAX function that we'll set up next
58
+ post_ids: $post_ids, // and these are the 2 parameters we're passing to our function
59
+ post_views: $post_views,
60
+ current_post_views: $post_views,
61
+ }
62
+ } );
63
+ } );
64
+
65
  } )( jQuery );
js/admin-settings.js CHANGED
@@ -1,133 +1,133 @@
1
- ( function ( $ ) {
2
-
3
- $( document ).ready( function () {
4
-
5
- $( '.post-views-counter-settings' ).checkBo();
6
-
7
- var ip_boxes = $( '#pvc_exclude_ips' ).find( '.ip-box' ).length;
8
-
9
- $( '#pvc_exclude_ips .ip-box:first' ).find( '.remove-exclude-ip' ).hide();
10
-
11
- // ask whether to reset options to defaults
12
- $( document ).on( 'click', '.reset_pvc_settings', function () {
13
- return confirm( pvcArgsSettings.resetToDefaults );
14
- } );
15
-
16
- // ask whether to reset views
17
- $( document ).on( 'click', 'input[name="post_views_counter_reset_views"]', function () {
18
- return confirm( pvcArgsSettings.resetViews );
19
- } );
20
-
21
- // remove ip box
22
- $( document ).on( 'click', '.remove-exclude-ip', function ( e ) {
23
- e.preventDefault();
24
-
25
- ip_boxes--;
26
-
27
- var parent = $( this ).parent();
28
-
29
- // remove ip box
30
- parent.slideUp( 'fast', function () {
31
- $( this ).remove();
32
- } );
33
- } );
34
-
35
- // add ip box
36
- $( document ).on( 'click', '.add-exclude-ip', function () {
37
- ip_boxes++;
38
-
39
- var parent = $( this ).parents( '#pvc_exclude_ips' ),
40
- new_ip_box = parent.find( '.ip-box:last' ).clone().hide();
41
-
42
- // clear value
43
- new_ip_box.find( 'input' ).val( '' );
44
-
45
- if ( ip_boxes > 1 ) {
46
- new_ip_box.find( '.remove-exclude-ip' ).show();
47
- }
48
-
49
- // add and display new ip box
50
- parent.find( '.ip-box:last' ).after( new_ip_box ).next().slideDown( 'fast' );
51
- } );
52
-
53
- // add current ip
54
- $( document ).on( 'click', '.add-current-ip', function () {
55
- // fill input with user's current ip
56
- $( this ).parents( '#pvc_exclude_ips' ).find( '.ip-box' ).last().find( 'input' ).val( $( this ).attr( 'data-rel' ) );
57
- } );
58
-
59
- // toggle user roles
60
- $( '#pvc_exclude-roles, #pvc_restrict_display-roles' ).change( function () {
61
- if ( $( this ).is( ':checked' ) ) {
62
- $( '.pvc_user_roles' ).slideDown( 'fast' );
63
- } else {
64
- $( '.pvc_user_roles' ).slideUp( 'fast' );
65
- }
66
- } );
67
-
68
- } );
69
-
70
- } )( jQuery );
71
-
72
- /*
73
- * checkBo lightweight jQuery plugin v0.1.4 by @ElmahdiMahmoud
74
- * Licensed under the MIT license - https://github.com/elmahdim/checkbo/blob/master/LICENSE
75
- *
76
- * Custom checkbox and radio
77
- * Author URL: elmahdim.com
78
- */
79
- !function ( e ) {
80
- e.fn.checkBo = function ( c ) {
81
- return c = e.extend( { }, { checkAllButton: null, checkAllTarget: null, checkAllTextDefault: null, checkAllTextToggle: null }, c ), this.each( function () {
82
- function t( e ) {
83
- this.input = e
84
- }
85
- function n() {
86
- var c = e( this ).is( ":checked" );
87
- e( this ).closest( "label" ).toggleClass( "checked", c )
88
- }
89
- function i( e, c, t ) {
90
- e.text( e.parent( a ).hasClass( "checked" ) ? t : c )
91
- }
92
- function h( c ) {
93
- var t = c.attr( "data-show" );
94
- c = c.attr( "data-hide" ), e( t ).removeClass( "is-hidden" ), e( c ).addClass( "is-hidden" )
95
- }
96
- var l = e( this ), a = l.find( ".cb-checkbox" ), d = l.find( ".cb-radio" ), o = l.find( ".cb-switcher" ), s = a.find( "input:checkbox" ), f = d.find( "input:radio" );
97
- s.wrap( '<span class="cb-inner"><i></i></span>' ), f.wrap( '<span class="cb-inner"><i></i></span>' );
98
- var k = new t( "input:checkbox" ), r = new t( "input:radio" );
99
- if ( t.prototype.checkbox = function ( e ) {
100
- var c = e.find( this.input ).is( ":checked" );
101
- e.find( this.input ).prop( "checked", !c ).trigger( "change" )
102
- }, t.prototype.radiobtn = function ( c, t ) {
103
- var n = e( 'input:radio[name="' + t + '"]' );
104
- n.prop( "checked", !1 ), n.closest( n.closest( d ) ).removeClass( "checked" ), c.addClass( "checked" ), c.find( this.input ).get( 0 ).checked = c.hasClass( "checked" ), c.find( this.input ).change()
105
- }, s.on( "change", n ), f.on( "change", n ), a.find( "a" ).on( "click", function ( e ) {
106
- e.stopPropagation()
107
- } ), a.on( "click", function ( c ) {
108
- c.preventDefault(), k.checkbox( e( this ) ), c = e( this ).attr( "data-toggle" ), e( c ).toggleClass( "is-hidden" ), h( e( this ) )
109
- } ), d.on( "click", function ( c ) {
110
- c.preventDefault(), r.radiobtn( e( this ), e( this ).find( "input:radio" ).attr( "name" ) ), h( e( this ) )
111
- } ), e.fn.toggleCheckbox = function () {
112
- this.prop( "checked", !this.is( ":checked" ) )
113
- }, e.fn.switcherChecker = function () {
114
- var c = e( this ), t = c.find( "input" ), n = c.find( ".cb-state" );
115
- t.is( ":checked" ) ? ( c.addClass( "checked" ), n.html( t.attr( "data-state-on" ) ) ) : ( c.removeClass( "checked" ), n.html( t.attr( "data-state-off" ) ) )
116
- }, o.on( "click", function ( c ) {
117
- c.preventDefault(), c = e( this ), c.find( "input" ).toggleCheckbox(), c.switcherChecker(), e( c.attr( "data-toggle" ) ).toggleClass( "is-hidden" )
118
- } ), o.each( function () {
119
- e( this ).switcherChecker()
120
- } ), c.checkAllButton && c.checkAllTarget ) {
121
- var u = e( this );
122
- u.find( e( c.checkAllButton ) ).on( "click", function () {
123
- u.find( c.checkAllTarget ).find( "input:checkbox" ).each( function () {
124
- u.find( e( c.checkAllButton ) ).hasClass( "checked" ) ? u.find( c.checkAllTarget ).find( "input:checkbox" ).prop( "checked", !0 ).change() : u.find( c.checkAllTarget ).find( "input:checkbox" ).prop( "checked", !1 ).change()
125
- } ), i( u.find( e( c.checkAllButton ) ).find( ".toggle-text" ), c.checkAllTextDefault, c.checkAllTextToggle )
126
- } ), u.find( c.checkAllTarget ).find( a ).on( "click", function () {
127
- u.find( c.checkAllButton ).find( "input:checkbox" ).prop( "checked", !1 ).change().removeClass( "checked" ), i( u.find( e( c.checkAllButton ) ).find( ".toggle-text" ), c.checkAllTextDefault, c.checkAllTextToggle )
128
- } )
129
- }
130
- l.find( '[checked="checked"]' ).closest( "label" ).addClass( "checked" ), l.find( "input" ).is( "input:disabled" ) && l.find( "input:disabled" ).closest( "label" ).off().addClass( "disabled" )
131
- } )
132
- }
133
  }( jQuery, window, document );
1
+ ( function ( $ ) {
2
+
3
+ $( document ).ready( function () {
4
+
5
+ $( '.post-views-counter-settings' ).checkBo();
6
+
7
+ var ip_boxes = $( '#pvc_exclude_ips' ).find( '.ip-box' ).length;
8
+
9
+ $( '#pvc_exclude_ips .ip-box:first' ).find( '.remove-exclude-ip' ).hide();
10
+
11
+ // ask whether to reset options to defaults
12
+ $( document ).on( 'click', '.reset_pvc_settings', function () {
13
+ return confirm( pvcArgsSettings.resetToDefaults );
14
+ } );
15
+
16
+ // ask whether to reset views
17
+ $( document ).on( 'click', 'input[name="post_views_counter_reset_views"]', function () {
18
+ return confirm( pvcArgsSettings.resetViews );
19
+ } );
20
+
21
+ // remove ip box
22
+ $( document ).on( 'click', '.remove-exclude-ip', function ( e ) {
23
+ e.preventDefault();
24
+
25
+ ip_boxes--;
26
+
27
+ var parent = $( this ).parent();
28
+
29
+ // remove ip box
30
+ parent.slideUp( 'fast', function () {
31
+ $( this ).remove();
32
+ } );
33
+ } );
34
+
35
+ // add ip box
36
+ $( document ).on( 'click', '.add-exclude-ip', function () {
37
+ ip_boxes++;
38
+
39
+ var parent = $( this ).parents( '#pvc_exclude_ips' ),
40
+ new_ip_box = parent.find( '.ip-box:last' ).clone().hide();
41
+
42
+ // clear value
43
+ new_ip_box.find( 'input' ).val( '' );
44
+
45
+ if ( ip_boxes > 1 ) {
46
+ new_ip_box.find( '.remove-exclude-ip' ).show();
47
+ }
48
+
49
+ // add and display new ip box
50
+ parent.find( '.ip-box:last' ).after( new_ip_box ).next().slideDown( 'fast' );
51
+ } );
52
+
53
+ // add current ip
54
+ $( document ).on( 'click', '.add-current-ip', function () {
55
+ // fill input with user's current ip
56
+ $( this ).parents( '#pvc_exclude_ips' ).find( '.ip-box' ).last().find( 'input' ).val( $( this ).attr( 'data-rel' ) );
57
+ } );
58
+
59
+ // toggle user roles
60
+ $( '#pvc_exclude-roles, #pvc_restrict_display-roles' ).change( function () {
61
+ if ( $( this ).is( ':checked' ) ) {
62
+ $( '.pvc_user_roles' ).slideDown( 'fast' );
63
+ } else {
64
+ $( '.pvc_user_roles' ).slideUp( 'fast' );
65
+ }
66
+ } );
67
+
68
+ } );
69
+
70
+ } )( jQuery );
71
+
72
+ /*
73
+ * checkBo lightweight jQuery plugin v0.1.4 by @ElmahdiMahmoud
74
+ * Licensed under the MIT license - https://github.com/elmahdim/checkbo/blob/master/LICENSE
75
+ *
76
+ * Custom checkbox and radio
77
+ * Author URL: elmahdim.com
78
+ */
79
+ !function ( e ) {
80
+ e.fn.checkBo = function ( c ) {
81
+ return c = e.extend( { }, { checkAllButton: null, checkAllTarget: null, checkAllTextDefault: null, checkAllTextToggle: null }, c ), this.each( function () {
82
+ function t( e ) {
83
+ this.input = e
84
+ }
85
+ function n() {
86
+ var c = e( this ).is( ":checked" );
87
+ e( this ).closest( "label" ).toggleClass( "checked", c )
88
+ }
89
+ function i( e, c, t ) {
90
+ e.text( e.parent( a ).hasClass( "checked" ) ? t : c )
91
+ }
92
+ function h( c ) {
93
+ var t = c.attr( "data-show" );
94
+ c = c.attr( "data-hide" ), e( t ).removeClass( "is-hidden" ), e( c ).addClass( "is-hidden" )
95
+ }
96
+ var l = e( this ), a = l.find( ".cb-checkbox" ), d = l.find( ".cb-radio" ), o = l.find( ".cb-switcher" ), s = a.find( "input:checkbox" ), f = d.find( "input:radio" );
97
+ s.wrap( '<span class="cb-inner"><i></i></span>' ), f.wrap( '<span class="cb-inner"><i></i></span>' );
98
+ var k = new t( "input:checkbox" ), r = new t( "input:radio" );
99
+ if ( t.prototype.checkbox = function ( e ) {
100
+ var c = e.find( this.input ).is( ":checked" );
101
+ e.find( this.input ).prop( "checked", !c ).trigger( "change" )
102
+ }, t.prototype.radiobtn = function ( c, t ) {
103
+ var n = e( 'input:radio[name="' + t + '"]' );
104
+ n.prop( "checked", !1 ), n.closest( n.closest( d ) ).removeClass( "checked" ), c.addClass( "checked" ), c.find( this.input ).get( 0 ).checked = c.hasClass( "checked" ), c.find( this.input ).change()
105
+ }, s.on( "change", n ), f.on( "change", n ), a.find( "a" ).on( "click", function ( e ) {
106
+ e.stopPropagation()
107
+ } ), a.on( "click", function ( c ) {
108
+ c.preventDefault(), k.checkbox( e( this ) ), c = e( this ).attr( "data-toggle" ), e( c ).toggleClass( "is-hidden" ), h( e( this ) )
109
+ } ), d.on( "click", function ( c ) {
110
+ c.preventDefault(), r.radiobtn( e( this ), e( this ).find( "input:radio" ).attr( "name" ) ), h( e( this ) )
111
+ } ), e.fn.toggleCheckbox = function () {
112
+ this.prop( "checked", !this.is( ":checked" ) )
113
+ }, e.fn.switcherChecker = function () {
114
+ var c = e( this ), t = c.find( "input" ), n = c.find( ".cb-state" );
115
+ t.is( ":checked" ) ? ( c.addClass( "checked" ), n.html( t.attr( "data-state-on" ) ) ) : ( c.removeClass( "checked" ), n.html( t.attr( "data-state-off" ) ) )
116
+ }, o.on( "click", function ( c ) {
117
+ c.preventDefault(), c = e( this ), c.find( "input" ).toggleCheckbox(), c.switcherChecker(), e( c.attr( "data-toggle" ) ).toggleClass( "is-hidden" )
118
+ } ), o.each( function () {
119
+ e( this ).switcherChecker()
120
+ } ), c.checkAllButton && c.checkAllTarget ) {
121
+ var u = e( this );
122
+ u.find( e( c.checkAllButton ) ).on( "click", function () {
123
+ u.find( c.checkAllTarget ).find( "input:checkbox" ).each( function () {
124
+ u.find( e( c.checkAllButton ) ).hasClass( "checked" ) ? u.find( c.checkAllTarget ).find( "input:checkbox" ).prop( "checked", !0 ).change() : u.find( c.checkAllTarget ).find( "input:checkbox" ).prop( "checked", !1 ).change()
125
+ } ), i( u.find( e( c.checkAllButton ) ).find( ".toggle-text" ), c.checkAllTextDefault, c.checkAllTextToggle )
126
+ } ), u.find( c.checkAllTarget ).find( a ).on( "click", function () {
127
+ u.find( c.checkAllButton ).find( "input:checkbox" ).prop( "checked", !1 ).change().removeClass( "checked" ), i( u.find( e( c.checkAllButton ) ).find( ".toggle-text" ), c.checkAllTextDefault, c.checkAllTextToggle )
128
+ } )
129
+ }
130
+ l.find( '[checked="checked"]' ).closest( "label" ).addClass( "checked" ), l.find( "input" ).is( "input:disabled" ) && l.find( "input:disabled" ).closest( "label" ).off().addClass( "disabled" )
131
+ } )
132
+ }
133
  }( jQuery, window, document );
js/admin-widgets.js CHANGED
@@ -1,11 +1,11 @@
1
- ( function ( $ ) {
2
-
3
- $( document ).ready( function () {
4
-
5
- $( document ).on( 'change', '.pvc-show-post-thumbnail', function () {
6
- $( this ).closest( '.widget-content' ).find( '.pvc-post-thumbnail-size' ).fadeToggle( 300 );
7
- } );
8
-
9
- } );
10
-
11
  } )( jQuery );
1
+ ( function ( $ ) {
2
+
3
+ $( document ).ready( function () {
4
+
5
+ $( document ).on( 'change', '.pvc-show-post-thumbnail', function () {
6
+ $( this ).closest( '.widget-content' ).find( '.pvc-post-thumbnail-size' ).fadeToggle( 300 );
7
+ } );
8
+
9
+ } );
10
+
11
  } )( jQuery );
js/frontend.js CHANGED
@@ -1,56 +1,56 @@
1
- ( function ( $ ) {
2
-
3
- $( document ).ready( function () {
4
-
5
- // rest api request
6
- if ( pvcArgsFrontend.mode == 'rest_api' ) {
7
-
8
- var request = {
9
- id: pvcArgsFrontend.postID
10
- };
11
-
12
- $.ajax( {
13
- url: pvcArgsFrontend.requestURL + '?id=' + pvcArgsFrontend.postID,
14
- type: 'post',
15
- async: true,
16
- cache: false,
17
- data: request,
18
- beforeSend: function ( xhr ) {
19
- xhr.setRequestHeader( 'X-WP-Nonce', pvcArgsFrontend.nonce );
20
- }
21
- } ).done( function( response ) {
22
- // trigger pvcCheckPost event
23
- $.event.trigger( {
24
- type: 'pvcCheckPost',
25
- detail: response
26
- } );
27
- } );
28
-
29
- // admin ajax or fast ajax request
30
- } else {
31
-
32
- var request = {
33
- action: 'pvc-check-post',
34
- pvc_nonce: pvcArgsFrontend.nonce,
35
- id: pvcArgsFrontend.postID
36
- };
37
-
38
- $.ajax( {
39
- url: pvcArgsFrontend.requestURL,
40
- type: 'post',
41
- async: true,
42
- cache: false,
43
- data: request
44
- } ).done( function( response ) {
45
- // trigger pvcCheckPost event
46
- $.event.trigger( {
47
- type: 'pvcCheckPost',
48
- detail: response
49
- } );
50
- } );
51
-
52
- }
53
-
54
- } );
55
-
56
  } )( jQuery );
1
+ ( function ( $ ) {
2
+
3
+ $( document ).ready( function () {
4
+
5
+ // rest api request
6
+ if ( pvcArgsFrontend.mode == 'rest_api' ) {
7
+
8
+ var request = {
9
+ id: pvcArgsFrontend.postID
10
+ };
11
+
12
+ $.ajax( {
13
+ url: pvcArgsFrontend.requestURL + '?id=' + pvcArgsFrontend.postID,
14
+ type: 'post',
15
+ async: true,
16
+ cache: false,
17
+ data: request,
18
+ beforeSend: function ( xhr ) {
19
+ xhr.setRequestHeader( 'X-WP-Nonce', pvcArgsFrontend.nonce );
20
+ }
21
+ } ).done( function( response ) {
22
+ // trigger pvcCheckPost event
23
+ $.event.trigger( {
24
+ type: 'pvcCheckPost',
25
+ detail: response
26
+ } );
27
+ } );
28
+
29
+ // admin ajax or fast ajax request
30
+ } else {
31
+
32
+ var request = {
33
+ action: 'pvc-check-post',
34
+ pvc_nonce: pvcArgsFrontend.nonce,
35
+ id: pvcArgsFrontend.postID
36
+ };
37
+
38
+ $.ajax( {
39
+ url: pvcArgsFrontend.requestURL,
40
+ type: 'post',
41
+ async: true,
42
+ cache: false,
43
+ data: request
44
+ } ).done( function( response ) {
45
+ // trigger pvcCheckPost event
46
+ $.event.trigger( {
47
+ type: 'pvcCheckPost',
48
+ detail: response
49
+ } );
50
+ } );
51
+
52
+ }
53
+
54
+ } );
55
+
56
  } )( jQuery );
languages/post-views-counter.pot CHANGED
@@ -1,567 +1,567 @@
1
- #, fuzzy
2
- msgid ""
3
- msgstr ""
4
- "Project-Id-Version: Post Views Counter\n"
5
- "POT-Creation-Date: 2019-07-10 10:32+0200\n"
6
- "PO-Revision-Date: 2015-04-08 18:59+0100\n"
7
- "Last-Translator: Bartosz Arendt <info@dfactory.eu>\n"
8
- "Language-Team: dFactory <info@dfactory.eu>\n"
9
- "Language: en\n"
10
- "MIME-Version: 1.0\n"
11
- "Content-Type: text/plain; charset=UTF-8\n"
12
- "Content-Transfer-Encoding: 8bit\n"
13
- "X-Generator: Poedit 2.2.3\n"
14
- "X-Poedit-KeywordsList: gettext;gettext_noop;__;_e;esc_attr__;esc_attr_e;"
15
- "esc_html__;esc_html_e\n"
16
- "X-Poedit-Basepath: .\n"
17
- "X-Poedit-SourceCharset: UTF-8\n"
18
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
- "X-Poedit-SearchPath-0: ..\n"
20
-
21
- #: ../includes/columns.php:46 ../includes/columns.php:131
22
- #: ../includes/columns.php:176 ../includes/columns.php:311
23
- #: ../includes/columns.php:317 ../includes/columns.php:367
24
- #: ../includes/dashboard.php:30 ../includes/dashboard.php:102
25
- #: ../includes/dashboard.php:112 ../includes/dashboard.php:121
26
- #: ../includes/dashboard.php:197
27
- msgid "Post Views"
28
- msgstr ""
29
-
30
- #: ../includes/columns.php:86 ../includes/counter.php:218
31
- msgid "Invalid post ID."
32
- msgstr ""
33
-
34
- #: ../includes/columns.php:90 ../includes/columns.php:96
35
- msgid "You are not allowed to edit this item."
36
- msgstr ""
37
-
38
- #: ../includes/columns.php:132 ../includes/columns.php:189
39
- msgid "Adjust the views count for this post."
40
- msgstr ""
41
-
42
- #: ../includes/columns.php:133 ../includes/columns.php:194
43
- msgid "Cancel"
44
- msgstr ""
45
-
46
- #: ../includes/columns.php:185
47
- msgid "Edit"
48
- msgstr ""
49
-
50
- #: ../includes/columns.php:193
51
- msgid "OK"
52
- msgstr ""
53
-
54
- #: ../includes/counter.php:210
55
- msgid "REST API method is disabled."
56
- msgstr ""
57
-
58
- #: ../includes/counter.php:224
59
- msgid "Post type excluded."
60
- msgstr ""
61
-
62
- #: ../includes/cron.php:61
63
- msgid "Post Views Counter reset daily counts interval"
64
- msgstr ""
65
-
66
- #: ../includes/cron.php:66
67
- msgid "Post Views Counter cache flush interval"
68
- msgstr ""
69
-
70
- #: ../includes/dashboard.php:64 ../includes/dashboard.php:67
71
- msgid "You do not have permission to access this page."
72
- msgstr ""
73
-
74
- #: ../includes/dashboard.php:120
75
- msgid "Year"
76
- msgstr ""
77
-
78
- #: ../includes/dashboard.php:135 ../includes/dashboard.php:211
79
- msgid "Total Views"
80
- msgstr ""
81
-
82
- #: ../includes/functions.php:348
83
- msgid "No Posts"
84
- msgstr ""
85
-
86
- #: ../includes/settings.php:41
87
- msgid "PHP"
88
- msgstr ""
89
-
90
- #: ../includes/settings.php:42
91
- msgid "JavaScript"
92
- msgstr ""
93
-
94
- #: ../includes/settings.php:43
95
- msgid "Fast AJAX"
96
- msgstr ""
97
-
98
- #: ../includes/settings.php:47
99
- msgid "REST API"
100
- msgstr ""
101
-
102
- #: ../includes/settings.php:51
103
- msgid "minutes"
104
- msgstr ""
105
-
106
- #: ../includes/settings.php:52
107
- msgid "hours"
108
- msgstr ""
109
-
110
- #: ../includes/settings.php:53
111
- msgid "days"
112
- msgstr ""
113
-
114
- #: ../includes/settings.php:54
115
- msgid "weeks"
116
- msgstr ""
117
-
118
- #: ../includes/settings.php:55
119
- msgid "months"
120
- msgstr ""
121
-
122
- #: ../includes/settings.php:56
123
- msgid "years"
124
- msgstr ""
125
-
126
- #: ../includes/settings.php:60
127
- msgid "robots"
128
- msgstr ""
129
-
130
- #: ../includes/settings.php:61
131
- msgid "logged in users"
132
- msgstr ""
133
-
134
- #: ../includes/settings.php:62
135
- msgid "guests"
136
- msgstr ""
137
-
138
- #: ../includes/settings.php:63
139
- msgid "selected user roles"
140
- msgstr ""
141
-
142
- #: ../includes/settings.php:67
143
- msgid "before the content"
144
- msgstr ""
145
-
146
- #: ../includes/settings.php:68
147
- msgid "after the content"
148
- msgstr ""
149
-
150
- #: ../includes/settings.php:69
151
- msgid "manual"
152
- msgstr ""
153
-
154
- #: ../includes/settings.php:73
155
- msgid "icon"
156
- msgstr ""
157
-
158
- #: ../includes/settings.php:74
159
- msgid "label"
160
- msgstr ""
161
-
162
- #: ../includes/settings.php:79
163
- msgid "General"
164
- msgstr ""
165
-
166
- #: ../includes/settings.php:85
167
- msgid "Display"
168
- msgstr ""
169
-
170
- #: ../includes/settings.php:95
171
- msgid "Home"
172
- msgstr ""
173
-
174
- #: ../includes/settings.php:96
175
- msgid "Archives"
176
- msgstr ""
177
-
178
- #: ../includes/settings.php:97
179
- msgid "Single pages"
180
- msgstr ""
181
-
182
- #: ../includes/settings.php:98
183
- msgid "Search results"
184
- msgstr ""
185
-
186
- #: ../includes/settings.php:153 ../includes/settings.php:167
187
- #: ../includes/settings.php:179
188
- msgid "Post Views Counter"
189
- msgstr ""
190
-
191
- #: ../includes/settings.php:181
192
- msgid "Need support?"
193
- msgstr ""
194
-
195
- #: ../includes/settings.php:182
196
- #, php-format
197
- msgid ""
198
- "If you are having problems with this plugin, please browse it's <a href=\"%s"
199
- "\" target=\"_blank\">Documentation</a> or talk about them in the <a href=\"%s"
200
- "\" target=\"_blank\">Support forum</a>"
201
- msgstr ""
202
-
203
- #: ../includes/settings.php:184
204
- msgid "Do you like this plugin?"
205
- msgstr ""
206
-
207
- #: ../includes/settings.php:185
208
- #, php-format
209
- msgid "<a href=\"%s\" target=\"_blank\">Rate it 5</a> on WordPress.org"
210
- msgstr ""
211
-
212
- #: ../includes/settings.php:186
213
- #, php-format
214
- msgid ""
215
- "Blog about it & link to the <a href=\"%s\" target=\"_blank\">plugin page</a>."
216
- msgstr ""
217
-
218
- #: ../includes/settings.php:187
219
- #, php-format
220
- msgid ""
221
- "Check out our other <a href=\"%s\" target=\"_blank\">WordPress plugins</a>."
222
- msgstr ""
223
-
224
- #: ../includes/settings.php:190
225
- msgid "Created by"
226
- msgstr ""
227
-
228
- #: ../includes/settings.php:206
229
- msgid "Reset to defaults"
230
- msgstr ""
231
-
232
- #: ../includes/settings.php:222
233
- msgid "General settings"
234
- msgstr ""
235
-
236
- #: ../includes/settings.php:223
237
- msgid "Post Types Count"
238
- msgstr ""
239
-
240
- #: ../includes/settings.php:224
241
- msgid "Counter Mode"
242
- msgstr ""
243
-
244
- #: ../includes/settings.php:225
245
- msgid "Post Views Column"
246
- msgstr ""
247
-
248
- #: ../includes/settings.php:226
249
- msgid "Restrict Edit"
250
- msgstr ""
251
-
252
- #: ../includes/settings.php:227
253
- msgid "Count Interval"
254
- msgstr ""
255
-
256
- #: ../includes/settings.php:228
257
- msgid "Reset Data Interval"
258
- msgstr ""
259
-
260
- #: ../includes/settings.php:229
261
- msgid "Flush Object Cache Interval"
262
- msgstr ""
263
-
264
- #: ../includes/settings.php:230
265
- msgid "Exclude Visitors"
266
- msgstr ""
267
-
268
- #: ../includes/settings.php:231
269
- msgid "Exclude IPs"
270
- msgstr ""
271
-
272
- #: ../includes/settings.php:232
273
- msgid "Strict counts"
274
- msgstr ""
275
-
276
- #: ../includes/settings.php:233
277
- msgid "Tools"
278
- msgstr ""
279
-
280
- #: ../includes/settings.php:234
281
- msgid "Deactivation"
282
- msgstr ""
283
-
284
- #: ../includes/settings.php:238
285
- msgid "Display settings"
286
- msgstr ""
287
-
288
- #: ../includes/settings.php:239
289
- msgid "Post Views Label"
290
- msgstr ""
291
-
292
- #: ../includes/settings.php:240
293
- msgid "Post Type"
294
- msgstr ""
295
-
296
- #: ../includes/settings.php:241
297
- msgid "Page Type"
298
- msgstr ""
299
-
300
- #: ../includes/settings.php:242
301
- msgid "User Type"
302
- msgstr ""
303
-
304
- #: ../includes/settings.php:243
305
- msgid "Position"
306
- msgstr ""
307
-
308
- #: ../includes/settings.php:244 ../includes/widgets.php:150
309
- msgid "Display Style"
310
- msgstr ""
311
-
312
- #: ../includes/settings.php:245
313
- msgid "Icon Class"
314
- msgstr ""
315
-
316
- #: ../includes/settings.php:256
317
- msgid "Enter the label for the post views counter field."
318
- msgstr ""
319
-
320
- #: ../includes/settings.php:274
321
- msgid "Select post types for which post views will be counted."
322
- msgstr ""
323
-
324
- #: ../includes/settings.php:291
325
- msgid "Select post types for which the views count will be displayed."
326
- msgstr ""
327
-
328
- #: ../includes/settings.php:310
329
- msgid ""
330
- "Select the method of collecting post views data. If you are using any of the "
331
- "caching plugins select Javascript or REST API (if available)."
332
- msgstr ""
333
-
334
- #: ../includes/settings.php:310
335
- msgid ""
336
- "Optionally try the Fast AJAX experimental method, usually 10+ times faster "
337
- "than Javascript or REST API."
338
- msgstr ""
339
-
340
- #: ../includes/settings.php:320
341
- msgid ""
342
- "Enable to display post views count column for each of the selected post "
343
- "types."
344
- msgstr ""
345
-
346
- #: ../includes/settings.php:340
347
- msgid "Enter the time between single user visit count."
348
- msgstr ""
349
-
350
- #: ../includes/settings.php:360
351
- msgid ""
352
- "Delete single day post views data older than specified above. Enter 0 "
353
- "(number zero) if you want to preserve your data regardless of its age."
354
- msgstr ""
355
-
356
- #: ../includes/settings.php:380
357
- msgid ""
358
- "How often to flush cached view counts from the object cache into the "
359
- "database. This feature is used only if a persistent object cache is detected "
360
- "and the interval is greater than 0 (number zero)). When used, view counts "
361
- "will be collected and stored in the object cache instead of the database and "
362
- "will then be asynchronously flushed to the database according to the "
363
- "specified interval.<br /><strong>Notice:</strong> Potential data loss may "
364
- "occur if the object cache is cleared/unavailable for the duration of the "
365
- "interval."
366
- msgstr ""
367
-
368
- #: ../includes/settings.php:398 ../includes/settings.php:571
369
- msgid "Use it to hide the post views counter from selected type of visitors."
370
- msgstr ""
371
-
372
- #: ../includes/settings.php:406 ../includes/settings.php:580
373
- msgid "Use it to hide the post views counter from selected user roles."
374
- msgstr ""
375
-
376
- #: ../includes/settings.php:426 ../includes/settings.php:432
377
- msgid "Remove"
378
- msgstr ""
379
-
380
- #: ../includes/settings.php:437
381
- msgid "Add new"
382
- msgstr ""
383
-
384
- #: ../includes/settings.php:437
385
- msgid "Add my current IP"
386
- msgstr ""
387
-
388
- #: ../includes/settings.php:438
389
- msgid "Enter the IP addresses to be excluded from post views count."
390
- msgstr ""
391
-
392
- #: ../includes/settings.php:448
393
- msgid ""
394
- "Enable to prevent bypassing the counts interval (for e.g. using incognito "
395
- "browser window or by clearing cookies)."
396
- msgstr ""
397
-
398
- #: ../includes/settings.php:459
399
- msgid "Import views"
400
- msgstr ""
401
-
402
- #: ../includes/settings.php:459
403
- msgid "Override existing views data."
404
- msgstr ""
405
-
406
- #: ../includes/settings.php:460
407
- msgid "Import post views data from WP-PostViews plugin."
408
- msgstr ""
409
-
410
- #: ../includes/settings.php:461
411
- msgid "Delete views"
412
- msgstr ""
413
-
414
- #: ../includes/settings.php:462
415
- msgid "Delete ALL the existing post views data."
416
- msgstr ""
417
-
418
- #: ../includes/settings.php:473
419
- msgid "Enable to restrict post views editing to admins only."
420
- msgstr ""
421
-
422
- #: ../includes/settings.php:483
423
- msgid "Enable to delete all plugin data on deactivation."
424
- msgstr ""
425
-
426
- #: ../includes/settings.php:500
427
- msgid "Select page types where the views count will be displayed."
428
- msgstr ""
429
-
430
- #: ../includes/settings.php:519
431
- msgid ""
432
- "Select where would you like to display the post views counter. Use [post-"
433
- "views] shortcode for manual display."
434
- msgstr ""
435
-
436
- #: ../includes/settings.php:538
437
- msgid "Choose how to display the post views counter."
438
- msgstr ""
439
-
440
- #: ../includes/settings.php:549
441
- #, php-format
442
- msgid ""
443
- "Enter the post views icon class. Any of the <a href=\"%s\" target=\"_blank"
444
- "\">Dashicons</a> classes are available."
445
- msgstr ""
446
-
447
- #: ../includes/settings.php:609
448
- msgid "Post views data imported succesfully."
449
- msgstr ""
450
-
451
- #: ../includes/settings.php:611
452
- msgid "There was no post views data to import."
453
- msgstr ""
454
-
455
- #: ../includes/settings.php:617
456
- msgid "All existing data deleted succesfully."
457
- msgstr ""
458
-
459
- #: ../includes/settings.php:619
460
- msgid "Error occurred. All existing data were not deleted."
461
- msgstr ""
462
-
463
- #: ../includes/settings.php:795
464
- msgid "General settings restored to defaults."
465
- msgstr ""
466
-
467
- #: ../includes/settings.php:799
468
- msgid "Display settings restored to defaults."
469
- msgstr ""
470
-
471
- #: ../includes/update.php:75
472
- msgid ""
473
- "<strong>Post Views Counter</strong> - this version requires a database "
474
- "update. Make sure to back up your database first."
475
- msgstr ""
476
-
477
- #: ../includes/update.php:76
478
- msgid "Run the Update"
479
- msgstr ""
480
-
481
- #: ../includes/update.php:117
482
- msgid "Thank you! Datebase was succesfully updated."
483
- msgstr ""
484
-
485
- #: ../includes/widgets.php:42 ../includes/widgets.php:48
486
- msgid "Most Viewed Posts"
487
- msgstr ""
488
-
489
- #: ../includes/widgets.php:43
490
- msgid "Displays a list of the most viewed posts"
491
- msgstr ""
492
-
493
- #: ../includes/widgets.php:58
494
- msgid "No Posts found"
495
- msgstr ""
496
-
497
- #: ../includes/widgets.php:62
498
- msgid "Ascending"
499
- msgstr ""
500
-
501
- #: ../includes/widgets.php:63
502
- msgid "Descending"
503
- msgstr ""
504
-
505
- #: ../includes/widgets.php:67
506
- msgid "Unordered list"
507
- msgstr ""
508
-
509
- #: ../includes/widgets.php:68
510
- msgid "Ordered list"
511
- msgstr ""
512
-
513
- #: ../includes/widgets.php:114
514
- msgid "Title"
515
- msgstr ""
516
-
517
- #: ../includes/widgets.php:118
518
- msgid "Post Types"
519
- msgstr ""
520
-
521
- #: ../includes/widgets.php:130
522
- msgid "Number of posts to show"
523
- msgstr ""
524
-
525
- #: ../includes/widgets.php:134
526
- msgid "No posts message"
527
- msgstr ""
528
-
529
- #: ../includes/widgets.php:138
530
- msgid "Order"
531
- msgstr ""
532
-
533
- #: ../includes/widgets.php:162
534
- msgid "Display post views?"
535
- msgstr ""
536
-
537
- #: ../includes/widgets.php:164
538
- msgid "Display post excerpt?"
539
- msgstr ""
540
-
541
- #: ../includes/widgets.php:166
542
- msgid "Display post author?"
543
- msgstr ""
544
-
545
- #: ../includes/widgets.php:168
546
- msgid "Display post thumbnail?"
547
- msgstr ""
548
-
549
- #: ../includes/widgets.php:171
550
- msgid "Thumbnail size"
551
- msgstr ""
552
-
553
- #: ../post-views-counter.php:387
554
- msgid "Are you sure you want to reset these settings to defaults?"
555
- msgstr ""
556
-
557
- #: ../post-views-counter.php:388
558
- msgid "Are you sure you want to delete all existing data?"
559
- msgstr ""
560
-
561
- #: ../post-views-counter.php:437
562
- msgid "Support"
563
- msgstr ""
564
-
565
- #: ../post-views-counter.php:461
566
- msgid "Settings"
567
- msgstr ""
1
+ #, fuzzy
2
+ msgid ""
3
+ msgstr ""
4
+ "Project-Id-Version: Post Views Counter\n"
5
+ "POT-Creation-Date: 2019-07-10 10:32+0200\n"
6
+ "PO-Revision-Date: 2015-04-08 18:59+0100\n"
7
+ "Last-Translator: Bartosz Arendt <info@dfactory.eu>\n"
8
+ "Language-Team: dFactory <info@dfactory.eu>\n"
9
+ "Language: en\n"
10
+ "MIME-Version: 1.0\n"
11
+ "Content-Type: text/plain; charset=UTF-8\n"
12
+ "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Generator: Poedit 2.2.3\n"
14
+ "X-Poedit-KeywordsList: gettext;gettext_noop;__;_e;esc_attr__;esc_attr_e;"
15
+ "esc_html__;esc_html_e\n"
16
+ "X-Poedit-Basepath: .\n"
17
+ "X-Poedit-SourceCharset: UTF-8\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
+ "X-Poedit-SearchPath-0: ..\n"
20
+
21
+ #: ../includes/columns.php:46 ../includes/columns.php:131
22
+ #: ../includes/columns.php:176 ../includes/columns.php:311
23
+ #: ../includes/columns.php:317 ../includes/columns.php:367
24
+ #: ../includes/dashboard.php:30 ../includes/dashboard.php:102
25
+ #: ../includes/dashboard.php:112 ../includes/dashboard.php:121
26
+ #: ../includes/dashboard.php:197
27
+ msgid "Post Views"
28
+ msgstr ""
29
+
30
+ #: ../includes/columns.php:86 ../includes/counter.php:218
31
+ msgid "Invalid post ID."
32
+ msgstr ""
33
+
34
+ #: ../includes/columns.php:90 ../includes/columns.php:96
35
+ msgid "You are not allowed to edit this item."
36
+ msgstr ""
37
+
38
+ #: ../includes/columns.php:132 ../includes/columns.php:189
39
+ msgid "Adjust the views count for this post."
40
+ msgstr ""
41
+
42
+ #: ../includes/columns.php:133 ../includes/columns.php:194
43
+ msgid "Cancel"
44
+ msgstr ""
45
+
46
+ #: ../includes/columns.php:185
47
+ msgid "Edit"
48
+ msgstr ""
49
+
50
+ #: ../includes/columns.php:193
51
+ msgid "OK"
52
+ msgstr ""
53
+
54
+ #: ../includes/counter.php:210
55
+ msgid "REST API method is disabled."
56
+ msgstr ""
57
+
58
+ #: ../includes/counter.php:224
59
+ msgid "Post type excluded."
60
+ msgstr ""
61
+
62
+ #: ../includes/cron.php:61
63
+ msgid "Post Views Counter reset daily counts interval"
64
+ msgstr ""
65
+
66
+ #: ../includes/cron.php:66
67
+ msgid "Post Views Counter cache flush interval"
68
+ msgstr ""
69
+
70
+ #: ../includes/dashboard.php:64 ../includes/dashboard.php:67
71
+ msgid "You do not have permission to access this page."
72
+ msgstr ""
73
+
74
+ #: ../includes/dashboard.php:120
75
+ msgid "Year"
76
+ msgstr ""
77
+
78
+ #: ../includes/dashboard.php:135 ../includes/dashboard.php:211
79
+ msgid "Total Views"
80
+ msgstr ""
81
+
82
+ #: ../includes/functions.php:348
83
+ msgid "No Posts"
84
+ msgstr ""
85
+
86
+ #: ../includes/settings.php:41
87
+ msgid "PHP"
88
+ msgstr ""
89
+
90
+ #: ../includes/settings.php:42
91
+ msgid "JavaScript"
92
+ msgstr ""
93
+
94
+ #: ../includes/settings.php:43
95
+ msgid "Fast AJAX"
96
+ msgstr ""
97
+
98
+ #: ../includes/settings.php:47
99
+ msgid "REST API"
100
+ msgstr ""
101
+
102
+ #: ../includes/settings.php:51
103
+ msgid "minutes"
104
+ msgstr ""
105
+
106
+ #: ../includes/settings.php:52
107
+ msgid "hours"
108
+ msgstr ""
109
+
110
+ #: ../includes/settings.php:53
111
+ msgid "days"
112
+ msgstr ""
113
+
114
+ #: ../includes/settings.php:54
115
+ msgid "weeks"
116
+ msgstr ""
117
+
118
+ #: ../includes/settings.php:55
119
+ msgid "months"
120
+ msgstr ""
121
+
122
+ #: ../includes/settings.php:56
123
+ msgid "years"
124
+ msgstr ""
125
+
126
+ #: ../includes/settings.php:60
127
+ msgid "robots"
128
+ msgstr ""
129
+
130
+ #: ../includes/settings.php:61
131
+ msgid "logged in users"
132
+ msgstr ""
133
+
134
+ #: ../includes/settings.php:62
135
+ msgid "guests"
136
+ msgstr ""
137
+
138
+ #: ../includes/settings.php:63
139
+ msgid "selected user roles"
140
+ msgstr ""
141
+
142
+ #: ../includes/settings.php:67
143
+ msgid "before the content"
144
+ msgstr ""
145
+
146
+ #: ../includes/settings.php:68
147
+ msgid "after the content"
148
+ msgstr ""
149
+
150
+ #: ../includes/settings.php:69
151
+ msgid "manual"
152
+ msgstr ""
153
+
154
+ #: ../includes/settings.php:73
155
+ msgid "icon"
156
+ msgstr ""
157
+
158
+ #: ../includes/settings.php:74
159
+ msgid "label"
160
+ msgstr ""
161
+
162
+ #: ../includes/settings.php:79
163
+ msgid "General"
164
+ msgstr ""
165
+
166
+ #: ../includes/settings.php:85
167
+ msgid "Display"
168
+ msgstr ""
169
+
170
+ #: ../includes/settings.php:95
171
+ msgid "Home"
172
+ msgstr ""
173
+
174
+ #: ../includes/settings.php:96
175
+ msgid "Archives"
176
+ msgstr ""
177
+
178
+ #: ../includes/settings.php:97
179
+ msgid "Single pages"
180
+ msgstr ""
181
+
182
+ #: ../includes/settings.php:98
183
+ msgid "Search results"
184
+ msgstr ""
185
+
186
+ #: ../includes/settings.php:153 ../includes/settings.php:167
187
+ #: ../includes/settings.php:179
188
+ msgid "Post Views Counter"
189
+ msgstr ""
190
+
191
+ #: ../includes/settings.php:181
192
+ msgid "Need support?"
193
+ msgstr ""
194
+
195
+ #: ../includes/settings.php:182
196
+ #, php-format
197
+ msgid ""
198
+ "If you are having problems with this plugin, please browse it's <a href=\"%s"
199
+ "\" target=\"_blank\">Documentation</a> or talk about them in the <a href=\"%s"
200
+ "\" target=\"_blank\">Support forum</a>"
201
+ msgstr ""
202
+
203
+ #: ../includes/settings.php:184
204
+ msgid "Do you like this plugin?"
205
+ msgstr ""
206
+
207
+ #: ../includes/settings.php:185
208
+ #, php-format
209
+ msgid "<a href=\"%s\" target=\"_blank\">Rate it 5</a> on WordPress.org"
210
+ msgstr ""
211
+
212
+ #: ../includes/settings.php:186
213
+ #, php-format
214
+ msgid ""
215
+ "Blog about it & link to the <a href=\"%s\" target=\"_blank\">plugin page</a>."
216
+ msgstr ""
217
+
218
+ #: ../includes/settings.php:187
219
+ #, php-format
220
+ msgid ""
221
+ "Check out our other <a href=\"%s\" target=\"_blank\">WordPress plugins</a>."
222
+ msgstr ""
223
+
224
+ #: ../includes/settings.php:190
225
+ msgid "Created by"
226
+ msgstr ""
227
+
228
+ #: ../includes/settings.php:206
229
+ msgid "Reset to defaults"
230
+ msgstr ""
231
+
232
+ #: ../includes/settings.php:222
233
+ msgid "General settings"
234
+ msgstr ""
235
+
236
+ #: ../includes/settings.php:223
237
+ msgid "Post Types Count"
238
+ msgstr ""
239
+
240
+ #: ../includes/settings.php:224
241
+ msgid "Counter Mode"
242
+ msgstr ""
243
+
244
+ #: ../includes/settings.php:225
245
+ msgid "Post Views Column"
246
+ msgstr ""
247
+
248
+ #: ../includes/settings.php:226
249
+ msgid "Restrict Edit"
250
+ msgstr ""
251
+
252
+ #: ../includes/settings.php:227
253
+ msgid "Count Interval"
254
+ msgstr ""
255
+
256
+ #: ../includes/settings.php:228
257
+ msgid "Reset Data Interval"
258
+ msgstr ""
259
+
260
+ #: ../includes/settings.php:229
261
+ msgid "Flush Object Cache Interval"
262
+ msgstr ""
263
+
264
+ #: ../includes/settings.php:230
265
+ msgid "Exclude Visitors"
266
+ msgstr ""
267
+
268
+ #: ../includes/settings.php:231
269
+ msgid "Exclude IPs"
270
+ msgstr ""
271
+
272
+ #: ../includes/settings.php:232
273
+ msgid "Strict counts"
274
+ msgstr ""
275
+
276
+ #: ../includes/settings.php:233
277
+ msgid "Tools"
278
+ msgstr ""
279
+
280
+ #: ../includes/settings.php:234
281
+ msgid "Deactivation"
282
+ msgstr ""
283
+
284
+ #: ../includes/settings.php:238
285
+ msgid "Display settings"
286
+ msgstr ""
287
+
288
+ #: ../includes/settings.php:239
289
+ msgid "Post Views Label"
290
+ msgstr ""
291
+
292
+ #: ../includes/settings.php:240
293
+ msgid "Post Type"
294
+ msgstr ""
295
+
296
+ #: ../includes/settings.php:241
297
+ msgid "Page Type"
298
+ msgstr ""
299
+
300
+ #: ../includes/settings.php:242
301
+ msgid "User Type"
302
+ msgstr ""
303
+
304
+ #: ../includes/settings.php:243
305
+ msgid "Position"
306
+ msgstr ""
307
+
308
+ #: ../includes/settings.php:244 ../includes/widgets.php:150
309
+ msgid "Display Style"
310
+ msgstr ""
311
+
312
+ #: ../includes/settings.php:245
313
+ msgid "Icon Class"
314
+ msgstr ""
315
+
316
+ #: ../includes/settings.php:256
317
+ msgid "Enter the label for the post views counter field."
318
+ msgstr ""
319
+
320
+ #: ../includes/settings.php:274
321
+ msgid "Select post types for which post views will be counted."
322
+ msgstr ""
323
+
324
+ #: ../includes/settings.php:291
325
+ msgid "Select post types for which the views count will be displayed."
326
+ msgstr ""
327
+
328
+ #: ../includes/settings.php:310
329
+ msgid ""
330
+ "Select the method of collecting post views data. If you are using any of the "
331
+ "caching plugins select Javascript or REST API (if available)."
332
+ msgstr ""
333
+
334
+ #: ../includes/settings.php:310
335
+ msgid ""
336
+ "Optionally try the Fast AJAX experimental method, usually 10+ times faster "
337
+ "than Javascript or REST API."
338
+ msgstr ""
339
+
340
+ #: ../includes/settings.php:320
341
+ msgid ""
342
+ "Enable to display post views count column for each of the selected post "
343
+ "types."
344
+ msgstr ""
345
+
346
+ #: ../includes/settings.php:340
347
+ msgid "Enter the time between single user visit count."
348
+ msgstr ""
349
+
350
+ #: ../includes/settings.php:360
351
+ msgid ""
352
+ "Delete single day post views data older than specified above. Enter 0 "
353
+ "(number zero) if you want to preserve your data regardless of its age."
354
+ msgstr ""
355
+
356
+ #: ../includes/settings.php:380
357
+ msgid ""
358
+ "How often to flush cached view counts from the object cache into the "
359
+ "database. This feature is used only if a persistent object cache is detected "
360
+ "and the interval is greater than 0 (number zero)). When used, view counts "
361
+ "will be collected and stored in the object cache instead of the database and "
362
+ "will then be asynchronously flushed to the database according to the "
363
+ "specified interval.<br /><strong>Notice:</strong> Potential data loss may "
364
+ "occur if the object cache is cleared/unavailable for the duration of the "
365
+ "interval."
366
+ msgstr ""
367
+
368
+ #: ../includes/settings.php:398 ../includes/settings.php:571
369
+ msgid "Use it to hide the post views counter from selected type of visitors."
370
+ msgstr ""
371
+
372
+ #: ../includes/settings.php:406 ../includes/settings.php:580
373
+ msgid "Use it to hide the post views counter from selected user roles."
374
+ msgstr ""
375
+
376
+ #: ../includes/settings.php:426 ../includes/settings.php:432
377
+ msgid "Remove"
378
+ msgstr ""
379
+
380
+ #: ../includes/settings.php:437
381
+ msgid "Add new"
382
+ msgstr ""
383
+
384
+ #: ../includes/settings.php:437
385
+ msgid "Add my current IP"
386
+ msgstr ""
387
+
388
+ #: ../includes/settings.php:438
389
+ msgid "Enter the IP addresses to be excluded from post views count."
390
+ msgstr ""
391
+
392
+ #: ../includes/settings.php:448
393
+ msgid ""
394
+ "Enable to prevent bypassing the counts interval (for e.g. using incognito "
395
+ "browser window or by clearing cookies)."
396
+ msgstr ""
397
+
398
+ #: ../includes/settings.php:459
399
+ msgid "Import views"
400
+ msgstr ""
401
+
402
+ #: ../includes/settings.php:459
403
+ msgid "Override existing views data."
404
+ msgstr ""
405
+
406
+ #: ../includes/settings.php:460
407
+ msgid "Import post views data from WP-PostViews plugin."
408
+ msgstr ""
409
+
410
+ #: ../includes/settings.php:461
411
+ msgid "Delete views"
412
+ msgstr ""
413
+
414
+ #: ../includes/settings.php:462
415
+ msgid "Delete ALL the existing post views data."
416
+ msgstr ""
417
+
418
+ #: ../includes/settings.php:473
419
+ msgid "Enable to restrict post views editing to admins only."
420
+ msgstr ""
421
+
422
+ #: ../includes/settings.php:483
423
+ msgid "Enable to delete all plugin data on deactivation."
424
+ msgstr ""
425
+
426
+ #: ../includes/settings.php:500
427
+ msgid "Select page types where the views count will be displayed."
428
+ msgstr ""
429
+
430
+ #: ../includes/settings.php:519
431
+ msgid ""
432
+ "Select where would you like to display the post views counter. Use [post-"
433
+ "views] shortcode for manual display."
434
+ msgstr ""
435
+
436
+ #: ../includes/settings.php:538
437
+ msgid "Choose how to display the post views counter."
438
+ msgstr ""
439
+
440
+ #: ../includes/settings.php:549
441
+ #, php-format
442
+ msgid ""
443
+ "Enter the post views icon class. Any of the <a href=\"%s\" target=\"_blank"
444
+ "\">Dashicons</a> classes are available."
445
+ msgstr ""
446
+
447
+ #: ../includes/settings.php:609
448
+ msgid "Post views data imported succesfully."
449
+ msgstr ""
450
+
451
+ #: ../includes/settings.php:611
452
+ msgid "There was no post views data to import."
453
+ msgstr ""
454
+
455
+ #: ../includes/settings.php:617
456
+ msgid "All existing data deleted succesfully."
457
+ msgstr ""
458
+
459
+ #: ../includes/settings.php:619
460
+ msgid "Error occurred. All existing data were not deleted."
461
+ msgstr ""
462
+
463
+ #: ../includes/settings.php:795
464
+ msgid "General settings restored to defaults."
465
+ msgstr ""
466
+
467
+ #: ../includes/settings.php:799
468
+ msgid "Display settings restored to defaults."
469
+ msgstr ""
470
+
471
+ #: ../includes/update.php:75
472
+ msgid ""
473
+ "<strong>Post Views Counter</strong> - this version requires a database "
474
+ "update. Make sure to back up your database first."
475
+ msgstr ""
476
+
477
+ #: ../includes/update.php:76
478
+ msgid "Run the Update"
479
+ msgstr ""
480
+
481
+ #: ../includes/update.php:117
482
+ msgid "Thank you! Datebase was succesfully updated."
483
+ msgstr ""
484
+
485
+ #: ../includes/widgets.php:42 ../includes/widgets.php:48
486
+ msgid "Most Viewed Posts"
487
+ msgstr ""
488
+
489
+ #: ../includes/widgets.php:43
490
+ msgid "Displays a list of the most viewed posts"
491
+ msgstr ""
492
+
493
+ #: ../includes/widgets.php:58
494
+ msgid "No Posts found"
495
+ msgstr ""
496
+
497
+ #: ../includes/widgets.php:62
498
+ msgid "Ascending"
499
+ msgstr ""
500
+
501
+ #: ../includes/widgets.php:63
502
+ msgid "Descending"
503
+ msgstr ""
504
+
505
+ #: ../includes/widgets.php:67
506
+ msgid "Unordered list"
507
+ msgstr ""
508
+
509
+ #: ../includes/widgets.php:68
510
+ msgid "Ordered list"
511
+ msgstr ""
512
+
513
+ #: ../includes/widgets.php:114
514
+ msgid "Title"
515
+ msgstr ""
516
+
517
+ #: ../includes/widgets.php:118
518
+ msgid "Post Types"
519
+ msgstr ""
520
+
521
+ #: ../includes/widgets.php:130
522
+ msgid "Number of posts to show"
523
+ msgstr ""
524
+
525
+ #: ../includes/widgets.php:134
526
+ msgid "No posts message"
527
+ msgstr ""
528
+
529
+ #: ../includes/widgets.php:138
530
+ msgid "Order"
531
+ msgstr ""
532
+
533
+ #: ../includes/widgets.php:162
534
+ msgid "Display post views?"
535
+ msgstr ""
536
+
537
+ #: ../includes/widgets.php:164
538
+ msgid "Display post excerpt?"
539
+ msgstr ""
540
+
541
+ #: ../includes/widgets.php:166
542
+ msgid "Display post author?"
543
+ msgstr ""
544
+
545
+ #: ../includes/widgets.php:168
546
+ msgid "Display post thumbnail?"
547
+ msgstr ""
548
+
549
+ #: ../includes/widgets.php:171
550
+ msgid "Thumbnail size"
551
+ msgstr ""
552
+
553
+ #: ../post-views-counter.php:387
554
+ msgid "Are you sure you want to reset these settings to defaults?"
555
+ msgstr ""
556
+
557
+ #: ../post-views-counter.php:388
558
+ msgid "Are you sure you want to delete all existing data?"
559
+ msgstr ""
560
+
561
+ #: ../post-views-counter.php:437
562
+ msgid "Support"
563
+ msgstr ""
564
+
565
+ #: ../post-views-counter.php:461
566
+ msgid "Settings"
567
+ msgstr ""
post-views-counter.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  Plugin Name: Post Views Counter
4
  Description: Post Views Counter allows you to display how many times a post, page or custom post type had been viewed in a simple, fast and reliable way.
5
- Version: 1.3.1
6
  Author: Digital Factory
7
  Author URI: http://www.dfactory.eu/
8
  Plugin URI: http://www.dfactory.eu/plugins/post-views-counter/
@@ -12,7 +12,7 @@ Text Domain: post-views-counter
12
  Domain Path: /languages
13
 
14
  Post Views Counter
15
- Copyright (C) 2014-2019, Digital Factory - info@digitalfactory.pl
16
 
17
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
18
 
@@ -31,7 +31,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
31
  * Post Views Counter final class.
32
  *
33
  * @class Post_Views_Counter
34
- * @version 1.3.1
35
  */
36
  final class Post_Views_Counter {
37
 
@@ -63,7 +63,10 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
63
  'restrict_edit_views' => false,
64
  'deactivation_delete' => false,
65
  'cron_run' => true,
66
- 'cron_update' => true
 
 
 
67
  ),
68
  'display' => array(
69
  'label' => 'Post Views:',
@@ -81,22 +84,18 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
81
  'link_to_post' => true,
82
  'icon_class' => 'dashicons-chart-bar'
83
  ),
84
- 'version' => '1.3.1'
85
  );
86
 
87
  /**
88
  * Disable object clone.
89
  */
90
- private function __clone() {
91
-
92
- }
93
 
94
  /**
95
  * Disable unserializing of the class.
96
  */
97
- private function __wakeup() {
98
-
99
- }
100
 
101
  /**
102
  * Main plugin instance,
@@ -106,10 +105,9 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
106
  */
107
  public static function instance() {
108
  if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Post_Views_Counter ) ) {
109
-
110
  self::$instance = new Post_Views_Counter;
111
  self::$instance->define_constants();
112
-
113
  // minimal setup for Fast AJAX
114
  if ( defined( 'SHORTINIT' ) && SHORTINIT ) {
115
  include_once( POST_VIEWS_COUNTER_PATH . 'includes/counter.php' );
@@ -123,7 +121,6 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
123
  add_action( 'plugins_loaded', array( self::$instance, 'load_textdomain' ) );
124
 
125
  self::$instance->includes();
126
-
127
  self::$instance->update = new Post_Views_Counter_Update();
128
  self::$instance->settings = new Post_Views_Counter_Settings();
129
  self::$instance->query = new Post_Views_Counter_Query();
@@ -136,6 +133,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
136
  self::$instance->widgets = new Post_Views_Counter_Widgets();
137
  }
138
  }
 
139
  return self::$instance;
140
  }
141
 
@@ -197,6 +195,8 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
197
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
198
  add_action( 'wp_loaded', array( $this, 'load_pluggable_functions' ), 10 );
199
  // add_action( 'init', array( $this, 'gutenberg_blocks' ) );
 
 
200
 
201
  // filters
202
  add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
@@ -204,6 +204,153 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
204
  }
205
  }
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  /**
208
  * Multisite activation.
209
  *
@@ -276,7 +423,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
276
  $current_blog_id = $wpdb->blogid;
277
  $blogs_ids = $wpdb->get_col( $wpdb->prepare( 'SELECT blog_id FROM ' . $wpdb->blogs, '' ) );
278
 
279
- if ( ! ($activated_blogs = get_site_option( 'post_views_counter_activated_blogs', false, false )) )
280
  $activated_blogs = array();
281
 
282
  foreach ( $blogs_ids as $blog_id ) {
@@ -391,7 +538,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
391
 
392
  wp_enqueue_style( 'pvc-admin' );
393
 
394
- // load on single post page
395
  } elseif ( $page === 'post.php' || $page === 'post-new.php' ) {
396
  $post_types = Post_Views_Counter()->options['general']['post_types_count'];
397
 
@@ -402,6 +549,7 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
402
 
403
  wp_enqueue_style( 'pvc-admin' );
404
  wp_enqueue_script( 'pvc-admin-post' );
 
405
  } elseif ( $page === 'edit.php' ) {
406
  $post_types = Post_Views_Counter()->options['general']['post_types_count'];
407
 
@@ -415,8 +563,12 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
415
  // woocommerce
416
  if ( get_post_type() !== 'product' )
417
  wp_enqueue_script( 'pvc-admin-quick-edit' );
 
418
  } elseif ( $page === 'widgets.php' )
419
  wp_enqueue_script( 'pvc-admin-widgets', POST_VIEWS_COUNTER_URL . '/js/admin-widgets.js', array( 'jquery' ), $this->defaults['version'] );
 
 
 
420
  }
421
 
422
  /**
@@ -465,33 +617,6 @@ if ( ! class_exists( 'Post_Views_Counter' ) ) :
465
 
466
  return $links;
467
  }
468
-
469
- /**
470
- * Add admin notices.
471
- */
472
- public function add_notice( $html = '', $status = '', $paragraph = false ) {
473
- $this->notices[] = array(
474
- 'html' => $html,
475
- 'status' => $status,
476
- 'paragraph' => $paragraph
477
- );
478
-
479
- add_action( 'admin_notices', array( $this, 'display_notice' ) );
480
- }
481
-
482
- /**
483
- * Print admin notices.
484
- */
485
- public function display_notice() {
486
- foreach ( $this->notices as $notice ) {
487
- echo '
488
- <div class="post-views-counter ' . $notice['status'] . '">
489
- ' . ( $notice['paragraph'] ? '<p>' : '' ) . '
490
- ' . $notice['html'] . '
491
- ' . ( $notice['paragraph'] ? '</p>' : '' ) . '
492
- </div>';
493
- }
494
- }
495
  }
496
 
497
  endif; // end if class_exists check
2
  /*
3
  Plugin Name: Post Views Counter
4
  Description: Post Views Counter allows you to display how many times a post, page or custom post type had been viewed in a simple, fast and reliable way.
5
+ Version: 1.3.2
6
  Author: Digital Factory
7
  Author URI: http://www.dfactory.eu/
8
  Plugin URI: http://www.dfactory.eu/plugins/post-views-counter/
12
  Domain Path: /languages
13
 
14
  Post Views Counter
15
+ Copyright (C) 2014-2020, Digital Factory - info@digitalfactory.pl
16
 
17
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
18
 
31
  * Post Views Counter final class.
32
  *
33
  * @class Post_Views_Counter
34
+ * @version 1.3.2
35
  */
36
  final class Post_Views_Counter {
37
 
63
  'restrict_edit_views' => false,
64
  'deactivation_delete' => false,
65
  'cron_run' => true,
66
+ 'cron_update' => true,
67
+ 'update_version' => 1,
68
+ 'update_notice' => true,
69
+ 'update_delay_date' => 0
70
  ),
71
  'display' => array(
72
  'label' => 'Post Views:',
84
  'link_to_post' => true,
85
  'icon_class' => 'dashicons-chart-bar'
86
  ),
87
+ 'version' => '1.3.2'
88
  );
89
 
90
  /**
91
  * Disable object clone.
92
  */
93
+ private function __clone() {}
 
 
94
 
95
  /**
96
  * Disable unserializing of the class.
97
  */
98
+ private function __wakeup() {}
 
 
99
 
100
  /**
101
  * Main plugin instance,
105
  */
106
  public static function instance() {
107
  if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Post_Views_Counter ) ) {
 
108
  self::$instance = new Post_Views_Counter;
109
  self::$instance->define_constants();
110
+
111
  // minimal setup for Fast AJAX
112
  if ( defined( 'SHORTINIT' ) && SHORTINIT ) {
113
  include_once( POST_VIEWS_COUNTER_PATH . 'includes/counter.php' );
121
  add_action( 'plugins_loaded', array( self::$instance, 'load_textdomain' ) );
122
 
123
  self::$instance->includes();
 
124
  self::$instance->update = new Post_Views_Counter_Update();
125
  self::$instance->settings = new Post_Views_Counter_Settings();
126
  self::$instance->query = new Post_Views_Counter_Query();
133
  self::$instance->widgets = new Post_Views_Counter_Widgets();
134
  }
135
  }
136
+
137
  return self::$instance;
138
  }
139
 
195
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
196
  add_action( 'wp_loaded', array( $this, 'load_pluggable_functions' ), 10 );
197
  // add_action( 'init', array( $this, 'gutenberg_blocks' ) );
198
+ add_action( 'admin_init', array( $this, 'update_notice' ) );
199
+ add_action( 'wp_ajax_pvc_dismiss_notice', array( $this, 'dismiss_notice' ) );
200
 
201
  // filters
202
  add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
204
  }
205
  }
206
 
207
+ /**
208
+ * Update notice.
209
+ *
210
+ * @return void
211
+ */
212
+ public function update_notice() {
213
+ if ( ! current_user_can( 'install_plugins' ) )
214
+ return;
215
+
216
+ $current_update = 2;
217
+
218
+ // get current time
219
+ $current_time = time();
220
+
221
+ if ( $this->options['general']['update_version'] < $current_update ) {
222
+ // check version, if update version is lower than plugin version, set update notice to true
223
+ $this->options['general'] = array_merge( $this->options['general'], array( 'update_version' => $current_update, 'update_notice' => true ) );
224
+
225
+ update_option( 'post_views_counter_settings_general', $this->options['general'] );
226
+
227
+ // set activation date
228
+ $activation_date = get_option( 'post_views_counter_activation_date' );
229
+
230
+ if ( $activation_date === false )
231
+ update_option( 'post_views_counter_activation_date', $current_time );
232
+ }
233
+
234
+ // display current version notice
235
+ if ( $this->options['general']['update_notice'] === true ) {
236
+ // include notice js, only if needed
237
+ add_action( 'admin_print_scripts', array( $this, 'admin_inline_js' ), 999 );
238
+
239
+ // get activation date
240
+ $activation_date = get_option( 'post_views_counter_activation_date' );
241
+
242
+ if ( (int) $this->options['general']['update_delay_date'] === 0 ) {
243
+ if ( $activation_date + 1209600 > $current_time )
244
+ $this->options['general']['update_delay_date'] = $activation_date + 1209600;
245
+ else
246
+ $this->options['general']['update_delay_date'] = $current_time;
247
+
248
+ update_option( 'post_views_counter_settings_general', $this->options['general'] );
249
+ }
250
+
251
+ if ( ( ! empty( $this->options['general']['update_delay_date'] ) ? (int) $this->options['general']['update_delay_date'] : $current_time ) <= $current_time )
252
+ $this->add_notice( sprintf( __( "Hey, you've been using <strong>Post Views Counter</strong> for more than %s.", 'post-views-counter' ), human_time_diff( $activation_date, $current_time ) ) . '<br />' . __( 'Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation.', 'post-views-counter' ) . '<br /><br />' . __( 'Your help is much appreciated. Thank you very much', 'post-views-counter' ) . ' ~ <strong>Bartosz Arendt</strong>, ' . sprintf( __( 'founder of <a href="%s" target="_blank">dFactory</a> plugins.', 'post-views-counter' ), 'https://dfactory.eu/' ) . '<br /><br />' . sprintf( __( '<a href="%s" class="pvc-dismissible-notice" target="_blank" rel="noopener">Ok, you deserve it</a><br /><a href="javascript:void(0);" class="pvc-dismissible-notice pvc-delay-notice" rel="noopener">Nope, maybe later</a><br /><a href="javascript:void(0);" class="pvc-dismissible-notice" rel="noopener">I already did</a>', 'post-views-counter' ), 'https://wordpress.org/support/plugin/post-views-counter/reviews/?filter=5#new-post' ), 'notice notice-info is-dismissible pvc-notice' );
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Add admin notices.
258
+ *
259
+ * @param string $html
260
+ * @param string $status
261
+ * @param bool $paragraph
262
+ */
263
+ public function add_notice( $html = '', $status = 'error', $paragraph = true ) {
264
+ $this->notices[] = array(
265
+ 'html' => $html,
266
+ 'status' => $status,
267
+ 'paragraph' => $paragraph
268
+ );
269
+
270
+ add_action( 'admin_notices', array( $this, 'display_notice' ) );
271
+ }
272
+
273
+ /**
274
+ * Print admin notices.
275
+ *
276
+ * @return mixed
277
+ */
278
+ public function display_notice() {
279
+ foreach( $this->notices as $notice ) {
280
+ echo '
281
+ <div class="' . $notice['status'] . '">
282
+ ' . ( $notice['paragraph'] ? '<p>' : '' ) . '
283
+ ' . $notice['html'] . '
284
+ ' . ( $notice['paragraph'] ? '</p>' : '' ) . '
285
+ </div>';
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Print admin scripts.
291
+ *
292
+ * @return mixed
293
+ */
294
+ public function admin_inline_js() {
295
+ if ( ! current_user_can( 'install_plugins' ) )
296
+ return;
297
+ ?>
298
+ <script type="text/javascript">
299
+ ( function ( $ ) {
300
+ $( document ).ready( function () {
301
+ // save dismiss state
302
+ $( '.pvc-notice.is-dismissible' ).on( 'click', '.notice-dismiss, .pvc-dismissible-notice', function ( e ) {
303
+ var notice_action = 'hide';
304
+
305
+ if ( $( e.currentTarget ).hasClass( 'pvc-delay-notice' ) ) {
306
+ notice_action = 'delay'
307
+ }
308
+
309
+ $.post( ajaxurl, {
310
+ action: 'pvc_dismiss_notice',
311
+ notice_action: notice_action,
312
+ url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
313
+ nonce: '<?php echo wp_create_nonce( 'pvc_dismiss_notice' ); ?>'
314
+ } );
315
+
316
+ $( e.delegateTarget ).slideUp( 'fast' );
317
+ } );
318
+ } );
319
+ } )( jQuery );
320
+ </script>
321
+ <?php
322
+ }
323
+
324
+ /**
325
+ * Dismiss notice.
326
+ */
327
+ public function dismiss_notice() {
328
+ if ( ! current_user_can( 'install_plugins' ) )
329
+ return;
330
+
331
+ if ( wp_verify_nonce( esc_attr( $_REQUEST['nonce'] ), 'pvc_dismiss_notice' ) ) {
332
+ $notice_action = empty( $_REQUEST['notice_action'] ) || $_REQUEST['notice_action'] === 'hide' ? 'hide' : esc_attr( $_REQUEST['notice_action'] );
333
+
334
+ switch ( $notice_action ) {
335
+ // delay notice
336
+ case 'delay':
337
+ // set delay period to 1 week from now
338
+ $this->options['general'] = array_merge( $this->options['general'], array( 'update_delay_date' => time() + 1209600 ) );
339
+ update_option( 'post_views_counter_settings_general', $this->options['general'] );
340
+ break;
341
+
342
+ // hide notice
343
+ default:
344
+ $this->options['general'] = array_merge( $this->options['general'], array( 'update_notice' => false ) );
345
+ $this->options['general'] = array_merge( $this->options['general'], array( 'update_delay_date' => 0 ) );
346
+
347
+ update_option( 'post_views_counter_settings_general', $this->options['general'] );
348
+ }
349
+ }
350
+
351
+ exit;
352
+ }
353
+
354
  /**
355
  * Multisite activation.
356
  *
423
  $current_blog_id = $wpdb->blogid;
424
  $blogs_ids = $wpdb->get_col( $wpdb->prepare( 'SELECT blog_id FROM ' . $wpdb->blogs, '' ) );
425
 
426
+ if ( ! ( $activated_blogs = get_site_option( 'post_views_counter_activated_blogs', false, false ) ) )
427
  $activated_blogs = array();
428
 
429
  foreach ( $blogs_ids as $blog_id ) {
538
 
539
  wp_enqueue_style( 'pvc-admin' );
540
 
541
+ // load on single post page
542
  } elseif ( $page === 'post.php' || $page === 'post-new.php' ) {
543
  $post_types = Post_Views_Counter()->options['general']['post_types_count'];
544
 
549
 
550
  wp_enqueue_style( 'pvc-admin' );
551
  wp_enqueue_script( 'pvc-admin-post' );
552
+ // edit post
553
  } elseif ( $page === 'edit.php' ) {
554
  $post_types = Post_Views_Counter()->options['general']['post_types_count'];
555
 
563
  // woocommerce
564
  if ( get_post_type() !== 'product' )
565
  wp_enqueue_script( 'pvc-admin-quick-edit' );
566
+ // widgets
567
  } elseif ( $page === 'widgets.php' )
568
  wp_enqueue_script( 'pvc-admin-widgets', POST_VIEWS_COUNTER_URL . '/js/admin-widgets.js', array( 'jquery' ), $this->defaults['version'] );
569
+ // media
570
+ elseif ( $page === 'upload.php' )
571
+ wp_enqueue_style( 'pvc-admin' );
572
  }
573
 
574
  /**
617
 
618
  return $links;
619
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
620
  }
621
 
622
  endif; // end if class_exists check
readme.txt CHANGED
@@ -1,11 +1,11 @@
1
  === Post Views Counter ===
2
  Contributors: dfactory
3
- Donate link: http://www.dfactory.eu/
4
  Tags: counter, hits, posts, postviews, post views, views, count, statistics, stats, analytics, pageviews, tracking
5
  Requires at least: 4.0
6
  Requires PHP: 5.2.4
7
- Tested up to: 5.2.2
8
- Stable tag: 1.3.1
9
  License: MIT License
10
  License URI: http://opensource.org/licenses/MIT
11
 
@@ -15,7 +15,7 @@ Post Views Counter allows you to display how many times a post, page or custom p
15
 
16
  [Post Views Counter](http://www.dfactory.eu/plugins/post-views-counter/) allows you to display how many times a post, page or custom post type had been viewed with this simple, fast and easy to use plugin.
17
 
18
- For more information, check out plugin page at [dFactory](http://www.dfactory.eu/) or plugin [support forum](http://www.dfactory.eu/support/forum/post-views-counter/).
19
 
20
  = Features include: =
21
 
@@ -62,6 +62,11 @@ No questions yet.
62
 
63
  == Changelog ==
64
 
 
 
 
 
 
65
  = 1.3.1 =
66
  * Fix: Gutenberg CSS file missing
67
  * Tweak: POT translation file update
@@ -196,6 +201,6 @@ Initial release
196
 
197
  == Upgrade Notice ==
198
 
199
- = 1.3.1 =
200
- * Fix: Gutenberg CSS file missing
201
- * Tweak: POT translation file update
1
  === Post Views Counter ===
2
  Contributors: dfactory
3
+ Donate link: http://dfactory.eu/
4
  Tags: counter, hits, posts, postviews, post views, views, count, statistics, stats, analytics, pageviews, tracking
5
  Requires at least: 4.0
6
  Requires PHP: 5.2.4
7
+ Tested up to: 5.4.1
8
+ Stable tag: 1.3.2
9
  License: MIT License
10
  License URI: http://opensource.org/licenses/MIT
11
 
15
 
16
  [Post Views Counter](http://www.dfactory.eu/plugins/post-views-counter/) allows you to display how many times a post, page or custom post type had been viewed with this simple, fast and easy to use plugin.
17
 
18
+ For more information, check out plugin page at [dFactory](http://dfactory.eu/) or plugin [support forum](http://www.dfactory.eu/support/forum/post-views-counter/).
19
 
20
  = Features include: =
21
 
62
 
63
  == Changelog ==
64
 
65
+ = 1.3.2 =
66
+ * New: Introducing dashboard widget navigation
67
+ * New: Counter support for Media (attachments)
68
+ * Tweak: Extended views query for handling complex date/time requests
69
+
70
  = 1.3.1 =
71
  * Fix: Gutenberg CSS file missing
72
  * Tweak: POT translation file update
201
 
202
  == Upgrade Notice ==
203
 
204
+ = 1.3.2 =
205
+ * New: Introducing dashboard widget navigation
206
+ * New: Counter support for Media (attachments)