Update: New version online, α build 2.  All old links below point to the current archive.  I'm letting this go now so that I can get some feedback.  Please, if you take it - come back and leave comments.  Any thoughts?  Things you'd like to see?  Graphs?  Download BAStats, a web server statistics plugin for WordPress.  Unzip the BAStats directory in the archive into wp-content/plugins, so that you've created wp-content/plugins/BAStats.  Activate the plugin in the WordPress admin panel.  View your stats as they emerge from the Dashboard » Stats menu.


When I want to look at the Recent Search Phrases and the Top Search Phrases I get

"Warning: array_keys(): The first argument should be an array in /home/basketti/public_html/weblog/wp-content/plugins/BAStats/BAStats.php on line 258"

What to do? I don't know what's wrong?

Hey Owen. I just installed your BAStats plugin and I'm getting this error...

Invalid argument supplied for foreach() in E:\Websites\zacharyforrest.com\wordpress\wp-content\plugins\BAStats\BAStats.php on line 142

any ideas?

I got that too:
Warning: Invalid argument supplied for foreach() in /home/makanani/public_html/wp-content/plugins/BAStats/BAStats.php on line 142
Only there isn't a nevermind for me. You should be able to login and see mine...

I'm getting

Fatal error: Cannot redeclare class basp in /home/heschj/public_html/wp-content/plugins/BAStats/BAStats.php on line 41

when trying to access the stats link from within the Dashboard.

I'm also getting

WordPress database error: [You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1] INSERT INTO wp_bas_log (visit, stamp, outbound, page) VALUES (5, '2005-02-15 18:22:19', 0, );

Ok. Please be sure that you have a 1.5 release (not a alpha/beta/gamma) before attempting this plugin. I know that some of you might not and it's still working, but I don't know if the early February builds will work because there's a new function for adding admin menus. So, John, I think you might need to upgrade. Sorry.

Assuming you've got the released 1.5 online and it's still not working, we'll work it out. But I'm pretty sure that's causing at least some of the problem.

The issue "...BAStats.php on line 142" will resolve itself if you get a hit on your site before you try looking at the stats.

Also, if you aren't seeing IP addresses, you'll need to download the update (which you should do anyway, just to be on the safe side).

Okay Owen, I've upgraded WordPress and have your update, but I am still waiting for some IP addresses to show up. (At least for now.)

Question - does this appear for all users or just those with a higher level?

I upgraded from Gamma to 1.5 stable. I still received the MySQL error BUT, then I refreshed the page and the error is gone and the stats page works fine.

All is well now.

Thanks for the plugin. I'm off to get your plugin listed pn Blogging Pro.


You need user level 8 to see the stats.

IP Addresses should start showing up only for new hits, unfortunately. Indeed, having looked at your stats, this is the case.

If you're not recording hosts, you need the update (same one as above). I was using REMOTE_HOST instead of REMOTE_ADDR. If this REMOTE_ADDR is not good on your system, I'll need to add a check.

If there are more errors with this version, please drop them here and I'll get to them soon.

Thanks for the link, John.

I just wanted to say this kicks ass. Worked perfectly in about 10 seconds. Easily the quickest and most painless install of a stats program ever. :)

Only thing it needs is a way to deal with referral spam. It's something I've been dealing with for some time.

Your code looks very clean, I think I might hack some referral spam filtering into it using the MT-Blacklist when I get a chance.

I had a problem with the Dashboard link to Stats not working when I didn't follow the installation instructions. But when I read them again, and actually followed them (by uploading the directory and its contents, instead of just the contents, to my plug-ins folder), it, well, just worked.

Very cool!

Hey there,

I just uploaded and installed the stats plugin and had no problems what so ever. Thanks for developing this! I'll let you know how performance is...

Hey Owen. I got this running at speakbold.com with 1.5 strayhorn. I'll probably be making this my stat utility of choice, replacing stattraq. Thanks for developing it.

Here a big suggestion: Could you include a way to view a summary of all of the statistics at once? That's one nice thing about stattraq and dstats, is that you can see a summary of pages viewed, referrers, browsers, search words, unique vs. hits, etc.

Also, does this count admin activity? I'm not talking about activity in the admin cp; I'm talking about does it record when the administrator surfs around his own website. I'd like to be able to surf around my own site without effecting my statistics; I want my traffic report to reflect what others are doing alone, with my own traffic taken into account.

Anyhow, great beginning. I love, love, love that this is embedded in the admin cp. Great job.

Hmm... summary... I'll have to think about how to accomplish that one, since all output is currently funneled through the same table builder. A special case might be needed. Not a big deal, considering my future plans for this.

Regarding admin activity, it's strange that you should ask. BAStats does not track traffic to the WordPress admin pages, but it does track traffic caused by a logged-in administrator. That's an interesting feature to add, though.

Try this: Go to BAStats.php, and at the bottom of the file you'll see the code that does the actual logging. You'll see how it filters requests of the admin console. You could easily add something that filters out logged-in users of a certain level. Like:

/* Actually DO statistics logging */ $do_logging = true; get_currentuserinfo(); if (isset($user_level) && ($user_level >= 8 )) $do_logging = false; if(strstr($_SERVER['REQUEST_URI'], '/wp-admin')) $do_logging = false; if($do_logging) { BAStats::log($title); }

Hey, that's pretty cool. Time to make an "options" page... ;)

i'm getting the error with the release candidate, so i turned it off, but when on i get:
WordPress database error: [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1] INSERT INTO wp_bas_log (visit, stamp, outbound, page) VALUES (3, '2005-02-16 07:28:32', 0, );

Great work! One wish: the referer view should only show hits with referers - currently it seems to show all hits and just add the referer info to those that have one, but I think this should be condensed to only referer-carrying hits.

