PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.10.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.10.0
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Metrics.php
matomo / app / core Last commit date
API 3 months ago Access 5 months ago Application 3 months ago Archive 3 months ago ArchiveProcessor 3 months ago Archiver 2 years ago AssetManager 3 months ago Auth 8 months ago Category 8 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 5 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 6 months ago Http 6 months ago Intl 5 months ago Log 2 years ago Mail 1 year ago Measurable 8 months ago Menu 3 months ago Metrics 5 months ago Notification 8 months ago Period 3 months ago Plugin 3 months ago Policy 3 months ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 5 months ago Request 5 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 5 months ago Updater 3 months ago Updates 3 months ago Validators 1 year ago View 3 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 3 months ago AssetManager.php 3 months ago Auth.php 8 months ago AuthResult.php 8 months ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 6 months ago CliMulti.php 3 months ago Common.php 3 months ago Config.php 3 months ago Console.php 5 months ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 3 months ago DI.php 5 months ago DataArray.php 3 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 8 months ago EventDispatcher.php 3 months ago ExceptionHandler.php 6 months ago FileIntegrity.php 3 months ago Filechecks.php 1 year ago Filesystem.php 3 months ago FrontController.php 6 months ago Http.php 3 months ago IP.php 1 year ago Log.php 5 months ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 3 months ago NoAccessException.php 2 years ago Nonce.php 8 months ago Notification.php 3 months ago NumberFormatter.php 7 months ago Option.php 7 months ago Period.php 3 months ago Piwik.php 3 months ago Plugin.php 3 months ago Process.php 3 months ago Profiler.php 8 months ago ProxyHeaders.php 6 months ago ProxyHttp.php 7 months ago QuickForm2.php 5 months ago RankingQuery.php 3 months ago ReportRenderer.php 3 months ago Request.php 3 months ago Segment.php 3 months ago Sequence.php 8 months ago Session.php 5 months ago SettingsPiwik.php 3 months ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 3 months ago SiteContentDetector.php 3 months ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 3 months 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 5 months ago Url.php 5 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 8 months ago
Metrics.php
485 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 /**
103 * @var string[]
104 */
105 public static $mappingFromIdToName = [
106 \Piwik\Metrics::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors',
107 \Piwik\Metrics::INDEX_NB_UNIQ_FINGERPRINTS => 'nb_uniq_fingerprints',
108 \Piwik\Metrics::INDEX_NB_VISITS => 'nb_visits',
109 \Piwik\Metrics::INDEX_NB_ACTIONS => 'nb_actions',
110 \Piwik\Metrics::INDEX_NB_USERS => 'nb_users',
111 \Piwik\Metrics::INDEX_MAX_ACTIONS => 'max_actions',
112 \Piwik\Metrics::INDEX_SUM_VISIT_LENGTH => 'sum_visit_length',
113 \Piwik\Metrics::INDEX_BOUNCE_COUNT => 'bounce_count',
114 \Piwik\Metrics::INDEX_NB_VISITS_CONVERTED => 'nb_visits_converted',
115 \Piwik\Metrics::INDEX_NB_CONVERSIONS => 'nb_conversions',
116 \Piwik\Metrics::INDEX_REVENUE => 'revenue',
117 \Piwik\Metrics::INDEX_GOALS => 'goals',
118 \Piwik\Metrics::INDEX_SUM_DAILY_NB_UNIQ_VISITORS => 'sum_daily_nb_uniq_visitors',
119 \Piwik\Metrics::INDEX_SUM_DAILY_NB_USERS => 'sum_daily_nb_users',
120 \Piwik\Metrics::INDEX_NB_HITS => 'hits',
121 // Actions metrics
122 \Piwik\Metrics::INDEX_PAGE_NB_HITS => 'nb_hits',
123 \Piwik\Metrics::INDEX_PAGE_SUM_TIME_SPENT => 'sum_time_spent',
124 \Piwik\Metrics::INDEX_PAGE_SUM_TIME_GENERATION => 'sum_time_generation',
125 \Piwik\Metrics::INDEX_PAGE_NB_HITS_WITH_TIME_GENERATION => 'nb_hits_with_time_generation',
126 \Piwik\Metrics::INDEX_PAGE_MIN_TIME_GENERATION => 'min_time_generation',
127 \Piwik\Metrics::INDEX_PAGE_MAX_TIME_GENERATION => 'max_time_generation',
128 \Piwik\Metrics::INDEX_PAGE_EXIT_NB_UNIQ_VISITORS => 'exit_nb_uniq_visitors',
129 \Piwik\Metrics::INDEX_PAGE_EXIT_NB_VISITS => 'exit_nb_visits',
130 \Piwik\Metrics::INDEX_PAGE_EXIT_SUM_DAILY_NB_UNIQ_VISITORS => 'sum_daily_exit_nb_uniq_visitors',
131 \Piwik\Metrics::INDEX_PAGE_ENTRY_NB_UNIQ_VISITORS => 'entry_nb_uniq_visitors',
132 \Piwik\Metrics::INDEX_PAGE_ENTRY_SUM_DAILY_NB_UNIQ_VISITORS => 'sum_daily_entry_nb_uniq_visitors',
133 \Piwik\Metrics::INDEX_PAGE_ENTRY_NB_VISITS => 'entry_nb_visits',
134 \Piwik\Metrics::INDEX_PAGE_ENTRY_NB_ACTIONS => 'entry_nb_actions',
135 \Piwik\Metrics::INDEX_PAGE_ENTRY_SUM_VISIT_LENGTH => 'entry_sum_visit_length',
136 \Piwik\Metrics::INDEX_PAGE_ENTRY_BOUNCE_COUNT => 'entry_bounce_count',
137 \Piwik\Metrics::INDEX_PAGE_IS_FOLLOWING_SITE_SEARCH_NB_HITS => 'nb_hits_following_search',
138 // Items reports metrics
139 \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_REVENUE => 'revenue',
140 \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_QUANTITY => 'quantity',
141 \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_PRICE => 'price',
142 \Piwik\Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED => 'price_viewed',
143 \Piwik\Metrics::INDEX_ECOMMERCE_ORDERS => 'orders',
144 // Events
145 \Piwik\Metrics::INDEX_EVENT_NB_HITS => 'nb_events',
146 \Piwik\Metrics::INDEX_EVENT_SUM_EVENT_VALUE => 'sum_event_value',
147 \Piwik\Metrics::INDEX_EVENT_MIN_EVENT_VALUE => 'min_event_value',
148 \Piwik\Metrics::INDEX_EVENT_MAX_EVENT_VALUE => 'max_event_value',
149 \Piwik\Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE => 'nb_events_with_value',
150 // Contents
151 \Piwik\Metrics::INDEX_CONTENT_NB_IMPRESSIONS => 'nb_impressions',
152 \Piwik\Metrics::INDEX_CONTENT_NB_INTERACTIONS => 'nb_interactions',
153 ];
154 /**
155 * @var string[]
156 */
157 public static $mappingFromIdToNameGoal = [\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'];
158 /**
159 * @var int[]
160 */
161 protected static $metricsAggregatedFromLogs = [\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];
162 /**
163 * @return array<int, string>
164 */
165 public static function getMappingFromIdToName()
166 {
167 $cache = PiwikCache::getTransientCache();
168 $cacheKey = \Piwik\CacheId::siteAware(\Piwik\CacheId::pluginAware('Metrics.mappingFromIdToName'));
169 /** @var array<int, string>|false $value */
170 $value = $cache->fetch($cacheKey);
171 if (empty($value)) {
172 $value = self::$mappingFromIdToName;
173 /**
174 * Use this event if your plugin uses custom metric integer IDs to associate those IDs with the
175 * actual metric names (eg, 2 => nb_visits). This allows matomo to automate the replacing
176 * of IDs => metric names for your new metrics.
177 *
178 * **Example**
179 *
180 * public function addMetricIdToNameMapping(&$mapping)
181 * {
182 * $mapping[Archiver::INDEX_MY_NEW_METRIC] = $mapping['MyPlugin_myNewMetric'];
183 * }
184 *
185 * @ignore
186 */
187 \Piwik\Piwik::postEvent('Metrics.addMetricIdToNameMapping', [&$value]);
188 $cache->save($cacheKey, $value);
189 }
190 return $value;
191 }
192 /**
193 * @return array<int, string>
194 */
195 public static function getVisitsMetricNames()
196 {
197 $names = [];
198 foreach (self::$metricsAggregatedFromLogs as $metricId) {
199 $names[$metricId] = self::$mappingFromIdToName[$metricId];
200 }
201 return $names;
202 }
203 /**
204 * @return array<string, int>
205 */
206 public static function getMappingFromNameToId()
207 {
208 static $nameToId = null;
209 if ($nameToId === null) {
210 $nameToId = array_flip(self::$mappingFromIdToName);
211 }
212 return $nameToId;
213 }
214 /**
215 * @return array<string, int>
216 */
217 public static function getMappingFromNameToIdGoal()
218 {
219 static $nameToId = null;
220 if ($nameToId === null) {
221 $nameToId = array_flip(self::$mappingFromIdToNameGoal);
222 }
223 return $nameToId;
224 }
225 /**
226 * Is a lower value for a given column better?
227 * @param string $column
228 * @return bool
229 *
230 * @ignore
231 */
232 public static function isLowerValueBetter($column)
233 {
234 $isLowerBetter = null;
235 /**
236 * Use this event to define if a lower value of a metric is better.
237 *
238 * @param string $isLowerBetter should be set to a boolean indicating if lower is better
239 * @param string $column name of the column to determine
240 *
241 * **Example**
242 *
243 * public function checkIsLowerMetricValueBetter(&$isLowerBetter, $metric)
244 * {
245 * if ($metric === 'position') {
246 * $isLowerBetter = true;
247 * }
248 * }
249 */
250 \Piwik\Piwik::postEvent('Metrics.isLowerValueBetter', [&$isLowerBetter, $column]);
251 if (!is_null($isLowerBetter)) {
252 return \true;
253 }
254 $lowerIsBetterPatterns = array('bounce', 'exit');
255 foreach ($lowerIsBetterPatterns as $pattern) {
256 if (strpos($column, $pattern) !== \false) {
257 return \true;
258 }
259 }
260 return \false;
261 }
262 /**
263 * Derive the unit name from a column name
264 * @param string $column
265 * @param string|int $idSite
266 * @return string
267 * @ignore
268 */
269 public static function getUnit($column, $idSite)
270 {
271 $nameToUnit = array('_rate' => '%', 'revenue' => \Piwik\Site::getCurrencySymbolFor((int) $idSite), '_time_' => 's');
272 /** @var string|null $unit */
273 $unit = null;
274 /**
275 * Use this event to define units for custom metrics used in evolution graphs and row evolution only.
276 *
277 * @param string $unit should hold the unit (e.g. %, €, s or empty string)
278 * @param string $column name of the column to determine
279 * @param string $idSite id of the current site
280 */
281 \Piwik\Piwik::postEvent('Metrics.getEvolutionUnit', [&$unit, $column, $idSite]);
282 if (!empty($unit)) {
283 return $unit;
284 }
285 foreach ($nameToUnit as $pattern => $type) {
286 if (strpos($column, $pattern) !== \false) {
287 return $type;
288 }
289 }
290 return '';
291 }
292 /**
293 * @return array<string, string>
294 */
295 public static function getDefaultMetricSemanticTypes() : array
296 {
297 $cacheId = \Piwik\CacheId::pluginAware('DefaultMetricSemanticTypes');
298 $cache = PiwikCache::getTransientCache();
299 /** @var array<string, string>|false $types */
300 $types = $cache->fetch($cacheId);
301 if (empty($types)) {
302 $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];
303 /**
304 * Use this event to notify Matomo of the semantic types of metrics your plugin adds.
305 *
306 * A metric's semantic type is metadata used primarily in integrations with Matomo
307 * and third party services/applications. It provides information that can be used
308 * to determine how to display or use the information.
309 *
310 * It is recommended for your plugin to provide this information so users of third
311 * party services that connect with Matomo can make full use of the data your plugin
312 * tracks.
313 *
314 * See {@link Metrics} for the list of available semantic types.
315 *
316 * @param string $types The array mapping of metric_name => metric semantic type
317 */
318 \Piwik\Piwik::postEvent('Metrics.getDefaultMetricSemanticTypes', [&$types]);
319 $cache->save($cacheId, $types);
320 }
321 return $types;
322 }
323 /**
324 * @return array<string, string>
325 */
326 public static function getDefaultMetricTranslations()
327 {
328 $cacheId = \Piwik\CacheId::pluginAware('DefaultMetricTranslations');
329 $cache = PiwikCache::getTransientCache();
330 if ($cache->contains($cacheId)) {
331 /** @var array<string, string> */
332 return $cache->fetch($cacheId);
333 }
334 $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');
335 $dailySum = ' (' . \Piwik\Piwik::translate('General_DailySum') . ')';
336 $afterEntry = ' ' . \Piwik\Piwik::translate('General_AfterEntry');
337 $translations['sum_daily_nb_uniq_visitors'] = \Piwik\Piwik::translate('General_ColumnNbUniqVisitors') . $dailySum;
338 $translations['sum_daily_nb_users'] = \Piwik\Piwik::translate('General_ColumnNbUsers') . $dailySum;
339 $translations['sum_daily_entry_nb_uniq_visitors'] = \Piwik\Piwik::translate('General_ColumnUniqueEntrances') . $dailySum;
340 $translations['sum_daily_exit_nb_uniq_visitors'] = \Piwik\Piwik::translate('General_ColumnUniqueExits') . $dailySum;
341 $translations['entry_nb_actions'] = \Piwik\Piwik::translate('General_ColumnNbActions') . $afterEntry;
342 $translations['entry_sum_visit_length'] = \Piwik\Piwik::translate('General_ColumnSumVisitLength') . $afterEntry;
343 $translations = array_merge(self::getDefaultMetrics(), self::getDefaultProcessedMetrics(), $translations);
344 /**
345 * Use this event to register translations for metrics processed by your plugin.
346 *
347 * @param string $translations The array mapping of column_name => Plugin_TranslationForColumn
348 */
349 \Piwik\Piwik::postEvent('Metrics.getDefaultMetricTranslations', array(&$translations));
350 $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations);
351 $cache->save($cacheId, $translations);
352 return $translations;
353 }
354 /**
355 * @return array<string, string>
356 */
357 public static function getDefaultMetrics()
358 {
359 $cacheId = \Piwik\CacheId::languageAware('DefaultMetrics');
360 $cache = PiwikCache::getTransientCache();
361 if ($cache->contains($cacheId)) {
362 /** @var array<string, string> */
363 return $cache->fetch($cacheId);
364 }
365 $translations = array('nb_visits' => 'General_ColumnNbVisits', 'nb_uniq_visitors' => 'General_ColumnNbUniqVisitors', 'nb_actions' => 'General_ColumnNbActions', 'nb_users' => 'General_ColumnNbUsers');
366 $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations);
367 $cache->save($cacheId, $translations);
368 return $translations;
369 }
370 /**
371 * @return array<string, string>
372 */
373 public static function getDefaultProcessedMetrics()
374 {
375 $cacheId = \Piwik\CacheId::languageAware('DefaultProcessedMetrics');
376 $cache = PiwikCache::getTransientCache();
377 if ($cache->contains($cacheId)) {
378 /** @var array<string, string> */
379 return $cache->fetch($cacheId);
380 }
381 $translations = array(
382 // Processed in AddColumnsProcessedMetrics
383 'nb_actions_per_visit' => 'General_ColumnActionsPerVisit',
384 'avg_time_on_site' => 'General_ColumnAvgTimeOnSite',
385 'bounce_rate' => 'General_ColumnBounceRate',
386 'conversion_rate' => 'General_ColumnConversionRate',
387 );
388 $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations);
389 $cache->save($cacheId, $translations);
390 return $translations;
391 }
392 /**
393 * @param int|string $columnIdRaw
394 * @return int|string
395 */
396 public static function getReadableColumnName($columnIdRaw)
397 {
398 $mappingIdToName = self::$mappingFromIdToName;
399 if (array_key_exists($columnIdRaw, $mappingIdToName)) {
400 return $mappingIdToName[$columnIdRaw];
401 }
402 return $columnIdRaw;
403 }
404 /**
405 * @return int[]
406 */
407 public static function getMetricIdsToProcessReportTotal()
408 {
409 return [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];
410 }
411 /**
412 * @return array<string, string>
413 */
414 public static function getDefaultMetricsDocumentation()
415 {
416 $cacheId = \Piwik\CacheId::pluginAware('DefaultMetricsDocumentation');
417 $cache = PiwikCache::getTransientCache();
418 if ($cache->contains($cacheId)) {
419 /** @var array<string, string> */
420 return $cache->fetch($cacheId);
421 }
422 $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');
423 /**
424 * Use this event to register translations for metrics documentation processed by your plugin.
425 *
426 * @param string[] $translations The array mapping of column_name => Plugin_TranslationForColumnDocumentation
427 */
428 \Piwik\Piwik::postEvent('Metrics.getDefaultMetricDocumentationTranslations', array(&$translations));
429 $translations = array_map(array('\\Piwik\\Piwik', 'translate'), $translations);
430 $cache->save($cacheId, $translations);
431 return $translations;
432 }
433 /**
434 * @return string
435 */
436 public static function getPercentVisitColumn()
437 {
438 return str_replace(' ', '&nbsp;', \Piwik\Piwik::translate('General_ColumnPercentageVisits'));
439 }
440 /**
441 * This is a utility method used when building records through log aggregation.
442 *
443 * In records with per-goal conversion metrics the metrics are stored within DataTable Rows
444 * as a column with an array a value. The array is indexed by the goal ID and the column name
445 * is set to `Metrics::INDEX_GOALS`, for example:
446 *
447 * ```
448 * $columns = [
449 * Metrics::INDEX_GOALS = [
450 * $idGoal => [
451 * // ... conversion metrics ...
452 * ],
453 * ],
454 * ];
455 * $row = new Row([DataTable::COLUMNS => $columns]);
456 * ```
457 *
458 * This methods returns an array like `$columns` above based on a goal ID and a row of
459 * metric values for the goal. The result can be added directly to a DataTable record via `sumRowWithLabel()`.
460 *
461 * The goal metrics returned will differ based on whether the goal is user defined or an ecommerce goal.
462 *
463 * @param array<int, int|float> $goalsMetrics
464 * @return array<int, float>
465 */
466 public static function makeGoalColumnsRow(int $idGoal, array $goalsMetrics) : array
467 {
468 if ($idGoal > GoalManager::IDGOAL_ORDER) {
469 // user defined goal
470 $columns = [\Piwik\Metrics::INDEX_GOAL_NB_CONVERSIONS, \Piwik\Metrics::INDEX_GOAL_NB_VISITS_CONVERTED, \Piwik\Metrics::INDEX_GOAL_REVENUE];
471 } elseif ($idGoal == GoalManager::IDGOAL_ORDER) {
472 // ecommerce order
473 $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];
474 } else {
475 // idGoal == GoalManager::IDGOAL_CART (abandoned cart)
476 $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];
477 }
478 $values = [];
479 foreach ($columns as $column) {
480 $values[$column] = (float) ($goalsMetrics[$column] ?? 0);
481 }
482 return $values;
483 }
484 }
485