PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
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 1 month ago Access 3 months ago Application 1 month ago Archive 1 month ago ArchiveProcessor 1 month ago Archiver 2 years ago AssetManager 1 month ago Auth 6 months ago Category 6 months ago Changes 1 month ago CliMulti 1 year ago Columns 1 month ago Concurrency 1 month ago Config 1 month ago Container 1 month ago CronArchive 3 months ago DataAccess 1 month ago DataFiles 2 years ago DataTable 2 weeks ago Db 2 weeks 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 1 month ago Metrics 3 months ago Notification 6 months ago Period 1 month ago Plugin 2 weeks ago Policy 1 month ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 3 months ago Request 3 months ago Scheduler 1 month ago Segment 1 month ago Session 2 weeks ago Settings 1 month ago Tracker 2 weeks ago Translation 1 month ago Twig 1 year ago UpdateCheck 3 months ago Updater 1 month ago Updates 3 days ago Validators 1 year ago View 1 month ago ViewDataTable 2 weeks ago Visualization 1 year ago Widget 1 month ago .htaccess 2 years ago Access.php 1 month ago Archive.php 1 month ago ArchiveProcessor.php 1 month ago AssetManager.php 1 month 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 1 month ago Common.php 2 weeks ago Config.php 1 month ago Console.php 3 months ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 1 month ago DI.php 3 months ago DataArray.php 1 month ago DataTable.php 1 month ago Date.php 1 month ago Db.php 1 month ago DbHelper.php 1 month ago Development.php 1 year ago ErrorHandler.php 6 months ago EventDispatcher.php 1 month ago ExceptionHandler.php 4 months ago FileIntegrity.php 1 month ago Filechecks.php 1 year ago Filesystem.php 1 month ago FrontController.php 4 months ago Http.php 1 month ago IP.php 1 year ago Log.php 3 months ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 1 month ago NoAccessException.php 2 years ago Nonce.php 6 months ago Notification.php 1 month ago NumberFormatter.php 5 months ago Option.php 5 months ago Period.php 1 month ago Piwik.php 1 month ago Plugin.php 1 month ago Process.php 1 month ago Profiler.php 6 months ago ProxyHeaders.php 4 months ago ProxyHttp.php 5 months ago QuickForm2.php 3 months ago RankingQuery.php 1 month ago ReportRenderer.php 1 month ago Request.php 1 month ago Segment.php 1 month ago Sequence.php 6 months ago Session.php 2 weeks ago SettingsPiwik.php 1 month ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 1 month ago SiteContentDetector.php 1 month ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 1 month ago Tracker.php 1 month ago Twig.php 1 month ago Unzip.php 1 year ago UpdateCheck.php 1 month ago Updater.php 1 month ago UpdaterErrorException.php 2 years ago Updates.php 3 months ago Url.php 3 months ago UrlHelper.php 1 month ago Version.php 3 days ago View.php 1 month ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 6 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