Joomla article hit counter not working because of cache

1,246 views
Skip to first unread message

Gopi A

unread,
May 20, 2014, 2:01:07 AM5/20/14
to joomla-...@googlegroups.com
Hi,

I have seen this issues still  present in Joomla from older version to current version.

If we enabled the cache then Article hit was stop counting.

Because of this issues some of the valuable Article page hits are not increasing.

I found some code in Forum,they are asking us to place this code in index.php

Eg:

if (isset($_GET['view']) && strtolower($_GET['view']) == 'article') {
 $articleId = (int) $_GET['id']; 
  
 $db = JFactory::getDBO();
 $db->setQuery(
                        'UPDATE #__content' .
                        ' SET hits = hits + 1' .
                        ' WHERE id = '.(int) $articleId
                );
 $db->query(); 
}


But I don't think this will be permanent solution. 

Any ideas?

Thanks in Advance


Bakual

unread,
May 20, 2014, 6:13:46 AM5/20/14
to joomla-...@googlegroups.com
David did a PR here: https://github.com/joomla/joomla-cms/pull/3591 which I think does address your issue.
It just needs testers :-)

Seth Warburton

unread,
May 21, 2014, 3:36:34 AM5/21/14
to joomla-...@googlegroups.com
Isn't the whole point of the cache to stop requests hitting the DB?

I wouldn't expect the hit counter to work with caching enabled, if it did then caching would not be working properly.

Bakual

unread,
May 21, 2014, 4:18:18 AM5/21/14
to joomla-...@googlegroups.com
The shown hitcount would be wrong anyway when caching is enabled :)

Gopi A

unread,
May 21, 2014, 4:31:13 AM5/21/14
to joomla-...@googlegroups.com
Yes, When I disabled the cache setting, then count will increase twice.
I am thinking no other permanent solution for this issues until editing the core code.




--
You received this message because you are subscribed to the Google Groups "Joomla! CMS Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to joomla-dev-cm...@googlegroups.com.
To post to this group, send email to joomla-...@googlegroups.com.
Visit this group at http://groups.google.com/group/joomla-dev-cms.
For more options, visit https://groups.google.com/d/optout.



--
      Regards
gopi a on about.me
        Gopi A

Gopi A

unread,
May 21, 2014, 5:53:19 AM5/21/14
to joomla-...@googlegroups.com
For temporary solution, I have used this script:

Placed it in your templates/index.php

<?php if (isset($view) && strtolower($view) == 'article') : $articleId =  JRequest::getVar('id'); ?>
<script type='text/javascript'>
  jQuery(document).ready(function($){
jQuery.post('../hits_counter.php',
{
option:'com_content',
view:'article',
id:'<?php echo $articleId;?>'
});
});

</script>
<?php endif; ?>

In hits_counter.php file

<?php

define( '_JEXEC', 1 );
//chdir("../");
getcwd();
define('JPATH_BASE', getcwd() );

define('DS', DIRECTORY_SEPARATOR);

