summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/HitCounter.php95
-rw-r--r--app/Module/ExtraInformationModule.php6
-rw-r--r--app/Stats.php6
-rw-r--r--app/Theme/BaseTheme.php69
-rw-r--r--includes/hitcount.php91
-rw-r--r--includes/session.php7
-rw-r--r--index.php15
-rw-r--r--themes/clouds/css-1.7.0/style.css21
-rw-r--r--themes/colors/css-1.7.0/style.css21
-rw-r--r--themes/fab/css-1.7.0/style.css21
-rw-r--r--themes/minimal/css-1.7.0/style.css23
-rw-r--r--themes/webtrees/css-1.7.0/style.css21
-rw-r--r--themes/xenea/css-1.7.0/style.css21
13 files changed, 185 insertions, 232 deletions
diff --git a/app/HitCounter.php b/app/HitCounter.php
new file mode 100644
index 0000000000..6e5dff03fa
--- /dev/null
+++ b/app/HitCounter.php
@@ -0,0 +1,95 @@
+<?php
+namespace Fisharebest\Webtrees;
+
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2015 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Class HitCounter - measure page popularity
+ */
+class HitCounter {
+ /**
+ * Count the number of times this page has been viewed.
+ *
+ * @param Tree $tree
+ * @param string $page
+ * @param string $parameter
+ *
+ * @return integer
+ */
+ public static function countHit(Tree $tree, $page, $parameter) {
+ global $WT_SESSION;
+
+ // Don't increment the counter while we stay on the same page.
+ if (
+ $WT_SESSION->last_tree_id === $tree->getTreeId() &&
+ $WT_SESSION->last_page === $page &&
+ $WT_SESSION->last_parameter === $parameter
+ ) {
+ return $WT_SESSION->last_count;
+ }
+
+ $page_count = self::getCount($tree, $page, $parameter);
+
+ if ($page_count === 0) {
+ Database::prepare(
+ "INSERT INTO `##hit_counter` (gedcom_id, page_name, page_parameter, page_count)" .
+ " VALUES (:tree_id, :page, :parameter, 1)"
+ )->execute(array(
+ 'tree_id' => $tree->getTreeId(),
+ 'page' => $page,
+ 'parameter' => $parameter,
+ ));
+ } else {
+ Database::prepare(
+ "UPDATE `##hit_counter` SET page_count = page_count + 1" .
+ " WHERE gedcom_id = :tree_id AND page_name = :page AND page_parameter = :parameter"
+ )->execute(array(
+ 'tree_id' => $tree->getTreeId(),
+ 'page' => $page,
+ 'parameter' => $parameter,
+ ));
+ }
+
+ $page_count++;
+
+ $WT_SESSION->last_tree_id = $tree->getTreeId();
+ $WT_SESSION->last_page = $page;
+ $WT_SESSION->last_parameter = $parameter;
+ $WT_SESSION->last_count = $page_count;
+
+ return $page_count;
+ }
+
+ /**
+ * How many times has a page been viewed
+ *
+ * @param Tree $tree
+ * @param string $page
+ * @param string $parameter
+ *
+ * @return integer
+ */
+ public static function getCount(Tree $tree, $page, $parameter) {
+ return (int) Database::prepare(
+ "SELECT page_count FROM `##hit_counter`" .
+ " WHERE gedcom_id = :tree_id AND page_name = :page AND page_parameter = :parameter"
+ )->execute(array(
+ 'tree_id' => $tree->getTreeId(),
+ 'page' => $page,
+ 'parameter' => $parameter,
+ ))->fetchOne();
+ }
+}
diff --git a/app/Module/ExtraInformationModule.php b/app/Module/ExtraInformationModule.php
index 70e2d8ebd6..8641aae33f 100644
--- a/app/Module/ExtraInformationModule.php
+++ b/app/Module/ExtraInformationModule.php
@@ -61,11 +61,7 @@ class ExtraInformationModule extends Module implements ModuleSidebarInterface {
print_fact($fact, $controller->record);
}
}
- if ($WT_TREE->getPreference('SHOW_COUNTER')) {
- $hitCount = 0;
- require WT_ROOT . 'includes/hitcount.php';
- echo '<div id="hitcounter">', I18N::translate('Page views'), ' ', $hitCount, '</div>';
- }
+
return strip_tags(ob_get_clean(), '<a><div><span>');
}
diff --git a/app/Stats.php b/app/Stats.php
index cb5ed61cf9..1f2b20ee64 100644
--- a/app/Stats.php
+++ b/app/Stats.php
@@ -5722,11 +5722,7 @@ class Stats {
// indi/fam/sour/etc.
}
- $count = Database::prepare(
- "SELECT SQL_NO_CACHE page_count FROM `##hit_counter`" .
- " WHERE gedcom_id=? AND page_name=? AND page_parameter=?"
- )->execute(array($this->tree->getTreeId(), $page_name, $page_parameter))->fetchOne();
- return '<span class="hit-counter">' . I18N::number($count) . '</span>';
+ return '<span class="odometer">' . I18N::digits(HitCounter::getCount($this->tree, $page_name, $page_parameter)) . '</span>';
}
/**
diff --git a/app/Theme/BaseTheme.php b/app/Theme/BaseTheme.php
index 798cc2d84e..1fca7216af 100644
--- a/app/Theme/BaseTheme.php
+++ b/app/Theme/BaseTheme.php
@@ -31,6 +31,9 @@ abstract class BaseTheme {
/** @var string An escaped version of the "ged=XXX" URL parameter */
protected $tree_url;
+ /** @var integer The number of times this page has been shown */
+ protected $page_views;
+
/**
* Custom themes should place their initialization code in the function hookAfterInit(), not in
* the constructor, as all themes get constructed - whether they are used or not.
@@ -366,7 +369,8 @@ abstract class BaseTheme {
protected function footerContent() {
return
$this->formatContactLinks() .
- $this->logoPoweredBy();
+ $this->logoPoweredBy() .
+ $this->formatPageViews($this->page_views);
}
/**
@@ -401,6 +405,25 @@ abstract class BaseTheme {
}
/**
+ * Add markup to the hit counter.
+ *
+ * @param integer $count
+ *
+ * @return string
+ */
+ protected function formatPageViews($count) {
+ if ($count > 0) {
+ return
+ '<div class="page-views">' .
+ I18N::plural('This page has been viewed %s time.', 'This page has been viewed %s times.', $count,
+ '<span class="odometer">' . I18N::digits($count) . '</span>') .
+ '</div>';
+ } else {
+ return '';
+ }
+ }
+
+ /**
* Create a pending changes link for the page footer.
*
* @return string
@@ -486,6 +509,9 @@ abstract class BaseTheme {
* @return string
*/
public function head(PageController $controller) {
+ // Record this now. By the time we render the footer, $controller no longer exists.
+ $this->page_views = $this->pageViews($controller);
+
return
'<head>' .
$this->headContents($controller) .
@@ -988,6 +1014,21 @@ abstract class BaseTheme {
}
/**
+ * Generate a menu item to change the blocks on the current (index.php) page.
+ *
+ * @return Menu|null
+ */
+ protected function menuChangeBlocks() {
+ if (WT_SCRIPT_NAME === 'index.php' && Auth::check() && Filter::get('ctype', 'gedcom|user', 'user') === 'user') {
+ return new Menu(I18N::translate('Customize this page'), 'index_edit.php?user_id=' . Auth::id(), 'menu-change-blocks');
+ } elseif (WT_SCRIPT_NAME === 'index.php' && Auth::isManager($this->tree)) {
+ return new Menu(I18N::translate('Customize this page'), 'index_edit.php?gedcom_id=' . Auth::id(), 'menu-change-blocks');
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Generate a menu for each of the different charts.
*
* @param Individual $individual
@@ -1534,6 +1575,7 @@ abstract class BaseTheme {
$this->menuMyIndividualRecord(),
$this->menuMyPedigree(),
$this->menuMyAccount(),
+ $this->menuChangeBlocks(),
$this->menuControlPanel(),
)));
} else {
@@ -1743,6 +1785,31 @@ abstract class BaseTheme {
}
/**
+ * How many times has the current page been shown?
+ *
+ * @param PageController $controller
+ *
+ * @return integer Number of views, or zero for pages that aren't logged.
+ */
+ protected function pageViews(PageController $controller) {
+ if ($this->tree->getPreference('SHOW_COUNTER')) {
+ if (isset($controller->record) && $controller->record instanceof GedcomRecord) {
+ return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->record->getXref());
+ } elseif (isset($controller->root) && $controller->root instanceof GedcomRecord) {
+ return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, $controller->root->getXref());
+ } elseif (WT_SCRIPT_NAME === 'index.php') {
+ if (Auth::check() && Filter::get('ctype') !== 'gedcom') {
+ return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, 'user:' . Auth::id());
+ } else {
+ return HitCounter::countHit($this->tree, WT_SCRIPT_NAME, 'gedcom:' . $this->tree->getTreeId());
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /**
* Misecellaneous dimensions, fonts, styles, etc.
*
* @param string $parameter_name
diff --git a/includes/hitcount.php b/includes/hitcount.php
deleted file mode 100644
index d2be22318e..0000000000
--- a/includes/hitcount.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-namespace Fisharebest\Webtrees;
-
-/**
- * webtrees: online genealogy
- * Copyright (C) 2015 webtrees development team
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Defined in session.php
- *
- * @global Tree $WT_TREE
- */
-global $WT_TREE;
-
-// Only record hits for certain pages
-switch (WT_SCRIPT_NAME) {
-case 'index.php':
- switch (Filter::get('ctype', 'gedcom|user', Auth::check() ? 'user' : 'gedcom')) {
- case 'user':
- $page_parameter = 'user:' . Auth::check();
- break;
- case 'gedcom':
- $page_parameter = 'gedcom:' . $WT_TREE->getTreeId();
- break;
- default:
- $page_parameter = '';
- break;
- }
- break;
-case 'individual.php':
- $page_parameter = Filter::get('pid', WT_REGEX_XREF);
- break;
-case 'family.php':
- $page_parameter = Filter::get('famid', WT_REGEX_XREF);
- break;
-case 'source.php':
- $page_parameter = Filter::get('sid', WT_REGEX_XREF);
- break;
-case 'repo.php':
- $page_parameter = Filter::get('rid', WT_REGEX_XREF);
- break;
-case 'note.php':
- $page_parameter = Filter::get('nid', WT_REGEX_XREF);
- break;
-case 'mediaviewer.php':
- $page_parameter = Filter::get('mid', WT_REGEX_XREF);
- break;
-default:
- $page_parameter = '';
- break;
-}
-if ($page_parameter) {
- $hitCount = Database::prepare(
- "SELECT page_count FROM `##hit_counter`" .
- " WHERE gedcom_id=? AND page_name=? AND page_parameter=?"
- )->execute(array($WT_TREE->getTreeId(), WT_SCRIPT_NAME, $page_parameter))->fetchOne();
-
- // Only record one hit per session
- if ($page_parameter && empty($WT_SESSION->SESSION_PAGE_HITS[WT_SCRIPT_NAME . $page_parameter])) {
- $WT_SESSION->SESSION_PAGE_HITS[WT_SCRIPT_NAME . $page_parameter] = true;
- if (is_null($hitCount)) {
- $hitCount = 1;
- Database::prepare(
- "INSERT INTO `##hit_counter` (gedcom_id, page_name, page_parameter, page_count) VALUES (?, ?, ?, ?)"
- )->execute(array($WT_TREE->getTreeId(), WT_SCRIPT_NAME, $page_parameter, $hitCount));
- } else {
- $hitCount++;
- Database::prepare(
- "UPDATE `##hit_counter` SET page_count=?" .
- " WHERE gedcom_id=? AND page_name=? AND page_parameter=?"
- )->execute(array($hitCount, $WT_TREE->getTreeId(), WT_SCRIPT_NAME, $page_parameter));
- }
- }
-} else {
- $hitCount = 1;
-}
-
-$hitCount = '<span class="hit-counter">' . I18N::number($hitCount) . '</span>';
-
-unset($page_name, $page_parameter);
diff --git a/includes/session.php b/includes/session.php
index f0e20baab5..0d1d8024e6 100644
--- a/includes/session.php
+++ b/includes/session.php
@@ -543,13 +543,6 @@ if (substr(WT_SCRIPT_NAME, 0, 5) === 'admin' || WT_SCRIPT_NAME === 'module.php'
$WT_SESSION->theme_id = $theme_id;
}
-// Page hit counter - load after theme, as we need theme formatting
-if ($WT_TREE && $WT_TREE->getPreference('SHOW_COUNTER') && !Auth::isSearchEngine()) {
- require WT_ROOT . 'includes/hitcount.php';
-} else {
- $hitCount = '';
-}
-
// Search engines are only allowed to see certain pages.
if (Auth::isSearchEngine() && !in_array(WT_SCRIPT_NAME, array(
'index.php', 'indilist.php', 'module.php', 'mediafirewall.php',
diff --git a/index.php b/index.php
index af28e682c4..fcdddef5fc 100644
--- a/index.php
+++ b/index.php
@@ -131,17 +131,4 @@ if ($blocks['side']) {
}
echo '</div>';
}
-
-echo '<div id="link_change_blocks">';
-
-if ($ctype === 'user') {
- echo '<a href="index_edit.php?user_id=' . Auth::id() . '">', I18N::translate('Change the blocks on this page'), '</a>';
-} elseif ($ctype === 'gedcom' && Auth::isManager($WT_TREE)) {
- echo '<a href="index_edit.php?gedcom_id=' . $WT_TREE->getTreeId() . '">', I18N::translate('Change the blocks on this page'), '</a>';
-}
-
-if ($WT_TREE->getPreference('SHOW_COUNTER')) {
- echo '<span>' . /* I18N: The number of [...] */ I18N::translate('Page views') . ' ' . $hitCount . '</span>';
-}
-
-echo '</div></div>';
+echo '</div>';
diff --git a/themes/clouds/css-1.7.0/style.css b/themes/clouds/css-1.7.0/style.css
index 149c17633d..7f624987ea 100644
--- a/themes/clouds/css-1.7.0/style.css
+++ b/themes/clouds/css-1.7.0/style.css
@@ -2132,10 +2132,11 @@ dd .deletelink {
float: left;
}
-.hit-counter {
+.odometer {
+ font-family: courier, mono-space;
+ font-weight: bold;
background: #000;
color: #fff;
- font-weight: bold;
}
/* ======= General sprite ==== */
@@ -4586,22 +4587,6 @@ footer .error {
white-space: nowrap;
}
-#link_change_blocks {
- clear: both;
- margin: 0 auto;
- padding: 25px 0 0;
- text-align: center;
- width: 400px;
-}
-
-#link_change_blocks span {
- padding: 0 50px;
-}
-
-#link_change_blocks span span {
- padding: 0 3px;
-}
-
/* ====== End Theme Footer ===== */
/* ====== Theme Icons ========== */
diff --git a/themes/colors/css-1.7.0/style.css b/themes/colors/css-1.7.0/style.css
index 817cb46d90..32c0adcef5 100644
--- a/themes/colors/css-1.7.0/style.css
+++ b/themes/colors/css-1.7.0/style.css
@@ -2134,10 +2134,11 @@ dd .deletelink {
float: left;
}
-.hit-counter {
+.odometer {
+ font-family: courier, mono-space;
+ font-weight: bold;
background: #000;
color: #fff;
- font-weight: bold;
}
/* ======= General sprite ==== */
@@ -4511,22 +4512,6 @@ footer {
content: url(images/powered-by-webtrees.png);
}
-#link_change_blocks {
- clear: both;
- margin: 0 auto;
- padding: 25px 0 0;
- text-align: center;
- width: 400px;
-}
-
-#link_change_blocks span {
- padding: 0 50px;
-}
-
-#link_change_blocks span span {
- padding: 0 3px;
-}
-
/* ====== End Theme Footer ===== */
/* ====== Theme Icons ========== */
diff --git a/themes/fab/css-1.7.0/style.css b/themes/fab/css-1.7.0/style.css
index 89fd646035..3ca561c630 100644
--- a/themes/fab/css-1.7.0/style.css
+++ b/themes/fab/css-1.7.0/style.css
@@ -2045,10 +2045,11 @@ dd .deletelink {
float: left;
}
-.hit-counter {
+.odometer {
+ font-family: courier, mono-space;
+ font-weight: bold;
background: #000;
color: #fff;
- font-weight: bold;
}
/* ======= General sprite ==== */
@@ -4426,22 +4427,6 @@ footer {
content: url(images/powered-by-webtrees.png);
}
-#link_change_blocks {
- clear: both;
- margin: 0 auto;
- padding: 25px 0 0;
- text-align: center;
- width: 400px;
-}
-
-#link_change_blocks span {
- padding: 0 50px;
-}
-
-#link_change_blocks span span {
- padding: 0 3px;
-}
-
/* ====== End Theme Footer ===== */
/* ====== Theme Icons ========== */
diff --git a/themes/minimal/css-1.7.0/style.css b/themes/minimal/css-1.7.0/style.css
index e65e917790..5436e619e6 100644
--- a/themes/minimal/css-1.7.0/style.css
+++ b/themes/minimal/css-1.7.0/style.css
@@ -2050,10 +2050,11 @@ dd .deletelink {
float: left;
}
-.hit-counter {
- background: #555;
- color: #fff;
+.odometer {
+ font-family: courier, mono-space;
font-weight: bold;
+ background: #000;
+ color: #fff;
}
/* ======= General sprite ==== */
@@ -4388,22 +4389,6 @@ footer {
margin-top: 10px;
}
-#link_change_blocks {
- clear: both;
- margin: 0 auto;
- padding: 25px 0 0;
- text-align: center;
- width: 400px;
-}
-
-#link_change_blocks span {
- padding: 0 50px;
-}
-
-#link_change_blocks span span {
- padding: 0 3px;
-}
-
/* ====== End Theme Footer ===== */
/* ====== Theme Icons ========== */
diff --git a/themes/webtrees/css-1.7.0/style.css b/themes/webtrees/css-1.7.0/style.css
index a161dd324f..714b208042 100644
--- a/themes/webtrees/css-1.7.0/style.css
+++ b/themes/webtrees/css-1.7.0/style.css
@@ -2038,10 +2038,11 @@ dd .deletelink {
float: left;
}
-.hit-counter {
+.odometer {
+ font-family: courier, mono-space;
+ font-weight: bold;
background: #000;
color: #fff;
- font-weight: bold;
}
/* ======= General sprite ==== */
@@ -4429,22 +4430,6 @@ footer {
content: url(images/powered-by-webtrees.png);
}
-#link_change_blocks {
- clear: both;
- margin: 0 auto;
- padding: 25px 0 0;
- text-align: center;
- width: 400px;
-}
-
-#link_change_blocks span {
- padding: 0 50px;
-}
-
-#link_change_blocks span span {
- padding: 0 3px;
-}
-
/* ====== End Theme Footer ===== */
/* ====== Theme Icons ========== */
diff --git a/themes/xenea/css-1.7.0/style.css b/themes/xenea/css-1.7.0/style.css
index 2701bd213d..51ffaa0fb0 100644
--- a/themes/xenea/css-1.7.0/style.css
+++ b/themes/xenea/css-1.7.0/style.css
@@ -2049,10 +2049,11 @@ dd .deletelink {
float: left;
}
-.hit-counter {
+.odometer {
+ font-family: courier, mono-space;
+ font-weight: bold;
background: #000;
color: #fff;
- font-weight: bold;
}
/* ======= General sprite ==== */
@@ -4441,22 +4442,6 @@ footer {
content: url(images/powered-by-webtrees.png);
}
-#link_change_blocks {
- clear: both;
- margin: 0 auto;
- padding: 25px 0 0;
- text-align: center;
- width: 400px;
-}
-
-#link_change_blocks span {
- padding: 0 50px;
-}
-
-#link_change_blocks span span {
- padding: 0 3px;
-}
-
/* ====== End Theme Footer ===== */
/* ====== Theme Icons ========== */