Incidentally, the code in that last comment will prevent BAStats from logging those hits, not filter out hits by admin users in the reports.

Just writing that last sentence throws up the hairs on the back of my neck.

While it's on my mind: It should be very easy to use the stats to determine if a visitor is spamming you with referrers. BAStats only records the first incoming referrer for a visitor session (and so it's already difficult to spam the BAStats referrer logs). Sessions are maintained by BAStats by cookie or, if no cookie is sent, using an identical IP within 20 minutes. If subsequent referrers for a session are off-site, they have a high likelihood of being spam.

You could easily compare the referrer string to the one stored for the session - if it's different and off-site, you have a good spam candidate.

By the way, it does record admin cp activity inadvertently. I'm getting query results from, ironically, when the exhibit10.php file is accessed from the post interface.

Exhibit files are in the wp-content directory, so they are logged. I'm not sure whether they should be or not. Of course, if you're not logging admin-level users, these shouldn't show up anyway.

Maybe I'll add an output filter to display a human-readable label for those files instead of the filename.

That's true, if you make an option to exclude all admin activity, those files would be excluded by default. Good call.

Also, are "sessions" equal to "unique users"? If not, does this tool log that data, and where? I'd like to have just a number value on the front page that tells me how many unique users, registered or unregistered, have visited my site in a given period.

Hehe...sorry for spamming here. Another thing, it would be nice in the options section to be able to set the default of what is displayed when first accessing the stats page, such as whether it's recent or grouped by default, whether it's the last 10 minutes or the current day by default, etc.

"Sessions" is not equal to "Unique Users". Unfortunately, BAStats doesn't keep track of unique users. If you take a 20 minute break when rading a site, you generate a new session. As long as there isn't a 20-minute gap between page views, you're in the same session.

To track unique visitors, BAStats would have to add another cookie to the output and track that, too. It's probably not difficult, but I'm getting confused with all of the tables I already have. :)

You might get a close unique visitor count by crafting a query that returns a count of distinct IPs. Check the *bas_visitors.visit_ip field.

Those sound like good options for the option page. I'm reworking how the reports are generated right now, and when they're finalized, I might start on the options page (if I don't get distracted by graphs/charts first).

Ah, but the Exhibit files that it logs are just the ones used to display popups and such, not the actual image files. The BAStats::log() function is not executed when an image is served.

I'll have to craft a way to log image hits, too, if that's needed.

How about an output filter that looks for img tags with a local src and replaces them with a redirector that logs the image hit?

I noted a weird discrepancy between search strings and referers: in search strings there are google queries shown that are not shown when looking into the referers view ...

Oh, and regarding my previous request (somehow the comment didn't make it through your spam system?), I added the following three lines after line 200 in BAStats.php:

if ($what=='referers') {
$where .= " and referer_string != '' ";

This is directly above the switch on the method and ensures that the referer listing only shows hits with referers.

Here's a new one from the stats page:

Warning: array_keys() [function.array-keys]: The first argument should be an array in /space/home/jinx/www/ifeelhappy.com/htdocs/wp-content/plugins/BAStats/BAStats.php on line 258

I can't think of a reason why the tables couldn't be created. It uses the same code as WordPress does to create tables if they don't already exist. Maybe your permissions are off? I'm guessing now, without more to go on.

I recognize that you might not want to list blank entries in the referrer report, but I really do want at least a "No Referrer" entry in those rows. This lets you have a vague idea of who came to your site by typing it in, bookmark, or hidden referrer value.

About the array_keys() error: Feel free to delete that line - it doesn't affect functionality at all and is only displayed when there are no results for a report. Originally this line was for debugging; as you might notice it's inside of an HTML comment, but that doesn't keep the PHP from executing. I'll be more careful to remove these in the next release.

I'm not even messing around any more...

New version (build 3) has improved Search Phrase/Search Engine support. Added support for incoming Technorati Tag links (treated like search engine) and for filtering search phrases by search engine.

This might be the last update for today. My brains hurt.


I am using the Nicer Archives hack, and when I loaded this plugin I am now getting this error message at the top of it:

Warning: Cannot modify header information - headers already sent by (output started at /home/cruzcont/public_html/blog/narchives.php:8) in /home/cruzcont/public_html/blog/wp-content/plugins/BAStats/BAStats_logger.php on line 95

here is the link to the page: http://www.cruzcontroller.com/blog/narchives.php

Any ideas? Or are the two just not compatible?

Wow, I was already impressed with version 1, but I just installed version 3 and it is amazing. I love all the new things you have added. Keep up the great work. I was looking for just something like this to track how many people visit my site for my new WP 1.5 theme (shameless plug - http://www.fuegodesigns.com/blog/?p=109), and your plugin was just the thing I needed.

Could the plugin track images and other file types (like zip, jar, etc) that are downloaded?


downloaded this plugin and I find it very useful, thanks. It installed without a hitch on my WP 1.5 - up and running literally in seconds - great work.

Any idea when you plan to update it once more?



I don't know what the deal is with Nicer Archives. I've gotten two reports about it today, unrelated to each other. Weird. Just to be clear, I did not write Nicer Archives.

There is a new version of Nixer Archives at the Weblog Tools Collection site. I don't know if this will resolve your issues, but I have a feeling this problem is related to that code, not the BAStats code.

Tracking images and downloads is going to involve a little output buffering and redirection. Since the logging doesn't occur at the server layer, this is the only way I can think to do it. If that works for you, keep watching for an update. I like "Red & Blue make White", by the way, Josh.

Tom, I updated three times yesterday. Slavedriver. ;)

Only three times yesterday Owen?

You'll have to be more ambitious then, won't you? Why not aim for four times today, five times tomorrow, and so on?


Thanks Owen. I hope other people start to like it and maybe even use it on their blogs. Same with this amazing plugin.

Thanks for all your hard work on making this stats plug-in as painless to install, and extremely useful. It was just the ticket that I was looking for in my new 1.5 Blog.

Hi, it would be nice with an sceenshot of the plugin in action, or even a demo site. Also an list what is does in more detail would be nice.


I absolutely love it. It's nice that it's actually part of the wp admin.

What I would like to be honest is for me to setup my preference of what I see, via cookies maybe?

I would like some graphs in the same way stattraq does somethings. Definitely one of my favourite plugins so far and I use A LOT of plugins. Thanks dude.

AWESOME plugin! I have a couple of requests: 1) option to exclude IPs. 2) include internal search results in search list. 3) a whois link on IPs.