$id = $_POST['id'];
//JPATH_LIBRARIES . '/legacy/application/application.php'
require_once( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once( JPATH_BASE .DS.'includes'.DS.'framework.php' );
//require_once( JPATH_BASE .DS.'includes'.DS.'application.php' );
require_once( JPATH_BASE .DS.'libraries'.DS.'legacy'.DS.'application'.DS.'application.php' );//libraries\legacy\application\application.php
// Get a db connection.
$db = JFactory::getDbo();
$s = 'select hits from #__content where id='.$id;
$db->setQuery($s);
$currentHits =  $db->loadResult();
$updateHits = $currentHits+1;

$update = 'update #__content set hits='.$updateHits.' where id='.$id;
$db->setQuery($update);$db->Query();

$s1 = 'select hits from #__content where id='.$id;
$db->setQuery($s1);
$NowHits =  $db->loadResult();exit;
?>

In above code will store the hits by counting +1,

At the same time, if you want to show the hits in your front end sites without hanging in Cache.

Go to com_content/views/article/default.php ( you can overwrite this file and placed it in your template file,If you overwrite then your path will be your_template/html/com_content/article/default.php )

search line <span class="icon-eye-open"></span>

place this below code,

<span class="icon-eye-open"></span>
<script type='text/javascript'>
$(document).ready(function() {
     $.ajax({    //create an ajax request to load_page.php
       type: "POST",
       url: "../view_hits.php",
       data: { id:"<?php echo $this->item->id; ?>" },
       dataType: "html",   //expect html to be returned
       success: function(response){
           $("#my_ArticleView_cnt").text(response);
           //alert(response);
       }

   });
});
</script>

<?php  echo JText::sprintf('COM_CONTENT_ARTICLE_HITS', '<span id="my_ArticleView_cnt"></span>'); ?>

In view_hits.php place this below code:

<?php

 define( '_JEXEC', 1 );
//chdir("../");
getcwd();
define('JPATH_BASE', getcwd() );

define('DS', DIRECTORY_SEPARATOR);

@$id = $_POST['id'];
@$fetch = $_POST['fetch'];

//JPATH_LIBRARIES . '/legacy/application/application.php'
require_once( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once( JPATH_BASE .DS.'includes'.DS.'framework.php' );
//require_once( JPATH_BASE .DS.'includes'.DS.'application.php' );
require_once( JPATH_BASE .DS.'libraries'.DS.'legacy'.DS.'application'.DS.'application.php' );//libraries\legacy\application\application.php
// Get a db connection.
$db = JFactory::getDbo();
$s = 'select hits from #__content where id='.$id;
$db->setQuery($s);
echo $currentHits =  $db->loadResult(); exit;
?>



Same code you can used it for intro text view or full text article view.

Now you will get the Hits count without hanging in Cache.

Nils Rückmann

unread,
May 21, 2014, 6:20:40 AM5/21/14
to joomla-...@googlegroups.com
Tracking the hits via AJAX is the only way to solve this due to page cache (or by using a proxy cache). I mentioned that month ago, but the only response i got was "AJAX has nothing to do with caching" ...

Mark Dexter

unread,
May 21, 2014, 10:38:15 AM5/21/14
to Joomla! CMS Development
One issue that is potentially easy to solve is to store hit counts in a separate table from the articles or other items. That way you don't have to worry about whether a row is checked out for editing. But it doesn't solve the caching issue. The table storing hits could not be cached, but the item tables could. Mark


On Wed, May 21, 2014 at 3:20 AM, Nils Rückmann <syb...@gmail.com> wrote:
Tracking the hits via AJAX is the only way to solve this due to page cache (or by using a proxy cache). I mentioned that month ago, but the only response i got was "AJAX has nothing to do with caching" ...

--

Georgios Papadakis

unread,
May 21, 2014, 5:13:17 PM5/21/14
to joomla-...@googlegroups.com
Hello

1. in my custom component i solved this issue by moving the cache hit code (similar to the code already written above) to the onAfterRender event of a system plugin,

but this still does not solve the issue with not counting hits when page is served via a proxy, but adding AJAX code to update hits maybe exploited by people wanted to increment the hits counter on their listings ... e.g. in a subscriptions web-site,


2. about the hits counter being wrong until the page is reupdated, this is ok,

- the issue is about counting hits while caching is enabled and not about always showing an updated hits value
- as soon as the cache expires the hits will reflect correct value

3. furthermore the hits counting does not count unique visitors, i think we could add into the user's session an array of the articles the user has seen, so that duplicates hits are not counted
i know that a user can circumvent this, but it is a lot better than counting 10 hits is the users clicks 10 times refresh on an article
optionally we could store the last IP per article ID to tighten the above method and setting a limit of e.g. 10 minutes before counting a 2nd hit from same IP

- the above solution is what i followed in my custom component,

if you decide to do unique hits the code to do it should be small, but i can contribute it if you want

Regards

Nils Rückmann

unread,
May 21, 2014, 5:24:40 PM5/21/14
to joomla-...@googlegroups.com
My personal opinion:

1. Drop the hits column and separate the logic to another package like "com_stats".
2. Build "com_stats" on a solid ground and with core interfaces, which will guarantee the possibility to change "com_stats" with other, more complex/detailed extensions (like third party extensions)

Sergio Manzi

unread,
May 21, 2014, 7:02:04 PM5/21/14
to joomla-...@googlegroups.com
I totally agree.

Personally when I need access statistics I use Google Analytics, Awstats or the raw access logs. Of course there are other options.

It seems Hannes Papenberg is working on a revamped router (this is something *really* needed, IMHO!): wouldn't that be a possible place where to raise events to which an hypothetical  statistics plugin/component could react and collect results not only for com_content but for every other possible URL?

Then, drop the #_content "hits" column at the earliest possible occasion.

Everything that can make Joomla! more streamlined and efficient is a great welcome, for me.

smz

Georgios Papadakis

unread,
May 21, 2014, 7:19:16 PM5/21/14
to joomla-...@googlegroups.com
Hello

i don't disagree with you,

but this discussion has gotten a little of topic and i partially contributed to this

before doing various things that were suggested here e.g.  dropping column hits and/or creating a new statistics component (what will the cost of it be?),

let's solve the current problem, let's make hits work while caching is on

--  a simple solution , that

a. need minimal implementatation
b. does not compromise compatibility
c. has minical execution cost
d. solves the problem now and not having to wait for the statistics component

is increment hits counter in a Joomla system plugin using the AfterRender event,

Regards

Sergio Manzi

unread,
May 21, 2014, 8:05:46 PM5/21/14
to joomla-...@googlegroups.com
Hi Georgios!

As Bakual pointed out in the first answer to this thread, a "quick and dirty" solution (no offense to the PR coder!!) has already been been proposed in https://github.com/joomla/joomla-cms/pull/3591

Anyway, I'm not totally sure I'd like to see it implemented, as it will imply a higher impact on the DB even when caching is enabled and this can be significant on highly trafficked sites, the ones that most benefit of having cache enabled.

As the OP has apparently implemented his own workaround through ajax, I think it would be better to look forward for a better and more flexible implementation. With "flexible" I mean a solution that can be turned "On" or Off" depending on the site's necessities and that can be overridden by 3rd party extensions (I can even fancy a statistics extension that for its storage doesn't use MySQL but another, lighter and decoupled DB)

Regards,
smz

Matt Thomas

unread,
May 21, 2014, 8:11:25 PM5/21/14
to joomla-...@googlegroups.com

The Ajax solution is a very intriguing idea, and could be something that might be easily implemented as a plugin utilizing com_ajax ( http://docs.joomla.org/Using_Joomla_Ajax_Interface). With being a plugin, it could be easily disabled and uncoupled from the current hits implementation.

Best,

Matt Thomas
203.632.9322
http://betweenbrain.com/

Sent from mobile. Please pardon any typos or brevity.

--
You received this message because you are subscribed to the Google Groups "Joomla! CMS Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to joomla-dev-cm...@googlegroups.com.
To post to this group, send an email to joomla-...@googlegroups.com.

Sergio Manzi

unread,
May 21, 2014, 8:13:38 PM5/21/14
to joomla-...@googlegroups.com
Matt, don't you think an event triggered in the router can be good solution?

Georgios Papadakis

unread,
May 21, 2014, 8:31:16 PM5/21/14
to joomla-...@googlegroups.com
Hello

so is using AJAX best solution ?

- perfomance difference ?
no, in fact you will be loading Joomla API  twice for every page load, so minor performance disadvantage  ("increase_hits.php" will load Joomla API right ?)

- easier to disable than adding code inside the AfterRoute event of any -existing- system plugin ? (by mistake, above, i said AfterRender )
no, the code inside the AfterRoute event  can be disabled via configuration

- insecure as i said above? (exploited to increment the hits counter)
ok no , i was wrong above,  because ,anyway, now anyone can hit the real article view repeately to increment the hits counter, so both solution would need to keep some accounting session info to avoid this

- important benefit is that it will count hits behind a proxy
well, it will not count hits behind a -transparent- proxy of some ISPs, because such a proxy will not allow the server to be reached,

but appending a random variable to the AJAX URL will bypass the proxy (but there is another method to bypass a transparent proxy right ??)


---> so probably using AJAX is good alternative, because it is good for counting hits behind transparent proxies,    other than this benefit the server side code will be similar


Regards

Gopi A

unread,
May 22, 2014, 2:01:47 AM5/22/14
to joomla-...@googlegroups.com
Hi,

 After go threw all post, I came with one solution which It could be solve this Hits counter.

At first, 

- If we use the Ajax for alternative solution, the problem will solve but at the same time once the cache expired then it will update the hits column once again in #__content table.So your hits count will show wrong count and this is not a good solution.

then, how to solve this issues ? I have one idea either it will work or not but any how I am sharing with you.

- Don't want to disturb the core code of Joomla anywhere.
- We create one system plugin which it will store the hits when the page refresh in separate table.
- Here we need to store the unique hits,So we have to validate using IP address as well as if there is return user we can count the return user using IP address.( For Analytics)
- If we think,this system plugin will also struggle with cache, then we can use AJAX post url code via system plugin to store the hit count details in table when page refreshed.
So, Above system plugin will do all the counting,validating IP address and return user count in separate table.

 we stored all the details in Table, now we want to fetch the details and display in article page without hanging with Cache.

Tracking the hits via AJAX is the only way to solve this due to page cache (or by using a proxy cache) by Nils Rückmann

Thanks for your suggestion, We can track the hits using AJAX via "Content plugin" 

- So, In content plugin what does, In content plugin using AJAX we can track the hits count and easy to placed this count in above article page.

For getting and storing the hits we are using System Plugin and fetching the info and placing in Article page using Content plugin with AJAX.

This above process will look like big circle to get the solution, but this the way I got from my site.

Any suggestion, Always welcome to make pull stop for this issues.

OR 

Joomla developer community can fix this issue in future version.

Thanks 


To post to this group, send email to joomla-...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages