Changeset 3755015
- Timestamp:
- 10/19/2026 02:48:39 PM (3 weeks ago)
- Location:
- wp-content-copy-protector
- Files:
-
- 83 added
- 12 edited
-
tags/4.3 (added)
-
tags/4.3/activity-panel.php (added)
-
tags/4.3/activity.php (added)
-
tags/4.3/admin-bar-insights.php (added)
-
tags/4.3/admin-core.php (added)
-
tags/4.3/css (added)
-
tags/4.3/css/activity.css (added)
-
tags/4.3/css/admin-bar-insights.css (added)
-
tags/4.3/css/error-monitor.css (added)
-
tags/4.3/css/simpletabs.css (added)
-
tags/4.3/css/style-review.css (added)
-
tags/4.3/css/style.css (added)
-
tags/4.3/css/upgrade-hint.css (added)
-
tags/4.3/css/wpb-admin.css (added)
-
tags/4.3/deactivation-survey.php (added)
-
tags/4.3/error-monitor.php (added)
-
tags/4.3/fonts (added)
-
tags/4.3/fonts/inter-latin-var.woff2 (added)
-
tags/4.3/images (added)
-
tags/4.3/images/ad.png (added)
-
tags/4.3/images/click-here-arrow.png (added)
-
tags/4.3/images/icon-128x128.png (added)
-
tags/4.3/images/logo-icons-all-sizes (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-128x128.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-16x16.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-192x192.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-24x24.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-256x256.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-32x32.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-384x384.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-48x48.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-512x512.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-64x64.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-96x96.webp (added)
-
tags/4.3/images/logo-icons-all-sizes/wccp-free-box-original-1122x1402.webp (added)
-
tags/4.3/images/notice.png (added)
-
tags/4.3/images/right-click-protection.webp (added)
-
tags/4.3/images/smart-phones-protection.webp (added)
-
tags/4.3/images/warning.png (added)
-
tags/4.3/images/watermark-adv.webp (added)
-
tags/4.3/images/watermarking-adv-examples.webp (added)
-
tags/4.3/images/wccp-free-box-96x96.webp (added)
-
tags/4.3/js (added)
-
tags/4.3/js/License.txt (added)
-
tags/4.3/js/activity-tracker.js (added)
-
tags/4.3/js/activity.js (added)
-
tags/4.3/js/admin-bar-insights.js (added)
-
tags/4.3/js/error-monitor.js (added)
-
tags/4.3/js/simpletabs_1.3.js (added)
-
tags/4.3/js/upgrade-hint.js (added)
-
tags/4.3/js/wpb-admin.js (added)
-
tags/4.3/languages (added)
-
tags/4.3/languages/wp-content-copy-protector-ar.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-ar.po (added)
-
tags/4.3/languages/wp-content-copy-protector-de_DE.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-de_DE.po (added)
-
tags/4.3/languages/wp-content-copy-protector-es_ES.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-es_ES.po (added)
-
tags/4.3/languages/wp-content-copy-protector-fr_FR.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-fr_FR.po (added)
-
tags/4.3/languages/wp-content-copy-protector-it_IT.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-it_IT.po (added)
-
tags/4.3/languages/wp-content-copy-protector-ja.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-ja.po (added)
-
tags/4.3/languages/wp-content-copy-protector-nl_NL.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-nl_NL.po (added)
-
tags/4.3/languages/wp-content-copy-protector-pt_BR.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-pt_BR.po (added)
-
tags/4.3/languages/wp-content-copy-protector-pt_PT.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-pt_PT.po (added)
-
tags/4.3/languages/wp-content-copy-protector-ru_RU.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-ru_RU.po (added)
-
tags/4.3/languages/wp-content-copy-protector-zh_CN.mo (added)
-
tags/4.3/languages/wp-content-copy-protector-zh_CN.po (added)
-
tags/4.3/languages/wp-content-copy-protector.pot (added)
-
tags/4.3/notice-filter.php (added)
-
tags/4.3/notifications.php (added)
-
tags/4.3/preventer-index.php (added)
-
tags/4.3/readme.txt (added)
-
tags/4.3/the_globals.php (added)
-
tags/4.3/uninstall.php (added)
-
tags/4.3/upgrade-hint.php (added)
-
trunk/activity-panel.php (modified) (3 diffs)
-
trunk/activity.php (modified) (1 diff)
-
trunk/admin-bar-insights.php (modified) (10 diffs)
-
trunk/admin-core.php (modified) (20 diffs)
-
trunk/css/admin-bar-insights.css (modified) (4 diffs)
-
trunk/css/error-monitor.css (modified) (2 diffs)
-
trunk/css/wpb-admin.css (modified) (1 diff)
-
trunk/error-monitor.php (modified) (4 diffs)
-
trunk/js/admin-bar-insights.js (modified) (3 diffs)
-
trunk/js/error-monitor.js (modified) (4 diffs)
-
trunk/notice-filter.php (added)
-
trunk/preventer-index.php (modified) (12 diffs)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
wp-content-copy-protector/trunk/activity-panel.php
r3707909 r3755015 20 20 $wccp_free_ac_labels = wccp_free_activity_labels(); 21 21 $wccp_free_ac_started = wccp_free_activity_started(); 22 $wccp_free_ac_upgrade = add_query_arg(array('utm_source' => 'plugin', 'utm_medium' => 'protection-center'), $wccp_free_pro_url);23 22 24 23 if (! function_exists('wccp_free_ac_num')) { … … 166 165 <p><?php esc_html_e('See 30 days, 90 days or 12 months of activity, spot seasonal peaks and follow how each page trends over time.', 'wp-content-copy-protector'); ?></p> 167 166 </div> 168 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_ac_upgrade); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('See PRO', 'wp-content-copy-protector'); ?></a>167 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('protection-center-history-btn-primary')); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('See PRO', 'wp-content-copy-protector'); ?></a> 169 168 </div> 170 169 </div> … … 401 400 </div> 402 401 <div class="wpb-ac-hint__acts"> 403 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_ac_upgrade); ?>"><?php echo esc_html($wccp_free_ac_hint['cta']); ?></a>402 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('protection-center-hint-btn-primary')); ?>"><?php echo esc_html($wccp_free_ac_hint['cta']); ?></a> 404 403 <button type="button" class="wpb-btn wpb-btn--quiet" data-ac-hide-hint><?php esc_html_e('Not now', 'wp-content-copy-protector'); ?></button> 405 404 </div> -
wp-content-copy-protector/trunk/activity.php
r3707909 r3755015 656 656 $table = wccp_free_activity_table(); 657 657 658 // hits is not in the primary key, so sorting by (hour, hits) over the whole 659 // table forces a filesort. Pin the latest hour via the index, then rank only its rows. 658 660 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- Own table, no input. 659 $row = $wpdb->get_row("SELECT hour, object_id FROM $table ORDER BY hour DESC,hits DESC LIMIT 1", ARRAY_A);661 $row = $wpdb->get_row("SELECT hour, object_id FROM $table WHERE hour = (SELECT MAX(hour) FROM $table) ORDER BY hits DESC LIMIT 1", ARRAY_A); 660 662 661 663 if (! $row) { -
wp-content-copy-protector/trunk/admin-bar-insights.php
r3707909 r3755015 3 3 /** 4 4 * Admin bar insights: the card that opens when an admin hovers the plugin's 5 * admin bar icon inside wp-admin. 5 * admin bar icon, in wp-admin and on the front end, plus the "new errors" 6 * count shown on the icon. 6 7 * 7 8 * It is a teaser, not a report: one headline number, a 7 day sparkline, error … … 22 23 * - nothing is computed while a page loads except the icon dot, which reads 23 24 * the same cached count as the admin menu bubble and a stored error snapshot 24 * (rate-limited, see wccp_free_abi_dot()); 25 * (rate-limited, see wccp_free_abi_dot()), and the error count, which reads 26 * that stored snapshot too; a stale snapshot is refreshed over admin-ajax 27 * after the page has loaded (wccp_free_abi_ajax_count()); 25 28 * - the card's data comes over admin-ajax on first hover, cached per user for 26 29 * WCCP_FREE_ABI_CACHE; log files are read at most every WCCP_FREE_ABI_ERR_TTL. … … 38 41 39 42 /** 40 * Can the current screen show the card at all? 43 * Can the current screen show the card at all? wp-admin and the front end alike. 41 44 */ 42 45 function wccp_free_abi_available() … … 44 47 global $wccp_settings; 45 48 46 if (! is_admin () || ! is_admin_bar_showing() || ! current_user_can('manage_options')) {49 if (! is_admin_bar_showing() || is_customize_preview() || ! current_user_can('manage_options')) { 47 50 return false; 48 51 } … … 208 211 209 212 /** 213 * The icon's error count: issues new since the admin last opened the Error 214 * Monitor (or in the last 24 hours), the same number as the card's "New 215 * issues" tile. Reads the stored snapshot only, so it can run on every page. 216 * 217 * @param bool $fresh Rescan the logs if the snapshot is stale (admin-ajax only). 218 * @return array{count:int, stale:bool, text:string, label:string} 219 */ 220 function wccp_free_abi_error_badge($fresh = false) 221 { 222 $snapshot = wccp_free_abi_errors($fresh); 223 $count = 0; 224 $stale = true; 225 226 if (is_array($snapshot)) { 227 $today = (new DateTime('now', wccp_free_em_site_zone()))->format('Y-m-d'); 228 $stale = $snapshot['day'] !== $today || $snapshot['time'] <= time() - WCCP_FREE_ABI_ERR_TTL; 229 $count = wccp_free_abi_new_issues($snapshot, (int) get_user_meta(get_current_user_id(), 'wccp_free_em_seen', true)); 230 } 231 232 return array( 233 'count' => $count, 234 'stale' => $stale, 235 'text' => $count > 99 ? '99+' : number_format_i18n($count), 236 /* translators: %s: number of new error issues. */ 237 'label' => sprintf(_n('%s new error', '%s new errors', $count, 'wp-content-copy-protector'), number_format_i18n($count)), 238 ); 239 } 240 241 /** 210 242 * Numbers and stories from the error logs. 211 243 * … … 777 809 778 810 /** 811 * The page rendered the error count from a stale snapshot: rescan (at most 812 * every WCCP_FREE_ABI_ERR_TTL, shared by every admin) and return the new count. 813 */ 814 function wccp_free_abi_ajax_count() 815 { 816 check_ajax_referer('wccp_free_abi'); 817 818 if (! wccp_free_em_can()) { 819 wp_send_json_error(null, 403); 820 } 821 822 $badge = wccp_free_abi_error_badge(true); 823 unset($badge['stale']); 824 825 // The card's cached tiles predate the rescan. 826 wccp_free_abi_forget(); 827 828 wp_send_json_success($badge); 829 } 830 add_action('wp_ajax_wccp_free_abi_count', 'wccp_free_abi_ajax_count'); 831 832 /** 833 * Append the error count to the plugin's admin bar item. The element is always 834 * there (hidden at 0) so the script can fill it after a refresh. 835 */ 836 function wccp_free_abi_bar_count($admin_bar) 837 { 838 if (! wccp_free_abi_available() || ! wccp_free_em_can()) { 839 return; 840 } 841 842 $node = $admin_bar->get_node('wccp_free_top_button'); 843 if (! $node) { 844 return; 845 } 846 847 $badge = wccp_free_abi_error_badge(); 848 849 $admin_bar->add_node(array( 850 'id' => 'wccp_free_top_button', 851 'title' => $node->title . sprintf( 852 '<span class="wccp-abi-count count-%1$d"><span aria-hidden="true">%2$s</span><span class="screen-reader-text">%3$s</span></span>', 853 $badge['count'], 854 esc_html($badge['text']), 855 esc_html($badge['label']) 856 ), 857 )); 858 } 859 add_action('admin_bar_menu', 'wccp_free_abi_bar_count', 41); 860 861 /** 779 862 * Should the icon carry a "something new" dot on this page load? 780 863 * … … 857 940 } 858 941 859 function wccp_free_abi_enqueue($hook) 860 { 861 // The plugin page itself is where the card would send you. 862 if ($hook === 'toplevel_page_wccpoptionspro' || ! wccp_free_abi_available()) { 942 /** 943 * @param string $hook Admin page hook; empty on the front end. 944 */ 945 function wccp_free_abi_enqueue($hook = '') 946 { 947 if (! wccp_free_abi_available()) { 863 948 return; 864 949 } 865 950 951 // The error count is on every page. 866 952 wp_enqueue_style( 867 953 'wccp-admin-bar-insights', … … 870 956 WCCP_FREE_VERSION 871 957 ); 958 959 // The plugin page itself is where the card would send you. 960 if ($hook === 'toplevel_page_wccpoptionspro') { 961 return; 962 } 963 964 $badge = wccp_free_em_can() ? wccp_free_abi_error_badge() : null; 872 965 873 966 wp_enqueue_script( … … 883 976 'nonce' => wp_create_nonce('wccp_free_abi'), 884 977 'dot' => wccp_free_abi_dot(), 978 'stale' => $badge && $badge['stale'], 885 979 'i18n' => array( 886 980 'loading' => __('Loading your numbers…', 'wp-content-copy-protector'), … … 895 989 } 896 990 add_action('admin_enqueue_scripts', 'wccp_free_abi_enqueue', 30); 991 add_action('wp_enqueue_scripts', 'wccp_free_abi_enqueue', 30); -
wp-content-copy-protector/trunk/admin-core.php
r3707909 r3755015 212 212 213 213 $wccp_free_admin_email = get_bloginfo('admin_email'); 214 $wccp_free_pro_url = 'https://www.wp-buy.com/product/wp-content-copy-protection-pro/';214 $wccp_free_pro_url = WCCP_FREE_PRO_URL; 215 215 $wccp_free_docs_url = 'https://www.wp-buy.com/category/plugins-support/copy-protection-plugin-support/'; 216 216 $wccp_free_support_url = 'https://www.wp-buy.com/contact-us/'; … … 244 244 if (localStorage.getItem('wpccp_subscribed') != 'wpccp_subsbc_user') { 245 245 var admin_email_wccp = document.getElementById('admin_email_wccp').value; 246 window.open( 'https://www.wp-buy.com/wpccp-subscribe/?email=' + admin_email_wccp, '_blank');246 window.open(<?php echo wp_json_encode(wccp_free_utm_url('header-subscribe-popup')); ?> + '&email=' + encodeURIComponent(admin_email_wccp), '_blank'); 247 247 } 248 248 } … … 289 289 <div class="wpb-featured__buy"> 290 290 <div class="wpb-featured__price"><?php esc_html_e('Live Demo', 'wp-content-copy-protector'); ?></div> 291 <a class="wpb-featured__btn" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php esc_html_e('View Details', 'wp-content-copy-protector'); ?></a>291 <a class="wpb-featured__btn" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('header-featured-banner-btn')); ?>"><?php esc_html_e('View Details', 'wp-content-copy-protector'); ?></a> 292 292 <span class="wpb-featured__mbg"><?php esc_html_e('30-Day Money Back', 'wp-content-copy-protector'); ?></span> 293 293 </div> … … 383 383 <span class="wpb-field__label"><?php echo wp_kses(__('Exclude <u>Admin</u> from protection', 'wp-content-copy-protector'), $wccp_free_allowed_tags); ?></span> 384 384 <span class="wpb-field__locked"> 385 <a class="wpb-tag wpb-tag--pro" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Premium', 'wp-content-copy-protector'); ?></a>385 <a class="wpb-tag wpb-tag--pro" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('main-settings-btn-exclude-admin')); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Premium', 'wp-content-copy-protector'); ?></a> 386 386 </span> 387 387 <p class="wpb-field__hint"><?php echo wp_kses(__('If <u>Yes</u>, The protection functions will be inactive for the admin when he is logged in', 'wp-content-copy-protector'), $wccp_free_allowed_tags); ?></p> … … 405 405 <span class="wpb-chip"><?php wccp_free_icon('phone'); ?><?php esc_html_e('Desktop & mobile', 'wp-content-copy-protector'); ?></span> 406 406 </div> 407 <a class="wpb-btn wpb-btn--ghost" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('Unlock more options', 'wp-content-copy-protector'); ?></a>407 <a class="wpb-btn wpb-btn--ghost" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('main-settings-btn-unlock-options')); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('Unlock more options', 'wp-content-copy-protector'); ?></a> 408 408 </div> 409 409 </div> … … 451 451 <span class="wpb-field__label"><?php echo wp_kses(__('Disable <u>RightClick</u> on', 'wp-content-copy-protector'), $wccp_free_allowed_tags); ?></span> 452 452 <span class="wpb-field__locked"> 453 <a class="wpb-tag wpb-tag--pro" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Any post type', 'wp-content-copy-protector'); ?></a>453 <a class="wpb-tag wpb-tag--pro" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('rightclick-tag-pro-post-types')); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Any post type', 'wp-content-copy-protector'); ?></a> 454 454 </span> 455 455 <p class="wpb-field__hint"><?php echo wp_kses(__('<b>PRO</b> unlocks the same right-click lock on <u>any</u> post type you pick - WooCommerce products, listings, portfolios, courses, downloads. Sell on a marketplace? Your product photos and descriptions stop being one right-click away from a competitor.', 'wp-content-copy-protector'), $wccp_free_allowed_tags); ?></p> … … 467 467 468 468 <div class="wpb-shots"> 469 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>">469 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('rightclick-premium-preview-image')); ?>"> 470 470 <img src="<?php echo esc_url($wccp_free_pluginsurl); ?>/images/right-click-protection.webp" alt="<?php esc_attr_e('Right click protection options in the PRO version', 'wp-content-copy-protector'); ?>"> 471 471 </a> … … 476 476 <span class="wpb-chip"><?php wccp_free_icon('star'); ?><?php esc_html_e('Preview & Pricing', 'wp-content-copy-protector'); ?></span> 477 477 </div> 478 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('Get the PRO version', 'wp-content-copy-protector'); ?></a>478 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('rightclick-btn-primary-get-pro')); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('Get the PRO version', 'wp-content-copy-protector'); ?></a> 479 479 </div> 480 480 </div> … … 510 510 <span class="wpb-field__label"><?php echo wp_kses(__('<b>Pages</b> Protection by CSS', 'wp-content-copy-protector'), $wccp_free_allowed_tags); ?></span> 511 511 <span class="wpb-field__locked"> 512 <a class="wpb-tag wpb-tag--pro" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Premium', 'wp-content-copy-protector'); ?></a>512 <a class="wpb-tag wpb-tag--pro" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('css-protection-tag-pro')); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Premium', 'wp-content-copy-protector'); ?></a> 513 513 </span> 514 514 <p class="wpb-field__hint"><?php esc_html_e('Protect your static pages by CSS tricks', 'wp-content-copy-protector'); ?></p> … … 520 520 <span class="wpb-chip wpb-chip--safe"><?php wccp_free_icon('check'); ?><?php esc_html_e('Keeps working with JavaScript disabled', 'wp-content-copy-protector'); ?></span> 521 521 </div> 522 <a class="wpb-btn wpb-btn--ghost" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Unlock pages protection', 'wp-content-copy-protector'); ?></a>522 <a class="wpb-btn wpb-btn--ghost" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('css-protection-btn-unlock-pages')); ?>"><?php wccp_free_icon('lock'); ?><?php esc_html_e('Unlock pages protection', 'wp-content-copy-protector'); ?></a> 523 523 </div> 524 524 </div> … … 700 700 <!-- Icons the script clones into the markup it builds. --> 701 701 <template id="wpb-em-icons"> 702 <?php foreach (array('alert', 'check', 'info', 'clock', 'message', 'download', 'trash', 'server', 'file', 'copy' ) as $wccp_free_em_icon) : ?>702 <?php foreach (array('alert', 'check', 'info', 'clock', 'message', 'download', 'trash', 'server', 'file', 'copy', 'sparkles', 'lock') as $wccp_free_em_icon) : ?> 703 703 <span data-icon="<?php echo esc_attr($wccp_free_em_icon); ?>"><?php wccp_free_icon($wccp_free_em_icon); ?></span> 704 704 <?php endforeach; ?> … … 743 743 744 744 <div class="wpb-shots"> 745 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>">745 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-shot-smartphones')); ?>"> 746 746 <img src="<?php echo esc_url($wccp_free_pluginsurl); ?>/images/smart-phones-protection.webp" alt="<?php esc_attr_e('Smartphone protection in the PRO version', 'wp-content-copy-protector'); ?>"> 747 747 </a> 748 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>">748 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-shot-watermark')); ?>"> 749 749 <img src="<?php echo esc_url($wccp_free_pluginsurl); ?>/images/watermark-adv.webp" alt="<?php esc_attr_e('Image watermarking in the PRO version', 'wp-content-copy-protector'); ?>"> 750 750 </a> 751 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>">751 <a class="wpb-shot" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-shot-watermark-examples')); ?>"> 752 752 <img src="<?php echo esc_url($wccp_free_pluginsurl); ?>/images/watermarking-adv-examples.webp" alt="<?php esc_attr_e('Watermarking examples from the PRO version', 'wp-content-copy-protector'); ?>"> 753 753 </a> … … 760 760 <span class="wpb-chip"><?php wccp_free_icon('star'); ?><?php esc_html_e('Rated 4.9 by hundreds', 'wp-content-copy-protector'); ?></span> 761 761 </div> 762 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('See it now', 'wp-content-copy-protector'); ?></a>762 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-btn-primary-see-it-now')); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('See it now', 'wp-content-copy-protector'); ?></a> 763 763 </div> 764 764 </div> … … 784 784 <span class="wpb-plans__promo-ic"><?php wccp_free_icon('zap'); ?></span> 785 785 <p class="wpb-plans__promo-txt"> 786 <b><?php esc_html_e('These are the full prices, with no discount applied.', 'wp-content-copy-protector'); ?></b>787 786 <?php esc_html_e('A discount of up to 50% is waiting for you on our website - check the running offer before you buy.', 'wp-content-copy-protector'); ?> 788 787 </p> … … 800 799 </div> 801 800 802 <p class="wpb-plan__price"> 803 <span class="wpb-plan__amount"><span class="wpb-plan__cur">$</span>0</span> 804 <span class="wpb-plan__per"><?php esc_html_e('/ forever', 'wp-content-copy-protector'); ?></span> 805 </p> 806 <span class="wpb-tag wpb-tag--free wpb-plan__badge"><?php wccp_free_icon('check'); ?><?php esc_html_e('Current plan', 'wp-content-copy-protector'); ?></span> 801 <p class="wpb-plan__pitch"><?php esc_html_e('Everyday protection that keeps casual copying off your pages.', 'wp-content-copy-protector'); ?></p> 802 <span class="wpb-tag wpb-tag--free wpb-plan__badge"><?php wccp_free_icon('check'); ?><?php esc_html_e('Current plan / forever', 'wp-content-copy-protector'); ?></span> 807 803 808 804 <ul class="wpb-plan__list"> … … 826 822 </div> 827 823 828 <p class="wpb-plan__price"> 829 <span class="wpb-plan__amount"><span class="wpb-plan__cur">$</span>58</span> 830 <span class="wpb-plan__per"><?php esc_html_e('one-time', 'wp-content-copy-protector'); ?></span> 831 </p> 832 <span class="wpb-tag wpb-tag--layer wpb-plan__badge"><?php wccp_free_icon('clock'); ?><?php esc_html_e('Lifetime license', 'wp-content-copy-protector'); ?></span> 824 <p class="wpb-plan__pitch"><?php esc_html_e('Take full command of who sees, copies and prints your content.', 'wp-content-copy-protector'); ?></p> 825 <span class="wpb-tag wpb-tag--layer wpb-plan__badge"><?php wccp_free_icon('clock'); ?><?php esc_html_e('Lifetime license / one time payment', 'wp-content-copy-protector'); ?></span> 833 826 <p class="wpb-plan__care"><?php wccp_free_icon('refresh'); ?><?php esc_html_e('Support & updates $1 / month, paid as $9 per year.', 'wp-content-copy-protector'); ?></p> 834 827 … … 843 836 </ul> 844 837 845 <a class="wpb-btn wpb-btn--ghost wpb-plan__cta" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php esc_html_e('Upgrade to ESSENTIAL', 'wp-content-copy-protector'); ?></a>838 <a class="wpb-btn wpb-btn--ghost wpb-plan__cta" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-plan-essential-btn')); ?>"><?php esc_html_e('Explore the essential version', 'wp-content-copy-protector'); ?></a> 846 839 </div> 847 840 … … 857 850 </div> 858 851 859 <p class="wpb-plan__price"> 860 <span class="wpb-plan__amount"><span class="wpb-plan__cur">$</span>98</span> 861 <span class="wpb-plan__per"><?php esc_html_e('one-time', 'wp-content-copy-protector'); ?></span> 862 </p> 863 <span class="wpb-tag wpb-tag--layer wpb-plan__badge"><?php wccp_free_icon('clock'); ?><?php esc_html_e('Lifetime license', 'wp-content-copy-protector'); ?></span> 852 <p class="wpb-plan__pitch"><?php esc_html_e('Every protection layer, plus watermarks that follow your work everywhere.', 'wp-content-copy-protector'); ?></p> 853 <span class="wpb-tag wpb-tag--layer wpb-plan__badge"><?php wccp_free_icon('clock'); ?><?php esc_html_e('Lifetime license / one time payment', 'wp-content-copy-protector'); ?></span> 864 854 <p class="wpb-plan__care"><?php wccp_free_icon('refresh'); ?><?php esc_html_e('Support & updates $1 / month, paid as $9 per year.', 'wp-content-copy-protector'); ?></p> 865 855 … … 877 867 </ul> 878 868 879 <a class="wpb-btn wpb-btn--primary wpb-plan__cta" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php esc_html_e('Upgrade to COMPLETE', 'wp-content-copy-protector'); ?></a>869 <a class="wpb-btn wpb-btn--primary wpb-plan__cta" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-plan-complete-btn')); ?>"><?php esc_html_e('Explore the complete version', 'wp-content-copy-protector'); ?></a> 880 870 </div> 881 871 … … 1052 1042 /* translators: %s: link to the mailing list sign-up page. */ 1053 1043 esc_html__('%s to our mailing list to get flash discounts', 'wp-content-copy-protector'), 1054 '<a target="_blank" rel="noopener" href=" https://www.wp-buy.com/wpccp-subscribe">' . esc_html__('Subscribe', 'wp-content-copy-protector') . '</a>'1044 '<a target="_blank" rel="noopener" href="' . esc_url(wccp_free_utm_url('more-pro-footer-subscribe-link', 'https://www.wp-buy.com/wpccp-subscribe/')) . '">' . esc_html__('Subscribe', 'wp-content-copy-protector') . '</a>' 1055 1045 ); 1056 1046 ?> 1057 1047 </p> 1058 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url( $wccp_free_pro_url); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('See the premium plans', 'wp-content-copy-protector'); ?></a>1048 <a class="wpb-btn wpb-btn--primary" target="_blank" rel="noopener" href="<?php echo esc_url(wccp_free_utm_url('more-pro-footer-btn-primary-plans')); ?>"><?php wccp_free_icon('sparkles'); ?><?php esc_html_e('See the premium plans', 'wp-content-copy-protector'); ?></a> 1059 1049 </div> 1060 1050 </div> -
wp-content-copy-protector/trunk/css/admin-bar-insights.css
r3707909 r3755015 52 52 } 53 53 54 /* On the front end the theme's styles apply too. */ 55 #wccp-abi { 56 text-align: start; 57 letter-spacing: normal; 58 text-transform: none; 59 } 60 61 #wccp-abi li { 62 list-style: none; 63 } 64 65 #wccp-abi li::before, 66 #wccp-abi li::after { 67 content: none; 68 } 69 70 #wccp-abi a { 71 border: 0; 72 box-shadow: none; 73 } 74 54 75 /* Hover bridge over the gap between the icon and the card. */ 55 76 #wccp-abi::after { … … 421 442 } 422 443 444 /* New errors since the Error Monitor was last opened. */ 445 #wpadminbar #wp-admin-bar-wccp_free_top_button .wccp-abi-count { 446 display: inline-block; 447 box-sizing: border-box; 448 min-width: 18px; 449 height: 18px; 450 margin-inline-start: 6px; 451 padding: 0 5px; 452 border-radius: 9px; 453 background: #d63638; 454 color: #fff; 455 font-size: 11px; 456 font-weight: 600; 457 line-height: 18px; 458 text-align: center; 459 vertical-align: middle; 460 } 461 462 /* #wpadminbar * sets a 32px line-height and 13px font on every element. */ 463 #wpadminbar #wp-admin-bar-wccp_free_top_button .wccp-abi-count > span[aria-hidden] { 464 display: block; 465 color: inherit; 466 font-size: inherit; 467 font-weight: inherit; 468 line-height: inherit; 469 } 470 471 #wpadminbar #wp-admin-bar-wccp_free_top_button .wccp-abi-count.count-0 { 472 display: none; 473 } 474 475 /* Pulsing yellow ring around the item while the error count is above 0. 476 Driven by the count's class, so it follows the AJAX refresh too; the 477 upgrade hint's purple ring takes precedence while that card is open. */ 478 #wpadminbar #wp-admin-bar-wccp_free_top_button:not(.wccp-hint-target) > .ab-item:has(.wccp-abi-count:not(.count-0)) { 479 position: relative; 480 } 481 482 #wpadminbar #wp-admin-bar-wccp_free_top_button:not(.wccp-hint-target) > .ab-item:has(.wccp-abi-count:not(.count-0))::after { 483 content: ""; 484 position: absolute; 485 inset: 3px; 486 border-radius: 6px; 487 box-shadow: 0 0 0 0 rgba(250, 204, 21, .9); 488 animation: wccp-abi-alert 10s ease-out infinite; 489 pointer-events: none; 490 } 491 423 492 #wpadminbar #wp-admin-bar-wccp_free_top_button.wccp-abi-open > .ab-item { 424 493 background: #2c3338; 425 494 color: #72aee6; 495 } 496 497 /* Keep the item still on the plugin's own settings page (every tab): the 498 admin is already where the ring and dot are pointing. */ 499 body.toplevel_page_wccpoptionspro #wpadminbar #wp-admin-bar-wccp_free_top_button .wccp-abi-dot, 500 body.toplevel_page_wccpoptionspro #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item, 501 body.toplevel_page_wccpoptionspro #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item::after { 502 animation: none !important; 503 transition: none !important; 504 } 505 506 body.toplevel_page_wccpoptionspro #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item::after { 507 box-shadow: none !important; 426 508 } 427 509 … … 441 523 70% { box-shadow: 0 0 0 2px #1d2327, 0 0 0 9px rgba(249, 115, 22, 0); } 442 524 100% { box-shadow: 0 0 0 2px #1d2327, 0 0 0 2px rgba(249, 115, 22, 0); } 525 } 526 527 /* Two 1.6s pulses back to back, then rest until the 10s cycle repeats. */ 528 @keyframes wccp-abi-alert { 529 0%, 16% { box-shadow: 0 0 0 0 rgba(250, 204, 21, .9); } 530 11.2%, 27.2% { box-shadow: 0 0 0 10px rgba(250, 204, 21, 0); } 531 15.9%, 32%, 100% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0); } 443 532 } 444 533 … … 460 549 #wccp-abi .wccp-abi__pulse, 461 550 #wccp-abi .wccp-abi__skeleton, 462 #wpadminbar #wp-admin-bar-wccp_free_top_button .wccp-abi-dot { 551 #wpadminbar #wp-admin-bar-wccp_free_top_button .wccp-abi-dot, 552 #wpadminbar #wp-admin-bar-wccp_free_top_button:not(.wccp-hint-target) > .ab-item:has(.wccp-abi-count:not(.count-0))::after { 463 553 animation: none; 464 554 transition: none; -
wp-content-copy-protector/trunk/css/error-monitor.css
r3707909 r3755015 546 546 } 547 547 548 /* "Ask AI for help" PRO teaser - the amber .wpb-tag--pro chip, with the 549 lock dimmed like the locked range buttons in the Protection Center. */ 550 #wpb-admin .wpb-em-issue__ai { 551 flex-shrink: 0; 552 margin-top: 1px; 553 } 554 555 #wpb-admin .wpb-em-issue__ai:focus-visible { 556 outline: 2px solid var(--wpb-primary); 557 outline-offset: 2px; 558 } 559 560 /* Unlocked rows: the same chip as a real button that copies the AI prompt. */ 561 #wpb-admin .wpb-em-issue__ai--free { 562 border: 0; 563 font-family: inherit; 564 line-height: inherit; 565 cursor: pointer; 566 } 567 568 #wpb-admin .wpb-em-issue__ai--free:hover { 569 background: rgba(108, 99, 255, .18); 570 } 571 572 #wpb-admin .wpb-em-issue__ai--free.wpb-tag--free:hover { 573 background: rgba(16, 185, 129, .2); 574 } 575 576 #wpb-admin .wpb-em-issue__ai--free svg { 577 width: 12px; 578 height: 12px; 579 } 580 581 #wpb-admin .wpb-tag--pro.wpb-em-issue__ai svg:last-child { 582 width: 11px; 583 height: 11px; 584 opacity: .7; 585 } 586 548 587 .wpb-em-issue__count strong { 549 588 display: inline-block; … … 894 933 .wpb-em-issue__sum { 895 934 gap: 8px; 935 flex-wrap: wrap; 936 } 937 938 .wpb-em-issue__main { 939 flex-basis: 100%; 940 } 941 942 #wpb-admin .wpb-em-issue__ai { 943 margin-inline-start: auto; 896 944 } 897 945 -
wp-content-copy-protector/trunk/css/wpb-admin.css
r3693765 r3755015 1249 1249 } 1250 1250 1251 #wpb-admin .wpb-plan__price { 1252 display: flex; 1253 align-items: baseline; 1254 gap: 6px; 1255 flex-wrap: wrap; 1256 margin: 0 0 12px; 1251 /* One-line pitch under the plan title - accent rule on the left, no prices. */ 1252 #wpb-admin .wpb-plan__pitch { 1253 margin: 0 0 14px; 1254 padding-left: 10px; 1255 border-left: 3px solid var(--wpb-border-soft); 1256 font-size: .84rem; 1257 font-weight: 600; 1258 line-height: 1.45; 1257 1259 color: var(--wpb-secondary); 1258 1260 } 1259 1261 1260 .wpb-plan__from, 1261 .wpb-plan__per { 1262 font-size: .78rem; 1263 font-weight: 600; 1264 color: var(--wpb-text-secondary); 1265 } 1266 1267 .wpb-plan__amount { 1268 font-size: 1.7rem; 1269 font-weight: 800; 1270 letter-spacing: -0.02em; 1271 line-height: 1.1; 1272 } 1273 1274 .wpb-plan__cur { 1275 font-size: 1.05rem; 1276 font-weight: 700; 1277 margin-right: 1px; 1278 } 1279 1262 #wpb-admin .wpb-plan--popular .wpb-plan__pitch { 1263 border-left-color: var(--wpb-primary); 1264 } 1265 1266 /* Longer badge copy may wrap in narrow columns instead of overflowing the card. */ 1280 1267 #wpb-admin .wpb-plan__badge { 1281 1268 align-self: flex-start; 1282 margin: -4px 0 12px; 1283 } 1284 1285 /* Lifetime licences still carry an optional support line - it sits under the price. */ 1269 max-width: 100%; 1270 margin: 0 0 12px; 1271 white-space: normal; 1272 line-height: 1.35; 1273 border-radius: 12px; 1274 } 1275 1276 /* Lifetime licences still carry an optional support line - it sits under the badge. */ 1286 1277 #wpb-admin .wpb-plan__care { 1287 1278 display: flex; -
wp-content-copy-protector/trunk/error-monitor.php
r3707909 r3755015 234 234 $names = array(); 235 235 foreach (get_plugins() as $plugin_file => $plugin) { 236 $names[strtolower(strtok($plugin_file, '/'))] = $plugin['Name'];236 $names[strtolower(strtok($plugin_file, '/'))] = array($plugin['Name'], $plugin['Version']); 237 237 } 238 238 $mu_names = array(); 239 239 foreach (get_mu_plugins() as $plugin_file => $plugin) { 240 $mu_names[strtolower($plugin_file)] = $plugin['Name'];240 $mu_names[strtolower($plugin_file)] = array($plugin['Name'], $plugin['Version']); 241 241 } 242 242 … … 267 267 $low = strtolower($slug); 268 268 269 if ($kind === 'plugin') { 270 $name = isset($cache['plugins'][$low]) ? $cache['plugins'][$low] : $slug; 271 } elseif ($kind === 'mu') { 272 $name = isset($cache['mu'][$low]) ? $cache['mu'][$low] : $slug; 269 $name = $slug; 270 $version = ''; 271 272 if ($kind === 'theme') { 273 $theme = wp_get_theme($slug); 274 if ($theme->exists()) { 275 $name = $theme->get('Name'); 276 $version = $theme->get('Version'); 277 } 273 278 } else { 274 $theme = wp_get_theme($slug); 275 $name = $theme->exists() ? $theme->get('Name') : $slug; 276 } 277 278 return array('key' => $kind . ':' . $low, 'kind' => $kind, 'name' => $name); 279 $known = $kind === 'plugin' ? $cache['plugins'] : $cache['mu']; 280 if (isset($known[$low])) { 281 list($name, $version) = $known[$low]; 282 } 283 } 284 285 // The version goes into the "Ask AI for help" prompt. 286 return array('key' => $kind . ':' . $low, 'kind' => $kind, 'name' => $name, 'version' => (string) $version); 279 287 } 280 288 … … 638 646 'locale' => str_replace('_', '-', get_user_locale()), 639 647 'tailLabel' => size_format(WCCP_FREE_EM_TAIL_BYTES), 648 'proUrl' => wccp_free_utm_url('error-monitor-ai-analysis-link'), 649 // Site facts for the "Ask AI for help" prompt. 650 'env' => array( 651 'wp' => get_bloginfo('version'), 652 'php' => PHP_VERSION, 653 'theme' => trim(wp_get_theme()->get('Name') . ' ' . wp_get_theme()->get('Version')), 654 'multisite' => is_multisite(), 655 ), 640 656 'i18n' => array( 641 657 'levels' => array( … … 701 717 'copy' => __('Copy', 'wp-content-copy-protector'), 702 718 'copied' => __('Copied', 'wp-content-copy-protector'), 719 'askAi' => __('Ask AI for help', 'wp-content-copy-protector'), 720 'askAiPro' => __('PRO feature - get an AI explanation and fix for this error', 'wp-content-copy-protector'), 721 'askAiFree' => __('Copy a ready-made prompt about this error, then paste it into ChatGPT, Claude or any AI assistant', 'wp-content-copy-protector'), 722 'aiCopied' => __('Ready prompt copied', 'wp-content-copy-protector'), 723 'aiCopyFailed' => __('Copy failed', 'wp-content-copy-protector'), 724 'yes' => __('yes', 'wp-content-copy-protector'), 725 'no' => __('no', 'wp-content-copy-protector'), 726 'aiNotGiven' => __('not given in the log', 'wp-content-copy-protector'), 727 /* translators: 1: file path, 2: line number. */ 728 'aiFileLine' => __('%1$s (line %2$s)', 'wp-content-copy-protector'), 729 /* translators: 1: plugin or theme name, 2: kind, e.g. "Plugin", 3: version number. */ 730 'aiSourceVer' => __('%1$s (%2$s, version %3$s)', 'wp-content-copy-protector'), 731 /* translators: 1: plugin or theme name, 2: kind, e.g. "Plugin". */ 732 'aiSourceKind' => __('%1$s (%2$s)', 'wp-content-copy-protector'), 733 'aiOnce' => __('once', 'wp-content-copy-protector'), 734 /* translators: %s: number of times (2 or more). */ 735 'aiTimes' => __('%s times', 'wp-content-copy-protector'), 736 /* translators: 1: e.g. "20 times", 2: number of days, 3: e.g. "35 times". */ 737 'aiOften' => __('%1$s in the last %2$s days (%3$s in the whole log)', 'wp-content-copy-protector'), 738 /* translators: The prompt copied by the "Ask AI for help" button. Keep the {placeholders} and line breaks unchanged. */ 739 'aiPrompt' => __("I run a WordPress website and its error log shows the PHP error below. Please help me understand it and fix it.\n\n== Error details ==\nSeverity: {severity}\nMessage:\n{message}\nFile: {file}\nComes from: {source}\nHow often: {often}\nFirst seen: {first}\nLast seen: {last}\n\n== Site environment ==\nWordPress version: {wp}\nPHP version: {php}\nActive theme: {theme}\nMultisite: {multisite}\n\n== What I need from you ==\n1. Explain in plain language what this error means and whether it can break my site or is only a warning.\n2. Tell me the most likely cause, based on the message, the file and the plugin or theme it comes from.\n3. Give me a step-by-step fix, starting with the safest options (updating, reconfiguring or replacing the plugin/theme) before any code change.\n4. If a code change is really needed, show the exact change, which file to edit, and how to back up the site first. Prefer a fix that survives plugin/theme updates (a child theme or a small custom plugin) over editing the original files.\n5. Tell me how to check that the error is gone and how to stop it from coming back.\n6. If you need more information (for example the code around that line or a full stack trace), tell me exactly what to send you.\n\nThis error was detected by the WP Content Copy Protection & No Right Click free WordPress plugin.", 'wp-content-copy-protector'), 703 740 ), 704 741 )); -
wp-content-copy-protector/trunk/js/admin-bar-insights.js
r3707909 r3755015 22 22 return; 23 23 } 24 25 // Error count rendered by wccp_free_abi_bar_count() (absent without Error Monitor access). 26 var badge = link.querySelector( '.wccp-abi-count' ); 27 var linkLabel = ( badge ? link.textContent.replace( badge.textContent, '' ) : link.textContent ).trim(); 24 28 25 29 var t = cfg.i18n; … … 200 204 card.id = 'wccp-abi'; 201 205 card.setAttribute( 'role', 'region' ); 202 card.setAttribute( 'aria-label', link .textContent.trim());206 card.setAttribute( 'aria-label', linkLabel ); 203 207 204 208 arrow = h( 'span', 'wccp-abi__arrow' ); … … 501 505 link.setAttribute( 'aria-expanded', 'false' ); 502 506 507 function badgeCount() { 508 return badge ? parseInt( badge.className.replace( /.*\bcount-(\d+).*/, '$1' ), 10 ) || 0 : 0; 509 } 510 511 // The page was rendered from an error snapshot older than its TTL: rescan after load. 512 if ( badge && cfg.stale ) { 513 var countParams = new URLSearchParams( { action: 'wccp_free_abi_count', _ajax_nonce: cfg.nonce } ); 514 515 window.fetch( cfg.ajaxUrl, { method: 'POST', credentials: 'same-origin', body: countParams } ) 516 .then( function ( response ) { 517 return response.json(); 518 } ) 519 .then( function ( json ) { 520 if ( ! json || ! json.success ) { 521 return; 522 } 523 badge.className = 'wccp-abi-count count-' + json.data.count; 524 badge.firstChild.textContent = json.data.text; 525 badge.lastChild.textContent = json.data.label; 526 } ) 527 .catch( function () {} ); 528 } 529 503 530 // cfg.dot: seconds the dot may still show in this hour's allowance. 504 if ( cfg.dot > 0 ) { 531 // A visible error count already says "something new". 532 if ( cfg.dot > 0 && ! badgeCount() ) { 505 533 var dot = h( 'span', 'wccp-abi-dot' ); 506 534 dot.setAttribute( 'role', 'img' ); -
wp-content-copy-protector/trunk/js/error-monitor.js
r3707909 r3755015 32 32 var LEVEL_ICONS = { fatal: 'alert', warning: 'alert', notice: 'info', deprecated: 'clock', other: 'message' }; 33 33 var PAGE = 25; 34 // "Ask AI for help" copies a prompt on this many top rows; the rest stay a PRO teaser. 35 var AI_FREE_ROWS = 3; 34 36 35 37 var state = { … … 816 818 } 817 819 820 function aiPrompt( row ) { 821 var issue = row.issue; 822 var env = cfg.env || {}; 823 var kind = t.kinds[ issue.source.kind ]; 824 var times = function ( n ) { 825 return n === 1 ? t.aiOnce : fill( t.aiTimes, num( n ) ); 826 }; 827 var source = issue.source.name; 828 829 if ( kind && issue.source.version ) { 830 source = fill( t.aiSourceVer, source, kind, issue.source.version ); 831 } else if ( kind ) { 832 source = fill( t.aiSourceKind, source, kind ); 833 } 834 835 var values = { 836 severity: t.levels[ issue.level ], 837 message: ( issue.type && issue.level === 'other' ? issue.type + ': ' : '' ) + issue.message, 838 file: issue.file ? ( issue.line ? fill( t.aiFileLine, issue.file, issue.line ) : issue.file ) : t.aiNotGiven, 839 source: source, 840 often: fill( t.aiOften, times( row.count ), num( state.range ), times( issue.count ) ), 841 first: issue.firstLabel, 842 last: issue.lastLabel, 843 wp: env.wp, 844 php: env.php, 845 theme: env.theme, 846 multisite: env.multisite ? t.yes : t.no 847 }; 848 849 // One pass, so a {token} inside a log message is never expanded. 850 return t.aiPrompt.replace( /\{(\w+)\}/g, function ( match, key ) { 851 return Object.prototype.hasOwnProperty.call( values, key ) ? String( values[ key ] ) : match; 852 } ); 853 } 854 855 // navigator.clipboard only exists on HTTPS / localhost; plain-http admins 856 // fall back to a hidden textarea and execCommand. 857 function copyText( text ) { 858 if ( navigator.clipboard && window.isSecureContext ) { 859 return navigator.clipboard.writeText( text ); 860 } 861 862 return new Promise( function ( resolve, reject ) { 863 var area = h( 'textarea' ); 864 865 area.value = text; 866 area.setAttribute( 'readonly', '' ); 867 area.style.position = 'fixed'; 868 area.style.top = '-1000px'; 869 document.body.appendChild( area ); 870 area.select(); 871 872 var ok = false; 873 874 try { 875 ok = document.execCommand( 'copy' ); 876 } catch ( e ) {} 877 878 document.body.removeChild( area ); 879 ( ok ? resolve : reject )(); 880 } ); 881 } 882 883 function aiButton( row ) { 884 var button = h( 'button', 'wpb-tag wpb-em-issue__ai wpb-em-issue__ai--free' ); 885 var label = h( 'span', '', t.askAi ); 886 887 button.type = 'button'; 888 button.title = t.askAiFree; 889 button.appendChild( icon( 'sparkles' ) ); 890 button.appendChild( label ); 891 892 button.addEventListener( 'click', function ( event ) { 893 // Inside <summary>: copy only, do not open/close the row. 894 event.preventDefault(); 895 event.stopPropagation(); 896 897 copyText( aiPrompt( row ) ).then( function () { 898 label.textContent = t.aiCopied; 899 button.classList.add( 'wpb-tag--free' ); 900 }, function () { 901 label.textContent = t.aiCopyFailed; 902 } ); 903 } ); 904 905 return button; 906 } 907 818 908 function renderIssues( rows ) { 819 909 clear( el.issues ); … … 846 936 } ); 847 937 848 rows.slice( 0, state.limit ).forEach( function ( row ) {938 rows.slice( 0, state.limit ).forEach( function ( row, index ) { 849 939 var issue = row.issue; 850 940 var item = h( 'li', 'wpb-em-issue wpb-em-issue--' + issue.level ); … … 874 964 count.appendChild( h( 'strong', '', '×' + num( row.count ) ) ); 875 965 966 var ai; 967 968 if ( index < AI_FREE_ROWS ) { 969 ai = aiButton( row ); 970 } else { 971 // PRO teaser: a plain link to the upgrade page. A link is 972 // interactive content, so clicking it does not toggle the row. 973 ai = h( 'a', 'wpb-tag wpb-tag--pro wpb-em-issue__ai' ); 974 ai.href = cfg.proUrl; 975 ai.target = '_blank'; 976 ai.rel = 'noopener'; 977 ai.title = t.askAiPro; 978 ai.appendChild( icon( 'sparkles' ) ); 979 ai.appendChild( document.createTextNode( t.askAi ) ); 980 ai.appendChild( icon( 'lock' ) ); 981 } 982 876 983 summary.appendChild( main ); 984 summary.appendChild( ai ); 877 985 summary.appendChild( count ); 878 986 details.appendChild( summary ); -
wp-content-copy-protector/trunk/preventer-index.php
r3707909 r3755015 4 4 Plugin URI: https://wordpress.org/plugins/wp-content-copy-protector/ 5 5 Description: This wp plugin protect the posts content from being copied by any other web site author , you dont want your content to spread without your permission!! 6 Version: 4. 26 Version: 4.3 7 7 Author: wp-buy 8 8 Text Domain: wp-content-copy-protector … … 17 17 //define all variables the needed alot 18 18 define('WCCP_FREE_PLUGIN_FILE', __FILE__); 19 define('WCCP_FREE_VERSION', '4.2'); // keep in sync with the plugin header above 19 define('WCCP_FREE_VERSION', '4.3'); // keep in sync with the plugin header above 20 define('WCCP_FREE_PRO_URL', 'https://www.wp-buy.com/product/wp-content-copy-protection-pro/'); 21 22 /** 23 * Tag a promotional link with a utm_element parameter so each click can be 24 * traced back to the button, tag or banner it came from. 25 * 26 * @param string $element Slug naming the element and where it sits (e.g. 'main-settings-btn-exclude-admin'). 27 * @param string $url Destination; defaults to the PRO product page. An existing query string is kept. 28 * @return string 29 */ 30 function wccp_free_utm_url($element, $url = WCCP_FREE_PRO_URL) 31 { 32 return add_query_arg('utm_element', sanitize_key($element), $url); 33 } 20 34 include 'the_globals.php'; 21 35 include_once('notifications.php'); … … 25 39 include_once('activity.php'); 26 40 include_once('admin-bar-insights.php'); 41 include_once('notice-filter.php'); 27 42 $wccp_settings = wccp_read_options(); 28 43 … … 79 94 function wccp_free_disable_right_click() 80 95 { 96 global $wccp_settings; 81 97 ?> 82 98 <script id="wpcp_disable_Right_Click" type="text/javascript"> 99 var wpcp_right_click_msg = "<?php echo esc_js($wccp_settings['smessage']); ?>"; 100 83 101 document.ondragstart = function() { 84 102 return false; … … 86 104 87 105 function nocontext(e) { 106 // show_wpcp_message() is printed in the footer, so guard against an early right click 107 if (typeof show_wpcp_message === "function") show_wpcp_message(wpcp_right_click_msg); 88 108 return false; 89 109 } … … 111 131 } 112 132 113 if (e.ctrlKey ) {133 if (e.ctrlKey || e.metaKey) { // metaKey = Cmd on macOS 114 134 var key; 115 135 if (window.event) … … 289 309 window.addEventListener("touchend", touchend, false); 290 310 }); 311 312 //Safari on macOS: a trackpad Force Click selects the word and opens Look Up 313 document.addEventListener("webkitmouseforcewillbegin", function(e) { 314 var elemtype = (e.target.nodeName || "").toUpperCase(); 315 if (elemtype == "TEXTAREA" || elemtype == "INPUT" || elemtype == "SELECT" || elemtype == "OPTION" || elemtype == "EMBED") return; 316 if (wccp_free_iscontenteditable(e)) return; 317 e.preventDefault(); 318 }, false); 291 319 292 320 function wccp_pro_is_passive() { … … 476 504 global $wccp_settings; 477 505 if (!wccp_free_visitor_is_protected()) return false; 478 if ((is_home() || is_front_page() || is_archive() || is_post_type_archive() || is_404() || is_attachment() || is_author() || is_category() || is_feed() ) && $wccp_settings['home_css_protection'] == 'Enabled') return true;506 if ((is_home() || is_front_page() || is_archive() || is_post_type_archive() || is_404() || is_attachment() || is_author() || is_category() || is_feed() || is_search()) && $wccp_settings['home_css_protection'] == 'Enabled') return true; 479 507 if (is_single() && $wccp_settings['posts_css_protection'] == 'Enabled') return true; 480 508 if (is_page() && !is_front_page() && $wccp_settings['pages_css_protection'] == 'Enabled') return true; … … 496 524 global $wccp_settings; 497 525 if (!wccp_free_visitor_is_protected()) return false; 498 if ((is_home() || is_front_page() || is_archive() || is_post_type_archive() || is_404() || is_attachment() || is_author() || is_category() || is_feed() ) && $wccp_settings['right_click_protection_homepage'] == 'checked') return true;526 if ((is_home() || is_front_page() || is_archive() || is_post_type_archive() || is_404() || is_attachment() || is_author() || is_category() || is_feed() || is_search()) && $wccp_settings['right_click_protection_homepage'] == 'checked') return true; 499 527 if (is_single() && $wccp_settings['right_click_protection_posts'] == 'checked') return true; 500 528 if (is_page() && !is_front_page() && $wccp_settings['right_click_protection_posts'] == 'checked') return true; … … 655 683 array_push($links, $settings_link); 656 684 657 $go_pro_link = '<a title="' . esc_attr__('Upgrade to PRO version Now', 'wp-content-copy-protector') . '" target="_blank" style="font-weight:bold;color: chocolate;" href=" https://www.wp-buy.com/product/wp-content-copy-protection-pro/">' . __('Go PRO', 'wp-content-copy-protector') . '</a>';685 $go_pro_link = '<a title="' . esc_attr__('Upgrade to PRO version Now', 'wp-content-copy-protector') . '" target="_blank" style="font-weight:bold;color: chocolate;" href="' . esc_url(wccp_free_utm_url('plugins-list-go-pro-link')) . '">' . __('Go PRO', 'wp-content-copy-protector') . '</a>'; 658 686 array_push($links, $go_pro_link); 659 687 … … 678 706 679 707 $class_name = sanitize_html_class(dirname($plugin_file)); 680 $p_url = 'https://www.wp-buy.com/product/wp-content-copy-protection-pro/';708 $p_url = wccp_free_utm_url('plugins-list-update-notice-cta'); 681 709 682 710 $messages = [ … … 924 952 transform: rotate(45deg); 925 953 } 954 955 /* Green glow while hovered, keyboard focused or its insights card is open. 956 Inset, so it stays inside the bar and never fights the ::after rings. */ 957 #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item, 958 #wpadminbar #wp-admin-bar-wccp_free_top_button .ab-icon:before { 959 transition: box-shadow .2s ease, text-shadow .2s ease; 960 } 961 962 #wpadminbar:not(.mobile) #wp-admin-bar-wccp_free_top_button:hover > .ab-item, 963 #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item:focus-visible, 964 #wpadminbar #wp-admin-bar-wccp_free_top_button.wccp-abi-open > .ab-item { 965 box-shadow: inset 0 0 0 1px rgba(2, 202, 2, .45), inset 0 0 12px rgba(2, 202, 2, .35); 966 } 967 968 #wpadminbar:not(.mobile) #wp-admin-bar-wccp_free_top_button:hover .ab-icon:before, 969 #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item:focus-visible .ab-icon:before, 970 #wpadminbar #wp-admin-bar-wccp_free_top_button.wccp-abi-open .ab-icon:before { 971 text-shadow: 0 0 6px rgba(2, 202, 2, .9); 972 } 973 974 @media (prefers-reduced-motion: reduce) { 975 #wpadminbar #wp-admin-bar-wccp_free_top_button > .ab-item, 976 #wpadminbar #wp-admin-bar-wccp_free_top_button .ab-icon:before { 977 transition: none; 978 } 979 } 926 980 </style> 927 981 <?php -
wp-content-copy-protector/trunk/readme.txt
r3707909 r3755015 5 5 License URI: http://www.gnu.org/licenses/gpl-2.0.html 6 6 Requires at least: 4.8 7 Tested up to: 7.1. 18 Stable tag: 4. 27 Tested up to: 7.1.3 8 Stable tag: 4.3 9 9 Requires PHP: 7.4 10 10 … … 20 20 Are you tired of seeing your original content copied and spread across the web without your permission? The WP Content Copy Protection & No Right Click plugin is here to safeguard your posts and home page from unauthorized copying. 21 21 22 ✨ *Key Features:* 23 🛡️ * Content Protection:*22 ==Key Features== 23 🛡️ **Content Protection:** 24 24 Ensure your hard work remains yours. This plugin employs advanced content-protection techniques to keep your text and images safe from being copied by other web authors. 25 25 26 🔒 * Copy Protection:*26 🔒 **Copy Protection:** 27 27 With robust copy protection mechanisms, this plugin prevents unauthorized duplication of your content. It effectively disables common methods used for content theft, ensuring your intellectual property remains secure. 28 28 29 ©️ * Copyright Enforcement:*29 ©️ **Copyright Enforcement:** 30 30 Maintain control over your copyrighted material. The plugin acts as a virtual guardian, enforcing copyright rules and deterring potential infringers. 31 31 32 🖱️ * Disable Right Click:*32 🖱️ **Disable Right Click:** 33 33 Stop users from right-clicking on your content. By disabling right-click functionality, this plugin adds an extra layer of security, preventing easy access to the context menu used for copying content. 34 34 35 🚫 * Deny Copy Paste:*35 🚫 **Deny Copy Paste:** 36 36 Block the ability to copy and paste your content. This plugin uses a combination of JavaScript and CSS techniques to make copying and pasting from your site nearly impossible. 37 37 38 👥 * Control Who Can Copy:*38 👥 **Control Who Can Copy:** 39 39 Take charge of your content distribution. With this plugin, you have the power to control who can and cannot copy your content, giving you peace of mind that your work is protected. 40 40 41 💧 * Watermark Images (Pro Version):*41 💧 **Watermark Images (Pro Version):** 42 42 Upgrade to the Pro version to add watermarks to your images. This feature ensures that even if your images are copied, they will still carry your watermark, maintaining your brand visibility and deterring unauthorized use. 43 43 44 📊 * Protection Center (New, free):*44 📊 **Protection Center (New, free):** 45 45 See your protection working instead of guessing. The Protection Center counts every blocked action on your site - blocked right-clicks, blocked text selections, blocked copy shortcuts, image interactions and print attempts - and shows what happened since your last visit: visits with blocked actions, a daily chart for the last 7 days, the pages people try to copy the most, the busiest hours and the mix between text, images and right-clicks. Built on privacy: no IP address, no cookie and no personal data is ever stored, logged-in editors and admins are never counted, everything stays in your own database, and you can switch it off or wipe it with one click at any time. 46 46 47 📧 * Weekly Protection Report (New, free):*47 📧 **Weekly Protection Report (New, free):** 48 48 Do not want to log in to check? Turn on the weekly digest and the plugin emails your site admin a short summary every Monday - only in weeks that actually had activity - with the number of visits with blocked copy actions and how that compares to the week before. 49 49 50 🔔 * Admin Bar Insights (New, free):*50 🔔 **Admin Bar Insights (New, free):** 51 51 A small card that opens from the plugin icon in the WordPress admin bar, wherever you are in wp-admin. One headline number, a 7-day sparkline, your error count, and two short insights that change on every visit ("copy attempts are up 38% this week", "one page drew 41% of the activity"). It costs nothing on page load - the numbers are fetched only when you open the card, and cached. 52 52 53 🩺 * Error Monitor (New, free):*53 🩺 **Error Monitor (New, free):** 54 54 Not only protection: the plugin now finds the error logs your site writes to (wp-content/debug.log, the PHP log set by your server, and error_log files in the site root, wp-admin and wp-content) and explains what is going wrong in plain language. Repeated errors are folded into single issues with a counter, each issue names the plugin, theme or part of WordPress behind it with the file and line, and charts show errors per day by severity and which plugins produce the most. It also warns you when your log file can be downloaded by anyone from the web and shows how to block it. Only the newest part of each log is read, so even huge log files do not slow down your admin. 55 55 56 🌍 * Speaks Your Language (New):*56 🌍 **Speaks Your Language (New)** 57 57 The whole plugin - settings, help notes, Protection Center and Error Monitor - is now fully translated into 11 languages besides English: Arabic, German, Spanish, French, Italian, Japanese, Dutch, Portuguese (Brazil and Portugal), Russian and Simplified Chinese, with full right-to-left (RTL) support. 58 58 59 *Unique Benefits:* 59 ==Unique Benefits:== 60 60 Unparalleled Protection: Unlike other WordPress plugins, our unique combination of JavaScript and CSS techniques offers a level of protection not found elsewhere. 61 61 Free to Use: Enjoy all these powerful features without any cost. Protect your content with the free version of our plugin, and upgrade to the Pro version for additional benefits like image watermarking. … … 118 118 119 119 == Changelog == 120 = 4.3 = 121 <ul> 122 <li>Admin Bar Insights on the front end: the insights card now also opens when you hover the plugin icon in the admin bar while viewing your site, not only inside wp-admin. It stays hidden in the Customizer preview and on small screens.</li> 123 <li>New feature: New errors count on the admin bar icon. A red counter next to "Protection" shows how many new error issues appeared since you last opened the Error Monitor (or in the last 24 hours if you have not opened it yet), the same number as the "New issues" tile in the card. It shows "99+" above 99, is hidden when there is nothing new, and is reset once you open the Error Monitor.</li> 124 <li>New errors count: repeated lines of an error the logs already had are not counted again, so old noise such as the same deprecation notice logged every day does not keep the counter up. Only problems that were not happening before are counted.</li> 125 <li>New errors count performance: page loads only read the stored error snapshot. When the snapshot is older than 10 minutes the count is refreshed in the background after the page has loaded, so your pages are never slowed down by reading log files.</li> 126 <li>Notifications: the "New activity" dot is no longer shown while the new errors count is visible, so the icon never carries two signals at once.</li> 127 <li>New feature: "Ask AI for help" in the Error Monitor, free for the top 3 issues in the list. One click copies a ready-made prompt about that error, ready to paste into ChatGPT, Claude or any AI assistant, and the button changes to "Ready prompt copied". The button is still a PRO feature for the other issues.</li> 128 <li>Ask AI for help: the prompt includes the severity, the full message, the file and line, the plugin or theme behind the error with its version, how often it happened in the selected period and in the whole log, and the first and last seen dates. It also lists your WordPress version, PHP version, active theme and whether the site is a multisite, and asks for a plain-language explanation and a safe, step-by-step fix.</li> 129 <li>Ask AI for help: copying also works on admin pages served over plain http (no https), and the prompt text is translatable.</li> 130 <li>Interface: the insights card is protected against front end theme styles (list bullets, link borders, text alignment), so it looks the same on your site as in wp-admin.</li> 131 <li>Interface: a cleaner settings page. Notifications from other plugins, themes and WordPress are hidden on the plugin settings page only, behind a "Show hidden notifications" button that shows how many there are. One click shows them again, and dismiss buttons keep working. The plugin's own notices stay visible, and every other admin page is unchanged.</li> 132 <li>Fix: a single right-click now shows your alert message. Before, the context menu was blocked silently and the message only appeared on a double-click.</li> 133 <li>Fix for Mac users: copy shortcuts are now blocked with the Cmd key too (Cmd+A, Cmd+C, Cmd+S, Cmd+U and the Safari source and developer tools shortcuts), not only with Ctrl. Text fields and editable areas still accept them.</li> 134 <li>Fix for Mac users: in Safari, a Force Click on the trackpad no longer selects a word and opens the Look Up popup on protected pages. Text fields and editable areas are not affected.</li> 135 <li>Fix: right-click protection and CSS protection now also cover search results pages, using the same setting as the homepage and archives. Selection protection already did.</li> 136 </ul> 120 137 = 4.2 = 121 138 <ul>
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)