Changeset 3311724
- Timestamp:
- 06/15/2025 12:16:17 AM (10 months ago)
- Location:
- wpecounter
- Files:
-
- 52 added
- 10 edited
-
tags/2.1 (added)
-
tags/2.1/.gitignore (added)
-
tags/2.1/LICENSE (added)
-
tags/2.1/README.md (added)
-
tags/2.1/assets (added)
-
tags/2.1/assets/css (added)
-
tags/2.1/assets/css/settings.css (added)
-
tags/2.1/assets/js (added)
-
tags/2.1/assets/js/reset-views.js (added)
-
tags/2.1/assets/js/settings.js (added)
-
tags/2.1/block.json (added)
-
tags/2.1/build (added)
-
tags/2.1/build/index.asset.php (added)
-
tags/2.1/build/index.js (added)
-
tags/2.1/includes (added)
-
tags/2.1/includes/class-views.php (added)
-
tags/2.1/includes/functions.php (added)
-
tags/2.1/includes/plugin-utils.php (added)
-
tags/2.1/includes/scripts.php (added)
-
tags/2.1/includes/settings.php (added)
-
tags/2.1/includes/version.php (added)
-
tags/2.1/includes/widget.php (added)
-
tags/2.1/index.php (added)
-
tags/2.1/languages (added)
-
tags/2.1/languages/wpecounter-en_US.pot (added)
-
tags/2.1/languages/wpecounter-es_ES.mo (added)
-
tags/2.1/languages/wpecounter-es_ES.po (added)
-
tags/2.1/languages/wpecounter-sr_RS.mo (added)
-
tags/2.1/languages/wpecounter-sr_RS.po (added)
-
tags/2.1/package-lock.json (added)
-
tags/2.1/package.json (added)
-
tags/2.1/readme.txt (added)
-
tags/2.1/screenshot-1.png (added)
-
tags/2.1/screenshot-2.png (added)
-
tags/2.1/screenshot-3.png (added)
-
tags/2.1/screenshot-4.png (added)
-
tags/2.1/src (added)
-
tags/2.1/src/index.js (added)
-
tags/2.1/src/style-index.css (added)
-
tags/2.1/wpecounter.php (added)
-
trunk/.gitignore (added)
-
trunk/README.md (modified) (1 diff)
-
trunk/assets/js/reset-views.js (added)
-
trunk/assets/js/settings.js (modified) (1 diff)
-
trunk/block.json (added)
-
trunk/build (added)
-
trunk/build/index.asset.php (added)
-
trunk/build/index.js (added)
-
trunk/includes/class-views.php (modified) (4 diffs)
-
trunk/includes/plugin-utils.php (modified) (2 diffs)
-
trunk/includes/settings.php (modified) (17 diffs)
-
trunk/package-lock.json (added)
-
trunk/package.json (added)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/screenshot-1.png (modified) (previous)
-
trunk/screenshot-2.png (modified) (previous)
-
trunk/screenshot-3.png (modified) (previous)
-
trunk/screenshot-4.png (added)
-
trunk/src (added)
-
trunk/src/index.js (added)
-
trunk/src/style-index.css (added)
-
trunk/wpecounter.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
wpecounter/trunk/README.md
r2781621 r3311724 1 # wpecounter2 3 1 === WP Views Counter === 4 2 5 Contributors: etruel, khaztiel 3 Contributors: etruel, khaztiel, gerarjos14 6 4 7 5 Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7267TH4PT3GSW 8 6 9 Tags: views, visit counter, visits counter, post views, visits, counter, post visits, ajax counter, page count, count visits, popular posts.7 Tags: post views, views counter, popular posts, ajax counter, analytics 10 8 11 9 Requires at least: 3.1 12 10 13 Tested up to: 6. 0.211 Tested up to: 6.8.2 14 12 15 Stable tag: trunk 13 Requires PHP: 5.6 14 15 Stable tag: 2.1 16 16 17 17 License: GPLv2 18 18 19 19 20 Visits Post(types) counter. Shown the number of visits on lists of posts, pages and/or custom post types and shortcode. 21 20 Track your content’s popularity with a fast, reliable post views counter. Smarter and lighter than other bloated plugins. 22 21 23 22 == Description == 24 23 25 Knows how much views has every post, page or custom post type, just on wordpress list. 26 You can select on plugin settings, which types must count. Also you can print using shortcode [WPeCounter] in widgets, post or pages. 24 **WP Views Counter** is a lightweight yet powerful plugin to track how many times each post, page, or custom post type is viewed — from inside the WordPress admin or via shortcode or block. 27 25 28 Works with Easy Digital Downloads Products to see how many views has every Download, also with other plugins that work with public custom post types.26 Designed for performance and precision, it's ideal for blogs, WooCommerce stores, or Easy Digital Downloads shops where knowing what content attracts the most attention is critical. 29 27 30 Is extremely lightweight because it works with ajax. 28 Unlike bloated analytics solutions, WP Views Counter focuses on just one thing — accurate view tracking — without slowing down your site. 31 29 32 Developer and bugtracker on github repository: https://github.com/Etruel-Developments/wpecounter/issues 30 = Why choose WP Views Counter over other counters? = 33 31 34 Feel free to fork it and propose new enhancements or Pull Requests. 32 ✅ **Accurate post view counts** shown in the admin list, shortcodes, or blocks 33 ✅ **Metabox in each post** with manual reset option 34 ✅ **Exclude views by user role** or logged-in users 35 ✅ **Works with all post types** and EDD 36 ✅ **Lightweight AJAX-based tracking** — no page reloads 37 ✅ **Gutenberg block included** to display most viewed content 38 ✅ **Import views from other plugins** 39 ✅ **Multilingual and developer-friendly** 40 41 Track content performance at a glance and optimize your content strategy with a tool that just works — no tracking scripts, no third-party APIs, and no clutter. 42 43 Developer-friendly: [GitHub Repository](https://github.com/Etruel-Developments/wpecounter/issues) 44 Contributions, forks and feedback welcome. -
wpecounter/trunk/assets/js/settings.js
r2789038 r3311724 1 jQuery(document).ready(function ($) { 2 // If any role is checked, uncheck "All roles" 3 $('#views_counter_rol_list').on('change', '.views_counter_rol_role', function () { 4 if ($(this).is(':checked')) { 5 $('#views_counter_rol_all').prop('checked', false); 6 } 7 }); 8 // If "All roles" is checked, uncheck all others 9 $('#views_counter_rol_list').on('change', '#views_counter_rol_all', function () { 10 if ($(this).is(':checked')) { 11 $('.views_counter_rol_role').prop('checked', false); 12 } 13 }); 14 }); -
wpecounter/trunk/includes/class-views.php
r3279485 r3311724 53 53 /* Admin filters */ 54 54 add_action('admin_init', array($this, 'admin_init')); 55 } 56 57 /** 58 * Adds support for 'wpecounter' to the 'post', 'page', and 'attachment' post types (default WordPress 55 add_action('add_meta_boxes', array(__CLASS__, 'add_views_metabox')); 56 } 57 58 59 public static function add_views_metabox(){ 60 $options = get_option('WPeCounter_Options'); // $WPeCounterSettings->options_key); 61 $cpostypes = $options['cpostypes']; 62 $screens = array(); 63 $args = array('public' => true); 64 $output = 'names'; // names or objects 65 $post_types = get_post_types($args, $output); 66 67 foreach ($post_types as $post_type) { 68 if (@$cpostypes[$post_type]) { 69 $screens[] = $post_type; 70 } 71 } 72 add_meta_box( 73 'views_metabox', 74 __('Views Counter', 'wpecounter'), 75 array(__CLASS__, 'render_views_metabox'), 76 $screens, 77 'side', 78 'default' 79 ); 80 } 81 82 /** 83 * Renders the views metabox. 84 * 85 * @param WP_Post $post The current post object. 86 */ 87 public static function render_views_metabox($post) { 88 89 // Print styles once 90 self::print_reset_views_button_styles(); 91 92 // Prepare nonce and button 93 $nonce = wp_create_nonce('wpecounter_reset_views_' . $post->ID); 94 $reset_button = sprintf( 95 '<a href="#" class="wpecounter-reset-views-btn editor-post-publish-button editor-post-publish-button__button button-primary is-compact" data-postid="%d" data-nonce="%s" title="%s">%s</a>', 96 esc_attr($post->ID), 97 esc_attr($nonce), 98 esc_attr__('Reset Views', 'wpecounter'), 99 esc_attr__('Reset', 'wpecounter') 100 ); 101 102 // Get views count 103 $views = self::get_post_views_count($post->ID); 104 105 // Output metabox content 106 printf( 107 '<div class="wpecounter-views-box"><label id="wpecounter-views-count" class="wpecounter-views-label">%s </label>%s</div>', 108 sprintf('%d', $views), 109 $reset_button 110 ); 111 } 112 113 /** 114 * Adds support for 'wpecounter' to the 'post', 'page', and 'attachment' post types (default WordPress 59 115 * post types). For all other post types, the theme should explicitly register support for this feature. 60 116 * … … 155 211 */ 156 212 function update_single_views($post_id) { 157 /* If we're on a singular view of a post, calculate the number of views. */ 158 if (!empty($post_id)) { 159 160 /* Allow devs to override the meta key used. By default, this is 'Views'. */ 213 214 // Get plugin options from the database 215 $options = get_option('WPeCounter_Options'); 216 217 // Get the list of roles for which views should be counted 218 $not_allowed_roles = isset($options['views_counter_rol']) ? (array)$options['views_counter_rol'] : array(); 219 220 // Flag to determine if the view should be counted 221 $should_count = false; 222 223 // If role-based counting is enabled and not set to 'all_roles' 224 // Always count views for guests (not logged in) 225 if (!is_user_logged_in()) { 226 $should_count = true; 227 } else { 228 // Only count for logged-in users not in the not allowed roles 229 if (!empty($not_allowed_roles) && is_array($not_allowed_roles) && !in_array('all_roles', $not_allowed_roles)) { 230 $current_user = wp_get_current_user(); 231 // If the current user's roles intersect with the not allowed roles, do not count the view 232 if (!empty($current_user->roles) && array_intersect($current_user->roles, $not_allowed_roles)) { 233 $should_count = false; 234 } else { 235 $should_count = true; 236 } 237 } else { 238 // If no roles are restricted, count the view for all logged-in users 239 $should_count = false; 240 } 241 } 242 243 // If the view should be counted and the post ID is valid 244 if ($should_count && !empty($post_id)) { 245 // Get the meta key for storing views 161 246 $meta_key = $this->wpecounter_views_meta_key(); 162 163 /* Get the number of views the post currently has. */ 247 // Get the current number of views 164 248 $old_views = get_post_meta($post_id, $meta_key, true); 165 166 /* Add +1 to the number of current views. */ 249 // Increment the view count by 1 167 250 $new_views = absint($old_views) + 1; 168 169 /* Update the view count with the new view count. */ 251 // Update the post meta with the new view count 170 252 update_post_meta($post_id, $meta_key, $new_views, $old_views); 171 253 } … … 237 319 } 238 320 239 /** 240 * Init filters to display column and order by views on post types lists. 241 * 242 * @access public 243 * @return object 244 */ 321 // /** 322 // * Init filters to display column and order by views on post types lists. 323 // * 324 // * @access public 325 // * @return object 326 // */ 327 // public function admin_init() { 328 // global $options; 329 // $options = get_option('WPeCounter_Options'); // $WPeCounterSettings->options_key); 330 // $cpostypes = $options['cpostypes']; 331 332 // $args = array('public' => true); 333 // $output = 'names'; // names or objects 334 // $post_types = get_post_types($args, $output); 335 // foreach ($post_types as $post_type) { 336 // if (@$cpostypes[$post_type]) { 337 // // add_filter('manage_'.$post_type.'_posts_columns', array( $this, 'posts_columns_id'), 5); 338 // add_filter('manage_edit-' . $post_type . '_columns', array($this, 'posts_columns_id'), 10); 339 // add_action('manage_' . $post_type . '_posts_custom_column', array($this, 'posts_custom_id_columns'), 10, 2); 340 // //Order 341 // add_filter('manage_edit-' . $post_type . '_sortable_columns', array($this, 'views_column_register_sortable')); 342 // } 343 // } 344 // add_action('pre_get_posts', array($this, 'views_column_orderby')); 345 // // add_action('parse_query', array($this, 'views_column_orderby')); 346 // add_action('admin_head', array($this, 'post_views_column_width')); 347 // // 348 // // 349 // // add_filter('manage_edit-' . $post_type . '_columns', array(__CLASS__, 'set_edit_wpematico_columns')); 350 // // add_action('manage_' . $post_type . '_posts_custom_column', array(__CLASS__, 'custom_wpematico_column'), 10, 2); 351 // // add_filter("manage_edit-' . $post_type . '_sortable_columns", array(__CLASS__, "sortable_columns")); 352 // // add_action('pre_get_posts', array(__CLASS__, 'column_orderby')); 353 // // 354 // } 355 // public function posts_columns_id($columns) { 356 // global $options; 357 // $cfg = $options; 358 359 // $column_post_views = array('post_views' => '' . __('Views', 'wpecounter') . ''); 360 // $column_pos = (isset($cfg['wpecounter_column_pos']) and $cfg['wpecounter_column_pos'] > 0 ) ? $cfg['wpecounter_column_pos'] : 5; 361 // $columns = array_slice($columns, 0, $column_pos, true) + $column_post_views + array_slice($columns, $column_pos, NULL, true); 362 // $columns = array_merge($columns, $column_post_views); 363 // return $columns; 364 // } 365 366 public function posts_custom_id_columns($column_name, $id) { 367 if ($column_name === 'post_views') { 368 echo '' . wpecounter_post_views(array('post_id' => $id)) . ''; 369 } 370 } 371 public static function print_reset_views_button_styles() { 372 echo '<style> 373 .wpecounter-views-box{ 374 display: flex; 375 align-items: flex-end; 376 justify-content: center; 377 text-align: center; 378 } 379 .wpecounter-views-box .button-primary.wpecounter-reset-views-btn { 380 vertical-align: -webkit-baseline-middle; 381 font-size: 10px; 382 min-height: 20px; 383 line-height: 2; 384 margin-left: 15px; 385 } 386 .wpecounter-views-label{ 387 display: inline-flex; 388 font-size: 60px; 389 font-weight: bold; 390 color: grey; 391 line-height: 45px; 392 } 393 </style>'; 394 } 395 396 // Add the new column to the posts table 397 public function posts_columns_id($columns) { 398 global $options; 399 $cfg = $options; 400 401 $column_post_views = array('post_views' => '' . __('Views', 'wpecounter') . ''); 402 $column_pos = (isset($cfg['wpecounter_column_pos']) and $cfg['wpecounter_column_pos'] > 0 ) ? $cfg['wpecounter_column_pos'] : 5; 403 $columns = array_slice($columns, 0, $column_pos, true) + $column_post_views + array_slice($columns, $column_pos, NULL, true); 404 $columns = array_merge($columns, $column_post_views); 405 return $columns; 406 } 407 408 // Enqueue admin JS for AJAX reset 245 409 public function admin_init() { 410 global $options; 246 411 $options = get_option('WPeCounter_Options'); // $WPeCounterSettings->options_key); 247 412 $cpostypes = $options['cpostypes']; … … 252 417 foreach ($post_types as $post_type) { 253 418 if (@$cpostypes[$post_type]) { 254 // add_filter('manage_'.$post_type.'_posts_columns', array( $this, 'posts_columns_id'), 5);255 419 add_filter('manage_edit-' . $post_type . '_columns', array($this, 'posts_columns_id'), 10); 256 420 add_action('manage_' . $post_type . '_posts_custom_column', array($this, 'posts_custom_id_columns'), 10, 2); 257 //Order258 421 add_filter('manage_edit-' . $post_type . '_sortable_columns', array($this, 'views_column_register_sortable')); 259 422 } 260 423 } 261 424 add_action('pre_get_posts', array($this, 'views_column_orderby')); 262 // add_action('parse_query', array($this, 'views_column_orderby'));263 425 add_action('admin_head', array($this, 'post_views_column_width')); 264 // 265 // 266 // add_filter('manage_edit-' . $post_type . '_columns', array(__CLASS__, 'set_edit_wpematico_columns')); 267 // add_action('manage_' . $post_type . '_posts_custom_column', array(__CLASS__, 'custom_wpematico_column'), 10, 2); 268 // add_filter("manage_edit-' . $post_type . '_sortable_columns", array(__CLASS__, "sortable_columns")); 269 // add_action('pre_get_posts', array(__CLASS__, 'column_orderby')); 270 // 271 } 272 273 public function posts_columns_id($columns) { 274 275 $column_post_views = array('post_views' => '' . __('Views', 'wpecounter') . ''); 276 // 5to lugar 277 //$columns = array_slice( $columns, 0, 5, true ) + $column_post_views + array_slice( $columns, 5, NULL, true ); 278 $columns = array_merge($columns, $column_post_views); 279 return $columns; 280 } 281 282 public function posts_custom_id_columns($column_name, $id) { 283 if ($column_name === 'post_views') { 284 echo '' . wpecounter_post_views(array('post_id' => $id)) . ''; 285 } 426 427 // Enqueue JS only on post list screens 428 add_action('admin_enqueue_scripts', function ($hook) { 429 wp_enqueue_script('wpecounter-reset-views', plugins_url('../assets/js/reset-views.js', __FILE__), array('jquery'), null, true); 430 wp_localize_script('wpecounter-reset-views', 'wpecounterResetViews', array( 431 'ajax_url' => admin_url('admin-ajax.php'), 432 'confirm' => __('Are you sure you want to reset the views for this post?', 'wpecounter'), 433 )); 434 }); 435 add_action('wp_ajax_wpecounter_reset_views', array($this, 'ajax_reset_views')); 436 } 437 438 // AJAX handler to reset views 439 public function ajax_reset_views() { 440 if ( 441 !isset($_POST['post_id'], $_POST['nonce']) || 442 !wp_verify_nonce($_POST['nonce'], 'wpecounter_reset_views_' . absint($_POST['post_id'])) 443 ) { 444 wp_send_json_error(array('message' => __('Invalid request.', 'wpecounter'))); 445 } 446 $post_id = absint($_POST['post_id']); 447 if ($post_id) { 448 delete_post_meta($post_id, $this->wpecounter_views_meta_key()); 449 wp_send_json_success(array('message' => __('Views reset.', 'wpecounter'))); 450 } 451 wp_send_json_error(array('message' => __('Invalid post ID.', 'wpecounter'))); 286 452 } 287 453 -
wpecounter/trunk/includes/plugin-utils.php
r3279485 r3311724 7 7 } 8 8 9 /* function boilerplate_license_menu() {10 add_submenu_page(11 'edit.php?post_type=wpematico',12 'Boilerplate Settings',13 'BoilerPlate <span class="dashicons-before dashicons-admin-plugins"></span>',14 'manage_options',15 'boilerplate_license',16 'boilerplate_license_page'17 );18 //add_plugins_page( 'Plugin License', 'Plugin License', 'manage_options', 'boilerplate_license', 'boilerplate_license_page' );19 }20 add_action('admin_menu', 'boilerplate_license_menu');21 */22 23 9 24 10 … … 27 13 class WPeCounterPluginUtils { 28 14 15 // Constructor: Hooks into WordPress actions and filters 29 16 function __construct() { 30 // add_filter('admin_init', array(__CLASS__, 'init'), 10, 2); 31 // } 32 // 33 // public static function init() { 34 //Additional links on the plugin page 17 // Register the block during init 18 add_action('init', array(__CLASS__, 'mvpb_register_block')); 19 20 // Enqueue editor assets for the block 21 add_action('enqueue_block_editor_assets', array(__CLASS__, 'wpecounter_enqueue_block_editor_assets')); 22 23 // Add a custom block category to the block editor 24 add_filter('block_categories_all', function ($categories, $post) { 25 $custom_category = [ 26 [ 27 'slug' => 'wpecounter', 28 'title' => __('WP Views Counter', 'wpecounter'), 29 'icon' => 'visibility', // Optional icon 30 ], 31 ]; 32 // Add the custom category at the beginning of the list 33 return array_merge($custom_category, $categories); 34 }, 10, 2); 35 36 // Add custom links in the plugin list 35 37 add_filter('plugin_row_meta', array(__CLASS__, 'init_row_meta'), 10, 2); 36 38 add_filter('plugin_action_links_' . plugin_basename(WPECOUNTER_PLUGIN_FILE), array(__CLASS__, 'init_action_links')); 37 39 } 38 40 41 // Register the dynamic block and link the render callback 42 public static function mvpb_register_block() { 43 register_block_type(WPECOUNTER_PLUGIN_DIR, array( 44 'render_callback' => array(__CLASS__, 'mvpb_render_most_viewed'), 45 )); 46 } 47 48 // Render callback for the dynamic block (frontend output) 49 public static function mvpb_render_most_viewed($attributes){ 50 // Set default values for attributes 51 if (! isset($attributes['postType'])) { 52 $attributes['postType'] = 'post'; 53 } 54 if (! isset($attributes['limit'])) { 55 $attributes['limit'] = 5; 56 } 57 if (! isset($attributes['order'])) { 58 $attributes['order'] = 'DESC'; 59 } 60 if (! isset($attributes['title'])) { 61 $attributes['title'] = __('Most Popular', 'text-domain'); 62 } 63 64 // Instantiate the views counter object if not already set 65 if (!isset($WPeCounterViews)) { 66 $WPeCounterViews = new WPeCounterViews(); 67 } 68 69 // Query arguments to retrieve the most viewed posts 70 $args = array( 71 'post_type' => sanitize_text_field($attributes['postType']), 72 'posts_per_page' => intval($attributes['limit']), 73 'post_status' => 'publish', 74 'meta_key' => $WPeCounterViews->wpecounter_views_meta_key(), 75 'orderby' => 'meta_value_num', 76 'order' => in_array(strtoupper($attributes['order']), ['ASC', 'DESC']) ? strtoupper($attributes['order']) : 'DESC', 77 'no_found_rows' => true, 78 'ignore_sticky_posts' => true, 79 ); 80 81 $posts = get_posts($args); 82 83 // If no posts found, return fallback message 84 if (empty($posts)) { 85 return '<p>' . esc_html__('No popular posts found.', 'text-domain') . '</p>'; 86 } 87 88 // Wrapper with dynamic block attributes (e.g., className, etc.) 89 $wrapper = get_block_wrapper_attributes(); 90 91 // Start building HTML output 92 $output = "<div {$wrapper}>"; 93 $output .= '<div class="mvpb-block">'; 94 $output .= '<h3 class="mvpb-block-title">' . esc_html($attributes['title']) . '</h3>'; 95 $output .= '<ul class="mvpb-post-list">'; 96 97 // Loop through the posts and create a list item for each 98 foreach ($posts as $post) { 99 $title = esc_html(get_the_title($post->ID)); 100 $url = esc_url(get_permalink($post->ID)); 101 $views = $WPeCounterViews->get_post_views_count($post->ID); 102 $output .= "<li class='mvpb-post-item'><a href='{$url}'>{$title}</a> ({$views})</li>"; 103 } 104 105 $output .= '</ul>'; 106 $output .= '</div>'; 107 $output .= '</div>'; 108 109 return $output; 110 } 111 112 // Enqueue JavaScript and pass data to the block editor 113 public static function wpecounter_enqueue_block_editor_assets(){ 114 wp_enqueue_script( 115 'wpecounter-block-editor', WPECOUNTER_PLUGIN_DIR . 'build/index.js', 116 ); 117 118 // Get plugin options 119 $options = get_option('WPeCounter_Options'); 120 $cpostypes = isset($options['cpostypes']) ? (array) $options['cpostypes'] : []; 121 122 // Get all public post types 123 $args = array('public' => true); 124 $post_types = get_post_types($args, 'names'); 125 126 // List of post types to exclude 127 $exclude = array('attachment', 'revision', 'nav_menu_item'); 128 129 // Filter post types based on user settings and exclusion list 130 $post_types_filtered = array_filter($post_types, function ($pt) use ($exclude, $cpostypes) { 131 return !in_array($pt, $exclude, true) && isset($cpostypes[$pt]) && $cpostypes[$pt] === '1'; 132 }); 133 134 // Format the post types for Select dropdown in block editor 135 $select_options = []; 136 foreach ($post_types_filtered as $pt) { 137 $select_options[] = [ 138 'label' => ucfirst($pt), 139 'value' => $pt, 140 ]; 141 } 142 143 // Pass the data to the block editor script 144 wp_localize_script( 145 'wpecounter-block-editor', 146 'wpecounterData', 147 array( 148 'postTypes' => $select_options, 149 ) 150 ); 151 } 39 152 /** 40 153 * Actions-Links del Plugin -
wpecounter/trunk/includes/settings.php
r2789038 r3311724 22 22 * Some settings to use by default 23 23 */ 24 protected $SettingsPage = 'WPeCounter'; 25 protected $section = 'WPeCounter-settings'; 26 protected $options_key = 'WPeCounter_Options'; 27 protected $heading = 'WP Views Counter Options'; 28 protected $description = 'These options are applied to the selected post-types counters.'; 29 protected $default_options = array( 30 'cpostypes' => array( 31 'post' => 1, 32 'page' => 1 33 ) 24 protected $SettingsPage = 'WPeCounter'; 25 protected $section = 'WPeCounter-settings'; 26 protected $options_key = 'WPeCounter_Options'; 27 protected $heading = 'WP Views Counter Options'; 28 protected $description = 'These options are applied to the selected post-types counters.'; 29 protected $default_options = array( 30 'cpostypes' => array( 31 'post' => 1, 32 'page' => 1 33 ), 34 'views_counter_rol' => array('all_roles'), 34 35 ); 35 36 … … 77 78 public function register_settings() { 78 79 79 // delete_option($this->options_key);80 //$section = $this->section;81 //$option_group = $this->options_key;82 80 // no options - create them. 83 81 if (false == get_option($this->options_key)) { … … 86 84 87 85 $options = get_option($this->options_key); 88 89 86 /** 90 87 * Check is exist each option and assign by default values … … 92 89 if (false == isset($options['cpostypes'])) { 93 90 $options['cpostypes'] = $this->default_options['cpostypes']; 91 } 92 if (false == isset($options['views_counter_rol'])) { 93 $options['views_counter_rol'] = $this->default_options['views_counter_rol']; 94 94 } 95 95 … … 107 107 $this->SettingsPage, 108 108 $this->section, 109 array('id' => 'cpostypes', 109 array( 110 'id' => 'cpostypes', 110 111 'name' => 'WPeCounter_Options[cpostypes]', 111 112 'values' => $options['cpostypes'] … … 113 114 ); 114 115 115 // add_settings_field( 116 // 'impofield', 117 // __('CAMPO DE TEXTo:', 'wpecounter'), 118 // array($this, 'textinput'), 119 // $this->SettingsPage, 120 // $this->section, 121 // array('id' => 'impofield', 122 // 'name' => 'WPeCounter_Options[cpostypes]', 123 // 'value' => $options['cpostypes'] 124 // ) 125 // ); 126 // finally 116 // Add setting for campaign_in_postslist and column_campaign_pos 117 add_settings_field( 118 'campaign_in_postslist', 119 __('Column position on lists:', 'wpecounter'), 120 function ($args) use ($options) { 121 $wpecounter_column_pos = isset($options['wpecounter_column_pos']) ? intval($options['wpecounter_column_pos']) : 0; 122 ?> 123 <p> 124 <span id="wpecounter_column_pos_field" class="insidesec" > 125 <label> 126 <input name="WPeCounter_Options[wpecounter_column_pos]" id="wpecounter_column_pos" class="small-text" min="0" type="number" value="<?php echo esc_attr($wpecounter_column_pos); ?>" /> 127 </label> 128 </span> 129 <br> 130 <span class="description"><?php esc_html_e('Position of the Views column in the posts(-type) lists.', 'wpecounter'); ?></span> 131 </p> 132 133 <?php 134 }, 135 $this->SettingsPage, 136 $this->section 137 ); 138 139 // Add multi-select for views_counter_rol 140 add_settings_field( 141 'views_counter_rol', 142 __('Do not count views for:', 'wpecounter'), 143 function ($args) use ($options) { 144 global $wp_roles; 145 if (!isset($wp_roles)) { 146 $wp_roles = new WP_Roles(); 147 } 148 $roles = $wp_roles->get_names(); 149 $current = isset($options['views_counter_rol']) ? (array) $options['views_counter_rol'] : array(); 150 $all_roles_checked = in_array('all_roles', $current) && count($current) === 1; 151 echo '<div id="views_counter_rol_list">'; 152 echo '<label><input type="checkbox" id="views_counter_rol_all" name="WPeCounter_Options[views_counter_rol][]" value="all_roles"' . ($all_roles_checked ? ' checked' : '') . '> ' . esc_html__('All logged in users', 'wpecounter') . '</label><br>'; 153 foreach ($roles as $role_key => $role_name) { 154 printf( 155 '<label><input type="checkbox" class="views_counter_rol_role" name="WPeCounter_Options[views_counter_rol][]" value="%s"%s> %s</label><br>', 156 esc_attr($role_key), 157 in_array($role_key, $current) ? ' checked' : '', 158 esc_html($role_name) 159 ); 160 } 161 echo '</div>'; 162 }, 163 $this->SettingsPage, 164 $this->section 165 ); 166 /* add_settings_field( 167 'reset_counters', 168 __('Reset Counters', 'wpecounter'), 169 function($args) use ($options) { 170 // Get all public post types 171 $post_types = get_post_types(['public' => true], 'objects'); 172 173 ?> 174 <div> 175 <label> 176 <input type="radio" name="WPeCounter_Options[reset_scope]" value="all" checked> 177 <?php _e('Reset all counters (all post types)', 'wpecounter'); ?> 178 </label> 179 <br> 180 <label> 181 <input type="radio" name="WPeCounter_Options[reset_scope]" value="by_type"> 182 <?php _e('Reset by post type:', 'wpecounter'); ?> 183 </label> 184 <select name="WPeCounter_Options[reset_post_type]" style="margin-left:10px;"> 185 <?php 186 foreach ($post_types as $post_type) : 187 if ($post_type->name == 'attachment') 188 continue; 189 190 ?> 191 <option value="<?php echo esc_attr($post_type->name); ?>"><?php echo esc_html($post_type->labels->singular_name); ?></option> 192 <?php endforeach; ?> 193 </select> 194 <br><br> 195 <button type="submit" name="reset_counters_btn" class="button button-secondary" onclick="return confirm('//<?php echo esc_js(__('Are you sure you want to reset the counters? This cannot be undone.', 'wpecounter')); ?>');"> 196 <?php _e('Reset Counters', 'wpecounter'); ?> 197 </button> 198 <p class="description">//<?php _e('This will set all selected counters to zero. This action cannot be undone.', 'wpecounter'); ?></p> 199 </div> 200 <?php 201 }, 202 $this->SettingsPage, 203 $this->section 204 ); 205 */ 206 // Handle reset counters action 207 if (isset($_POST['reset_counters_btn'])) { 208 global $wpdb; 209 if (!isset($WPeCounterViews)) { 210 $WPeCounterViews = new WPeCounterViews(); 211 } 212 $meta_key = $WPeCounterViews->wpecounter_views_meta_key(); 213 $scope = isset($_POST['WPeCounter_Options']['reset_scope']) ? $_POST['WPeCounter_Options']['reset_scope'] : 'all'; 214 $reset_count = 0; 215 if ($scope === 'all') { 216 // Reset all counters for all public post types 217 $reset_count = $wpdb->query( 218 $wpdb->prepare( 219 "UPDATE $wpdb->postmeta pm 220 INNER JOIN $wpdb->posts p ON pm.post_id = p.ID 221 SET pm.meta_value = '0' 222 WHERE pm.meta_key = %s AND p.post_type != %s", 223 $meta_key, 224 'attachment' 225 ) 226 ); 227 } elseif ($scope === 'by_type' && !empty($_POST['WPeCounter_Options']['reset_post_type'])) { 228 $post_type = sanitize_text_field($_POST['WPeCounter_Options']['reset_post_type']); 229 $reset_count = $wpdb->query( 230 $wpdb->prepare( 231 "UPDATE $wpdb->postmeta pm 232 INNER JOIN $wpdb->posts p ON pm.post_id = p.ID 233 SET pm.meta_value = '0' 234 WHERE pm.meta_key = %s AND p.post_type = %s", 235 $meta_key, 236 $post_type 237 ) 238 ); 239 } 240 if ($reset_count !== false) { 241 add_settings_error($this->SettingsPage, '', sprintf(__('Reset %d counters to zero.', 'wpecounter'), $reset_count), 'success'); 242 } else { 243 add_settings_error($this->SettingsPage, '', __('Failed to reset counters.', 'wpecounter'), 'error'); 244 } 245 } 246 127 247 register_setting( 128 248 $this->options_key, … … 152 272 <br /> 153 273 <div> 154 <?php // echo $desc; ?>274 <?php // echo $desc; ?> 155 275 </div> 156 276 157 <?php //echo settings_errors($this->SettingsPage); ?>277 <?php //echo settings_errors($this->SettingsPage); ?> 158 278 159 279 <div id="tab_container"> … … 162 282 <div class="postbox inside"> 163 283 <div class="inside"> 284 <h3><span class="dashicons dashicons-welcome-view-site"></span><?php _e('General Options', 'wpecounter'); ?></h3> 285 <hr /> 164 286 <table class="form-table"> 165 287 <?php … … 177 299 <div class="inside"> 178 300 <h3><span class="dashicons dashicons-sos"></span><?php _e('Danger Area', 'wpecounter'); ?></h3> 301 <hr /> 302 <?php 303 // Get all public post types 304 $post_types = get_post_types(['public' => true], 'objects'); 305 ?> 306 <div><p> 307 <label> 308 <input type="radio" name="WPeCounter_Options[reset_scope]" value="by_type" checked> 309 <?php _e('Reset by post type:', 'wpecounter'); ?> 310 </label> 311 <select name="WPeCounter_Options[reset_post_type]" style="margin-left:10px;"> 312 <?php 313 foreach ($post_types as $post_type) : 314 if ($post_type->name == 'attachment') 315 continue; 316 ?> 317 <option value="<?php echo esc_attr($post_type->name); ?>"><?php echo esc_html($post_type->labels->singular_name); ?></option> 318 <?php endforeach; ?> 319 </select> 320 <br> 321 <label> 322 <input type="radio" name="WPeCounter_Options[reset_scope]" value="all"> 323 <?php _e('Reset all counters (all post types)', 'wpecounter'); ?> 324 </label> 325 </p><p> 326 <button type="submit" name="reset_counters_btn" class="button button-secondary" onclick="return confirm('<?php echo esc_js(__('Are you sure you want to reset the counters? This cannot be undone.', 'wpecounter')); ?>');"> 327 <?php _e('Reset Counters', 'wpecounter'); ?> 328 </button> 329 </p> 330 <p class="description"><?php _e('This will set all selected counters to zero. This action cannot be undone.', 'wpecounter'); ?></p> 331 332 </div> 333 <hr /> 334 <p> 179 335 <strong><?php _e('Be careful with these options. There are not undo. Be sure to make backup of postmeta table.', 'wpecounter'); ?></strong> 336 </p> 180 337 <p><label> 181 <input type="checkbox" class="checkbox" name="showimpo" value="1" onclick="jQuery('#metaimpo').toggle();" /> 182 <?php _e('Show Options.', 'wpecounter'); ?></label> 338 <input type = "checkbox" class = "checkbox" name = "showimpo" value = "1" onclick = "jQuery('#metaimpo').toggle();" /> 339 <?php _e('Show more options below:', 'wpecounter'); 340 ?></label> 183 341 </p> 184 342 <div id="metaimpo" style="display:none;"> … … 250 408 public static function checkboxes_callback($data, $echo = true) { 251 409 // Currently selected post types 252 $cpostypes = $data['values'];410 $cpostypes = $data['values']; 253 411 unset($cpostypes['attachment']); // Do not allow Views counter for attachments 254 412 // only publics as privates doesn't have visits 255 $args = array('public' => true);256 $post_types = get_post_types($args, 'names'); // names or objects413 $args = array('public' => true); 414 $post_types = get_post_types($args, 'names'); // names or objects 257 415 258 416 foreach ($post_types as $post_type) { … … 299 457 300 458 foreach ($args['options'] as $option => $name) { 301 $selected = selected($option, $value, false);302 $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';303 } 304 305 $html .= '</select>';306 $html .= '<label for="wpedpc_settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';459 $selected = selected($option, $value, false); 460 $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>'; 461 } 462 463 $html .= '</select>'; 464 $html .= '<label for="wpedpc_settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>'; 307 465 308 466 if ($echo) { … … 331 489 // Loop through the input and sanitize each of the values 332 490 foreach ($input as $key => $val) { 333 $new_input[$key] = (!is_array($val) ) ? sanitize_text_field($val) : $val;491 $new_input[$key] = (!is_array($val)) ? sanitize_text_field($val) : $val; 334 492 } 335 493 … … 368 526 $WPeCounterViews->wpecounter_views_meta_key(), 369 527 $impoviews 370 ));528 )); 371 529 // Prepare updated messages 372 530 if ($introws > 0) { … … 432 590 433 591 // Currently selected post types 434 $cpostypes = $new_input['cpostypes'];435 $sPostTypes = "'" . implode("', '", array_keys($cpostypes)) . "'";592 $cpostypes = $new_input['cpostypes']; 593 $sPostTypes = "'" . implode("', '", array_keys($cpostypes)) . "'"; 436 594 437 595 $query = "SELECT … … 454 612 $results = $wpdb->get_results($query); 455 613 456 $insertQuery = "INSERT INTO $wpdb->postmeta (post_id,meta_key,meta_value) VALUES ";457 $insertQueryValues = array();614 $insertQuery = "INSERT INTO $wpdb->postmeta (post_id,meta_key,meta_value) VALUES "; 615 $insertQueryValues = array(); 458 616 foreach ($results as $value) { 459 617 $array = (array) $value; … … 462 620 } 463 621 $insertValues = implode(",", $insertQueryValues); 464 $insertQuery .= $insertValues;465 622 $insertQuery .= $insertValues; 623 466 624 $metafixed = $wpdb->query($insertQuery); 467 625 // var_dump($wpdb->last_query); 468 469 626 // $metafixed = $wpdb->query(" 470 627 // INSERT INTO `$wpdb->postmeta` (`post_id`,`meta_key`,`meta_value`) … … 521 678 return self::$instance; 522 679 } 523 524 680 } 525 681 -
wpecounter/trunk/readme.txt
r3306765 r3311724 1 1 === WP Views Counter === 2 Contributors: etruel, khaztiel, gerarjos14 3 Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7267TH4PT3GSW 4 Tags: views, count visits, post views, post visits, ajax counter5 Requires at least: 3.1 6 Tested up to: 6.8 7 Requires PHP: 5.6 8 Stable tag: 2. 0.49 License: GPLv2 2 Contributors: etruel, khaztiel, gerarjos14 3 Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7267TH4PT3GSW 4 Tags: post views, views counter, popular posts, ajax counter, analytics 5 Requires at least: 3.1 6 Tested up to: 6.8.2 7 Requires PHP: 5.6 8 Stable tag: 2.1 9 License: GPLv2 10 10 11 A lightweight and powerful post views counter. Displays visits in post lists and via shortcode or widget. Ideal for tracking popularity across all post types.11 Fast, lightweight post views counter. Display views in admin, blocks or shortcodes — no tracking scripts required. 12 12 13 13 == Description == 14 14 15 **WP Views Counter** lets you see how many views each post, page or custom post type entry has directly in the WordPress admin list table or with a shortcode.15 **WP Views Counter** is a lightweight, high-performance plugin that accurately tracks and displays post, page, and custom post type views — directly in the WordPress admin, via shortcode, or with a Gutenberg block. 16 16 17 Perfect for bloggers, marketers and eCommerce site owners, this plugin is designed for speed and simplicity. Whether you're running a WooCommerce shop, an Easy Digital Downloads store, or a content-heavy blog — you'll benefit from knowing what content your users engage with the most.17 Built for bloggers, marketers, store owners, and developers, it works seamlessly across all post types — including WooCommerce and Easy Digital Downloads — with minimal impact on your site’s speed. No external scripts. No unnecessary bloat. 18 18 19 Th e counter is AJAX-based, making it efficient and non-intrusive, even on high-traffic sites.19 This plugin does one job and does it exceptionally well: it tells you which content is getting the most attention. 20 20 21 = Why choose WP Views Counter?=21 = Key Benefits = 22 22 23 ✅ **Fast and lightweight** — built for performance 24 ✅ **Seamless integration** with all custom post types 25 ✅ **Easy Digital Downloads compatible** 26 ✅ **Popular posts widget included** 27 ✅ **Counts views via shortcode or in admin columns** 28 ✅ **Multilingual ready** 23 ✅ **Accurate view counts** in admin columns, shortcode, or block 24 ✅ **Metabox per post** with real-time views and reset button 25 ✅ **Exclude views from logged-in users or specific roles** 26 ✅ **Fully AJAX-powered** — no page reloads or slowdowns 27 ✅ **Works with all post types**, including EDD and WooCommerce 28 ✅ **Block to display popular posts** — no legacy widgets required 29 ✅ **Developer-friendly and fully translatable** 30 ✅ **Import views from other plugins** 29 31 30 Unlike bloated analytics plugins, WP Views Counter focuses only on what matters: showing you the view count where you need it.32 Whether you're optimizing your content strategy or simply want to know what's working, **WP Views Counter** is the simple and effective alternative to bloated analytics plugins. 31 33 32 Developer-friendly on GitHub: https://github.com/Etruel-Developments/wpecounter/issues 33 We welcome forks, feedback and pull requests. 34 📦 Start tracking your most popular content today — with clarity, speed and control. 34 35 35 == Features == 36 37 * Display post views in the admin post list columns. 38 * Count views on any custom post type. 39 * Shortcode `[WPeCounter]` to display views anywhere. 40 * AJAX-based counting — no page reloads needed. 41 * Order admin lists by view count. 42 * Easy Digital Downloads (EDD) integration: track views for Downloads. 43 * Legacy widget to show most visited posts or products. 44 * Import views from other counters. 45 * Fully translatable — multilingual support out of the box. 46 47 == Coming Soon == 48 49 * Option to ignore visits from logged-in users or specific roles. 50 * Choose display position of Views column per post type. 36 💡 Developer-friendly: [Contribute on GitHub](https://github.com/Etruel-Developments/wpecounter/issues) — forks and pull requests welcome. 51 37 52 38 == Frequently Asked Questions == 53 39 54 = Can I upgrade from an older version without losing data? = 40 = Can I upgrade from an older version without losing data? = 55 41 Yes. Version 2.0+ automatically imports your previous data and settings. You can also manually import custom view fields. Always make a backup first. 56 42 … … 69 55 70 56 == Changelog == 57 58 = 2.1 – Jun 13, 2025 = 59 * Added a post metabox showing view count with a "Reset" button per post.(Deprecated Legacy Widget will be deleted on future release.) 60 * Introduced a Gutenberg block to replace the legacy popular posts widget. 61 * New option to choose the Views column position in each post type list. 62 * Added feature to exclude logged-in users (or by role) from the view count. 63 * New tools to reset all view counters or by post type. 71 64 72 65 = 2.0.4 – Jun 4, 2025 = … … 121 114 122 115 == Upgrade Notice == 123 = 2. 0.4=124 Recommended security and stability update. Compatible with WordPress 6.8.116 = 2.1 = 117 Major update: Adds Gutenberg block, per-post view metabox with reset, role-based view filtering, and tools to reset counters. Fully compatible with WP 6.8.2. -
wpecounter/trunk/wpecounter.php
r3306765 r3311724 4 4 * Plugin URI: https://etruel.com/downloads/wpecounter 5 5 * Description: Counts visits on post lists, pages and/or custom post types. It also displays them in posts, pages or text widget content, shortcode [WPeCounter]. 6 * Version: 2. 0.46 * Version: 2.1 7 7 * Author: Etruel Developments LLC 8 8 * Author URI: https://etruel.com … … 15 15 // Plugin version 16 16 if (!defined('WPECOUNTER_VERSION')) 17 define('WPECOUNTER_VERSION', '2. 0.4');17 define('WPECOUNTER_VERSION', '2.1'); 18 18 19 19 if (!class_exists('WPeCounter')) :
Note: See TracChangeset
for help on using the changeset viewer.