I'm liking this so far... Once I play with it more I'll give more feed back.

This is EXACTLY what I have been looking for btw :)

New version. Build 5. Includes graphs.

If you have suggestions for additional reports, please leave them in the comments or email. Thanks.

If I can pry myself away from the keyboard, I think I'll go to bed soon. Tomorrow is Exhibit Day...

I am getting an SQL error.

SELECT *, count(page_id) AS `Count` FROM wp_bas_pages, wp_bas_log WHERE page = page_id AND stamp >= '2005-02-21 01:41:29' AND stamp It seems it cannot find the tables - I have checked phpMyAdmin and the tables are indeed there and named correctly. Maybe it is a path problem? Looks like this plugin could potentially be an awesome stats plugin.

I have now noticed the stats does not log logged in users. When I log out and browse the site I get stats from those sessions - however I get this error at the top of all my pages:

Warning: in_array() [function.in-array]: Wrong datatype for second argument in c:\wamp\www\slowshirts\wp-content\plugins\BAStats\BAStats_logger.php on line 114

Further investigation - the options page does not work, is there supposed to be a table for storing the options (wp_bas_options) because this is not created upon install.

No, BAS options are stored in the wp_options table.

When you say that the options page does not work, do you mean that it's not appearing in the admin, or that it's not storing your options, or that it's not cooking your breakfast?

I just did a fresh install on a fresh WordPress SVN checkout and it's working fine for me.

Thanks again for the great plugin... it's a fantastic piece of work. I am only encountering one issue, and that's the same as comment #54 above (the options page doesn't come up.) It seems that the page it opens from the options page is BAStats.php... when I change the URL in my browser to go to BAStats_options.php then I see what I think is the options page that should come up... but I could be wrong...??? Again, thanks...

I think the comments above are due to a tab appearing on the dashboard page and options page. The one on the options page is directing to options-general.php?page=BAStats/BAStats.php not index.php? etc.
Another great plugin btw.

Please be sure that when you install this plugin you follow the instructions in the readme.txt concerning uploading the directory and not just the files.

The Options page should point to BAStats.php. The plugin figures out what page to display. I'm not sure that loading the options page as BAStats_options.php would work like it's supposed to, but since you're not supposed to run it this way, I'm not going to bother testing it.

Then again, it's entirely possible that this plugin will not work on WordPress 1.5, but only 1.5.1 due to a 1.5 bug. I'll have to look into that.


the plugin works fine in 1.5 for me with one or two minor things I'd like to ask you about, 'cos I'm not sure are they mistakes I made or misunderstandings on my part.

The graphs options in the dropdown doesn't appear to draw graphs for me. When I chose these reports I get a list of results with coloured bullet points. Is this as it should be?

Also, in the Referrer Spam section on the Options page I have entered a spamming domain both in the form domain.tld and www.domain.tld. I have ticked the two boxes below that and still that domain is appearing in Recent Referring Pages report.

Owen, I love this plugin. Thanks a million for it.


Owen, I must say, I've been addicted to BAStats since I installed BAStats 1.0b3, however, I deleted it to upgrade to 1.0b5 and now I'm experiencing errors that I didn't with the previous release, such as:

On my blog page
Warning: in_array(): Wrong datatype for second argument in /home/vincentb/public_html/blog/wp-content/plugins/BAStats/BAStats_logger.php on line 114

On BAStats tab
SELECT *, count(page_id) AS `Count` FROM wp_bas_pages, wp_bas_log WHERE page = page_id AND stamp >= '2005-02-21 09:21:59' AND stamp

Hmm... It should be drawing graphs. I should mention that you need GD enabled in your PHP installation to draw graphs.

If possible, look at the source of your stats page that should contain a graph and find the image that it's trying (unsuccessfully) to display. Open the URL of the image in your browser and forward any errors you see. Thanks!

I'm going to guess (I've made a couple changes to my local source since build 5) that your options array isn't set. Just view the Options|Stats page once and that may fix the [BAStats_logger.php line 114] error.

One of the things that's fixed in build 6 (not online yet) is the referrer stuff. With the proper options (see the Options|Stats page) you can create a blacklist of referer spammers. Apart from not logging spam hits, BAStats also provides the option to block referer spammers that are listed in your blacklist.

This is done in by the logger, which means tht any existing records of spammers will still show, but new hits won't be logged.

Update later today, after I look into some oddness in the search phrase report.

Works great for me... except the options page, of course. But awesome... graphs... :)

Ok, the official word on the missing Options page:

It is a bug in 1.5. The URL provided by the BAStats plugin to its options page is correct, but WordPress won't display it.

If you want to see the Options page, you'll need the 1.5.1-alpha version of menu-header.php:

Download menu-header.zip.
Unzip it.
Upload menu-header.php to your /wp-admin directory.

Now any plugin should be able to add more than one page to your admin panel.

Val, see if yours is working.

Ok, I grabbed the latest nighly (1.5 2005-02-21) and it fixed the issue of having the line 114 error display on blog/index.php. I'm loving this. :D

