PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.7.2
Post Views Counter v1.7.2
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / class-columns.php
post-views-counter / includes Last commit date
class-admin.php 5 months ago class-columns.php 5 months ago class-counter.php 5 months ago class-crawler-detect.php 5 months ago class-cron.php 5 months ago class-dashboard.php 5 months ago class-frontend.php 5 months ago class-functions.php 5 months ago class-import.php 5 months ago class-integration-gutenberg.php 5 months ago class-integrations.php 5 months ago class-query.php 5 months ago class-settings-api.php 5 months ago class-settings-display.php 5 months ago class-settings-general.php 5 months ago class-settings-integrations.php 5 months ago class-settings-other.php 5 months ago class-settings-reports.php 5 months ago class-settings.php 5 months ago class-toolbar.php 5 months ago class-update.php 5 months ago class-widgets.php 5 months ago functions.php 5 months ago
class-columns.php
669 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Post_Views_Counter_Columns class.
8 *
9 * @class Post_Views_Counter_Columns
10 */
11 class Post_Views_Counter_Columns {
12
13 /**
14 * Class constructor.
15 *
16 * @return void
17 */
18 public function __construct() {
19 // actions
20 add_action( 'admin_init', [ $this, 'register_new_column' ] );
21 add_action( 'post_submitbox_misc_actions', [ $this, 'submitbox_views' ] );
22 add_action( 'attachment_submitbox_misc_actions', [ $this, 'submitbox_views' ] );
23 add_action( 'save_post', [ $this, 'save_post' ], 10, 2 );
24 add_action( 'edit_attachment', [ $this, 'save_post' ], 10 );
25 add_action( 'bulk_edit_custom_box', [ $this, 'quick_edit_custom_box' ], 10, 2 );
26 add_action( 'quick_edit_custom_box', [ $this, 'quick_edit_custom_box' ], 10, 2 );
27 add_action( 'wp_ajax_save_bulk_post_views', [ $this, 'save_bulk_post_views' ] );
28 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_chart_modal_assets' ] );
29 add_action( 'wp_ajax_pvc_column_chart', [ $this, 'ajax_column_chart' ] );
30 }
31 /**
32 * Output post views for single post.
33 *
34 * @global object $post
35 *
36 * @return void
37 */
38 public function submitbox_views() {
39 global $post;
40
41 // get main instance
42 $pvc = Post_Views_Counter();
43
44 // break if display is not allowed
45 if ( ! $pvc->options['display']['post_views_column'] || ! in_array( $post->post_type, $pvc->options['general']['post_types_count'] ) )
46 return;
47
48 // check if user can see post stats
49 if ( apply_filters( 'pvc_admin_display_post_views', true, $post->ID ) === false )
50 return;
51
52 // get total post views
53 $count = (int) pvc_get_post_views( $post->ID ); ?>
54
55 <div class="misc-pub-section" id="post-views">
56
57 <?php wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?>
58
59 <span id="post-views-display">
60 <?php echo __( 'Post Views', 'post-views-counter' ) . ': <b>' . number_format_i18n( $count ) . '</b>'; ?>
61 </span>
62
63 <?php
64 // allow editing
65 $allow_edit = (bool) $pvc->options['display']['restrict_edit_views'];
66
67 // allow editing condition
68 $allow_edit_condition = (bool) current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) );
69
70 if ( $allow_edit === true && $allow_edit_condition === true ) {
71 ?>
72 <a href="#post-views" class="edit-post-views hide-if-no-js"><?php _e( 'Edit', 'post-views-counter' ); ?></a>
73
74 <div id="post-views-input-container" class="hide-if-js">
75
76 <p><?php _e( 'Adjust the views count for this post.', 'post-views-counter' ); ?></p>
77 <input type="hidden" name="current_post_views" id="post-views-current" value="<?php echo esc_attr( $count ); ?>" />
78 <input type="text" name="post_views" id="post-views-input" value="<?php echo esc_attr( $count ); ?>"/><br />
79 <p>
80 <a href="#post-views" class="save-post-views hide-if-no-js button"><?php _e( 'OK', 'post-views-counter' ); ?></a>
81 <a href="#post-views" class="cancel-post-views hide-if-no-js"><?php _e( 'Cancel', 'post-views-counter' ); ?></a>
82 </p>
83
84 </div>
85 <?php
86 }
87 ?>
88
89 </div>
90 <?php
91 }
92
93 /**
94 * Save post views data.
95 *
96 * @param int $post_id
97 * @param object $post
98 * @return void
99 */
100 public function save_post( $post_id, $post = null ) {
101 // break if doing autosave
102 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
103 return;
104
105 // break if current user can't edit this post
106 if ( ! current_user_can( 'edit_post', $post_id ) )
107 return;
108
109 // is post views set
110 if ( ! isset( $_POST['post_views'] ) )
111 return;
112
113 // cast numeric post views
114 $post_views = (int) $_POST['post_views'];
115
116 // unchanged post views value?
117 if ( isset( $_POST['current_post_views'] ) && $post_views === (int) $_POST['current_post_views'] )
118 return;
119
120 // get main instance
121 $pvc = Post_Views_Counter();
122
123 // break if post views in not one of the selected
124 $post_types = (array) $pvc->options['general']['post_types_count'];
125
126 // get post type
127 if ( is_null( $post ) )
128 $post_type = get_post_type( $post_id );
129 else
130 $post_type = $post->post_type;
131
132 // invalid post type?
133 if ( ! in_array( $post_type, $post_types, true ) )
134 return;
135
136 // allow editing
137 $allow_edit = (bool) $pvc->options['display']['restrict_edit_views'];
138
139 // allow editing condition
140 $allow_edit_condition = (bool) current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) );
141
142 // break if views editing not allowed or editing condition not met
143 if ( $allow_edit === false || $allow_edit_condition === false )
144 return;
145
146 // validate data
147 if ( ! isset( $_POST['pvc_nonce'] ) || ! wp_verify_nonce( $_POST['pvc_nonce'], 'post_views_count' ) )
148 return;
149
150 // update post views
151 pvc_update_post_views( $post_id, $post_views );
152
153 do_action( 'pvc_after_update_post_views_count', $post_id );
154 }
155
156 /**
157 * Register post views column for specific post types.
158 *
159 * @return void
160 */
161 public function register_new_column() {
162 // get main instance
163 $pvc = Post_Views_Counter();
164
165 // is posts views column active?
166 if ( ! $pvc->options['display']['post_views_column'] )
167 return false;
168
169 // get post types
170 $post_types = $pvc->options['general']['post_types_count'];
171
172 // any post types?
173 if ( ! empty( $post_types ) ) {
174 foreach ( $post_types as $post_type ) {
175 if ( $post_type === 'attachment' ) {
176 // actions
177 add_action( 'manage_media_custom_column', [ $this, 'add_new_column_content' ], 10, 2 );
178
179 // filters
180 add_filter( 'manage_media_columns', [ $this, 'add_new_column' ] );
181 add_filter( 'manage_upload_sortable_columns', [ $this, 'register_sortable_custom_column' ] );
182 } else {
183 // actions
184 add_action( 'manage_' . $post_type . '_posts_custom_column', [ $this, 'add_new_column_content' ], 10, 2 );
185
186 // filters
187 add_filter( 'manage_' . $post_type . '_posts_columns', [ $this, 'add_new_column' ] );
188 add_filter( 'manage_edit-' . $post_type . '_sortable_columns', [ $this, 'register_sortable_custom_column' ] );
189
190 // bbPress?
191 if ( class_exists( 'bbPress' ) ) {
192 if ( $post_type === 'forum' )
193 add_filter( 'bbp_admin_forums_column_headers', [ $this, 'add_new_column' ] );
194 elseif ( $post_type === 'topic' )
195 add_filter( 'bbp_admin_topics_column_headers', [ $this, 'add_new_column' ] );
196 }
197 }
198 }
199 }
200 }
201
202 /**
203 * Register sortable post views column.
204 *
205 * @param array $columns
206 * @return array
207 */
208 public function register_sortable_custom_column( $columns ) {
209 global $post_type;
210
211 // get main instance
212 $pvc = Post_Views_Counter();
213
214 // break if display is disabled
215 if ( ! $pvc->options['display']['post_views_column'] || ! in_array( $post_type, $pvc->options['general']['post_types_count'] ) )
216 return $columns;
217
218 // check if user can see stats
219 if ( apply_filters( 'pvc_admin_display_post_views', true ) === false )
220 return $columns;
221
222 // add new sortable column
223 $columns['post_views'] = 'post_views';
224
225 return $columns;
226 }
227
228 /**
229 * Add post views column.
230 *
231 * @param array $columns
232 * @return array
233 */
234 public function add_new_column( $columns ) {
235 // date column exists?
236 if ( isset( $columns['date'] ) ) {
237 // store date column
238 $date = $columns['date'];
239
240 // unset date column
241 unset( $columns['date'] );
242 }
243
244 // comments column exists?
245 if ( isset( $columns['comments'] ) ) {
246 // store comments column
247 $comments = $columns['comments'];
248
249 // unset comments column
250 unset( $columns['comments'] );
251 }
252
253 // add post views column
254 $columns['post_views'] = '<span class="dash-icon dashicons dashicons-chart-bar" title="' . esc_attr__( 'Post Views', 'post-views-counter' ) . '"><span class="screen-reader-text">' . esc_attr__( 'Post Views', 'post-views-counter' ) . '</span></span>';
255
256 // restore date column
257 if ( isset( $date ) )
258 $columns['date'] = $date;
259
260 // restore comments column
261 if ( isset( $comments ) )
262 $columns['comments'] = $comments;
263
264 return $columns;
265 }
266
267 /**
268 * Add post views column content.
269 *
270 * @param string $column_name
271 * @param int $id
272 * @return void
273 */
274 public function add_new_column_content( $column_name, $id ) {
275 if ( $column_name === 'post_views' ) {
276 // get total post views
277 $count = pvc_get_post_views( $id );
278
279 // check if user can see stats
280 if ( apply_filters( 'pvc_admin_display_post_views', true, $id ) === false ) {
281 echo '';
282 return;
283 }
284
285 // get post title
286 $post_title = get_the_title( $id );
287
288 if ( $post_title === '' )
289 $post_title = __( '(no title)', 'post-views-counter' );
290
291 // get post type labels
292 $post_type_object = get_post_type_object( get_post_type( $id ) );
293
294 if ( $post_type_object ) {
295 $post_type_labels = get_post_type_labels( $post_type_object );
296 }
297
298 if ( $post_type_labels ) {
299 $post_title = $post_type_labels->singular_name . ': ' . $post_title;
300 }
301
302 // clickable link (modal opening handled via JavaScript)
303 echo '<a href="#" class="pvc-view-chart" data-post-id="' . esc_attr( $id ) . '" data-post-title="' . esc_attr( $post_title ) . '">' . esc_html( $count ) . '</a>';
304 }
305 }
306
307 /**
308 * Handle quick edit.
309 *
310 * @global string $pagenow
311 *
312 * @param string $column_name
313 * @param string $post_type
314 * @return void
315 */
316 function quick_edit_custom_box( $column_name, $post_type ) {
317 global $pagenow, $post;
318
319 if ( $pagenow !== 'edit.php' )
320 return;
321
322 if ( $column_name !== 'post_views' )
323 return;
324
325 if ( ! $post )
326 return;
327
328 // get main instance
329 $pvc = Post_Views_Counter();
330
331 // break if display is not allowed
332 if ( ! $pvc->options['display']['post_views_column'] || ! in_array( $post_type, $pvc->options['general']['post_types_count'] ) )
333 return;
334
335 // check if user can see stats
336 if ( apply_filters( 'pvc_admin_display_post_views', true, $post->ID ) === false )
337 return;
338
339 // allow editing
340 $allow_edit = (bool) $pvc->options['display']['restrict_edit_views'];
341
342 // allow editing condition
343 $allow_edit_condition = (bool) current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) );
344 ?>
345 <fieldset class="inline-edit-col-left">
346 <div id="inline-edit-post_views" class="inline-edit-col">
347 <label class="inline-edit-group">
348 <span class="title"><?php _e( 'Post Views', 'post-views-counter' ); ?></span>
349 <?php if ( $allow_edit === true && $allow_edit_condition === true ) { ?>
350 <span class="input-text-wrap"><input type="text" name="post_views" class="title text" value=""></span>
351 <input type="hidden" name="current_post_views" value="" />
352 <?php wp_nonce_field( 'post_views_count', 'pvc_nonce' ); ?>
353 <?php } else { ?>
354 <span class="input-text-wrap"><input type="text" name="post_views" class="title text" value="" disabled readonly /></span>
355 <?php } ?>
356 </label>
357 </div>
358 </fieldset>
359 <?php
360 }
361
362 /**
363 * Bulk save post views.
364 *
365 * @global object $wpdb
366 *
367 * @return void
368 */
369 function save_bulk_post_views() {
370 global $wpdb;
371
372 // check nonce
373 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'pvc_save_bulk_post_views' ) )
374 exit;
375
376 $count = null;
377
378 if ( isset( $_POST['post_views'] ) && is_numeric( trim( $_POST['post_views'] ) ) ) {
379 $count = (int) $_POST['post_views'];
380
381 if ( $count < 0 )
382 $count = 0;
383 }
384
385 // check post ids
386 $post_ids = ( ! empty( $_POST['post_ids'] ) && is_array( $_POST['post_ids'] ) ) ? array_map( 'absint', $_POST['post_ids'] ) : [];
387
388 if ( is_null( $count ) )
389 exit;
390
391 // allow editing
392 $allow_edit = (bool) $pvc->options['display']['restrict_edit_views'];
393
394 // allow editing condition
395 $allow_edit_condition = (bool) current_user_can( apply_filters( 'pvc_restrict_edit_capability', 'manage_options' ) );
396
397 // break if views editing not allowed or editing condition not met
398 if ( $allow_edit === false || $allow_edit_condition === false )
399 exit;
400
401 // any post ids?
402 if ( ! empty( $post_ids ) ) {
403 foreach ( $post_ids as $post_id ) {
404 // break if current user can't edit this post
405 if ( ! current_user_can( 'edit_post', $post_id ) )
406 continue;
407
408 // insert or update db post views count
409 $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 ) );
410 }
411 }
412
413 exit;
414 }
415
416 /**
417 * Enqueue chart modal assets on post list screens.
418 *
419 * @param string $page
420 * @return void
421 */
422 public function enqueue_chart_modal_assets( $page ) {
423 // only on edit.php and upload.php
424 if ( ! in_array( $page, [ 'edit.php', 'upload.php' ], true ) )
425 return;
426
427 $screen = get_current_screen();
428 $pvc = Post_Views_Counter();
429
430 // break if display is not allowed
431 if ( ! $pvc->options['display']['post_views_column'] || ! in_array( $screen->post_type, $pvc->options['general']['post_types_count'], true ) )
432 return;
433
434 // check if user can see stats
435 if ( apply_filters( 'pvc_admin_display_post_views', true ) === false )
436 return;
437
438 // enqueue Micromodal
439 wp_enqueue_script( 'pvc-micromodal', POST_VIEWS_COUNTER_URL . '/assets/micromodal/micromodal.min.js', [], '0.4.10', true );
440
441 // enqueue Chart.js (already registered)
442 wp_enqueue_script( 'pvc-chartjs' );
443
444 // enqueue modal assets
445 wp_enqueue_style( 'pvc-column-modal', POST_VIEWS_COUNTER_URL . '/css/column-modal.css', [], $pvc->defaults['version'] );
446 wp_enqueue_script( 'pvc-column-modal', POST_VIEWS_COUNTER_URL . '/js/column-modal.js', [ 'jquery', 'pvc-chartjs', 'pvc-micromodal' ], $pvc->defaults['version'], true );
447
448 // localize script
449 wp_add_inline_script( 'pvc-column-modal', 'var pvcColumnModal = ' . wp_json_encode( [
450 'ajaxURL' => admin_url( 'admin-ajax.php' ),
451 'nonce' => wp_create_nonce( 'pvc-column-modal' ),
452 'i18n' => [
453 'loading' => __( 'Loading...', 'post-views-counter' ),
454 'close' => __( 'Close', 'post-views-counter' ),
455 'error' => __( 'An error occurred while loading data.', 'post-views-counter' ),
456 'summary' => __( 'Total views in this period:', 'post-views-counter' ),
457 'view' => __( 'view', 'post-views-counter' ),
458 'views' => __( 'views', 'post-views-counter' )
459 ]
460 ] ) . "\n", 'before' );
461
462 // add modal HTML to footer
463 add_action( 'admin_footer', [ $this, 'render_modal_html' ] );
464 }
465
466 /**
467 * AJAX handler for column chart data.
468 *
469 * @return void
470 */
471 public function ajax_column_chart() {
472 // permission & nonce check
473 if ( ! check_ajax_referer( 'pvc-column-modal', 'nonce', false ) )
474 wp_send_json_error( [ 'message' => __( 'Permission denied.', 'post-views-counter' ) ] );
475
476 // get PVC instance
477 $pvc = Post_Views_Counter();
478
479 // get post ID
480 $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
481
482 if ( ! $post_id )
483 wp_send_json_error( [ 'message' => __( 'Invalid post ID.', 'post-views-counter' ) ] );
484
485 // check post exists
486 $post = get_post( $post_id );
487
488 if ( ! $post )
489 wp_send_json_error( [ 'message' => __( 'Post not found.', 'post-views-counter' ) ] );
490
491 // break if display is not allowed
492 if ( ! $pvc->options['display']['post_views_column'] )
493 wp_send_json_error( [ 'message' => __( 'Admin column disabled.', 'post-views-counter' ) ] );
494
495 // ensure post type is tracked
496 if ( ! in_array( $post->post_type, $pvc->options['general']['post_types_count'], true ) )
497 wp_send_json_error( [ 'message' => __( 'Post type is not tracked.', 'post-views-counter' ) ] );
498
499 // check display permission for this specific post
500 if ( apply_filters( 'pvc_admin_display_post_views', true, $post_id ) === false )
501 wp_send_json_error( [ 'message' => __( 'Access denied for this post.', 'post-views-counter' ) ] );
502
503 // get period (format: YYYYMM or empty for current month)
504 $period_str = isset( $_POST['period'] ) && ! empty( $_POST['period'] ) ? preg_replace( '/[^0-9]/', '', $_POST['period'] ) : '';
505
506 // parse period or use current
507 if ( $period_str && strlen( $period_str ) === 6 ) {
508 $year = substr( $period_str, 0, 4 );
509 $month = substr( $period_str, 4, 2 );
510 $date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() );
511
512 if ( ! $date )
513 $date = new DateTime( 'now', wp_timezone() );
514 } else {
515 $date = new DateTime( 'now', wp_timezone() );
516 }
517
518 $year = $date->format( 'Y' );
519 $month = $date->format( 'm' );
520 $last_day = $date->format( 't' );
521
522 // fetch views data
523 $views = pvc_get_views( [
524 'post_id' => $post_id,
525 'post_type' => $post->post_type,
526 'fields' => 'date=>views',
527 'views_query' => [
528 'year' => (int) $year,
529 'month' => (int) $month
530 ]
531 ] );
532
533 // get colors
534 $colors = $pvc->functions->get_colors();
535
536 // prepare response data
537 $data = [
538 'post_id' => $post_id,
539 'post_title'=> get_the_title( $post_id ),
540 'period' => $year . $month,
541 'design' => [
542 'fill' => true,
543 'backgroundColor' => 'rgba(' . $colors['r'] . ',' . $colors['g'] . ',' . $colors['b'] . ', 0.2)',
544 'borderColor' => 'rgba(' . $colors['r'] . ',' . $colors['g'] . ',' . $colors['b'] . ', 1)',
545 'borderWidth' => 1.2,
546 'borderDash' => [],
547 'pointBorderColor' => 'rgba(' . $colors['r'] . ',' . $colors['g'] . ',' . $colors['b'] . ', 1)',
548 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)',
549 'pointBorderWidth' => 1.2
550 ],
551 'data' => [
552 'labels' => [],
553 'dates' => [],
554 'datasets' => [
555 [
556 'label' => get_the_title( $post_id ),
557 'data' => []
558 ]
559 ]
560 ]
561 ];
562
563 // generate dates and data
564 for ( $i = 1; $i <= $last_day; $i++ ) {
565 $date_key = $year . $month . str_pad( $i, 2, '0', STR_PAD_LEFT );
566
567 // labels: show only odd days
568 $data['data']['labels'][] = ( $i % 2 === 0 ? '' : $i );
569
570 // formatted dates for tooltips
571 $data['data']['dates'][] = date_i18n( get_option( 'date_format' ), strtotime( $year . '-' . $month . '-' . str_pad( $i, 2, '0', STR_PAD_LEFT ) ) );
572
573 // view count
574 $data['data']['datasets'][0]['data'][] = isset( $views[$date_key] ) ? (int) $views[$date_key] : 0;
575 }
576
577 // calculate total views for the period
578 $data['total_views'] = array_sum( $data['data']['datasets'][0]['data'] );
579
580 // check if there is any period-specific data
581 $period_has_data = false;
582 foreach ( $data['data']['datasets'][0]['data'] as $val ) {
583 if ( (int) $val > 0 ) {
584 $period_has_data = true;
585 break;
586 }
587 }
588
589 $data['period_has_data'] = $period_has_data;
590
591 // generate date navigation HTML
592 $data['dates_html'] = $this->generate_modal_dates( (int) $year, (int) $month );
593
594 wp_send_json_success( $data );
595 }
596
597 /**
598 * Generate month navigation for modal.
599 *
600 * @param int $year
601 * @param int $month
602 * @return string
603 */
604 private function generate_modal_dates( $year, $month ) {
605 // previous month
606 $prev_date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() );
607 $prev_date->modify( '-1 month' );
608
609 // next month
610 $next_date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() );
611 $next_date->modify( '+1 month' );
612
613 // current
614 $current_date = DateTime::createFromFormat( 'Y-m', $year . '-' . $month, wp_timezone() );
615
616 // check if next is in the future
617 $now = new DateTime( 'now', wp_timezone() );
618 $can_go_next = $next_date <= $now;
619
620 $html = '<div class="pvc-modal-nav">';
621 $html .= '<a href="#" class="pvc-modal-nav-prev" data-period="' . $prev_date->format( 'Ym' ) . '">‹ ' . date_i18n( 'F Y', $prev_date->getTimestamp() ) . '</a>';
622 $html .= '<span class="pvc-modal-nav-current">' . date_i18n( 'F Y', $current_date->getTimestamp() ) . '</span>';
623
624 if ( $can_go_next )
625 $html .= '<a href="#" class="pvc-modal-nav-next" data-period="' . $next_date->format( 'Ym' ) . '">' . date_i18n( 'F Y', $next_date->getTimestamp() ) . ' ›</a>';
626 else
627 $html .= '<span class="pvc-modal-nav-next pvc-disabled">' . date_i18n( 'F Y', $next_date->getTimestamp() ) . ' ›</span>';
628
629 $html .= '</div>';
630
631 return $html;
632 }
633
634 /**
635 * Render modal HTML in admin footer.
636 *
637 * @return void
638 */
639 public function render_modal_html() {
640 ?>
641 <div id="pvc-chart-modal" class="pvc-modal micromodal-slide" aria-hidden="true">
642 <div class="pvc-modal__overlay" tabindex="-1" data-micromodal-close>
643 <div class="pvc-modal__container" role="dialog" aria-modal="true" aria-labelledby="pvc-modal-title">
644 <header class="pvc-modal__header">
645 <h2 class="pvc-modal__title" id="pvc-modal-title"></h2>
646 <button class="pvc-modal__close" aria-label="<?php esc_attr_e( 'Close', 'post-views-counter' ); ?>" data-micromodal-close></button>
647 </header>
648 <div class="pvc-modal__content">
649 <div class="pvc-modal-content-top">
650 <div class="pvc-modal-summary">
651 <span class="pvc-modal-views-label"></span>
652 <span class="pvc-modal-views-data">
653 <span class="pvc-modal-count"></span>
654 </span>
655 </div>
656 </div>
657 <div class="pvc-modal-chart-container">
658 <canvas id="pvc-modal-chart" height="200"></canvas>
659 <span class="spinner"></span>
660 </div>
661 <div class="pvc-modal-content-bottom pvc-modal-dates"></div>
662 </div>
663 </div>
664 </div>
665 </div>
666 <?php
667 }
668 }
669