Changeset 3285929
- Timestamp:
- 05/02/2025 01:34:13 AM (11 months ago)
- Location:
- advanced-views-counter/tags/1.0.0
- Files:
-
- 8 added
- 10 edited
-
app/Controllers/Settings.php (modified) (1 diff)
-
assets/admin/dist/assets/main-0dd2aa86.js (added)
-
assets/admin/dist/assets/main-0dd2aa86.js.map (added)
-
assets/admin/dist/assets/main-a9e416cc.css (added)
-
assets/admin/dist/manifest.json (modified) (1 diff)
-
assets/icons/icon-128x128.png (added)
-
inc/Assets/Admin.php (modified) (1 diff)
-
inc/Assets/Frontend.php (modified) (2 diffs)
-
readme.txt (modified) (3 diffs)
-
resources/js/admin/components/application-layout/LayoutOne.jsx (modified) (2 diffs)
-
resources/js/admin/components/navbar (added)
-
resources/js/admin/components/navbar/navbar-mobile.jsx (added)
-
resources/js/admin/components/navbar/navbar.jsx (added)
-
resources/js/admin/pages/dashboard/index.jsx (modified) (3 diffs)
-
resources/js/admin/pages/error/Error.tsx (modified) (2 diffs)
-
resources/js/admin/pages/layout.tsx (added)
-
resources/js/admin/pages/settings/layout.tsx (modified) (1 diff)
-
resources/js/frontend/visit.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
advanced-views-counter/tags/1.0.0/app/Controllers/Settings.php
r3282400 r3285929 45 45 $exclude_visitors = [ 46 46 ['id' => 'crawlers', 'label' => 'Crawlers'], 47 ['id' => 'bots', 'label' => ' AIBots'],47 ['id' => 'bots', 'label' => 'Bots'], 48 48 ['id' => 'logged_in', 'label' => 'Logged in Users'], 49 49 ['id' => 'guests', 'label' => 'Guests'], -
advanced-views-counter/tags/1.0.0/assets/admin/dist/manifest.json
r3282400 r3285929 1 1 { 2 2 "resources/js/admin/main.css": { 3 "file": "assets/main- b6630ac8.css",3 "file": "assets/main-a9e416cc.css", 4 4 "src": "resources/js/admin/main.css" 5 5 }, 6 6 "resources/js/admin/main.jsx": { 7 7 "css": [ 8 "assets/main- b6630ac8.css"8 "assets/main-a9e416cc.css" 9 9 ], 10 "file": "assets/main- 9cb5f271.js",10 "file": "assets/main-0dd2aa86.js", 11 11 "isEntry": true, 12 12 "src": "resources/js/admin/main.jsx" -
advanced-views-counter/tags/1.0.0/inc/Assets/Admin.php
r3282400 r3285929 56 56 { 57 57 add_action('admin_enqueue_scripts', array($this, 'enqueue_script')); 58 add_action('admin_head', function () { 59 // Only run on your plugin page 60 $screen = get_current_screen(); 61 if (!isset($screen->id) || !in_array($screen->id, $this->allowed_screens, true)) { 62 return; 63 } 64 65 // Remove all notices from other plugins 66 remove_all_actions('admin_notices'); 67 remove_all_actions('all_admin_notices'); 68 }); 58 69 } 59 70 -
advanced-views-counter/tags/1.0.0/inc/Assets/Frontend.php
r3282400 r3285929 109 109 if (!empty($settings['display_styles'])) { 110 110 if (in_array('icon', $settings['display_styles'])) { 111 $views_html .= '<span class="a vc-views-icon" style="display: inline-block; vertical-align: middle;">111 $views_html .= '<span class="advico-views-icon" style="display: inline-block; vertical-align: middle;"> 112 112 <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor" aria-hidden="true"> 113 113 <rect x="0" fill="none" width="24" height="24"/> … … 117 117 } 118 118 if (in_array('label', $settings['display_styles'])) { 119 $views_html .= '<span class="a vc-views-label">' . esc_html($settings['views_label']) . '</span>';119 $views_html .= '<span class="advico-views-label">' . esc_html($settings['views_label']) . '</span>'; 120 120 } 121 121 } -
advanced-views-counter/tags/1.0.0/readme.txt
r3283686 r3285929 1 === Advanced Views Counter ===1 === Advanced Views Counter – Post Views Counter Analytics & Popular Posts Tracker === 2 2 Contributors: schorpy 3 3 Tags: analytics, statistics, stats, insights, postviews … … 27 27 🌐 Top Referrers – Discover where your traffic is coming from 28 28 29 🔒 100% GDPR-compliant – no IPs or personal data stored 30 31 = Why Use Advanced Views Counter? = 32 ✅ Get real-time insights on what content performs best 33 34 ✅ No external dependencies – everything runs on your server 35 36 ✅ Perfect for blogs, news sites, or any content-focused website 37 38 ## Did you like Advanced Views Counter Plugin? 39 40 🙌 Join our [Facebook Group](https://web.facebook.com/groups/502458389926858) 41 42 🤝 Give us your useful [rating on WordPress.org](https://wordpress.org/support/plugin/advanced-views-counter/reviews/#new-post) 43 29 44 == Frequently Asked Questions == 30 45 = Does this plugin work with custom post types? = … … 39 54 = Can I customize where the view count appears? = 40 55 Yes, you can choose display locations. 56 57 = Is this plugin GDPR-compliant? = 58 Yes. Advanced Views Counter does **not collect or store IP addresses, user agents, or any personally identifiable information**. 41 59 42 60 == Screenshots == -
advanced-views-counter/tags/1.0.0/resources/js/admin/components/application-layout/LayoutOne.jsx
r3282400 r3285929 1 import { 2 CircleUser, 3 Home, 4 Mail, 5 Menu, 6 SlidersHorizontal, 7 Package2, 8 BarChart 1 import { useEffect } from "react"; 9 2 10 } from "lucide-react"11 import {12 NavigationMenu,13 NavigationMenuContent,14 NavigationMenuIndicator,15 NavigationMenuItem,16 NavigationMenuLink,17 NavigationMenuList,18 NavigationMenuTrigger,19 NavigationMenuViewport,20 } from "@/components/ui/navigation-menu"21 3 22 import { useEffect } from "react";23 import { Button } from "@/components/ui/button"4 import Navbar from "@/components/navbar/navbar" 5 import NavbarMobile from "@/components/navbar/navbar-mobile" 24 6 import { ModeToggle } from "../mode-toggle"; 25 7 26 import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet" 27 import { NavLink, Outlet, useLocation, useNavigate } from "react-router-dom"; 28 import Logo from "../Icons/Logo"; 29 import { clsx } from "clsx"; 8 import { Outlet } from "react-router-dom"; 30 9 31 32 const navigation = [33 {34 name: "Dashboard",35 href: "dashboard",36 icon: Home,37 current: true,38 },39 40 {41 name: "Settings",42 href: "settings",43 icon: SlidersHorizontal,44 current: false,45 }46 ];47 10 48 11 export default function LayoutOne() { 49 12 // let showApplicationLayout = !wpclickizy.isAdmin; 50 13 let showApplicationLayout = true; 51 let location = useLocation();52 const navigate = useNavigate();53 const pageTitle = location.pathname.split("/")[1];54 14 55 56 15 57 16 return ( … … 62 21 {showApplicationLayout && 63 22 <header className="sticky top-8 z-50 flex h-14 items-center bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 gap-4 border-b bg-muted/40 px-4 lg:h-[60px] lg:px-6"> 64 <Sheet> 65 <SheetTrigger asChild> 66 <Button 67 variant="outline" 68 size="icon" 69 className="shrink-0 md:hidden" 70 > 71 <Menu className="h-5 w-5" /> 72 <span className="sr-only">Toggle navigation menu</span> 73 </Button> 74 </SheetTrigger> 75 <SheetContent side="left" className="flex flex-col"> 76 <nav className="grid gap-2 text-lg font-medium"> 77 <a 78 href="#" 79 className="flex items-center gap-2 text-lg font-semibold" 80 > 81 <Package2 className="h-6 w-6" /> 82 <span className="sr-only">Plugin Name</span> 83 </a> 84 {navigation.map((item, index) => { 85 return <NavLink 86 to={item.href} 87 key={index} 88 className={ 89 clsx( 90 "flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary", 91 item.href === pageTitle 92 ? "text-primary bg-muted" 93 : "text-muted-foreground" 94 ) 95 } 96 > 97 <item.icon className="h-5 w-5" /> 98 {item.name} 99 </NavLink> 100 })} 101 102 103 </nav> 104 105 </SheetContent> 106 </Sheet> 107 <div className="w-full flex items-center h-full justify-between"> 108 <a href="#/dashboard" className="flex items-center gap-2 font-semibold"> 109 {/* <Logo /> */} 110 <img src={`${advico_plugin.logo}/icon-128x128.png`} width="32" alt="Advanced Views Counter Logo" /> 111 <span className="text-xl font-semibold">Advanced Views Counter</span> 112 </a> 113 <NavigationMenu> 114 <NavigationMenuList> 115 <NavigationMenuItem> 116 <a href="#" className="group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"> 117 <NavigationMenuLink> 118 Dashboard 119 </NavigationMenuLink> 120 </a> 121 </NavigationMenuItem> 122 123 <NavigationMenuItem> 124 <a href="#settings" className="group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"> 125 <NavigationMenuLink> 126 Settings 127 </NavigationMenuLink> 128 </a> 129 </NavigationMenuItem> 130 131 </NavigationMenuList> 132 </NavigationMenu> 133 134 </div> 23 <NavbarMobile/> 24 <Navbar/> 135 25 <ModeToggle /> 136 {/* <DropdownMenu> 137 <DropdownMenuTrigger asChild> 138 <Button variant="secondary" size="icon" className="rounded-full"> 139 <CircleUser className="h-5 w-5" /> 140 <span className="sr-only">Toggle user menu</span> 141 </Button> 142 </DropdownMenuTrigger> 143 <DropdownMenuContent align="end"> 144 <DropdownMenuLabel>My Account</DropdownMenuLabel> 145 <DropdownMenuSeparator /> 146 <DropdownMenuItem>Settings</DropdownMenuItem> 147 <DropdownMenuItem>Support</DropdownMenuItem> 148 <DropdownMenuSeparator /> 149 <DropdownMenuItem>Logout</DropdownMenuItem> 150 </DropdownMenuContent> 151 </DropdownMenu> */} 26 152 27 </header> 153 28 } -
advanced-views-counter/tags/1.0.0/resources/js/admin/pages/dashboard/index.jsx
r3282400 r3285929 1 1 import { useState, useEffect } from "react"; 2 2 3 3 import DashboardLayout from "../layout" 4 4 import { 5 5 Card, … … 36 36 return ( 37 37 <> 38 39 <div className="hidden dark:bg-gray-900 flex-col md:flex"> 40 {/* <div className="border-b"> 41 <div className="flex h-16 items-center px-4"> 42 <TeamSwitcher /> 43 <MainNav className="mx-6" /> 44 <div className="ml-auto flex items-center space-x-4"> 45 <Search /> 46 <UserNav /> 47 </div> 48 </div> 49 </div> */} 50 <div className="flex-1 space-y-4 p-8 pt-6"> 51 <div className="flex items-center justify-between space-y-2"> 52 <h2 className="text-3xl dark:text-white font-bold tracking-tight">Dashboard</h2> 53 <div className="flex items-center space-x-2"> 54 55 </div> 56 </div> 57 58 38 <DashboardLayout> 39 40 <div className="space-y-6"> 59 41 <div className=""> 60 42 <Card className=""> … … 126 108 127 109 </div> 128 </div>110 </DashboardLayout> 129 111 </> 130 112 ); -
advanced-views-counter/tags/1.0.0/resources/js/admin/pages/error/Error.tsx
r3282400 r3285929 1 1 import { useRouteError } from "react-router-dom"; 2 2 3 const Error = () => {3 const ErrorPage = () => { 4 4 const error: any = useRouteError(); 5 5 return ( … … 14 14 }; 15 15 16 export default Error ;16 export default ErrorPage; -
advanced-views-counter/tags/1.0.0/resources/js/admin/pages/settings/layout.tsx
r3282400 r3285929 25 25 <> 26 26 27 <div className=" hiddenspace-y-6 p-10 pb-16 md:block dark:bg-gray-900">27 <div className="space-y-6 p-10 pb-16 md:block dark:bg-gray-900"> 28 28 <div className="space-y-0.5"> 29 29 <h2 className="text-2xl font-bold tracking-tight dark:text-white">Settings</h2> -
advanced-views-counter/tags/1.0.0/resources/js/frontend/visit.js
r3282400 r3285929 1 1 2 var AdvicoCounter = {3 /**4 * Initialize counter.5 *6 * @param {object} args7 */8 init: function (args) {2 var AdvicoCounter = { 3 /** 4 * Initialize counter. 5 * 6 * @param {object} args 7 */ 8 init: function (args) { 9 9 this.args = args; 10 10 11 11 function getCookie(name) { 12 12 const cookies = document.cookie.split('; '); 13 13 for (let i = 0; i < cookies.length; i++) { 14 const [key, value] = cookies[i].split('=');15 if (decodeURIComponent(key) === name) {16 return decodeURIComponent(value);17 }14 const [key, value] = cookies[i].split('='); 15 if (decodeURIComponent(key) === name) { 16 return decodeURIComponent(value); 17 } 18 18 } 19 19 return null; 20 }20 } 21 21 // Build the payload 22 22 const data = { 23 postId: args.postId,24 userInfo: args.userInfo,25 visitId:getCookie(`advico_views[${args.postId}]`)23 postId: args.postId, 24 userInfo: args.userInfo, 25 visitId: getCookie(`advico_views[${args.postId}]`) 26 26 }; 27 27 28 28 // Log the visit 29 29 this.request(args.apiUrl + '/visit', data, 'POST', { 30 'Content-Type': 'application/json',31 'Referer': document.referrer,32 'X-WP-Nonce': args.nonce30 'Content-Type': 'application/json', 31 'Referer': document.referrer, 32 'X-WP-Nonce': args.nonce 33 33 }) 34 .then(data => {34 .then(data => { 35 35 36 if (data?.counted && data?.cookie) {37 const expiresIn = data.cookie.expiry - Math.floor(Date.now() / 1000);38 document.cookie = `${data.cookie.name}=${data.cookie.value}; max-age=${expiresIn}; path=/`;39 40 } else {41 console.log(`Post ${data.post_id} already viewed.`);42 }43 });44 36 if (data?.counted && data?.cookie) { 37 const expiresIn = data.cookie.expiry - Math.floor(Date.now() / 1000); 38 document.cookie = `${data.cookie.name}=${data.cookie.value}; max-age=${expiresIn}; path=/`; 39 40 } else { 41 console.log(`Post ${data.post_id} already viewed.`); 42 } 43 }); 44 45 45 // Get initial views count 46 46 this.getViews(); 47 },48 49 getViews: function() {47 }, 48 49 getViews: function () { 50 50 const data = { 51 postId: this.args.postId51 postId: this.args.postId 52 52 }; 53 53 54 54 this.request(this.args.apiUrl + '/views', data, 'POST', { 55 'Content-Type': 'application/json',56 'X-WP-Nonce': this.args.nonce55 'Content-Type': 'application/json', 56 'X-WP-Nonce': this.args.nonce 57 57 }) 58 .then(response => {59 60 if (response.status === 'success') {61 62 const counters = document.querySelector('#advico-views-count');63 58 .then(response => { 59 60 if (response.status === 'success') { 61 62 const counters = document.querySelector('#advico-views-count'); 63 64 64 counters.textContent = response.data.total_views; 65 66 }67 });68 },69 70 /**71 * Make request to REST API with JSON72 *73 * @param {string} url74 * @param {object} params75 * @param {string} method76 * @param {object} headers77 */78 request: function (url, params, method, headers) {65 66 } 67 }); 68 }, 69 70 /** 71 * Make request to REST API with JSON 72 * 73 * @param {string} url 74 * @param {object} params 75 * @param {string} method 76 * @param {object} headers 77 */ 78 request: function (url, params, method, headers) { 79 79 return fetch(url, { 80 80 method: method, 81 81 headers: headers, 82 82 body: JSON.stringify(params) 83 })83 }) 84 84 .then(response => { 85 if (!response.ok) throw new Error(response.statusText);86 return response.json();85 if (!response.ok) throw new Error(response.statusText); 86 return response.json(); 87 87 }) 88 88 .then(response => { 89 90 this.triggerEvent('avcVisitLogged', response);91 return response; // <- penting untuk meneruskan response ke .then selanjutnya89 90 this.triggerEvent('avcVisitLogged', response); 91 return response; // <- penting untuk meneruskan response ke .then selanjutnya 92 92 }) 93 93 .catch(error => { 94 console.error('AVCError:', error);94 console.error('Advico Error:', error); 95 95 }); 96 },97 98 /**99 * Trigger custom event100 *101 * @param {string} eventName102 * @param {object} data103 */104 triggerEvent: function (eventName, data) {96 }, 97 98 /** 99 * Trigger custom event 100 * 101 * @param {string} eventName 102 * @param {object} data 103 */ 104 triggerEvent: function (eventName, data) { 105 105 const event = new CustomEvent(eventName, { 106 bubbles: true,107 detail: data106 bubbles: true, 107 detail: data 108 108 }); 109 109 document.dispatchEvent(event); 110 }111 };112 113 114 110 } 111 }; 112 113 114 115 115 document.addEventListener('DOMContentLoaded', function () { 116 116 AdvicoCounter.init(advicoFrontend); // make sure avcFrontend is available 117 117 }); 118
Note: See TracChangeset
for help on using the changeset viewer.