Hiya Owen.

I've gotten far enough to see the stats when I'm logged in to my admin panel after installing. But like Vince, I'm getting the following error after logging out:

Warning: in_array(): Wrong datatype for second argument in /home/trish/public_html/greenblog/wp-content/plugins/BAStats/BAStats_logger.php on line 114

I downloaded the menu-header.zip file and installed but that doesn't help. Once this happens, I can't login until I delete the BAstats files from my server.

I'm also getting the following:

Warning: Cannot modify header information - headers already sent by (output started at /home/trish/public_html/greenblog/wp-content/plugins/BAStats/BAStats_logger.php:114) in /home/trish/public_html/greenblog/wp-login.php on line 7

Warning: Cannot modify header information - headers already sent by (output started at /home/trish/public_html/greenblog/wp-content/plugins/BAStats/BAStats_logger.php:114) in /home/trish/public_html/greenblog/wp-login.php on line 8

Warning: Cannot modify header information - headers already sent by (output started at /home/trish/public_html/greenblog/wp-content/plugins/BAStats/BAStats_logger.php:114) in /home/trish/public_html/greenblog/wp-login.php on line 9

Warning: Cannot modify header information - headers already sent by (output started at /home/trish/public_html/greenblog/wp-content/plugins/BAStats/BAStats_logger.php:114) in /home/trish/public_html/greenblog/wp-login.php on line 10

I got a brief look at the stats, they look great. As long as I don't log out. :D

Build 6 (now online) should solve this problem. If it doesn't, let me know.

Looking at the Options page should also solve the problem, but if you can't see the Options page (because of the WordPress bug I mentioned earlier) then that's a real problem.

After upgrading to the latest build I am still seeing

SELECT *, count(page_id) AS `Count` FROM wp_bas_pages, wp_bas_log WHERE page = page_id AND stamp >= '2005-02-21 19:47:06' AND stamp

Yeah, those queries are supposed to be there in this pre-release. This is not a bug unless that's all you are seeing.

It is not only helpful for me, but enterprising souls could use the query to display report results on a page other than the results page. Or even better, to make tweaks to the queries and send them to me for inclusion as new reports.

BrowserMap safari string

'^Mozilla/\d+\.\d+ \(Macintosh; U; PPC Mac OS X; en\) AppleWebKit/\d+\.\d+ \(KHTML, like Gecko\) Safari/(\d+\.\d+)'=>'Safari $1'

Otherwise it gets recorded as Mozilla

I changed some of the options on the options>stats page. Now I get the following error if the boxes aren't ticked:
Warning: in_array(): Wrong datatype for second argument in /home/thewayt/public_html/blog/wp-content/plugins/BAStats/BAStats_options.php on line 37 /> Same for each tickbox, no errors apparent when looking at my site while logged out.

I notice a quirk when loading a "page" with the same post slug as a "post". The post content shows before the page content. For example:

The page-

The post-

It only happens with your plugin. I've also disabled all plugins with only your's (and sk) active and it still happened. Please, try to duplicate this yourself.

Oh, and one other thing, my links won't work unless you're logged in as admin, if I log out, I don't see it. Weird huh?

Basicilly, users don't see it, but I see it when I'm logged in as admin. I'll try and test on my local box with a clean install if I get a chance. My site is using 1.5 stable.

Very cool plugin. Thanks! I had the same "header" problem some others had and as soon as I saw and came here, I already found the fix. Great work!

Wow, Owen! What an awesome plugin... I was up and running in 2.0 seconds flat. Love it! *huggles* Thank you for creating such a great statistics module.
:) Joy

Tiny bug, so to speak, but it is more related to WordPress:

I had removed the plugin, and I had manually dropped the db tables. Upon reinstalling it a bit later, it did not recreate the tables until I also removed any reference to it in the options.

My problem seems to have gone away, which is good. I think I might have caused it when trying to empty the tables. Would it be possible to add a 'clear stats' button in a future release?

Owen, your plugin is much more interesting than most stat analysers. May I make a feature request?

It would be neat to add a few digests. In particular:

- The number of individual visitors
- The number of feed subscribers
- The number of pages the average user visits
- The paths users take (i.e. /, then /post1, then...)

Well, you can get the path through the site to some degree already. Click on an IP address within one of the reports (like Recent Hosts). The Host Profile report will display. From there, choose the Recent Page Hits from x.x.x.x report, and you'll see a chronological list of all of the pages hit from that IP within the time range and limit specified.

I'll have to figure out how to work the other aggregate reports that you suggest. This might be interesting as a default report page.

Tracking the number of subscribed feed readers is difficult for a number of reasons. BAStats doesn't track returning visitors whose sessions have expired, so it can't tell if it's the same user that hit the feed page after a 30-minute delay. Many services (Bloglines, for example) add the number of users subscribed into their user agent string, but this is not a consistent behavior between services.

Plus, I still need to add image tracking...

Actually, I've experimented visitor tracking a bit, but with no real success so far. I think a webmaster's key concern, in many ways, is two-fold:

1. Where do new visitors land on my site, and how did they land on it (e.g. bookmark or rss feed, search engine, referring page)?

2. What did they do once on the site?

Most stat tools I've tried concentrate on providing stats for the first point, and give bulk, seldom useful data (top visited pages, top referring pages, etc.) related to the second. Your tool is among the better ones, but it is no different.

Imho, useful information is closer to the following two digests:

1. visitor-driven behavioral patterns: p visitors landed on page1 from a search on keyword1, then visited page2, cat_A, page3

2. page-driven behavioral patterns: of the q visitors which visited page1, r came from referrer1, s came from search1, t came from page2, u went to page3, v went to page4, etc.

