API
3 months ago
Access
3 months ago
Application
3 months ago
Archive
3 months ago
ArchiveProcessor
3 months ago
Archiver
2 years ago
AssetManager
3 months ago
Auth
6 months ago
Category
6 months ago
Changes
3 months ago
CliMulti
1 year ago
Columns
3 months ago
Concurrency
3 months ago
Config
3 months ago
Container
3 months ago
CronArchive
3 months ago
DataAccess
3 months ago
DataFiles
2 years ago
DataTable
3 months ago
Db
3 months ago
DeviceDetector
1 year ago
Email
2 years ago
Exception
4 months ago
Http
4 months ago
Intl
3 months ago
Log
2 years ago
Mail
1 year ago
Measurable
6 months ago
Menu
3 months ago
Metrics
3 months ago
Notification
6 months ago
Period
3 months ago
Plugin
3 months ago
Policy
3 months ago
ProfessionalServices
1 year ago
Report
1 year ago
ReportRenderer
3 months ago
Request
3 months ago
Scheduler
3 months ago
Segment
3 months ago
Session
3 months ago
Settings
3 months ago
Tracker
3 months ago
Translation
3 months ago
Twig
1 year ago
UpdateCheck
3 months ago
Updater
4 months ago
Updates
3 months ago
Validators
1 year ago
View
6 months ago
ViewDataTable
3 months ago
Visualization
1 year ago
Widget
3 months ago
.htaccess
2 years ago
Access.php
3 months ago
Archive.php
3 months ago
ArchiveProcessor.php
4 months ago
AssetManager.php
3 months ago
Auth.php
6 months ago
AuthResult.php
6 months ago
BaseFactory.php
2 years ago
Cache.php
2 years ago
CacheId.php
4 months ago
CliMulti.php
3 months ago
Common.php
3 months ago
Config.php
3 months ago
Console.php
3 months ago
Context.php
2 years ago
Cookie.php
1 year ago
CronArchive.php
3 months ago
DI.php
3 months ago
DataArray.php
5 months ago
DataTable.php
3 months ago
Date.php
3 months ago
Db.php
3 months ago
DbHelper.php
3 months ago
Development.php
1 year ago
ErrorHandler.php
6 months ago
EventDispatcher.php
1 year ago
ExceptionHandler.php
4 months ago
FileIntegrity.php
3 months ago
Filechecks.php
1 year ago
Filesystem.php
3 months ago
FrontController.php
4 months ago
Http.php
4 months ago
IP.php
1 year ago
Log.php
3 months ago
LogDeleter.php
1 year ago
Mail.php
1 year ago
Metrics.php
3 months ago
NoAccessException.php
2 years ago
Nonce.php
6 months ago
Notification.php
6 months ago
NumberFormatter.php
5 months ago
Option.php
5 months ago
Period.php
3 months ago
Piwik.php
3 months ago
Plugin.php
3 months ago
Process.php
1 year ago
Profiler.php
6 months ago
ProxyHeaders.php
4 months ago
ProxyHttp.php
5 months ago
QuickForm2.php
3 months ago
RankingQuery.php
5 months ago
ReportRenderer.php
3 months ago
Request.php
3 months ago
Segment.php
3 months ago
Sequence.php
6 months ago
Session.php
3 months ago
SettingsPiwik.php
3 months ago
SettingsServer.php
1 year ago
Singleton.php
2 years ago
Site.php
4 months ago
SiteContentDetector.php
3 months ago
SupportedBrowser.php
2 years ago
TCPDF.php
1 year ago
Theme.php
1 year ago
Timer.php
2 years ago
Tracker.php
3 months ago
Twig.php
3 months ago
Unzip.php
1 year ago
UpdateCheck.php
3 months ago
Updater.php
3 months ago
UpdaterErrorException.php
2 years ago
Updates.php
3 months ago
Url.php
3 months ago
UrlHelper.php
3 months ago
Version.php
3 months ago
View.php
3 months ago
bootstrap.php
1 year ago
dispatch.php
2 years ago
testMinimumPhpVersion.php
6 months ago
Metrics.php
433 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Matomo - free/libre analytics platform |
| 5 | * |
| 6 | * @link https://matomo.org |
| 7 | * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later |
| 8 | */ |
| 9 | namespace Piwik; |
| 10 | |
| 11 | use Piwik\Cache as PiwikCache; |
| 12 | use Piwik\Columns\Dimension; |
| 13 | use Piwik\Tracker\GoalManager; |
| 14 | require_once PIWIK_INCLUDE_PATH . "/core/Piwik.php"; |
| 15 | /** |
| 16 | * This class contains metadata regarding core metrics and contains several |
| 17 | * related helper functions. |
| 18 | * |
| 19 | * Of note are the `INDEX_...` constants. In the database, metric column names |
| 20 | * in {@link DataTable} rows are stored as integers to save space. The integer |
| 21 | * values used are determined by these constants. |
| 22 | * |
| 23 | * @api |
| 24 | */ |
| 25 | class Metrics |
| 26 | { |
| 27 | /* |
| 28 | * When saving DataTables in the DB, we replace all columns name with these IDs. This saves many bytes, |
| 29 | * eg. INDEX_NB_UNIQ_VISITORS is an integer: 4 bytes, but 'nb_uniq_visitors' is 16 bytes at least |
| 30 | */ |
| 31 | public const INDEX_NB_UNIQ_VISITORS = 1; |
| 32 | public const INDEX_NB_VISITS = 2; |
| 33 | public const INDEX_NB_ACTIONS = 3; |
| 34 | public const INDEX_MAX_ACTIONS = 4; |
| 35 | public const INDEX_SUM_VISIT_LENGTH = 5; |
| 36 | public const INDEX_BOUNCE_COUNT = 6; |
| 37 | public const INDEX_NB_VISITS_CONVERTED = 7; |
| 38 | public const INDEX_NB_CONVERSIONS = 8; |
| 39 | public const INDEX_REVENUE = 9; |
| 40 | public const INDEX_GOALS = 10; |
| 41 | public const INDEX_SUM_DAILY_NB_UNIQ_VISITORS = 11; |
| 42 | // Specific to the Actions reports |
| 43 | public const INDEX_PAGE_NB_HITS = 12; |
| 44 | public const INDEX_PAGE_SUM_TIME_SPENT = 13; |
| 45 | public const INDEX_PAGE_EXIT_NB_UNIQ_VISITORS = 14; |
| 46 | public const INDEX_PAGE_EXIT_NB_VISITS = 15; |
| 47 | public const INDEX_PAGE_EXIT_SUM_DAILY_NB_UNIQ_VISITORS = 16; |
| 48 | public const INDEX_PAGE_ENTRY_NB_UNIQ_VISITORS = 17; |
| 49 | public const INDEX_PAGE_ENTRY_SUM_DAILY_NB_UNIQ_VISITORS = 18; |
| 50 | public const INDEX_PAGE_ENTRY_NB_VISITS = 19; |
| 51 | public const INDEX_PAGE_ENTRY_NB_ACTIONS = 20; |
| 52 | public const INDEX_PAGE_ENTRY_SUM_VISIT_LENGTH = 21; |
| 53 | public const INDEX_PAGE_ENTRY_BOUNCE_COUNT = 22; |
| 54 | // Ecommerce Items reports |
| 55 | public const INDEX_ECOMMERCE_ITEM_REVENUE = 23; |
| 56 | public const INDEX_ECOMMERCE_ITEM_QUANTITY = 24; |
| 57 | public const INDEX_ECOMMERCE_ITEM_PRICE = 25; |
| 58 | public const INDEX_ECOMMERCE_ORDERS = 26; |
| 59 | public const INDEX_ECOMMERCE_ITEM_PRICE_VIEWED = 27; |
| 60 | // Site Search |
| 61 | public const INDEX_SITE_SEARCH_HAS_NO_RESULT = 28; |
| 62 | public const INDEX_PAGE_IS_FOLLOWING_SITE_SEARCH_NB_HITS = 29; |
| 63 | // Performance Analytics |
| 64 | public const INDEX_PAGE_SUM_TIME_GENERATION = 30; |
| 65 | public const INDEX_PAGE_NB_HITS_WITH_TIME_GENERATION = 31; |
| 66 | public const INDEX_PAGE_MIN_TIME_GENERATION = 32; |
| 67 | public const INDEX_PAGE_MAX_TIME_GENERATION = 33; |
| 68 | // Events |
| 69 | public const INDEX_EVENT_NB_HITS = 34; |
| 70 | public const INDEX_EVENT_SUM_EVENT_VALUE = 35; |
| 71 | public const INDEX_EVENT_MIN_EVENT_VALUE = 36; |
| 72 | public const INDEX_EVENT_MAX_EVENT_VALUE = 37; |
| 73 | public const INDEX_EVENT_NB_HITS_WITH_VALUE = 38; |
| 74 | // Number of unique User IDs |
| 75 | public const INDEX_NB_USERS = 39; |
| 76 | public const INDEX_SUM_DAILY_NB_USERS = 40; |
| 77 | // Contents |
| 78 | public const INDEX_CONTENT_NB_IMPRESSIONS = 41; |
| 79 | public const INDEX_CONTENT_NB_INTERACTIONS = 42; |
| 80 | // Unique visitors fingerprints (useful to process unique visitors across websites) |
| 81 | public const INDEX_NB_UNIQ_FINGERPRINTS = 43; |
| 82 | // Total number of hits |
| 83 | public const INDEX_NB_HITS = 44; |
| 84 | // Goal reports |
| 85 | public const INDEX_GOAL_NB_CONVERSIONS = 1; |
| 86 | public const INDEX_GOAL_REVENUE = 2; |
| 87 | public const INDEX_GOAL_NB_VISITS_CONVERTED = 3; |
| 88 | public const INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL = 4; |
| 89 | public const INDEX_GOAL_ECOMMERCE_REVENUE_TAX = 5; |
| 90 | public const INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING = 6; |
| 91 | public const INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT = 7; |
| 92 | public const INDEX_GOAL_ECOMMERCE_ITEMS = 8; |
| 93 | public const INDEX_GOAL_NB_PAGES_UNIQ_BEFORE = 9; |
| 94 | public const INDEX_GOAL_NB_CONVERSIONS_ATTRIB = 10; |
| 95 | public const INDEX_GOAL_NB_CONVERSIONS_PAGE_RATE = 11; |
| 96 | public const INDEX_GOAL_NB_CONVERSIONS_PAGE_UNIQ = 12; |
| 97 | public const INDEX_GOAL_NB_CONVERSIONS_ENTRY_RATE = 13; |
| 98 | public const INDEX_GOAL_REVENUE_PER_ENTRY = 14; |
| 99 | public const INDEX_GOAL_REVENUE_ATTRIB = 15; |
| 100 | public const INDEX_GOAL_NB_CONVERSIONS_ENTRY = 16; |
| 101 | public const INDEX_GOAL_REVENUE_ENTRY = 17; |
| 102 | public static $mappingFromIdToName = array( |
| 103 | \Piwik\Metrics::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors', |
| 104 | \Piwik\Metrics::INDEX_NB_UNIQ_FINGERPRINTS => 'nb_uniq_fingerprints', |
| 105 | \Piwik\Metrics::INDEX_NB_VISITS => 'nb_visits', |
| 106 | \Piwik\Metrics::INDEX_NB_ACTIONS => 'nb_actions', |
| 107 | \Piwik\Metrics::INDEX_NB_USERS => 'nb_users', |
| 108 | \Piwik\Metrics::INDEX_MAX_ACTIONS => 'max_actions', |
| 109 | \Piwik\Metrics::INDEX_SUM_VISIT_LENGTH => 'sum_visit_length', |
| 110 | \Piwik\Metrics::INDEX_BOUNCE_COUNT => 'bounce_count', |
| 111 | \Piwik\Metrics::INDEX_NB_VISITS_CONVERTED => 'nb_visits_converted', |
| 112 | \Piwik\Metrics::INDEX_NB_CONVERSIONS => 'nb_conversions', |
| 113 | \Piwik\Metrics::INDEX_REVENUE => 'revenue', |
| 114 | \Piwik\Metrics::INDEX_GOALS => 'goals', |
| 115 | \Piwik\Metrics::INDEX_SUM_DAILY_NB_UNIQ_VISITORS => 'sum_daily_nb_uniq_visitors', |
| 116 | \Piwik\Metrics::INDEX_SUM_DAILY_NB_USERS => 'sum_daily_nb_users', |
| 117 | \Piwik\Metrics::INDEX_NB_HITS => 'hits', |
| 118 | // Actions metrics |
| 119 | \Piwik\Metrics::INDEX_PAGE_NB_HITS => 'nb_hits', |
| 120 | \Piwik\Metrics::INDEX_PAGE_SUM_TIME_SPENT => 'sum_time_spent', |
| 121 | \Piwik\Metrics::INDEX_PAGE_SUM_TIME_GENERATION => 'sum_time_generation', |
| 122 | \Piwik\Metrics::INDEX_PAGE_NB_HITS_WITH_TIME_GENERATION => 'nb_hits_with_time_generation', |
| 123 | \Piwik\Metrics::INDEX_PAGE_MIN_TIME_GENERATION => 'min_time_generation', |
| 124 | \Piwik\Metrics::INDEX_PAGE_MAX_TIME_GENERATION => 'max_time_generation', |
| 125 | \Piwik\Metrics::INDEX_PAGE_EXIT_NB_UNIQ_VISITORS => 'exit_nb_uniq_visitors', |
| 126 | \Piwik\Metrics::INDEX_PAGE_EXIT_NB_VISITS => 'exit_nb_visits', |
| 127 | \Piwik\Metrics::INDEX_PAGE_EXIT_SUM_DAILY_NB_UNIQ_VISITORS => 'sum_daily_exit_nb_uniq_visitors', |
| 128 | \Piwik\Metrics::INDEX_PAGE_ENTRY_NB_UNIQ_VISITORS => 'entry_nb_uniq_visitors', |
| 129 | \Piwik\Metrics::INDEX_PAGE_ENTRY_SUM_DAILY_NB_UNIQ_VISITORS => 'sum_daily_entry_nb_uniq_visitors', |
| 130 | \Piwik\Metrics::INDEX_PAGE_ENTRY_NB_VISITS => 'entry_nb_visits', |
| 131 | \Piwik\Metrics::INDEX_PAGE_ENTRY_NB_ACTIONS => 'entry_nb_actions', |
| 132 | \Piwik\Metrics::INDEX_PAGE_ENTRY_SUM_VISIT_LENGTH => 'entry_sum_visit_length', |
| 133 | \Piwik\Metrics::INDEX_PAGE_ENTRY_BOUNCE_COUNT => 'entry_bounce_count', |
| 134 | \Piwik\Metrics::INDEX_PAGE_IS_FOLLOWING_SITE_SEARCH_NB_HITS => 'nb_hits_following_search', |
| 135 | // Items reports metrics |
| 136 | \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_REVENUE => 'revenue', |
| 137 | \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_QUANTITY => 'quantity', |
| 138 | \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_PRICE => 'price', |
| 139 | \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED => 'price_viewed', |
| 140 | \Piwik\Metrics::INDEX_ECOMMERCE_ORDERS => 'orders', |
| 141 | // Events |
| 142 | \Piwik\Metrics::INDEX_EVENT_NB_HITS => 'nb_events', |
| 143 | \Piwik\Metrics::INDEX_EVENT_SUM_EVENT_VALUE => 'sum_event_value', |
| 144 | \Piwik\Metrics::INDEX_EVENT_MIN_EVENT_VALUE => 'min_event_value', |
| 145 | \Piwik\Metrics::INDEX_EVENT_MAX_EVENT_VALUE => 'max_event_value', |
| 146 | \Piwik\Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE => 'nb_events_with_value', |
| 147 | // Contents |
| 148 | \Piwik\Metrics::INDEX_CONTENT_NB_IMPRESSIONS => 'nb_impressions', |
| 149 | \Piwik\Metrics::INDEX_CONTENT_NB_INTERACTIONS => 'nb_interactions', |
| 150 | ); |
| 151 | public static $mappingFromIdToNameGoal = array(\Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS => 'nb_conversions', \Piwik\Metrics::INDEX_GOAL_NB_VISITS_CONVERTED => 'nb_visits_converted', \Piwik\Metrics::INDEX_GOAL_REVENUE => 'revenue', \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL => 'revenue_subtotal', \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_TAX => 'revenue_tax', \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING => 'revenue_shipping', \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT => 'revenue_discount', \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_ITEMS => 'items', \Piwik\Metrics::INDEX_GOAL_NB_PAGES_UNIQ_BEFORE => 'nb_conv_pages_before', \Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS_ATTRIB => 'nb_conversions_attrib', \Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS_PAGE_RATE => 'nb_conversions_page_rate', \Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS_PAGE_UNIQ => 'nb_conversions_page_uniq', \Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS_ENTRY_RATE => 'nb_conversions_entry_rate', \Piwik\Metrics::INDEX_GOAL_REVENUE_PER_ENTRY => 'revenue_per_entry', \Piwik\Metrics::INDEX_GOAL_REVENUE_ATTRIB => 'revenue_attrib', \Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS_ENTRY => 'nb_conversions_entry', \Piwik\Metrics::INDEX_GOAL_REVENUE_ENTRY => 'revenue_entry'); |
| 152 | protected static $metricsAggregatedFromLogs = array(\Piwik\Metrics::INDEX_NB_UNIQ_VISITORS, \Piwik\Metrics::INDEX_NB_VISITS, \Piwik\Metrics::INDEX_NB_ACTIONS, \Piwik\Metrics::INDEX_NB_USERS, \Piwik\Metrics::INDEX_MAX_ACTIONS, \Piwik\Metrics::INDEX_SUM_VISIT_LENGTH, \Piwik\Metrics::INDEX_BOUNCE_COUNT, \Piwik\Metrics::INDEX_NB_VISITS_CONVERTED); |
| 153 | public static function getMappingFromIdToName() |
| 154 | { |
| 155 | $cache = PiwikCache::getTransientCache(); |
| 156 | $cacheKey = \Piwik\CacheId::siteAware(\Piwik\CacheId::pluginAware('Metrics.mappingFromIdToName')); |
| 157 | $value = $cache->fetch($cacheKey); |
| 158 | if (empty($value)) { |
| 159 | $value = self::$mappingFromIdToName; |
| 160 | /** |
| 161 | * Use this event if your plugin uses custom metric integer IDs to associate those IDs with the |
| 162 | * actual metric names (eg, 2 => nb_visits). This allows matomo to automate the replacing |
| 163 | * of IDs => metric names for your new metrics. |
| 164 | * |
| 165 | * **Example** |
| 166 | * |
| 167 | * public function addMetricIdToNameMapping(&$mapping) |
| 168 | * { |
| 169 | * $mapping[Archiver::INDEX_MY_NEW_METRIC] = $mapping['MyPlugin_myNewMetric']; |
| 170 | * } |
| 171 | * |
| 172 | * @ignore |
| 173 | */ |
| 174 | \Piwik\Piwik::postEvent('Metrics.addMetricIdToNameMapping', [&$value]); |
| 175 | $cache->save($cacheKey, $value); |
| 176 | } |
| 177 | return $value; |
| 178 | } |
| 179 | public static function getVisitsMetricNames() |
| 180 | { |
| 181 | $names = array(); |
| 182 | foreach (self::$metricsAggregatedFromLogs as $metricId) { |
| 183 | $names[$metricId] = self::$mappingFromIdToName[$metricId]; |
| 184 | } |
| 185 | return $names; |
| 186 | } |
| 187 | public static function getMappingFromNameToId() |
| 188 | { |
| 189 | static $nameToId = null; |
| 190 | if ($nameToId === null) { |
| 191 | $nameToId = array_flip(self::$mappingFromIdToName); |
| 192 | } |
| 193 | return $nameToId; |
| 194 | } |
| 195 | public static function getMappingFromNameToIdGoal() |
| 196 | { |
| 197 | static $nameToId = null; |
| 198 | if ($nameToId === null) { |
| 199 | $nameToId = array_flip(self::$mappingFromIdToNameGoal); |
| 200 | } |
| 201 | return $nameToId; |
| 202 | } |
| 203 | /** |
| 204 | * Is a lower value for a given column better? |
| 205 | * @param $column |
| 206 | * @return bool |
| 207 | * |
| 208 | * @ignore |
| 209 | */ |
| 210 | public static function isLowerValueBetter($column) |
| 211 | { |
| 212 | $isLowerBetter = null; |
| 213 | /** |
| 214 | * Use this event to define if a lower value of a metric is better. |
| 215 | * |
| 216 | * @param string $isLowerBetter should be set to a boolean indicating if lower is better |
| 217 | * @param string $column name of the column to determine |
| 218 | * |
| 219 | * **Example** |
| 220 | * |
| 221 | * public function checkIsLowerMetricValueBetter(&$isLowerBetter, $metric) |
| 222 | * { |
| 223 | * if ($metric === 'position') { |
| 224 | * $isLowerBetter = true; |
| 225 | * } |
| 226 | * } |
| 227 | */ |
| 228 | \Piwik\Piwik::postEvent('Metrics.isLowerValueBetter', [&$isLowerBetter, $column]); |
| 229 | if (!is_null($isLowerBetter)) { |
| 230 | return \true; |
| 231 | } |
| 232 | $lowerIsBetterPatterns = array('bounce', 'exit'); |
| 233 | foreach ($lowerIsBetterPatterns as $pattern) { |
| 234 | if (strpos($column, $pattern) !== \false) { |
| 235 | return \true; |
| 236 | } |
| 237 | } |
| 238 | return \false; |
| 239 | } |
| 240 | /** |
| 241 | * Derive the unit name from a column name |
| 242 | * @param $column |
| 243 | * @param $idSite |
| 244 | * @return string |
| 245 | * @ignore |
| 246 | */ |
| 247 | public static function getUnit($column, $idSite) |
| 248 | { |
| 249 | $nameToUnit = array('_rate' => '%', 'revenue' => \Piwik\Site::getCurrencySymbolFor($idSite), '_time_' => 's'); |
| 250 | $unit = null; |
| 251 | /** |
| 252 | * Use this event to define units for custom metrics used in evolution graphs and row evolution only. |
| 253 | * |
| 254 | * @param string $unit should hold the unit (e.g. %, €, s or empty string) |
| 255 | * @param string $column name of the column to determine |
| 256 | * @param string $idSite id of the current site |
| 257 | */ |
| 258 | \Piwik\Piwik::postEvent('Metrics.getEvolutionUnit', [&$unit, $column, $idSite]); |
| 259 | if (!empty($unit)) { |
| 260 | return $unit; |
| 261 | } |
| 262 | foreach ($nameToUnit as $pattern => $type) { |
| 263 | if (strpos($column, $pattern) !== \false) { |
| 264 | return $type; |
| 265 | } |
| 266 | } |
| 267 | return ''; |
| 268 | } |
| 269 | public static function getDefaultMetricSemanticTypes() : array |
| 270 | { |
| 271 | $cacheId = \Piwik\CacheId::pluginAware('DefaultMetricSemanticTypes'); |
| 272 | $cache = PiwikCache::getTransientCache(); |
| 273 | $types = $cache->fetch($cacheId); |
| 274 | if (empty($types)) { |
| 275 | $types = ['nb_visits' => Dimension::TYPE_NUMBER, 'nb_uniq_visitors' => Dimension::TYPE_NUMBER, 'nb_actions' => Dimension::TYPE_NUMBER, 'nb_users' => Dimension::TYPE_NUMBER, 'avg_time_on_page' => Dimension::TYPE_DURATION_S, 'sum_time_spent' => Dimension::TYPE_DURATION_S, 'sum_visit_length' => Dimension::TYPE_DURATION_S, 'bounce_count' => Dimension::TYPE_NUMBER, 'bounce_count_returning' => Dimension::TYPE_NUMBER, 'max_actions' => Dimension::TYPE_NUMBER, 'max_actions_returning' => Dimension::TYPE_NUMBER, 'nb_visits_converted_returning' => Dimension::TYPE_NUMBER, 'sum_visit_length_returning' => Dimension::TYPE_NUMBER, 'nb_visits_converted' => Dimension::TYPE_NUMBER, 'nb_conversions' => Dimension::TYPE_NUMBER, 'revenue' => Dimension::TYPE_MONEY, 'nb_hits' => Dimension::TYPE_NUMBER, 'hits' => Dimension::TYPE_NUMBER, 'entry_nb_visits' => Dimension::TYPE_NUMBER, 'entry_nb_uniq_visitors' => Dimension::TYPE_NUMBER, 'exit_nb_visits' => Dimension::TYPE_NUMBER, 'exit_nb_uniq_visitors' => Dimension::TYPE_NUMBER, 'entry_bounce_count' => Dimension::TYPE_NUMBER, 'exit_bounce_count' => Dimension::TYPE_NUMBER, 'exit_rate' => Dimension::TYPE_PERCENT, 'sum_daily_nb_uniq_visitors' => Dimension::TYPE_NUMBER, 'sum_daily_nb_users' => Dimension::TYPE_NUMBER, 'sum_daily_entry_nb_uniq_visitors' => Dimension::TYPE_NUMBER, 'sum_daily_exit_nb_uniq_visitors' => Dimension::TYPE_NUMBER, 'entry_nb_actions' => Dimension::TYPE_NUMBER, 'entry_sum_visit_length' => Dimension::TYPE_NUMBER, 'nb_actions_per_visit' => Dimension::TYPE_NUMBER, 'avg_time_on_site' => Dimension::TYPE_DURATION_S, 'bounce_rate' => Dimension::TYPE_PERCENT, 'conversion_rate' => Dimension::TYPE_PERCENT]; |
| 276 | /** |
| 277 | * Use this event to notify Matomo of the semantic types of metrics your plugin adds. |
| 278 | * |
| 279 | * A metric's semantic type is metadata used primarily in integrations with Matomo |
| 280 | * and third party services/applications. It provides information that can be used |
| 281 | * to determine how to display or use the information. |
| 282 | * |
| 283 | * It is recommended for your plugin to provide this information so users of third |
| 284 | * party services that connect with Matomo can make full use of the data your plugin |
| 285 | * tracks. |
| 286 | * |
| 287 | * See {@link Metrics} for the list of available semantic types. |
| 288 | * |
| 289 | * @param string $types The array mapping of metric_name => metric semantic type |
| 290 | */ |
| 291 | \Piwik\Piwik::postEvent('Metrics.getDefaultMetricSemanticTypes', [&$types]); |
| 292 | $cache->save($cacheId, $types); |
| 293 | } |
| 294 | return $types; |
| 295 | } |
| 296 | public static function getDefaultMetricTranslations() |
| 297 | { |
| 298 | $cacheId = \Piwik\CacheId::pluginAware('DefaultMetricTranslations'); |
| 299 | $cache = PiwikCache::getTransientCache(); |
| 300 | if ($cache->contains($cacheId)) { |
| 301 | return $cache->fetch($cacheId); |
| 302 | } |
| 303 | $translations = array('label' => 'General_ColumnLabel', 'date' => 'General_Date', 'avg_time_on_page' => 'General_ColumnAverageTimeOnPage', 'sum_time_spent' => 'General_ColumnSumVisitLength', 'sum_visit_length' => 'General_ColumnSumVisitLength', 'bounce_count' => 'General_ColumnBounces', 'bounce_count_returning' => 'VisitFrequency_ColumnBounceCountForReturningVisits', 'max_actions' => 'General_ColumnMaxActions', 'max_actions_returning' => 'VisitFrequency_ColumnMaxActionsInReturningVisit', 'nb_visits_converted_returning' => 'VisitFrequency_ColumnNbReturningVisitsConverted', 'sum_visit_length_returning' => 'VisitFrequency_ColumnSumVisitLengthReturning', 'nb_visits_converted' => 'General_ColumnVisitsWithConversions', 'nb_conversions' => 'Goals_ColumnConversions', 'revenue' => 'General_ColumnRevenue', 'nb_hits' => 'General_ColumnPageviews', 'hits' => 'General_ColumnHits', 'entry_nb_visits' => 'General_ColumnEntrances', 'entry_nb_uniq_visitors' => 'General_ColumnUniqueEntrances', 'exit_nb_visits' => 'General_ColumnExits', 'exit_nb_uniq_visitors' => 'General_ColumnUniqueExits', 'entry_bounce_count' => 'General_ColumnBounces', 'exit_bounce_count' => 'General_ColumnBounces', 'exit_rate' => 'General_ColumnExitRate'); |
| 304 | $dailySum = ' (' . \Piwik\Piwik::translate('General_DailySum') . ')'; |
| 305 | $afterEntry = ' ' . \Piwik\Piwik::translate('General_AfterEntry'); |
| 306 | $translations['sum_daily_nb_uniq_visitors'] = \Piwik\Piwik::translate('General_ColumnNbUniqVisitors') . $dailySum; |
| 307 | $translations['sum_daily_nb_users'] = \Piwik\Piwik::translate('General_ColumnNbUsers') . $dailySum; |
| 308 | $translations['sum_daily_entry_nb_uniq_visitors'] = \Piwik\Piwik::translate('General_ColumnUniqueEntrances') . $dailySum; |
| 309 | $translations['sum_daily_exit_nb_uniq_visitors'] = \Piwik\Piwik::translate('General_ColumnUniqueExits') . $dailySum; |
| 310 | $translations['entry_nb_actions'] = \Piwik\Piwik::translate('General_ColumnNbActions') . $afterEntry; |
| 311 | $translations['entry_sum_visit_length'] = \Piwik\Piwik::translate('General_ColumnSumVisitLength') . $afterEntry; |
| 312 | $translations = array_merge(self::getDefaultMetrics(), self::getDefaultProcessedMetrics(), $translations); |
| 313 | /** |
| 314 | * Use this event to register translations for metrics processed by your plugin. |
| 315 | * |
| 316 | * @param string $translations The array mapping of column_name => Plugin_TranslationForColumn |
| 317 | */ |
| 318 | \Piwik\Piwik::postEvent('Metrics.getDefaultMetricTranslations', array(&$translations)); |
| 319 | $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations); |
| 320 | $cache->save($cacheId, $translations); |
| 321 | return $translations; |
| 322 | } |
| 323 | public static function getDefaultMetrics() |
| 324 | { |
| 325 | $cacheId = \Piwik\CacheId::languageAware('DefaultMetrics'); |
| 326 | $cache = PiwikCache::getTransientCache(); |
| 327 | if ($cache->contains($cacheId)) { |
| 328 | return $cache->fetch($cacheId); |
| 329 | } |
| 330 | $translations = array('nb_visits' => 'General_ColumnNbVisits', 'nb_uniq_visitors' => 'General_ColumnNbUniqVisitors', 'nb_actions' => 'General_ColumnNbActions', 'nb_users' => 'General_ColumnNbUsers'); |
| 331 | $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations); |
| 332 | $cache->save($cacheId, $translations); |
| 333 | return $translations; |
| 334 | } |
| 335 | public static function getDefaultProcessedMetrics() |
| 336 | { |
| 337 | $cacheId = \Piwik\CacheId::languageAware('DefaultProcessedMetrics'); |
| 338 | $cache = PiwikCache::getTransientCache(); |
| 339 | if ($cache->contains($cacheId)) { |
| 340 | return $cache->fetch($cacheId); |
| 341 | } |
| 342 | $translations = array( |
| 343 | // Processed in AddColumnsProcessedMetrics |
| 344 | 'nb_actions_per_visit' => 'General_ColumnActionsPerVisit', |
| 345 | 'avg_time_on_site' => 'General_ColumnAvgTimeOnSite', |
| 346 | 'bounce_rate' => 'General_ColumnBounceRate', |
| 347 | 'conversion_rate' => 'General_ColumnConversionRate', |
| 348 | ); |
| 349 | $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations); |
| 350 | $cache->save($cacheId, $translations); |
| 351 | return $translations; |
| 352 | } |
| 353 | public static function getReadableColumnName($columnIdRaw) |
| 354 | { |
| 355 | $mappingIdToName = self::$mappingFromIdToName; |
| 356 | if (array_key_exists($columnIdRaw, $mappingIdToName)) { |
| 357 | return $mappingIdToName[$columnIdRaw]; |
| 358 | } |
| 359 | return $columnIdRaw; |
| 360 | } |
| 361 | public static function getMetricIdsToProcessReportTotal() |
| 362 | { |
| 363 | return array(self::INDEX_NB_VISITS, self::INDEX_NB_UNIQ_VISITORS, self::INDEX_NB_ACTIONS, self::INDEX_NB_HITS, self::INDEX_PAGE_NB_HITS, self::INDEX_NB_VISITS_CONVERTED, self::INDEX_NB_CONVERSIONS, self::INDEX_BOUNCE_COUNT, self::INDEX_PAGE_ENTRY_BOUNCE_COUNT, self::INDEX_PAGE_ENTRY_NB_VISITS, self::INDEX_PAGE_ENTRY_NB_ACTIONS, self::INDEX_PAGE_EXIT_NB_VISITS, self::INDEX_PAGE_EXIT_NB_UNIQ_VISITORS, self::INDEX_REVENUE); |
| 364 | } |
| 365 | public static function getDefaultMetricsDocumentation() |
| 366 | { |
| 367 | $cacheId = \Piwik\CacheId::pluginAware('DefaultMetricsDocumentation'); |
| 368 | $cache = PiwikCache::getTransientCache(); |
| 369 | if ($cache->contains($cacheId)) { |
| 370 | return $cache->fetch($cacheId); |
| 371 | } |
| 372 | $translations = array('nb_visits' => 'General_ColumnNbVisitsDocumentation', 'nb_uniq_visitors' => 'General_ColumnNbUniqVisitorsDocumentation', 'nb_actions' => 'General_ColumnNbActionsDocumentation', 'nb_users' => 'General_ColumnNbUsersDocumentation', 'nb_actions_per_visit' => 'General_ColumnActionsPerVisitDocumentation', 'avg_time_on_site' => 'General_ColumnAvgTimeOnSiteDocumentation', 'bounce_rate' => 'General_ColumnBounceRateDocumentation', 'conversion_rate' => 'General_ColumnConversionRateDocumentation', 'avg_time_on_page' => 'General_ColumnAverageTimeOnPageDocumentation', 'nb_hits' => 'General_ColumnPageviewsDocumentation', 'hits' => 'General_ColumnHitsDocumentation', 'exit_rate' => 'General_ColumnExitRateDocumentation', 'nb_visits_converted' => 'General_VisitConvertedGoalDocumentation'); |
| 373 | /** |
| 374 | * Use this event to register translations for metrics documentation processed by your plugin. |
| 375 | * |
| 376 | * @param string[] $translations The array mapping of column_name => Plugin_TranslationForColumnDocumentation |
| 377 | */ |
| 378 | \Piwik\Piwik::postEvent('Metrics.getDefaultMetricDocumentationTranslations', array(&$translations)); |
| 379 | $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations); |
| 380 | $cache->save($cacheId, $translations); |
| 381 | return $translations; |
| 382 | } |
| 383 | public static function getPercentVisitColumn() |
| 384 | { |
| 385 | $percentVisitsLabel = str_replace(' ', ' ', \Piwik\Piwik::translate('General_ColumnPercentageVisits')); |
| 386 | return $percentVisitsLabel; |
| 387 | } |
| 388 | /** |
| 389 | * This is a utility method used when building records through log aggregation. |
| 390 | * |
| 391 | * In records with per-goal conversion metrics the metrics are stored within DataTable Rows |
| 392 | * as a column with an array a value. The array is indexed by the goal ID and the column name |
| 393 | * is set to `Metrics::INDEX_GOALS`, for example: |
| 394 | * |
| 395 | * ``` |
| 396 | * $columns = [ |
| 397 | * Metrics::INDEX_GOALS = [ |
| 398 | * $idGoal => [ |
| 399 | * // ... conversion metrics ... |
| 400 | * ], |
| 401 | * ], |
| 402 | * ]; |
| 403 | * $row = new Row([DataTable::COLUMNS => $columns]); |
| 404 | * ``` |
| 405 | * |
| 406 | * This methods returns an array like `$columns` above based on a goal ID and a row of |
| 407 | * metric values for the goal. The result can be added directly to a DataTable record via `sumRowWithLabel()`. |
| 408 | * |
| 409 | * The goal metrics returned will differ based on whether the goal is user defined or an ecommerce goal. |
| 410 | * |
| 411 | * @param array $goalsMetrics |
| 412 | * @return array |
| 413 | */ |
| 414 | public static function makeGoalColumnsRow(int $idGoal, array $goalsMetrics) : array |
| 415 | { |
| 416 | if ($idGoal > GoalManager::IDGOAL_ORDER) { |
| 417 | // user defined goal |
| 418 | $columns = [\Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS, \Piwik\Metrics::INDEX_GOAL_NB_VISITS_CONVERTED, \Piwik\Metrics::INDEX_GOAL_REVENUE]; |
| 419 | } elseif ($idGoal == GoalManager::IDGOAL_ORDER) { |
| 420 | // ecommerce order |
| 421 | $columns = [\Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS, \Piwik\Metrics::INDEX_GOAL_NB_VISITS_CONVERTED, \Piwik\Metrics::INDEX_GOAL_REVENUE, \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL, \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_TAX, \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING, \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT, \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_ITEMS]; |
| 422 | } else { |
| 423 | // idGoal == GoalManager::IDGOAL_CART (abandoned cart) |
| 424 | $columns = [\Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS, \Piwik\Metrics::INDEX_GOAL_NB_VISITS_CONVERTED, \Piwik\Metrics::INDEX_GOAL_REVENUE, \Piwik\Metrics::INDEX_GOAL_ECOMMERCE_ITEMS]; |
| 425 | } |
| 426 | $values = []; |
| 427 | foreach ($columns as $column) { |
| 428 | $values[$column] = (float) ($goalsMetrics[$column] ?? 0); |
| 429 | } |
| 430 | return $values; |
| 431 | } |
| 432 | } |
| 433 |