sakkoulas Posted February 22, 2013 Share Posted February 22, 2013 hi, does anyone know if is it possible to count the views of a post??thanks Link to comment Share on other sites More sharing options...
diogo Posted February 22, 2013 Share Posted February 22, 2013 Create a field "counter" with type "integer" and set it as "hidden, not shown in the editor" or "always collapsed, requiring a click to open", as you prefer. Put this code on your template: $page->counter += 1; $page->of(false); $page->save('counter'); $page->of(true); echo $page->counter; voilá 11 Link to comment Share on other sites More sharing options...
sakkoulas Posted February 22, 2013 Author Share Posted February 22, 2013 (edited) oooo i like it, thanks diogo what exactly $page->of(false) means; Edited February 22, 2013 by sakkoulas Link to comment Share on other sites More sharing options...
diogo Posted February 22, 2013 Share Posted February 22, 2013 $page->of() is a short version of $page->setOutputFormatting(). This is what it says on the docs and cheatsheet: By default, output will be formatted according filters you may have defined with the field. If you are modifying the values of a page's custom fields, you will need to call $page->setOutputFormatting(false) before doing so. This turns off output formatting, which ensures that saved values don't already have runtime formatters applied to them. ProcessWire will throw an error if you attempt to save formatted fields. 1 Link to comment Share on other sites More sharing options...
sakkoulas Posted February 22, 2013 Author Share Posted February 22, 2013 thanks diogo Link to comment Share on other sites More sharing options...
Pete Posted February 23, 2013 Share Posted February 23, 2013 The trick with counters is to remove yourself from skewing the count. I find that when writing blog posts I load the page several times and this would increase the count several times. You could go a step further with diogo's code and do this to exclude your account (superuser) from increasing the count: if (!$user->isSuperuser()) { $page->counter += 1; $page->of(false); $page->save('counter'); $page->of(true); } echo $page->counter; Or you could do the same for multiple roles if you have different editors for your site (my example has some fake ones named "news" and "sports" below): if (!$user->hasRole('news') && !$user->hasRole('sports')) { $page->counter += 1; $page->of(false); $page->save('counter'); $page->of(true); } echo $page->counter; Just a thought 11 Link to comment Share on other sites More sharing options...
sakkoulas Posted February 25, 2013 Author Share Posted February 25, 2013 You are right Pete, just realized this , thank you Link to comment Share on other sites More sharing options...
encho Posted February 27, 2013 Share Posted February 27, 2013 This is great, I will use it for 'Most popular articles' in my sidebar. Another idea: how to take this even further and count today's views only? So we can have something like 'Most popular today'. Link to comment Share on other sites More sharing options...
diogo Posted February 27, 2013 Share Posted February 27, 2013 This should work. create a date field besides the counter field. and put change the code to this: if (!$user->isSuperuser()) { if( date('Ymd', strtotime($page->day)) != date('Ymd') ) { $page->counter = 0; $page->day = today(); } else { $page->counter += 1; } $page->of(false); $page->save('counter'); $page->of(true); } echo $page->counter; written in the browser and not tested. But it should give you an idea. 2 Link to comment Share on other sites More sharing options...
SiNNuT Posted February 27, 2013 Share Posted February 27, 2013 This is great, I will use it for 'Most popular articles' in my sidebar. Another idea: how to take this even further and count today's views only? So we can have something like 'Most popular today'. I don't think the most popular article is always equal to the one with the highest number of page views. Which one is more popular?: the one viewed 50 times by 50 unique visitors or the one viewed 51 times by 40 unique visitors. Link to comment Share on other sites More sharing options...
encho Posted February 28, 2013 Share Posted February 28, 2013 This should work. create a date field besides the counter field. and put change the code to this: if (!$user->isSuperuser()) { if( date('Ymd', strtotime($page->day)) != date('Ymd') ) { $page->counter = 0; $page->day = today(); } else { $page->counter += 1; } $page->of(false); $page->save('counter'); $page->of(true); } echo $page->counter; written in the browser and not tested. But it should give you an idea. Thanks, very useful post as always will try that. I don't think the most popular article is always equal to the one with the highest number of page views. Which one is more popular?: the one viewed 50 times by 50 unique visitors or the one viewed 51 times by 40 unique visitors. I agree, but unless you have an idea how to do this, this is good enough for me. Link to comment Share on other sites More sharing options...
encho Posted February 28, 2013 Share Posted February 28, 2013 It seems more complicated than I thought it would be (thanks to my beginner level in php). The following code seems to be working, but not sure about few things (and whether it will work tomorrow): <?php $page->of(false); if (!$user->isSuperuser()) { $datetoday = date('Ymd'); if(!isset($page->dateref)) { $dateref=$datetoday; } else $dateref = $page->dateref; if( $dateref != $datetoday ) { $page->counter = 1; $page->dateref = date('Ymd'); } else { $page->counter += 1; } } $page->save('counter'); $page->save('dateref'); $page->of(true); echo $page->counter; ?> (used 'dateref' field instead of 'date', as that one is already in use) 1. I had to setup the dateref field's output as Ymd in field settings, strtotime doesn't work for me. 2. If I don't put $page->of(false); before the code, it will produce an error "Call $page->setOutputFormatting(false) before getting/setting values that will be modified and saved." Any implications to place it in the beginning? 3. If dateref field is not set, the output will default to 1970... so I had to set that to date('Ymd') in case value does not exist. 4. $page->counter = 1: if set to 0, it won't register first visit. It is working as it is, but not sure how safe/proper the code is. Any insight appreciated. 1 Link to comment Share on other sites More sharing options...
ryan Posted March 2, 2013 Share Posted March 2, 2013 The logic you've got there seems to make sense to me. One thing to note about this sort of counter is that it would not work if you had page caching enabled. But so long as you don't, it should be fine. 1 Link to comment Share on other sites More sharing options...
encho Posted March 4, 2013 Share Posted March 4, 2013 What about ProCache? Would that impact the results? Link to comment Share on other sites More sharing options...
ryan Posted March 4, 2013 Share Posted March 4, 2013 What about ProCache? Would that impact the results? ProCache completely bypasses ProcessWire, so any code that saves a counter would not get executed. As a result, you probably don't want to cache pages (whether with ProCache or the built-in cache) that you need to execute the counter code on. This is one reason why using separate services or software for analytics is a good thing (Google Analytics, Piwik, etc.) Link to comment Share on other sites More sharing options...
encho Posted March 4, 2013 Share Posted March 4, 2013 Thanks again. The reason behind this is not to track the posts (I use Piwik for that), but to have convenient "Most read article" or "Popular today" section/block. Link to comment Share on other sites More sharing options...
SiNNuT Posted March 4, 2013 Share Posted March 4, 2013 I don't know Piwik, but glancing over their API documentation it seems fairly simple to grab and display to the data you want on the site. This would be more robust and flexible i think plus it would allow, as Ryan already mentioned, use in a cached environment. 2 Link to comment Share on other sites More sharing options...
Wanze Posted March 4, 2013 Share Posted March 4, 2013 Another option that would bypass Pw caching, even ProCache is to send an ajax request to handle the counter. If you use jQuery, this would be something like this: //Javascript <script> $(document).ready(function() { var data = {'action' : 'handleCounter'}; var url = '<?= $page->url?>'; $.post(url, data); }); </script> //PHP if ($config->ajax && $input->post->action == 'handleCounter') { //... //put your php code in here //... exit(); //Quit since this was only a request to update the counter } To make this work you would need to disable caching for the POST "action" variable. This is done in the template settings under Cache > Cache disabling POST variables 6 Link to comment Share on other sites More sharing options...
ryan Posted March 5, 2013 Share Posted March 5, 2013 Good idea Wanze. This would also have the benefit of excluding most crawlers from the counter. Though if a user really wanted to, they could manipulate the results, but of course they could do that either way. One question, which I'm sure has an obvious answer, but I don't know it. Would the $.post request hold up the page render, or would it occur behind the scenes?Basically I'm just wondering if the $.post should be done in a $(document).ready() rather than inline? Link to comment Share on other sites More sharing options...
interrobang Posted March 5, 2013 Share Posted March 5, 2013 Ryan, as far as I know a in-page javascript call would indeed hold up the rendering. But you can always put the javascript at the bottom of your body, and there is no need for $(document).ready() Btw, I found a similar thread with some other suggestions: http://processwire.com/talk/topic/1618-page-view-counter-and-cache/ Link to comment Share on other sites More sharing options...
Wanze Posted March 5, 2013 Share Posted March 5, 2013 Good idea Wanze. This would also have the benefit of excluding most crawlers from the counter. Though if a user really wanted to, they could manipulate the results, but of course they could do that either way. One question, which I'm sure has an obvious answer, but I don't know it. Would the $.post request hold up the page render, or would it occur behind the scenes?Basically I'm just wondering if the $.post should be done in a $(document).ready() rather than inline? Ryan, You are right of course Funny, when i wrote the js code I knew something is missing but I couldn't figure it out then. Corrected my post. 2 Link to comment Share on other sites More sharing options...
encho Posted March 8, 2013 Share Posted March 8, 2013 Just to hijack this topic, I am trying to integrate Piwik API, and here is what I have found till now. <?php $token_auth = 'xxx'; $url = "http://stats.site.com/"; $url .= "?module=API&method=Actions.getPageUrls"; $url .= "&idSite=3&period=day&date=today"; $url .= "&format=PHP&filter_limit=5"; $url .= "&token_auth=$token_auth&segment=pageUrl=@articles&flat=1"; $fetched = file_get_contents($url); $contentp = unserialize($fetched); // case error if(!$contentp) { print("Error, content fetched = ".$fetched); } echo "<ul>"; foreach($contentp as $row) { $keyword = htmlspecialchars(html_entity_decode(urldecode($row['label']), ENT_QUOTES), ENT_QUOTES); $hits = $row['nb_visits']; $keywordfull = rtrim($keyword,"/index"); $ptitle = $pages->get("path=$keywordfull"); echo "<li>"; echo "<a href='/".$keywordfull."'>".$ptitle->title."</a>"; echo " (".$hits.")"; echo "</li>"; } echo "</ul>"; ?> This is based on Piwik's own example, with few 'gotchas'. First, &segment=pageUrl=@articles is used to filter results to include only articles/*. Second, &flat=1 will include full list of urls. Third $content clashes with my template so I have used $contentp. But I am obviously doing something wrong, as site is reduced to crawl occassionaly, since I have implemented the idea. Maybe $pages->get is not efficient way to do it? Link to comment Share on other sites More sharing options...
Pete Posted March 26, 2013 Share Posted March 26, 2013 Well if it's a busy site they'll be querying Piwik potentially thousands of times an hour (not sure of your visitor numbers) whether they're a search engine spider or not. I think your solution here is to use MarkupCache and just update it once every hour. That way you're not hammering Piwik or slowing things down for your users. Even Google Analytics doesn't give you up-to-the-minute page counts by default (I think they update every 2-4 hours unless you're viewing some live stats). Of course if it's a site with very few visitors then I'm not sure why it would slow it down so much. 1 Link to comment Share on other sites More sharing options...
Can Posted June 28, 2014 Share Posted June 28, 2014 Made a little external link click counter based on this..so thanks guys the link template got this code if(!$user->isSuperuser() && !$user->hasRole('admin')) { $page->of(false); $page->count += 1; $page->save(); } $session->redirect($page->link); so in link-category template I'm linking to $child->url and not the link url works great..love processwire!! Link to comment Share on other sites More sharing options...
Can Posted July 7, 2014 Share Posted July 7, 2014 got a little question on this. how about counting the session table entries/id's? like so echo $db->query("SELECT id FROM sessions")->num_rows For now I´m doing it only in admin dashboard to have a clue what's going on How about using this on frontpage? Probably it's not the best to "count" everytime? Is there any "auto" deletion of expired/old session data going on somewhere in PW? Ah, the JS based counter is nice of course, but is there any reason to prefer template cache over markup cache? So I could markup cache any part I want to cache and everything else can still do it's job. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now