As an aside, note that the two patterns are semantically interesting: odds are strong that they describe related topics. As such, having the stat module interact with the search engine could be very interesting as a next step.

Well, I see a few stats packages trying to offer what you suggest. I spend some small part of my afternoon thinking about how to do it, and it seems reasonably easy to do, although it will add a bit more processing and data to the already "large" load I'm putting on the server.

Still, I've got to ask what purpose this will serve to a traditional blogger? I can see that this type of page path statistic would be userful to a business owner who wants to maximize purchases based on incoming links - make the best return path the primary result - but I don't see how knowing any of that will benefit the average blogger. Are you really trying to optimize your search engine results for specific terms so that people find your blog for them? That seems odd to me.

In any case, all of what you want done can be accomplished using the data that BAStats tracks. It just needs to be massaged to produce the report you want. I'm not sure if I'm going to commit to that yet, since I don't believe a page path report would be anything but a novelty for most blog users, but we'll see.

Beside the server load for high volume blogs (which is unavoidable without some sort of an RRD), INCREDIBLE!!

Regarding the raw statistic, it would depend on what you call a traditional blogger. Would you consider yourself a traditional blogger? If you would, that would mean you're writing for yourself only. Traffic or no traffic, you would not care less. But then, stats are pretty useless as well.

For a not-so-traditional blogger, traffic does count a minimum. More so for a business blogger. Your key interests become:

1. Which pages are bringing traffic into your blog?
2. Do users visiting these pages visit the rest of your blog (i.e. hit 'home' after visiting a plugin page)?
3. Do you they return (i.e. subscribe to your feed)?

Even if you are mostly writing for yourself, as most bloggers -- myself included -- do, all three points impact what you write in a way or another. For instance, if it is obvious that you never get repeat visitors, you might want to better introduce your posts, or even related links to one another manually, so as to make it easier for newcomers to catch the thread of your thoughts.

You're quite right regarding one point, though: These statistics mainly interest the business user, who is seeking to maximize the number of users that land on the 'buy' page.

What you miss is the border-effects the traditional blogger would be interested into.

On top of these, you could imagine that the stats communicate with the search engine module. I mentionned that WordPress' search engine is one of its weaknesses previously, both on my blog and in the support forum. One of the things stats can do about it is to serve as a guide to bend the results: If plenty of users click on the second result rather than the first, for instance, odds are it is more relevant.

More importantly in the short term, the stats module can also serve to automatically find related posts, if you insert a supervised machine-learning algorithm in the process. For instance, if you note that you're regularly getting A, B, C patterns, the server might want to try insert a link from A to C. If you start getting A, C patterns, then you keep the link; If not you discard the link and keep a reference that you tried. This can lead to results that are a lot more relevant that the related posts plugin.

I'm currently working on a protocol suggestion, to streamline the latter point, trackbacks and pingbacks. I'll give send you a notice when I post it on my blog.

Owen, you're counting pings and tracks in the stats. This can account for quite a number of hits -- e.g. I just got ~300 hits, for just one post with plenty of internal links.

So you're pinging yourself? Does everyone do this? It seems... naughty...

I can certainly add an option to filter out hits to the comments/trackback/pingback pages. Should it do this only if the ping is local?

naughty... lmfao... all you have to do is refer to and link to a past post and you've got a ping! ;-)
Yes, only local should be filtered out

Sure, why not? Say you mention a past post... That way, you can write a digest every now and then, and automatically get the link back to the digest. Backreferences makes a site a lot more navigable.

No, I wouldn't say it's stable, yet. There are a couple of things I want to do before the "non-beta release".

First, I need to fix the search phrase logging, which is doing weird things with referers. You'll notice that even in Build 6 some of the search phrases that appear in the report don't actually match the query string of the page that they're supposedly coming from. I think I have this fixed in my test site, but I have to let it run for a while to make sure.

Also, as Dougal pointed out, the spam referer code isn't working right. It's only filtering out the first entry in the list. I don't yet have an idea why it's not doing the others.

Finally, I've received a couple of emails already about the size of these tables getting pretty large. Mine is a really dumb size already. I need to provide a push-button way to archive and roll-up old info.

When all that's done - release time.

I should probably document somewhere that I'm a 31-year-old father of two with a full-time programming day job and a social life; I'm going to a Rusted Root concert with some old friends this Friday, possibly a funeral on Saturday (depending on whether that's the actual date or not), and hosting relatives for my son's christening on Sunday. I'm delacately balancing WordPress development (BAStats, Exhibit, RedAlt, and a few other surprises) with, you know, actually watching my kids grow up, while trying to get more than 2 hours of sleep each night.

The moral of my sad tale - Please be patient.

Owen, This plugin is way cool! It blows the doors off of StatTraq. Thanks for putting the time into such a great tool! I did run into one potential problem that you might want to know about...

I'm using a private address inside my firewall and BAStats was displaying for hits from all of my inside hosts. It looks like your iptoint function is correctly converting the address to an integer, but the inttoip was having trouble going back the other way. I found a function in php called long2ip() that fixed the display and I now get the correct IP on the Dashboard.

Hope this helps! ---Thom

Installed your BAStats at http://www.trommetter.com/log/ I realy like what you've done. One thing I might suggest is integration with something like WPBlacklist to filter out referer spam. I'd like to be able to separate the wheat from the chaff when I'm looking at my statistics.

Please, could you explain what are the "Unique Pages Served", is it like the unique visitors?
Thanks for the plugin

Unique Pages Served: The count on different URLs served by your site. If you have two different ways (permalinks) to access the same post, that might account for two of whatever this number is for your site, but generally speaking, one post/archive view/home page/feed equals only one unique page served. This number will get to a certain high mark, then slowly trickle up as you add new posts, creating new unique page URLs. My site has served content for 16452 unique URLs.

Total Sessions: This is the total number of contiguous user visits. If you come to the site and browse around over 80 pages for two hours, you add only one to this count. If during that time you take a single twenty-minute break, you add two to the count. My site has served 104091 sessions since I turned on BAStats.

Total Page Hits: This is the total number of pages served that are tracked by BAStats. If you look at two pages on the site, that adds two to this count. If you are just getting started in stat-watching, then you'll be excited about this number, but you should really be looking at what this number is divided by Total Sessions. My site has served 208820 pages since I turned on BAStats.

The conclusion is that my average visitor views just a hair more than 2 pages per visit. This is actually pretty darn good for a site like mine, and I'm very happy about it.

Make sense? ;)

