Jump to content

count views of post


sakkoulas

Recommended Posts

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á :)

  • Like 11
Link to comment
Share on other sites

$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.
  • Like 1
Link to comment
Share on other sites

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 :)

  • Like 11
Link to comment
Share on other sites

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.

  • Like 2
Link to comment
Share on other sites

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

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

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.

  • Like 1
Link to comment
Share on other sites

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. 

  • Like 1
Link to comment
Share on other sites

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

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.

  • Like 2
Link to comment
Share on other sites

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

  • Like 6
Link to comment
Share on other sites

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

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.

  • Like 2
Link to comment
Share on other sites

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

  • 3 weeks later...

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.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

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

  • 2 weeks later...

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...