diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php
index 004c5ae3db4..2a70aeb6a8b 100644
--- a/core/Plugin/Report.php
+++ b/core/Plugin/Report.php
@@ -21,10 +21,6 @@
use Piwik\Plugin\Dimension\ActionDimension;
use Piwik\Plugin\Dimension\ConversionDimension;
use Piwik\Plugin\Dimension\VisitDimension;
-use Piwik\Plugins\CoreHome\Columns\Metrics\BounceRate;
-use Piwik\Plugins\CoreHome\Columns\Metrics\ActionsPerVisit;
-use Piwik\Plugins\CoreHome\Columns\Metrics\AverageTimeOnSite;
-use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\ViewDataTable\Factory as ViewDataTableFactory;
use Exception;
@@ -370,15 +366,26 @@ public function render()
}
/**
- *
* Processing a uniqueId for each report, can be used by UIs as a key to match a given report
+ *
* @return string
*/
public function getId()
{
- $params = $this->getParameters();
+ return self::buildId($this->getModule(), $this->getAction(), $this->getParameters());
+ }
- $paramsKey = $this->getModule() . '.' . $this->getAction();
+ /**
+ * TODO
+ *
+ * @param string $module
+ * @param string $action
+ * @param array|null $params
+ * @return string
+ */
+ public static function buildId(string $module, string $action, ?array $params = null): string
+ {
+ $paramsKey = $module . '.' . $action;
if (!empty($params)) {
foreach ($params as $key => $value) {
@@ -436,7 +443,7 @@ public function getRecursiveLabelSeparator()
*/
public function getMetrics()
{
- return $this->getMetricTranslations($this->metrics);
+ return self::getMetricTranslations($this->metrics);
}
/**
@@ -494,7 +501,7 @@ public function getProcessedMetrics()
return $this->processedMetrics;
}
- return $this->getMetricTranslations($this->processedMetrics);
+ return self::getMetricTranslations($this->processedMetrics);
}
/**
@@ -795,7 +802,10 @@ protected function buildReportMetadata()
$report['metrics'] = $this->getMetrics();
$report['metricsDocumentation'] = $this->getMetricsDocumentation();
- $processedMetricMetadata = $this->getProcessedMetricsMetadata();
+ $processedMetricMetadata = self::getProcessedMetricsMetadata(
+ $this->processedMetrics ?: [],
+ $this->getProcessedMetrics() ?: null
+ );
$report['processedMetrics'] = $processedMetricMetadata['names'];
$report['processedMetricFormulas'] = $processedMetricMetadata['formulas'];
$report['temporaryMetricAggregationTypes'] = $processedMetricMetadata['temporaryMetricAggregationTypes'];
@@ -927,7 +937,8 @@ public function getParameters()
}
/**
- * Get the translated name of the category the report belongs to.
+ * Get the ID of the category the report belongs to.
+ * The ID should also be a valid translation key.
* @return string|null
* @ignore
*/
@@ -937,8 +948,9 @@ public function getCategoryId()
}
/**
- * Get the translated name of the subcategory the report belongs to.
+ * Get the ID of the subcategory the report belongs to.
* @return string|null
+ * The ID should also be a valid translation key.
* @ignore
*/
public function getSubcategoryId()
@@ -1094,7 +1106,7 @@ public function fetchSubtable($idSubtable, $paramOverride = array())
return Request::processRequest($module . '.' . $action, $paramOverride);
}
- private function getMetricTranslations($metricsToTranslate)
+ private static function getMetricTranslations($metricsToTranslate)
{
$translations = Metrics::getDefaultMetricTranslations();
$metrics = array();
@@ -1341,20 +1353,20 @@ private function isScopeSameOrSubsetOf(?string $scope, string $supersetScope): b
return false;
}
- private function getProcessedMetricsMetadata(): array
+ public static function getProcessedMetricsMetadata(?array $processedMetrics, ?array $processedMetricTranslations = null): array
{
$metadata = [
- 'names' => $this->getProcessedMetrics() ?: [],
+ 'names' => $processedMetricTranslations ?: self::getMetricTranslations($processedMetrics ?: []),
'formulas' => [],
'temporaryMetricAggregationTypes' => [],
'temporaryMetricSemanticTypes' => [],
];
- if (empty($this->processedMetrics)) {
+ if (empty($processedMetrics)) {
return $metadata;
}
- foreach ($this->processedMetrics as $processedMetric) {
+ foreach ($processedMetrics as $processedMetric) {
if (!($processedMetric instanceof ProcessedMetric)) {
continue;
}
diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php
index 40c1efe3f37..7d0d5b8c73a 100644
--- a/plugins/API/ProcessedReport.php
+++ b/plugins/API/ProcessedReport.php
@@ -17,7 +17,9 @@
use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\DataTable;
+use Piwik\DataTable\DataTableInterface;
use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal;
+use Piwik\DataTable\Map;
use Piwik\DataTable\Row;
use Piwik\DataTable\Simple;
use Piwik\Date;
@@ -25,7 +27,10 @@
use Piwik\Metrics\Formatter;
use Piwik\Period;
use Piwik\Piwik;
+use Piwik\Plugin\ProcessedMetric;
+use Piwik\Plugin\Report;
use Piwik\Plugin\ReportsProvider;
+use Piwik\Plugins\Goals\Columns\Metrics\GoalSpecificProcessedMetric;
use Piwik\Site;
use Piwik\Timer;
use Piwik\Url;
@@ -179,9 +184,10 @@ public function translateMetric($metric, $idSite, $apiMethodUniqueId)
* @param bool|Date $date
* @param bool $hideMetricsDoc
* @param bool $showSubtableReports
+ * @param array $dataTables TODO
* @return array
*/
- public function getReportMetadata($idSite, $period = false, $date = false, $hideMetricsDoc = false, $showSubtableReports = false)
+ public function getReportMetadata($idSite, $period = false, $date = false, $hideMetricsDoc = false, $showSubtableReports = false, ?array $dataTables = null)
{
Piwik::checkUserHasViewAccess($idSite);
@@ -200,7 +206,8 @@ public function getReportMetadata($idSite, $period = false, $date = false, $hide
$availableReports = array();
foreach ($this->reportsProvider->getAllReports() as $report) {
- $report->configureReportMetadata($availableReports, $parameters);
+ $dataTable = $dataTables[$report->getId()] ?? null;
+ $report->configureReportMetadata($availableReports, $parameters, $dataTable);
}
foreach ($availableReports as &$availableReport) {
@@ -432,6 +439,8 @@ public function getProcessedReport(
list($newReport, $columns, $rowsMetadata, $totals) = $this->handleTableReport($idSite, $dataTable, $reportMetadata, $showRawMetrics, $formatMetrics);
+ $this->handleExtraProcessedMetricsMetadata($dataTable, $reportMetadata);
+
if (function_exists('mb_substr')) {
foreach ($columns as &$name) {
if (substr($name, 0, 1) === mb_substr($name, 0, 1)) {
@@ -946,4 +955,38 @@ private function getIdGoalToUseForActionsReports($idGoal, string $requestMethod)
}
return $idGoal;
}
+
+ private function handleExtraProcessedMetricsMetadata(DataTableInterface $reportData, array &$reportMetadata): void
+ {
+ $dataTable = $this->getFirstDataTable($reportData);
+ if (empty($dataTable)) {
+ return;
+ }
+
+ $extraProcessedMetrics = $dataTable->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME);
+ if (empty($extraProcessedMetrics)) {
+ return;
+ }
+
+ $extraProcessedMetrics = array_filter($extraProcessedMetrics, function ($processedMetric) {
+ return $processedMetric instanceof ProcessedMetric
+ && !($processedMetric instanceof GoalSpecificProcessedMetric);
+ });
+
+ $extraMetadata = Report::getProcessedMetricsMetadata($extraProcessedMetrics);
+
+ $reportMetadata['processedMetrics'] = array_merge($reportMetadata['processedMetrics'] ?? [], $extraMetadata['names']);
+ $reportMetadata['processedMetricFormulas'] = array_merge($reportMetadata['processedMetricFormulas'] ?? [], $extraMetadata['formulas']);
+ $reportMetadata['temporaryMetricAggregationTypes'] = array_merge($reportMetadata['temporaryMetricAggregationTypes'] ?? [], $extraMetadata['temporaryMetricAggregationTypes']);
+ $reportMetadata['temporaryMetricSemanticTypes'] = array_merge($reportMetadata['temporaryMetricSemanticTypes'] ?? [], $extraMetadata['temporaryMetricSemanticTypes']);
+ }
+
+ private function getFirstDataTable(DataTableInterface $reportData)
+ {
+ $table = $reportData;
+ while ($table instanceof Map) {
+ $table = $table->getFirstRow();
+ }
+ return $table;
+ }
}
diff --git a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php
index 846c02379dd..fe5e6854fab 100644
--- a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php
+++ b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php
@@ -53,11 +53,6 @@ public function getMetrics()
);
}
- public function getProcessedMetrics()
- {
- return array();
- }
-
protected function getMetricsDocumentation()
{
return array(
diff --git a/tests/PHPUnit/System/ApiGetReportMetadataTest.php b/tests/PHPUnit/System/ApiGetReportMetadataTest.php
index 1b854d226b0..8cf8b6a778c 100644
--- a/tests/PHPUnit/System/ApiGetReportMetadataTest.php
+++ b/tests/PHPUnit/System/ApiGetReportMetadataTest.php
@@ -80,6 +80,21 @@ public function getApiForTesting()
],
],
+ [
+ 'API.getProcessedReport',
+ [
+ 'idSite' => $idSite,
+ 'date' => $dateTime,
+ 'apiModule' => 'UserCountry',
+ 'apiAction' => 'getCountry',
+ 'testSuffix' => '_withExtraProcessedMetrics',
+ 'otherRequestParameters' => [
+ 'filter_update_columns_when_show_all_goals' => '1',
+ 'idGoal' => '0',
+ ],
+ ],
+ ],
+
// Test w/ showRawMetrics=true
[
'API.getProcessedReport',
diff --git a/tests/PHPUnit/System/ApiGetReportMetadataYearTest.php b/tests/PHPUnit/System/ApiGetReportMetadataYearTest.php
index 72dee9be5d5..a9324c1d9e8 100644
--- a/tests/PHPUnit/System/ApiGetReportMetadataYearTest.php
+++ b/tests/PHPUnit/System/ApiGetReportMetadataYearTest.php
@@ -29,6 +29,7 @@ public function getApiForTesting()
'date' => self::$fixture->dateTime,
'periods' => 'year',
'language' => 'fr');
+ return [array('API.getProcessedReport', $params)];
return array(
array('API.getProcessedReport', $params),
array('LanguagesManager.getAvailableLanguageNames', $params),
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml
index 0a51612d31f..f23bdfae283 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml
@@ -29,9 +29,14 @@
Avg. Time on WebsiteBounce RateRevenue per Visit
+ Conversion Rate$revenue / ($nb_visits != 0 ? $nb_visits : $nb_conversions)
+ $nb_visits_converted / $nb_visits
+ $nb_actions / $nb_visits
+ $sum_visit_length / $nb_visits
+ $bounce_count / $nb_visitsnumber
@@ -72,6 +77,14 @@
index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=day&date=2009-01-04index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=day&date=2008-12-06,2009-01-04UserCountry_getCountry
+
+ sum
+ sum
+
+
+ number
+ number
+
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml
index 472657fb71c..865e57f2234 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml
@@ -1713,8 +1713,6 @@
sum
-
- Ecommerce order Revenue per Visit
@@ -2128,8 +2126,6 @@
sum
-
- Ecommerce order Revenue per Visit
@@ -2207,6 +2203,12 @@
The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.The number of times this page was visited.
+
+ Avg. time on page
+ Bounce Rate
+ Exit rate
+ Avg. generation time
+ $sum_time_spent / $nb_hits$entry_bounce_count / $entry_nb_visits
@@ -2297,6 +2299,12 @@
The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.The number of times this page was visited.
+
+ Avg. time on page
+ Bounce Rate
+ Exit rate
+ Avg. generation time
+ $sum_time_spent / $nb_hits$entry_bounce_count / $entry_nb_visits
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml
index 99b62f5c732..55389cd5bf2 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml
@@ -29,9 +29,14 @@
Avg. Time on WebsiteBounce RateRevenue per Visit
+ Conversion Rate$revenue / ($nb_visits != 0 ? $nb_visits : $nb_conversions)
+ $nb_visits_converted / $nb_visits
+ $nb_actions / $nb_visits
+ $sum_visit_length / $nb_visits
+ $bounce_count / $nb_visitsnumber
@@ -72,6 +77,14 @@
index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=day&date=2009-01-04index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=day&date=2008-12-06,2009-01-04UserCountry_getCountry
+
+ sum
+ sum
+
+
+ number
+ number
+
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_withExtraProcessedMetrics__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_withExtraProcessedMetrics__API.getProcessedReport_day.xml
new file mode 100644
index 00000000000..54a43cc70ed
--- /dev/null
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_withExtraProcessedMetrics__API.getProcessedReport_day.xml
@@ -0,0 +1,147 @@
+
+
+ Piwik test
+ Sunday, January 4, 2009
+
+ Visitors
+ Locations
+ Country
+ UserCountry
+ getCountry
+ Country
+ Shows which country your visitors connected from when accessing your website.
+
+ Visits
+ Unique visitors
+ Actions
+
+
+ If a visitor comes to your website for the first time or if they visit a page more than 30 minutes after their last page view, this will be recorded as a new visit.
+ The number of unduplicated visitors coming to your website. Every user is only counted once, even if they visit the website multiple times a day.
+ The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.
+ The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.
+ The average duration of a visit.
+ The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.
+ The percentage of visits that triggered a goal conversion.
+
+
+ Actions per Visit
+ Avg. Time on Website
+ Bounce Rate
+ Conversion Rate
+ Revenue per Visit
+
+
+ ($goals["idgoal=3"].revenue) / ($nb_visits != 0 ? $nb_visits : $nb_conversions)
+ $nb_visits_converted / $nb_visits
+ $nb_actions / $nb_visits
+ $sum_visit_length / $nb_visits
+ $bounce_count / $nb_visits
+
+
+ number
+ number
+ number
+ number
+ duration_s
+ percent
+ percent
+ money
+
+
+ sum
+ sum
+
+
+ Conversions
+ Revenue
+
+
+ number
+ money
+ money
+ percent
+
+
+ sum
+ sum
+
+
+ Ecommerce order Revenue per Visit
+ Ecommerce order conversion rate
+
+
+ $goals["idgoal={idGoal}"].revenue / ($nb_visits == 0 ? $goals["idgoal={idGoal}"].nb_conversions : $nb_visits)
+ $goals["idgoal={idGoal}"].nb_conversions / $nb_visits
+
+ index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=day&date=2009-01-04
+ index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=day&date=2008-12-06,2009-01-04
+ UserCountry_getCountry
+
+ sum
+ sum
+
+
+ number
+ number
+
+
+
+
+ Visits
+ Unique visitors
+ Actions
+ Actions per Visit
+ Avg. Time on Website
+ Bounce Rate
+ Conversion Rate
+ Revenue per Visit
+ Revenue
+
+
+
+
+ 1
+ 1
+ 1
+ $42.26
+ 100%
+ 1
+ 00:18:06
+ 100%
+ $42
+ 100%
+ 1
+ $42.26
+ $42.26
+
+
+
+
+ fr
+ plugins/Morpheus/icons/dist/flags/fr.png
+ countryCode==fr
+ 16
+
+
+
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1086
+ 1
+ 1
+
+
+ 1
+ 1
+ 42.26
+
+
+ 1
+ 42.26
+ 1
+
+
\ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml
index 4eb0835b059..06e3a127b6c 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml
@@ -28,9 +28,14 @@
Temps moyen sur le site webTaux de rebondRevenu par visite
+ Taux de conversion$revenue / ($nb_visits != 0 ? $nb_visits : $nb_conversions)
+ $nb_visits_converted / $nb_visits
+ $nb_actions / $nb_visits
+ $sum_visit_length / $nb_visits
+ $bounce_count / $nb_visitsnumber
@@ -71,6 +76,14 @@
index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=year&date=2009-01-04index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCountry&period=year&date=2000-01-01,2009-12-31UserCountry_getCountry
+
+ sum
+ sum
+
+
+ number
+ number
+