Bloody Awesome....Can't wait to watch it rack up.....This is not full version?
How can I have the stats page open to "Everything" "Last 24hrs"
Kick ass plug in..

This Kicks ass!
So I assume the final will have some sort of options. Opening View, Or a Summary Page (20 each referrer, pages, agents, etc on one page)
I'll blog about it after the release.
Thank You!

Better yet, uncheck the option on the Stats option panel that tracks hits from logged-in WordPress users of level 8+.

If I click on Options in WordPress and then click on Stats, I get essentially a blank page. It doesn't show me anything in terms of Stats options. Any idea what's going on?

This plug-in is great, I check it often.
An additional option that I think would be nice is a just a dumb tracking for overall over time, perhaps sessions per day, or sum of page hits. Top 5 works nicely for this function, but it would be nice to see an overall compact view for how traffic and viewors are growing or shrinking.

I installed BAStatts on a couple of blogs a few days ago, and it's running great. One problem: all the times in the reports are off by two hours. I've got my timezone set as GMT -6, but the times in the reports are all two hours earlier. Anyway to fix this?

Ditto Owen,

I'm getting a blank page on the Options -> Stats page as well.

Also, on this new theme Owen, the titles on Posts and comments are not appearing on Firefox on Mac. On Safari, post titles appear but are not links and comment titles (commenter name and date) don't appear either.

And finally, I am unable to submit comments using Firefox - I just get re-directed to a blank wp-comments-post.php and the comment doesn't appear.

I'm submitting this now using Safari



very cool plug in. I agree with brainwidth on the time zone issue. Mine is like 6 hours into the future. Not really too bad of a problem. Which php would have to be edited to alter this?

hmm.. I found this in BAStats_logger.php
{ BAStats::log_search($_SERVER['HTTP_REFERER'], $sdata->referer); if($page->page_id != '') { $wpdb->query("INSERT INTO {$wpdb->log} (visit, stamp, outbound, page) VALUES ({$sid}, '" . date('Y-m-d H:i:s') . "', 0, {$page->page_id});"); }
Is it possible to alter this to add or subtract a certain number of hours?

Ditto on the blank options page.

I'm digging now to see how I could have screwed up the install, but don't see how it is possible. (yet)



I had a problem with BA stats after an install, uninstall, manual table erase, and reinstall.

I solved this by deleting all options involving BAStats. You might want to try that.

It's only the "Stats" page in the Options that is blank. All else is fine. In fact, I'm getting data from the "Dashboard -> Stats" page. Simply don't have any options I can configure for BAStats.

Any ideas?

Omar I had the same problem and I did something. I think there are some problems with the options page (Ihad more problems with other plugins) so I recommend you to change the options location. In order to do this you have to:
1) delete line 73: add_options_page('BA Stats', 'Stats', 8, $pfile, array(&$this, 'plugin_options'));
2) write instead:
add_submenu_page('edit.php', 'BA Stats', 'Stats', 8, $pfile, array(&$this, 'plugin_options'));
Once you have changed this, I think you will be able to see the options in the management menu.

That killed the entire thing! I can get into nothing with that change in effect. All I get is the following:

"Parse error: parse error, unexpected T_STRING in /home/omar/public_html/bullspeak/wp-content/plugins/BAStats/BAStats.php on line 73"

Cripes! You guys are spamming subscribers...

Is this your issue? It probably is:

This problem will only show itself if you have another plugin activated that implements an Options panel in the admin. That's why it works for some people in 1.5 and not others. Whichever plugin you activate first is the one that will work.

If this is not your issue, then I don't know what the problem is. The BAStats option page works fine in any 1.5.1 alpha installs that I have going (it's a 1.5.1 plugin because 1.5 has the bug mentioned above). This plugin will not be officially released for WordPress 1.5 because of this issue (among some others).

Just installed it on both my blogs. Took hmmmm about 10 seconds a piece. Very nice.

One question I have though. Are the statictics being pulled from existing information are does the plugin install hooks into the wordpress api so it can begin gathering information? My main concern here being is that if you release a future version with a new graph, etc, etc will it's data only be relevant from the time the update is made.

Just curious. Nevertheless....very very nice and simple.

--Michael I.

Just installed it on my Wordpress 1.5 installation without a hitch. Very nice!

In addition to seeing the page, date, and host ip could we also see the hostname. I find it easier to identify hits using the hostname than the IP address.


Hey Owen,

Like everyone else has already said, awesome plugin. You rock.

My feature request is kinda related to the previous one - I thought that maybe you could do a filter for hosts like you do for pages? So if I get a lot of hits from Google, I can say that IP xxx.xxx.xxx.xxx should be displayed as Googlebot, and not have to go whois'ing every time I want to check hosts?

That would be awesome!

