Added Matomo Analytics support, both client JavaScript or server PHP - added metadata json files to cache

This commit is contained in:
Emidio Reggiani 2026-02-03 15:41:27 +01:00
commit e1a74fa05f
18 changed files with 3409 additions and 3 deletions

View file

@ -14,7 +14,8 @@
"jbroadway/urlify": "^1.0",
"pragmarx/google2fa": "^8.0",
"bacon/bacon-qr-code": "^3.0",
"phpmailer/phpmailer": "^6.5"
"phpmailer/phpmailer": "^6.5",
"matomo/matomo-php-tracker": "^3.4"
},
"autoload": {
"files": [

58
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c42e28f737dbacec77bc18555733d9d3",
"content-hash": "334f0e067748536eb03d835eab96ea90",
"packages": [
{
"name": "bacon/bacon-qr-code",
@ -356,6 +356,62 @@
"abandoned": true,
"time": "2016-08-02T19:12:55+00:00"
},
{
"name": "matomo/matomo-php-tracker",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/matomo-php-tracker.git",
"reference": "9462dc6eb718c711545ea1b0f590b9ae892a4212"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/matomo-php-tracker/zipball/9462dc6eb718c711545ea1b0f590b9ae892a4212",
"reference": "9462dc6eb718c711545ea1b0f590b9ae892a4212",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "~7.2 || ~7.3 || ~7.4 || ~8.0 || ~8.1 || ~8.2 || ~8.3 || ~8.4 || ~8.5"
},
"require-dev": {
"phpunit/phpunit": "^8.5 || ^9.3 || ^10.1"
},
"suggest": {
"ext-curl": "Using this extension to issue the HTTPS request to Matomo"
},
"type": "library",
"autoload": {
"classmap": [
"."
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "The Matomo Team",
"email": "hello@matomo.org",
"homepage": "https://matomo.org/team/"
}
],
"description": "PHP Client for Matomo Analytics Tracking API",
"homepage": "https://matomo.org",
"keywords": [
"analytics",
"matomo",
"piwik",
"tracker"
],
"support": {
"forum": "https://forum.matomo.org/",
"issues": "https://github.com/matomo-org/matomo-php-tracker/issues",
"source": "https://github.com/matomo-org/matomo-php-tracker"
},
"time": "2025-12-20T18:55:41+00:00"
},
{
"name": "michelf/php-markdown",
"version": "1.9.1",

View file

@ -94,6 +94,15 @@ github_pre_release = "Github pre-release"
google_analytics = "Google Analytics"
google_analytics_legacy = "Google Analytics (legacy)"
google_search_console = "Google Search Console"
matomo_analytics = "Matomo Analytics"
matomo_url = "Matomo URL"
matomo_site_id = "Matomo Site ID"
matomo_authtoken = "Matomo Auth. Token"
matomo_track_type = "Matomo Tracking Type"
matomo_track_type_js = "Javascript Client side (with cookies)"
matomo_track_type_php = "PHP Backend (no cookies)"
home = "Home"
if_left_empty_we_will_excerpt_it_from_the_content_below = "If leave empty we will excerpt it from the content below"
if_the_url_is_left_empty_we_will_use_the_page_title = "If the url leave empty we will use the page title"
@ -407,3 +416,33 @@ backtotop = "Back to top"
subpages = "Sub pages"
getstarted = "Get started"
onthispage = "On this page"
enable_jstime="Enable Javascript and timestamp anti-spam protection"
jstime_desc="Usually bots dont't use Javascript. Form also checks if submitted between 3 and 600 seconds (preventing bots fast submission)"
comment_email_admin_awaiting="New comment awaiting moderation"
comment_email_admin_new="New comment"
comment_email_subscription_subject = "Subscription confirmation to"
comment_email_new = "New comment on"
comment_email_from = "From"
comment_email_moderate = "Moderate comments"
comment_email_new_subscribed = "New reply on a subscribed thread"
comment_email_new_replied = "Someone replied to your comment on"
comment_email_view_comment = "View comment"
comment_subscribe_confirmation = "Subscription confirmation to"
comment_subscribe_thread = "Thread subscription at"
comment_subscribe_request = "We received a subscription request to a thread at"
comment_subscribe_never_requested = "If you never visited the site or requested to be notified on thread messages, please ignore this email."
comment_subscribe_click = "Click"
comment_subscribe_here = "HERE"
comment_subscribe_confirm_message = "to confirm your subscription and start receiving notification emails on replies on the thread."
comment_subscribe_unsubscribe_message = "You can unsubscribe all notifications from"
comment_subscribe_unsubscribe_anytime = "at any time using this link"
comment_unsubscribe = "unsubscribe"
sysmsg_subscribe_success = "Your will receive now new comment notifications on the subscribed threads."
sysmsg_subscribe_fail = "Something went wrong during subscription verification process."
sysmsg_unsubscribe_success = "You have successfully unsubscribed from notification emails."
sysmsg_unsubscribe_fail = "Something wrong during unsubscription process"
posts_not_found = "Posts not found!"
page_not_found = "Page not found!"

View file

@ -1728,48 +1728,78 @@ function clear_post_cache($post_date, $post_tag, $post_url, $filename, $category
if (file_exists($p)) {
unlink($p);
}
if (file_exists($p . '.meta.json')) {
unlink($p . '.meta.json');
}
// Delete post permalink
$pp = 'cache/page/' . $b . 'post#' . $post_url . '.cache';
if (file_exists($pp)) {
unlink($pp);
}
if (file_exists($pp . '.meta.json')) {
unlink($pp . '.meta.json');
}
// Delete homepage
$yd = 'cache/page/' . $b . '.cache';
if (file_exists($yd)) {
unlink($yd);
}
if (file_exists($yd . '.meta.json')) {
unlink($yd . '.meta.json');
}
foreach (glob('cache/page/' . $b . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Delete year
$yd = 'cache/page/' . $b . 'archive#' . $t[0] . '.cache';
if (file_exists($yd)) {
unlink($yd);
}
if (file_exists($yd . '.meta.json')) {
unlink($yd . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'archive#' . $t[0] . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'archive#' . $t[0] . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Delete year-month
$yd = 'cache/page/' . $b . 'archive#' . $t[0] . '-' . $t[1] . '.cache';
if (file_exists($yd)) {
unlink($yd);
}
if (file_exists($yd . '.meta.json')) {
unlink($yd . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'archive#' . $t[0] . '-' . $t[1] . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'archive#' . $t[0] . '-' . $t[1] . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Delete year-month-day
$yd = 'cache/page/' . $b . 'archive#' . $t[0] . '-' . $t[1] . '-' . $t[2] . '.cache';
if (file_exists($yd)) {
unlink($yd);
}
if (file_exists($yd . '.meta.json')) {
unlink($yd . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'archive#' . $t[0] . '-' . $t[1] . '-' . $t[2] . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'archive#' . $t[0] . '-' . $t[1] . '-' . $t[2] . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Delete tag
foreach ($c as $tag) {
@ -1777,33 +1807,54 @@ function clear_post_cache($post_date, $post_tag, $post_url, $filename, $category
if (file_exists($yd)) {
unlink($yd);
}
if (file_exists($yd . '.meta.json')) {
unlink($yd . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'tag#' . $tag . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'tag#' . $tag . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
}
// Delete search
foreach (glob('cache/page/' . $b . 'search#*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'search#*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Delete category
$cc = 'cache/page/' . $b . 'category#' . $category . '.cache';
if (file_exists($cc)) {
unlink($cc);
}
if (file_exists($cc . '.meta.json')) {
unlink($cc . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'category#' . $category . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'category#' . $category . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Delete type
$tp = 'cache/page/' . $b . 'type#' . $type . '.cache';
if (file_exists($tp)) {
unlink($tp);
}
if (file_exists($tp . '.meta.json')) {
unlink($tp . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'type#' . $type . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'type#' . $type . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
// Get cache post author
$arr = pathinfo($filename, PATHINFO_DIRNAME);
@ -1813,9 +1864,16 @@ function clear_post_cache($post_date, $post_tag, $post_url, $filename, $category
if (file_exists($a)) {
unlink($a);
}
if (file_exists($a . '.meta.json')) {
unlink($a . '.meta.json');
}
foreach (glob('cache/page/' . $b . 'author#' . $x[1] . '~*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/' . $b . 'author#' . $x[1] . '~*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
}
function clear_page_cache($url)
@ -1825,6 +1883,9 @@ function clear_page_cache($url)
if (file_exists($p)) {
unlink($p);
}
if (file_exists($p . '.meta.json')) {
unlink($p . '.meta.json');
}
}
function clear_cache()
@ -1832,6 +1893,9 @@ function clear_cache()
foreach (glob('cache/page/*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/*.cache.meta.json', GLOB_NOSORT) as $file) {
unlink($file);
}
}
function valueMaker($value)

View file

@ -10,6 +10,9 @@ rebuilt_cache('all');
foreach (glob('cache/page/*.cache', GLOB_NOSORT) as $file) {
unlink($file);
}
foreach (glob('cache/page/*.cache.meta.json', GLOB_NOSORT) as $filemeta) {
unlink($filemeta);
}
echo i18n('All_cache_has_been_deleted');

View file

@ -209,6 +209,69 @@
<small><em><?php echo i18n('For_msvalidate_01_meta');?></em></small>
</div>
</div>
<br>
<h4><?php echo i18n('Matomo_Analytics');?></h4>
<hr>
<div class="form-group row">
<label for="matomo.site.id" class="col-sm-2 col-form-label"><?php echo i18n('Matomo_Site_Id');?></label>
<div class="col-sm-10">
<input type="text" name="-config-matomo.site.id" class="form-control" id="matomo.site.id" value="<?php echo valueMaker(config('matomo.site.id'));?>" placeholder="<?php echo i18n('widget_key_placeholder');?>">
</div>
</div>
<div class="form-group row">
<label for="matomo-url" class="col-sm-2 col-form-label"><?php echo i18n('Matomo_Url');?></label>
<div class="col-sm-10">
<input type="text" name="-config-matomo.url" class="form-control" id="matomo.url" value="<?php echo valueMaker(config('matomo.url'));?>" placeholder="<?php echo i18n('widget_key_placeholder');?>">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label"><?php echo i18n('Matomo_Track_Type');?></label>
<div class="col-sm-10">
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="radio" name="-config-matomo.track.type" id="matomo.track.type1" value="js" <?php if (config('matomo.track.type') === 'js'):?>checked<?php endif;?>>
<label class="form-check-label" for="matomo.track.type1">
<?php echo i18n('matomo_track_type_js');?>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="-config-matomo.track.type" id="matomo.track.type2" value="php" <?php if (config('matomo.track.type') === 'php' || is_null(config('matomo.type'))):?>checked<?php endif;?>>
<label class="form-check-label" for="matomo.track.type2">
<?php echo i18n('matomo_track_type_php');?>
</label>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label for="matomo-authtoken" class="col-sm-2 col-form-label"><?php echo i18n('Matomo_AuthToken');?></label>
<div class="col-sm-10">
<input type="text" name="-config-matomo.authtoken" class="form-control" id="matomo.authtoken" value="<?php echo valueMaker(config('matomo.authtoken'));?>" placeholder="<?php echo i18n('widget_key_placeholder');?>">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label"><?php echo i18n('Matomo_Track_Type');?></label>
<div class="col-sm-10">
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="radio" name="-config-matomo.cookies" id="matomo.cookies.use1" value="js" <?php if (config('matomo.cookies') === 'no'):?>checked<?php endif;?>>
<label class="form-check-label" for="matomo.cookies.use1">
<?php echo i18n('matomo_track_type_js');?>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="-config-matomo.cookies" id="matomo.cookies.use2" value="php" <?php if (config('matomo.cookies') === 'yes' || is_null(config('matomo.cookies'))):?>checked<?php endif;?>>
<label class="form-check-label" for="matomo.cookies.use2">
<?php echo i18n('matomo_track_type_php');?>
</label>
</div>
</div>
</div>
</div>
<br>
<h4><?php echo i18n('Social_Media');?></h4>
<hr>

View file

@ -437,6 +437,183 @@ function content($value = null)
return stash('$content$', $value);
}
// Normalize cache metadata type
function normalize_titles_type($type, $canonical = null)
{
// Map internal types to simple types
$type_map = array(
'blogPost' => 'post',
'imagePost' => 'post',
'videoPost' => 'post',
'linkPost' => 'post',
'quotePost' => 'post',
'audioPost' => 'post',
'is_frontpage' => 'frontpage',
'is_tag' => 'tag',
'is_profile' => 'profile',
'is_category' => 'category',
'is_page' => 'page',
'is_subpage' => 'page',
'is_archive' => 'archive',
'is_search' => 'search'
);
$subtype_map = array(
'blogPost' => 'post',
'imagePost' => 'image',
'videoPost' => 'video',
'linkPost' => 'link',
'quotePost' => 'quote',
'audioPost' => 'audio',
'is_frontpage' => 'frontpage',
'is_tag' => '',
'is_profile' => '',
'is_category' => '',
'is_page' => '',
'is_subpage' => 'subpage',
'is_archive' => '',
'is_search' => ''
);
$type_prefix = array(
'blogPost' => '',
'imagePost' => '',
'videoPost' => '',
'linkPost' => '',
'quotePost' => '',
'audioPost' => '',
'is_frontpage' => i18n('Home') . ': ',
'is_tag' => i18n('Tag') . ': ',
'is_profile' => i18n('Author') . ': ',
'is_category' => i18n('Category') . ': ',
'is_page' => '',
'is_subpage' => '',
'is_archive' => i18n('Archives') . ': ',
'is_search' => i18n('Search') . ': '
);
// Return mapped type if found
if (isset($type_map[$type])) {
$return_type['type'] = $type_map[$type];
$return_type['subtype'] = $subtype_map[$type];
$return_type['prefix'] = $type_prefix[$type];
return $return_type;
}
// Try to derive from canonical URL
if ($canonical) {
$parsed = parse_url($canonical);
if (isset($parsed['path'])) {
$path = trim($parsed['path'], '/');
$segments = explode('/', $path);
// Get first segment after site path
$site_path = trim(site_path(), '/');
if (!empty($site_path) && isset($segments[0]) && $segments[0] === $site_path) {
array_shift($segments);
}
if (!empty($segments)) {
$first_segment = $segments[0];
// Check known URL patterns
if ($first_segment === 'tag') {
$return_type['type'] = 'tag';
$return_type['subtype'] = '';
$return_type['prefix'] = 'Tag: ';
return $return_type;
}
if ($first_segment === 'author') {
$return_type['type'] = 'profile';
$return_type['subtype'] = '';
$return_type['prefix'] = 'Profile: ';
return $return_type;
}
if ($first_segment === 'category') {
$return_type['type'] = 'category';
$return_type['subtype'] = '';
$return_type['prefix'] = 'Category: ';
return $return_type;
}
if ($first_segment === 'archive') {
$return_type['type'] = 'archive';
$return_type['subtype'] = '';
$return_type['prefix'] = 'Archive: ';
return $return_type;
}
if ($first_segment === 'search') {
$return_type['type'] = 'search';
$return_type['subtype'] = '';
$return_type['prefix'] = 'Search: ';
return $return_type;
}
// If it's a date pattern (YYYY/MM), it's a post
if (preg_match('/^\d{4}$/', $first_segment)) {
$return_type['type'] = 'post';
$return_type['subtype'] = '';
$return_type['prefix'] = '';
return $return_type;
}
}
}
}
// Default to page for unknown types
$return_type['type'] = 'page';
$return_type['subtype'] = '';
$return_type['prefix'] = '';
return $return_type;
}
function generate_meta_info($locals) {
if (is_array($locals) && count($locals)) {
extract($locals, EXTR_SKIP);
}
// Normalize type
$normalized_type = normalize_titles_type(
isset($type) ? $type : null,
isset($canonical) ? $canonical : null
);
// Extract menu name from static page or canonical URL
$filename = "content/data/menu.json";
if (file_exists($filename)) {
$menu_content = file_get_data($filename) ;
$menu_flat = flattenMenu(json_decode(json_decode($menu_content, true), true));
}
// Get language from config
$language = config('language');
if (isset($canonical)) {
$slug = parse_url($canonical, PHP_URL_PATH);
}
else {
$slug = '';
}
// Save metadata in separate cache file
// $metafile = $cachefile . '.meta.json';
$metadata = array(
'title' => isset($title) ? $title : null,
'prefix' => $normalized_type['prefix'],
'description' => isset($description) ? $description : '',
'canonical' => isset($canonical) ? $canonical : '',
'slug' => $slug,
'author' => isset($author) ? $author->name : '',
'type' => $normalized_type['type'],
'subtype' => $normalized_type['subtype'],
'menu' => isset($menu_flat[$slug]) ? $menu_flat[$slug] : '',
'language' => $language
);
return $metadata;
}
function render($view, $locals = null, $layout = null)
{
if (!login()) {
@ -487,8 +664,14 @@ function render($view, $locals = null, $layout = null)
if (config('cache.timestamp') == 'true') {
echo "\n" . '<!-- Cached page generated on '.date('Y-m-d H:i:s').' -->';
}
if (isset($cachefile))
if (isset($cachefile)) {
file_put_contents($cachefile, ob_get_contents(), LOCK_EX);
// Save metadata in separate cache file
$metafile = $cachefile . '.meta.json';
$metadata = generate_meta_info($locals);
file_put_contents($metafile, json_encode($metadata, JSON_UNESCAPED_UNICODE), LOCK_EX);
}
}
echo trim(ob_get_clean());
} else {

View file

@ -2697,6 +2697,93 @@ EOF;
}
}
// Matomo Analytics
function matomo($metadata, $locals = null)
{
$matomo_url = config('matomo.url');
$matomo_id = config('matomo.site.id');
$matomo_track_type = config('matomo.track.type');
if (config('matomo.cookies') == 'no') {
$matomo_nocookies = "_paq.push(['disableCookies']);";
}
else {
$matomo_nocookies = "";
}
if ($matomo_url && $matomo_id) {
if ($matomo_track_type == "js") {
$script = "
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like \"setCustomDimension\" should be called before \"trackPageView\" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u=\"" . slashUrl($matomo_url) . "\";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '" . $matomo_id . "']);
" . $matomo_nocookies . "
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
";
return $script;
}
else {
include_once('system/vendor/matomo/matomo-php-tracker/MatomoTracker.php');
// Initialize tracker
$t = new MatomoTracker((int)config('matomo.site.id'), config('matomo.url'));
// Optional: Set auth token (required for some features like custom IP or user ID)
$t->setTokenAuth(config('matomo.authtoken'));
if ($locals) {
$metadata = generate_meta_info($locals);
}
$pagePrefix = $metadata['prefix'] ?? '';
$pageTitle = trim($pagePrefix . $metadata['title']);
if (substr($pageTitle, -strlen(' - ' . blog_title())) === ' - ' . blog_title()) {
$pageTitle = substr($pageTitle, 0, -strlen(' - ' . blog_title()));
}
$t->setIp(client_ip());
if (config('matomo.cookies') == 'no') {
$t->disableCookieSupport();
}
// Track page view
$t->doTrackPageView($pageTitle);
return "";
}
}
}
function flattenMenu(array $items, array &$flat = []): array
{
foreach ($items as $item) {
// keep only slug + name
if ($item['slug'] != "#") {
$flat[$item['slug']] = $item['name'];
}
// recurse into children
if (!empty($item['children']) && is_array($item['children'])) {
flattenMenu($item['children'], $flat);
}
}
return $flat;
}
function slashUrl($url)
{
return rtrim($url, '/') . '/';
@ -3668,7 +3755,24 @@ function file_cache($request)
if (file_exists($cachefile)) {
if ($now - filemtime($cachefile) >= 60 * 60 * $hour) {
unlink($cachefile);
// Removes also metadata cache file
$metafile = $cachefile . '.meta.json';
if (file_exists($metafile)) {
unlink($metafile);
}
} else {
// Loads metadata before serving cache file
$metafile = $cachefile . '.meta.json';
$cache_metadata = array();
if (file_exists($metafile)) {
$cache_metadata = json_decode(file_get_contents($metafile), true);
}
// if Matomo analytics backend is active
if (config('matomo.url') && config('matomo.site.id') && config('matomo.track.type') == 'php') {
matomo($cache_metadata);
}
header('Content-type: text/html; charset=utf-8');
readfile($cachefile);
die;

View file

@ -83,6 +83,7 @@ return array(
'Kanti\\CacheOneFile' => $vendorDir . '/kanti/hub-updater/src/CacheOneFile.php',
'Kanti\\HelperClass' => $vendorDir . '/kanti/hub-updater/src/HelperClass.php',
'Kanti\\HubUpdater' => $vendorDir . '/kanti/hub-updater/src/HubUpdater.php',
'MatomoTracker' => $vendorDir . '/matomo/matomo-php-tracker/MatomoTracker.php',
'Michelf\\Markdown' => $vendorDir . '/michelf/php-markdown/Michelf/Markdown.php',
'Michelf\\MarkdownExtra' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownExtra.php',
'Michelf\\MarkdownInterface' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownInterface.php',
@ -104,6 +105,7 @@ return array(
'ParagonIE\\ConstantTime\\Encoding' => $vendorDir . '/paragonie/constant_time_encoding/src/Encoding.php',
'ParagonIE\\ConstantTime\\Hex' => $vendorDir . '/paragonie/constant_time_encoding/src/Hex.php',
'ParagonIE\\ConstantTime\\RFC4648' => $vendorDir . '/paragonie/constant_time_encoding/src/RFC4648.php',
'PiwikTracker' => $vendorDir . '/matomo/matomo-php-tracker/PiwikTracker.php',
'PragmaRX\\Google2FA\\Exceptions\\Contracts\\Google2FA' => $vendorDir . '/pragmarx/google2fa/src/Exceptions/Contracts/Google2FA.php',
'PragmaRX\\Google2FA\\Exceptions\\Contracts\\IncompatibleWithGoogleAuthenticator' => $vendorDir . '/pragmarx/google2fa/src/Exceptions/Contracts/IncompatibleWithGoogleAuthenticator.php',
'PragmaRX\\Google2FA\\Exceptions\\Contracts\\InvalidAlgorithm' => $vendorDir . '/pragmarx/google2fa/src/Exceptions/Contracts/InvalidAlgorithm.php',

View file

@ -185,6 +185,7 @@ class ComposerStaticInitd88c6c25320034df85dd42f1462fbda7
'Kanti\\CacheOneFile' => __DIR__ . '/..' . '/kanti/hub-updater/src/CacheOneFile.php',
'Kanti\\HelperClass' => __DIR__ . '/..' . '/kanti/hub-updater/src/HelperClass.php',
'Kanti\\HubUpdater' => __DIR__ . '/..' . '/kanti/hub-updater/src/HubUpdater.php',
'MatomoTracker' => __DIR__ . '/..' . '/matomo/matomo-php-tracker/MatomoTracker.php',
'Michelf\\Markdown' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/Markdown.php',
'Michelf\\MarkdownExtra' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/MarkdownExtra.php',
'Michelf\\MarkdownInterface' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/MarkdownInterface.php',
@ -206,6 +207,7 @@ class ComposerStaticInitd88c6c25320034df85dd42f1462fbda7
'ParagonIE\\ConstantTime\\Encoding' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Encoding.php',
'ParagonIE\\ConstantTime\\Hex' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/Hex.php',
'ParagonIE\\ConstantTime\\RFC4648' => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src/RFC4648.php',
'PiwikTracker' => __DIR__ . '/..' . '/matomo/matomo-php-tracker/PiwikTracker.php',
'PragmaRX\\Google2FA\\Exceptions\\Contracts\\Google2FA' => __DIR__ . '/..' . '/pragmarx/google2fa/src/Exceptions/Contracts/Google2FA.php',
'PragmaRX\\Google2FA\\Exceptions\\Contracts\\IncompatibleWithGoogleAuthenticator' => __DIR__ . '/..' . '/pragmarx/google2fa/src/Exceptions/Contracts/IncompatibleWithGoogleAuthenticator.php',
'PragmaRX\\Google2FA\\Exceptions\\Contracts\\InvalidAlgorithm' => __DIR__ . '/..' . '/pragmarx/google2fa/src/Exceptions/Contracts/InvalidAlgorithm.php',

View file

@ -365,6 +365,65 @@
"install-path": "../kanti/hub-updater"
},
{
"name": "matomo/matomo-php-tracker",
"version": "3.4.0",
"version_normalized": "3.4.0.0",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/matomo-php-tracker.git",
"reference": "9462dc6eb718c711545ea1b0f590b9ae892a4212"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/matomo-php-tracker/zipball/9462dc6eb718c711545ea1b0f590b9ae892a4212",
"reference": "9462dc6eb718c711545ea1b0f590b9ae892a4212",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "~7.2 || ~7.3 || ~7.4 || ~8.0 || ~8.1 || ~8.2 || ~8.3 || ~8.4 || ~8.5"
},
"require-dev": {
"phpunit/phpunit": "^8.5 || ^9.3 || ^10.1"
},
"suggest": {
"ext-curl": "Using this extension to issue the HTTPS request to Matomo"
},
"time": "2025-12-20T18:55:41+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"."
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "The Matomo Team",
"email": "hello@matomo.org",
"homepage": "https://matomo.org/team/"
}
],
"description": "PHP Client for Matomo Analytics Tracking API",
"homepage": "https://matomo.org",
"keywords": [
"analytics",
"matomo",
"piwik",
"tracker"
],
"support": {
"forum": "https://forum.matomo.org/",
"issues": "https://github.com/matomo-org/matomo-php-tracker/issues",
"source": "https://github.com/matomo-org/matomo-php-tracker"
},
"install-path": "../matomo/matomo-php-tracker"
},
{
"name": "michelf/php-markdown",
"version": "1.9.1",
"version_normalized": "1.9.1.0",

View file

@ -73,6 +73,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'matomo/matomo-php-tracker' => array(
'pretty_version' => '3.4.0',
'version' => '3.4.0.0',
'reference' => '9462dc6eb718c711545ea1b0f590b9ae892a4212',
'type' => 'library',
'install_path' => __DIR__ . '/../matomo/matomo-php-tracker',
'aliases' => array(),
'dev_requirement' => false,
),
'michelf/php-markdown' => array(
'pretty_version' => '1.9.1',
'version' => '1.9.1.0',

View file

@ -0,0 +1,41 @@
# Matomo PHP Tracker Changelog
This is the Developer Changelog for Matomo PHP Tracker. All breaking changes or new features are listed below.
## Matomo PHP Tracker 3.4.0
### Changed
- Fixed PHP 8.5 deprecation notice
- static `$URL` is deprecated
- a lot of arguments of `MatomoTracker` methods have explicitly types
- a lot of `MatomoTracker` method return types have strict types
### Added
- new private property `apiUrl` for storing API URL
## Matomo PHP Tracker 3.3.2
### Changed
- Support for formFactors client hint parameter, supported as of Matomo 5.2.0
## Matomo PHP Tracker 3.3.1
### Fixed
- closed curl connection
## Matomo PHP Tracker 3.3.0
### Removed
- support for PHP versions lower than 7.2
### Changed
- all `MatomoTracker` class constants are now explicitly public
- all `MatomoTracker` dynamic properties are now explicitly public
## Matomo PHP Tracker 3.0.0
Attention: This version of Matomo PHP Tracker is no longer compatible with Matomo 3.x or earlier
- Support for new page performance metrics (added in Matomo 4) has been added. You can use `setPerformanceTimings()` to set them for page views.
- Setting page generation time using `setGenerationTime()` has been discontinued. The method still exists to not break applications still using it, but it does not have any effect. Please use new page performance metrics as replacement.
- Sending requests using cURL will now throw an exception if an error occurs in a request.
- Matomo does not longer support tracking of these browser plugins: Gears, Director. Therefor the signature of `setPlugins()` changed.
- Implementation of ecommerce views changed from custom variables to raw parameters
- It is now possible to configure cookie options for Secure, HTTPOnly and SameSite.
- Add method setRequestMethodNonBulk() to allow (non bulk) POST requests.

View file

@ -0,0 +1,27 @@
Copyright (c) 2014, Matomo Open Source Analytics
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* For more information, see README.md
*
* @license released under BSD License http://www.opensource.org/licenses/bsd-license.php
* @link https://matomo.org/docs/tracking-api/
*
* @category Matomo
* @package MatomoTracker
*/
if (!class_exists('\MatomoTracker')) {
include_once('MatomoTracker.php');
}
/**
* Helper function to quickly generate the URL to track a page view.
*
* @deprecated
* @param $idSite
* @param string $documentTitle
* @return string
*/
function Piwik_getUrlTrackPageView($idSite, $documentTitle = '')
{
return Matomo_getUrlTrackPageView($idSite, $documentTitle);
}
/**
* Helper function to quickly generate the URL to track a goal.
*
* @deprecated
* @param $idSite
* @param $idGoal
* @param float $revenue
* @return string
*/
function Piwik_getUrlTrackGoal($idSite, $idGoal, $revenue = 0.0)
{
return Matomo_getUrlTrackGoal($idSite, $idGoal, $revenue);
}
/**
* For BC only
*
* @deprecated use MatomoTracker instead
*/
class PiwikTracker extends MatomoTracker {}

View file

@ -0,0 +1,53 @@
# PHP Client for Matomo Analytics Tracking API
The PHP Tracker Client provides all features of the [Matomo Javascript Tracker](https://developer.matomo.org/api-reference/tracking-javascript), such as Ecommerce Tracking, Custom Variables, Event Tracking and more.
## Documentation and examples
Check out our [Matomo-PHP-Tracker developer documentation](https://developer.matomo.org/api-reference/PHP-Piwik-Tracker) and [Matomo Tracking API guide](https://matomo.org/docs/tracking-api/).
```php
// Required variables
$matomoSiteId = 6; // Site ID
$matomoUrl = "https://example.tld"; // Your matomo URL
$matomoToken = ""; // Your authentication token
// Optional variable
$matomoPageTitle = ""; // The title of the page
// Load object
require_once("MatomoTracker.php");
// Matomo object
$matomoTracker = new MatomoTracker((int)$matomoSiteId, $matomoUrl);
// Set authentication token
$matomoTracker->setTokenAuth($matomoToken);
// Track page view
$matomoTracker->doTrackPageView($matomoPageTitle);
```
## Requirements:
* JSON extension (json_decode, json_encode)
* cURL or stream extension (to issue the HTTPS request to Matomo)
## Installation
### Composer
```
composer require matomo/matomo-php-tracker
```
### Manually
Alternatively, you can download the files and require the Matomo tracker manually:
```
require_once("MatomoTracker.php");
```
## License
Released under the [BSD License](https://opensource.org/licenses/BSD-3-Clause)

View file

@ -0,0 +1,37 @@
{
"name": "matomo/matomo-php-tracker",
"description": "PHP Client for Matomo Analytics Tracking API",
"keywords": ["matomo","piwik","tracker","analytics"],
"homepage": "https://matomo.org",
"license": "BSD-3-Clause",
"authors": [
{
"name": "The Matomo Team",
"email": "hello@matomo.org",
"homepage": "https://matomo.org/team/"
}
],
"support": {
"forum": "https://forum.matomo.org/",
"issues": "https://github.com/matomo-org/matomo-php-tracker/issues",
"source": "https://github.com/matomo-org/matomo-php-tracker"
},
"require": {
"php": "~7.2 || ~7.3 || ~7.4 || ~8.0 || ~8.1 || ~8.2 || ~8.3 || ~8.4 || ~8.5",
"ext-json": "*"
},
"suggest": {
"ext-curl": "Using this extension to issue the HTTPS request to Matomo"
},
"autoload": {
"classmap": ["."]
},
"autoload-dev": {
"psr-4": {
"\\": "tests/"
}
},
"require-dev": {
"phpunit/phpunit": "^8.5 || ^9.3 || ^10.1"
}
}