Again, thanks for BAstats.
I am having some strange behavior that I would like to report - maybe you are already aware.
When I graph (for example) Top 5 Page Hits Segmented over the last 7 days - I get a graph. 4 of the 5 results are from feeds, but the other is a specific page - call it "Post A".
When I just look at page hits for the last 7 days "Post A" is not even among the top ten (it's number 12). If I look at the stats for today (in the "from midnight today" looking right before midnight to get basically the full day's stats "Post A" is number 14.

The bottom of the Stats page is showing this:

SELECT *, count(page_id) AS `Count` FROM wp_bas_pages, wp_bas_log WHERE page = page_id AND stamp >= '2005-04-10 21:56:15' AND stamp

Any possibilty of expanding BAStats to guess the country of the viewer ( IP to country ) ?

Oh, by the way :

would it be possible to add a javascript function which could avoid us to clic on the "Show" button when choosing stats to be displayed via the dropdown menu ? (Yeah, I'm lazy ;))

Owen -

Would it be possible to also track username? I am thinking that registered/logged-in users can be tracked with the wordpressuser_$domainhash cookie, comment authors have the comment_author_$domainhash cookie, and for others default back to anonymous_at_IP_address.

I'd like to be able to know the last time when someone was on the site.

Just wanted to thank you for this great plugin. I never knew home many people searched for "Ashlee Simpson pictures" before (my site has a single picture of her wearing a T-shirt labeled "I like to get it on with boys who vote").

When re-installing BAstats (Deleted tables, and files), It doesnt re-create the tables at all. This is a bug you should fix. More info here:


Open BAStats.php from the plugin directory for editing.

Look for a line near the top that says:
`var $table_version = 6;

The number 6 may be a different number. Whatever it is, increase it by 1.

Save the file and reactivate the plugin to recreate the tables.

Apart from that, BAStats development is on a break. Why?

One reason- Because Asymptomatic gets 3000+ sessions (not hits, sessions) per day, and BAStats makes the MySQL process on the server eat processor time. I worry that as your traffic builds up, BAStats will start to have this effect on your system, too. Please report this if you're using the beta and it happens to you.

Another reason- I'm embroiled in other development (plugins, work, secret WP projects) at the moment, and figuring this one out isn't currently a priority for me.

Another reason- I wrote all of the reports myself, and some are slightly broken in ways that are difficult to fix. I get a lot of suggestions for what to add to the plugin, but never any suggestions on how to fix what's currently wrong with the plugin. Introducing new features when the existing features aren't perfect seems irresponsible. But maybe if people forwarded some fixes for the reports...

Keep in mind that BAStats has never left beta, although it's been there for a while and has had several updates. Everyone who uses it seems to like it, and I might be the only person who has problems (I'm on a Windows server, see, which may soon change), so I'm sure to get back to it eventually, just not this afternoon. I hope you understand.

Just installed it, looks cool...

options are also decent enough...

and yes graphical representation can make it much better...


oh, i just found graph option but it doesnt show the image for some reason...

No idea why, GB Library is enabled on the server...

You spend days trying to get your own plugin in to work then find that someone else has already done a much better job!

Thanks for the great plugin ;-)

P.S. Ubuntu Linux comes up as "Linux [unknown version]", presumably other Linux versions get a mention, could Ubuntu?

The thing is, as long as you do an INSERT for each page request and your page gets slashdotted (or something similar), you're really using the wrong dbms. MySQL can do queries very fast, but inserts are damn slow.

As I said, I haven't looked at the code yet in detail, but instead of the auto_increment, you might want to consider doing that in the PHP. When the code starts, do a SELECT MAX(id) on the tables and get the highest number and make it a global variable which you query with a function that automagically ups the variable with one. That's a lot more efficient than auto_increment and it solves the INSERT DELAYED thingy. Letting the PHP do the auto_increment is much more efficient, anyway.

This weekend I'll setup a test-site here and trash-test the stuff. If I get somewhere near the same results as you, we'll now your setup isn't screwy ;-) Besides, it's hard to believe anyone can mess up such a setup... It quite straight forward, really. Or is this site running on a... *shiver*... M$ host?? ;-)


Do you have a "TODO" list somewhere? Or a list of the things you consider b0rken? I'll be having some spare hours soon and I might want to hel fixing those problems. Let me know ;-)

Also, how exactly do you notice the plugin bogging down the MySQL server? Are SQL queries slower or something? Without having looked at the code in detail, might I suggest using "INSERT DELAYED"? It'll break a non-MySQL server (you might want to make it an option), but I expect it'll speed up the inserts quite a lot. Take a look at the documentation: http://dev.mysql.com/doc/mysql/en/insert-delayed.html

Btw, it's working for me, the plugin, and it looks quite nice. There is a wishlist here, though ;-) I'll post that one later.

I'm not snubbing Linux variants. I basically copied the list of user-OSes from somewhere else, and if the list returns "unknown" for your version of Linux, then feel free to add the appropriate regex to the OS list. It's pretty straightforward.

My to-do list is simple:

1.Fix the MySQL thrashing.
2.Correct the queries/code that return matches between search engine queries and referer strings, especially those for local searches.
3.Rearrange the code that returns data for graphs to make it more intelligible.
4.Add a stat-purge/archive feature to reduce the table size before the size starts to affect performance visibly.

I can tell MySQL is getting bogged down because while the plugin is active I'm watching the mysqld process use 98% CPU, and pages return from the server very slowly. I'm willing to concede that my configuration of MySQL/PHP might be screwy, though, and that there might not be an issue at all. But I don't want to go spreading around code that I know could cause people to lose their host due to overuse of server resources.

DELAYED seems like a good idea, and I was really excited to try it (it was a smack-the-forehead moment), but you'll have to figure out how to reliably get the next auto_increment number without munging subsequent request threads. I know there's a way to obtain the number (it'll use a SELECT and an INSERT DELAYED instead of just the INSERT), but I don't know if it'll hld up for simlutaneous requests or if on the whole the change will be more efficient.

Hey, I just upgraded to Wordpress 1.5.1-alpha and BAStats gives an error at get_currentuserinfo() on line 537. This is the only thing that has changed so I assume the upgrade was the issue.

Yeah, my advice (as always) is not to upgrade to the alpha on your production site.

The problem is caused by the relocatable functions. get_currentuserinfo() is one of those functions. What this means is that the function is not defined when plugins are loaded.

That entire chunk of BAStats code will need to move inside a hook before it works again.

I'll release something that works with 1.5.1 final before 1.5.1 final is available.

Great Thanks, valerie!!!

But i have a second question. It's possible to don't count the own visits. perhaps by host...

example: gethostbyname("xyz.ath.cx")


I also want to put in a suggestion that at least 2 people above already have suggested:

It is also easier for me to identify hits by hostname rather than (or in addition to) IP address, because on campus here at UCSD, our hostname includes our first initials and last name, so if I could automatically see all hostnames, then I know exactly who on campus is viewing my site.

Thanks! This is a great plugin!!

Using hostnames has two issues: First, it's resource intensive to go out fetching hostnames all the time. Second, not every server supports the commands that can do that. Tricky business.

Have you guys gone to the wp-hacks page to get the new version? It seems like it works with 1.5.1. I mean, I'm running it here (1.5.1) and it's working.

Would it be super tricky for the script to cache results of previous IP resolutions? Or maybe defer (cron?) lookups? Or run lookups only once a day adding to the cache? Or only lookup hosts with NN hits (per day)?

using bastats with wp 1.5.1 makes feeds crash and show "Warning: Cannot modify header information - headers already sent by (output started at /home/PATH OF THE BLOG/wp-content/plugins/BAStats/BAStats.php:560)". Deactivating the plugin solves the problem. i'm i doing something wrong?


I downloaded the latest version of BAStats and it is reporting that it is 1.0β build 8. I'm currently using 1.0β build 8 and it is causing my feeds to crash.

I'm using WP 1.5.1 with the latest updates for the bugs in 1.5.1 (i.e. latest versions of functions.php, wp-blog-header.php and xmlrpc.php).


Since the server move, that URL isn't good. I have changed the link in my original post above, and the link on the wp-hacks page itself has always been good. Try that.


can’t download the latest version of BAStats (currently using 1.0β build 8 and it is causing feeds crash).

When I try to download from http://www.asymptomatic.net/wp-hacks/BAStats.zip I get re-directed to http://www.asymptomatic.net/wp/wp-hacks/BAStats.zip which gives a “The requested document was not found on this server” error


Try overwriting the Build 8 that you have with the Build 8 that's available for download.

The next "build" will simply use the Subversion $Id$ marker, even though that is probably too granular for general use (you'll be updating a lot more often if you update on every build number change), it will apparently cause less problems than when I neglect to update a build number whenever I do a check-in. Gah!


this build 8 works (where the other didn't!).

Thanks for that - I really hate having to de-activate my stats - shows how much I love the plug-in!



For some reason, BAStats no longer recognizes the Google Images referrers properly. I'm guessing they probably changed the structure of their URIs or something, but I don't know enough about strings to help fix the code. Sorry!

The plugin works really nice on my site. I really like the local search, so I can find out what my readers are searching for. Thanks for the plugin!

Is there a known problem where BA Stats gives back instances of host IP for those of us who upgraded to 1.5.1? Do you know what this means and if there is a solution?


Hey Owen - when you do updates to the file and the original post, where you say "Update:" would you mind putting the date of the update? This way I'll know if it's a new file since the last one I downloaded...

Is that possible?


Oh, another question - is it possible to change the default setting for the stats for the "count" and "date range" and "report"?

It seems to default to the last 10 minutes, and well, I don't get THAT many visitors to need to look at it in that detail.

If not, perhaps an idea for the future?


Nick asked on 3 Jun

Oh, another question - is it possible to change the default setting for the stats for the “count” and “date range” and “report”?

It seems to default to the last 10 minutes, and well, I don’t get THAT many visitors to need to look at it in that detail.

I actually found a way to do it, although Owen may have reasons for not making the edits. Search through BAStats.php and find the values for the different arrays, making a note of the values you want to use. Then look for the function plugin_content and you can edit the variables there. Just be very careful or you could screw the pooch. I don't see the report definitions, but the initial Count and Date Range should be vairly easy to change.

What's your take on this, Owen?

My only reasons for not making the edits at present is that I'm concentrating on other things for the time being.

The method described for changing the default seems reasonable if you have some knowledge of PHP.

Don't come running to me when you screw the pooch; I have no interest in your turn to beastiality prompted by editing my plugins. :)

Oops, I tried to click the edit link and my post was deleted... I am a dummy... =

Nick - Just go throught the scripts and edit them to get any effect/funtionality you want... It's not hard as long as you know some basic PHP

Owen, thanks for this great plugin, and sorry you have to deal with all the idiots... To a point I know how you feel sometimes.

Well, here's a bug....long2ip() and ip2long() use negative values sometimes, but the make_tables() code sets up the visit_ip field to be unsigned in the DB. "higher" IPs can show up as because the value overflows.

just change this: (BAStats.php)
"$qry = "CREATE TABLE {$table_prefix}bas_visitors (
visit_ip BIGINT(11) UNSIGNED,"

Is there any way we van move the added "" below the XML declarationon each page? Not only is it giving me some problems with some of my feeds, it also keeps my blog from validating. It may be kind of minor, but I'm seeing it causing some issues and I know it's causing problems for others.

Thanks you very nicely done.

Only request would be a way to set the default. Having to change it each time is a little tiresome.


I'd like to request that you have a menu that allows one to see what internal searches are performed on the blog site. That way, I can create content based upon what my readers are searching upon using the wordpress search tool

Sorry, commenting on this post is disabled.