| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Plugins\Goals; |
|
|
| use Exception; |
| use Piwik\API\Request; |
| use Piwik\Archive; |
| use Piwik\CacheId; |
| use Piwik\Cache as PiwikCache; |
| use Piwik\Common; |
| use Piwik\DataTable; |
| use Piwik\DbHelper; |
| use Piwik\Metrics; |
| use Piwik\Piwik; |
| use Piwik\Plugin\Manager; |
| use Piwik\Plugins\API\DataTable\MergeDataTables; |
| use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate; |
| use Piwik\Plugins\Goals\Columns\Metrics\AverageOrderRevenue; |
| use Piwik\Plugin\ReportsProvider; |
| use Piwik\Plugins\Goals\Columns\Metrics\GoalConversionRate; |
| use Piwik\Plugins\Goals\Reports\GetMetrics; |
| use Piwik\Segment; |
| use Piwik\Segment\SegmentExpression; |
| use Piwik\Site; |
| use Piwik\Tracker\Cache; |
| use Piwik\Tracker\GoalManager; |
| use Piwik\Plugins\VisitFrequency\API as VisitFrequencyAPI; |
| use Piwik\Validators\Regex; |
| use Piwik\Validators\WhitelistedValue; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class API extends \Piwik\Plugin\API |
| { |
| public const AVG_PRICE_VIEWED = 'avg_price_viewed'; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public function getGoal(int $idSite, int $idGoal): ?array |
| { |
| Piwik::checkUserHasViewAccess($idSite); |
|
|
| $goal = $this->getModel()->getActiveGoal($idSite, $idGoal); |
|
|
| if (!empty($goal)) { |
| return $this->formatGoal($goal); |
| } |
|
|
| return null; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getGoals($idSite, bool $orderByName = false): array |
| { |
| if (is_array($idSite)) { |
| $idSite = array_map('intval', $idSite); |
| $idSite = implode(',', $idSite); |
| } |
|
|
| $cacheId = self::getCacheId($idSite); |
| $cache = $this->getGoalsInfoStaticCache(); |
| if (!$cache->contains($cacheId)) { |
| |
| |
| |
| $idSite = Site::getIdSitesFromIdSitesString($idSite, false, true); |
|
|
| if (empty($idSite)) { |
| return []; |
| } |
|
|
| Piwik::checkUserHasViewAccess($idSite); |
|
|
| $goals = $this->getModel()->getActiveGoals($idSite); |
| $cleanedGoals = []; |
| $indexByIdGoal = 1 === count($idSite); |
|
|
| foreach ($goals as &$goal) { |
| if ($indexByIdGoal) { |
| $cleanedGoals[$goal['idgoal']] = $this->formatGoal($goal); |
| } else { |
| $cleanedGoals[] = $this->formatGoal($goal); |
| } |
| } |
|
|
| $cache->save($cacheId, $cleanedGoals); |
| } |
|
|
| |
| $goals = $cache->fetch($cacheId); |
|
|
| if ($orderByName) { |
| uasort($goals, function ($a, $b) { |
| if ($a['name'] == $b['name']) { |
| return $a['idgoal'] > $b['idgoal'] ? -1 : 1; |
| } |
|
|
| return strcasecmp($a['name'], $b['name']); |
| }); |
| } |
|
|
| return $goals; |
| } |
|
|
| |
| |
| |
| |
| private function formatGoal(array $goal): array |
| { |
| $goal['name'] = Common::unsanitizeInputValue($goal['name']); |
| $goal['description'] = Common::unsanitizeInputValue($goal['description']); |
| $goal['pattern_type'] = Common::unsanitizeInputValue($goal['pattern_type']); |
| $goal['pattern'] = Common::unsanitizeInputValue($goal['pattern']); |
|
|
| if ($goal['match_attribute'] == 'manually') { |
| unset($goal['pattern']); |
| unset($goal['pattern_type']); |
| unset($goal['case_sensitive']); |
| } |
|
|
| return $goal; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function addGoal( |
| int $idSite, |
| string $name, |
| $matchAttribute, |
| $pattern, |
| $patternType, |
| $caseSensitive = false, |
| $revenue = false, |
| $allowMultipleConversionsPerVisit = false, |
| string $description = '', |
| $useEventValueAsRevenue = false |
| ) { |
| Piwik::checkUserHasWriteAccess($idSite); |
|
|
| $patternType = Common::unsanitizeInputValue($patternType); |
|
|
| $patternType = $this->checkPatternType($patternType, $matchAttribute); |
| $pattern = $this->checkPattern($pattern, $matchAttribute); |
| $this->checkPatternIsValid($patternType, $pattern, $matchAttribute); |
|
|
| $revenue = Common::forceDotAsSeparatorForDecimalPoint((float)$revenue); |
|
|
| $goal = array( |
| 'name' => $name, |
| 'description' => $description, |
| 'match_attribute' => $matchAttribute, |
| 'pattern' => $pattern, |
| 'pattern_type' => $patternType, |
| 'case_sensitive' => (int)$caseSensitive, |
| 'allow_multiple' => (int)$allowMultipleConversionsPerVisit, |
| 'revenue' => $revenue, |
| 'deleted' => 0, |
| 'event_value_as_revenue' => (int)$useEventValueAsRevenue, |
| ); |
|
|
| $idGoal = $this->getModel()->createGoalForSite($idSite, $goal); |
|
|
| $this->getGoalsInfoStaticCache()->delete(self::getCacheId($idSite)); |
|
|
| Cache::regenerateCacheWebsiteAttributes($idSite); |
| return $idGoal; |
| } |
|
|
| private function getModel(): Model |
| { |
| return new Model(); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function updateGoal( |
| int $idSite, |
| $idGoal, |
| string $name, |
| $matchAttribute, |
| $pattern, |
| $patternType, |
| $caseSensitive = false, |
| $revenue = false, |
| $allowMultipleConversionsPerVisit = false, |
| string $description = '', |
| $useEventValueAsRevenue = false |
| ): void { |
| Piwik::checkUserHasWriteAccess($idSite); |
|
|
| $patternType = Common::unsanitizeInputValue($patternType); |
|
|
| $patternType = $this->checkPatternType($patternType, $matchAttribute); |
| $pattern = $this->checkPattern($pattern, $matchAttribute); |
| $this->checkPatternIsValid($patternType, $pattern, $matchAttribute); |
|
|
| $revenue = Common::forceDotAsSeparatorForDecimalPoint((float)$revenue); |
|
|
| $goal = array( |
| 'name' => $name, |
| 'description' => $description, |
| 'match_attribute' => $matchAttribute, |
| 'pattern' => $pattern, |
| 'pattern_type' => $patternType, |
| 'case_sensitive' => (int)$caseSensitive, |
| 'allow_multiple' => (int)$allowMultipleConversionsPerVisit, |
| 'revenue' => $revenue, |
| 'event_value_as_revenue' => (int)$useEventValueAsRevenue, |
| ); |
|
|
| $this->checkEventValueAsRevenue($goal); |
|
|
| $this->getModel()->updateGoal($idSite, $idGoal, $goal); |
|
|
| $this->getGoalsInfoStaticCache()->delete(self::getCacheId($idSite)); |
|
|
| Cache::regenerateCacheWebsiteAttributes($idSite); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| private function checkEventValueAsRevenue(array $goal): void |
| { |
| if ($goal['event_value_as_revenue'] && !GoalManager::isEventMatchingGoal($goal)) { |
| throw new \Exception("'useEventValueAsRevenue' can only be 1 if the goal matches an event attribute."); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| private function checkPatternIsValid($patternType, $pattern, $matchAttribute): void |
| { |
| if ( |
| $patternType == 'exact' |
| && substr($pattern, 0, 4) != 'http' |
| && substr($matchAttribute, 0, 6) != 'event_' |
| && $matchAttribute != 'title' |
| ) { |
| throw new Exception(Piwik::translate('Goals_ExceptionInvalidMatchingString', array("http:// or https://", "http://www.yourwebsite.com/newsletter/subscribed.html"))); |
| } |
|
|
| if ($patternType == 'regex') { |
| $validator = new Regex(); |
| $validator->validate(GoalManager::formatRegex($pattern)); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| private function checkPatternType($patternType, $matchAttribute): string |
| { |
| if (empty($patternType)) { |
| return ''; |
| } |
|
|
| $patternType = strtolower($patternType); |
|
|
| if (in_array($matchAttribute, GoalManager::$NUMERIC_MATCH_ATTRIBUTES)) { |
| $validValues = ['greater_than']; |
| } else { |
| $validValues = ['exact', 'contains', 'regex']; |
| } |
|
|
| $validator = new WhitelistedValue($validValues); |
| $validator->validate($patternType); |
|
|
| return $patternType; |
| } |
|
|
| |
| |
| |
| |
| private function checkPattern($pattern, $matchAttribute): string |
| { |
| if ($matchAttribute !== 'manually' && $pattern === '') { |
| throw new \Exception(Piwik::translate('General_PleaseSpecifyValue', ['pattern'])); |
| } |
|
|
| if ( |
| in_array($matchAttribute, GoalManager::$NUMERIC_MATCH_ATTRIBUTES) |
| && !is_numeric($pattern) |
| ) { |
| throw new \Exception("Invalid pattern for match attribute '$matchAttribute'. (got '$pattern', expected numeric value)."); |
| } |
|
|
| return $pattern; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function deleteGoal(int $idSite, $idGoal) |
| { |
| Piwik::checkUserHasWriteAccess($idSite); |
|
|
| $this->getModel()->deleteGoal($idSite, $idGoal); |
| $this->getModel()->deleteGoalConversions($idSite, $idGoal); |
|
|
| $this->getGoalsInfoStaticCache()->delete(self::getCacheId($idSite)); |
|
|
| Cache::regenerateCacheWebsiteAttributes($idSite); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function getItems(string $recordName, $idSite, string $period, string $date, $abandonedCarts, $segment) |
| { |
| Piwik::checkUserHasViewAccess($idSite); |
|
|
| $recordNameFinal = $recordName; |
| if ($abandonedCarts) { |
| $recordNameFinal = Archiver::getItemRecordNameAbandonedCart($recordName); |
| } |
|
|
| $archive = Archive::build($idSite, $period, $date, $segment); |
| $dataTable = $archive->getDataTable($recordNameFinal); |
| |
| $dataTable->filter('ReplaceColumnNames'); |
|
|
| |
| |
| if (version_compare(DbHelper::getInstallVersion(), '4.0.0-b2', '<')) { |
| $this->enrichItemsTableWithViewMetrics($dataTable, $recordName, $idSite, $period, $date, $segment); |
| } |
|
|
| |
| $dataTable->filter(function (DataTable $table) { |
| foreach ($table->getRowsWithoutSummaryRow() as $row) { |
| if (!$row->getColumn('avg_price') && !$row->getColumn('price')) { |
| $row->renameColumn(self::AVG_PRICE_VIEWED, 'avg_price'); |
| } |
| $row->deleteColumn(self::AVG_PRICE_VIEWED); |
| } |
| }); |
|
|
| $reportToNotDefinedString = array( |
| 'Goals_ItemsSku' => Piwik::translate('General_NotDefined', Piwik::translate('Goals_ProductSKU')), |
| 'Goals_ItemsName' => Piwik::translate('General_NotDefined', Piwik::translate('Goals_ProductName')), |
| 'Goals_ItemsCategory' => Piwik::translate('General_NotDefined', Piwik::translate('Goals_ProductCategory')), |
| ); |
| $notDefinedStringPretty = $reportToNotDefinedString[$recordName]; |
| $this->renameNotDefinedRow($dataTable, $notDefinedStringPretty); |
|
|
| if ($abandonedCarts) { |
| $ordersColumn = 'abandoned_carts'; |
| $dataTable->renameColumn('orders', $ordersColumn); |
| } |
|
|
| $dataTable->queueFilter('ReplaceSummaryRowLabel'); |
| $dataTable->queueFilter('ColumnDelete', array('price')); |
|
|
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| protected function renameNotDefinedRow($dataTable, $notDefinedStringPretty): void |
| { |
| if ($dataTable instanceof DataTable\Map) { |
| foreach ($dataTable->getDataTables() as $table) { |
| $this->renameNotDefinedRow($table, $notDefinedStringPretty); |
| } |
| return; |
| } |
|
|
| $rowNotDefined = $dataTable->getRowFromLabel('Value not defined'); |
| if ($rowNotDefined) { |
| $rowNotDefined->setColumn('label', $notDefinedStringPretty); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| protected function enrichItemsDataTableWithItemsViewMetrics($dataTable, $idSite, string $period, string $date, $segment, $idSubtable): void |
| { |
| if (!Manager::getInstance()->isPluginActivated('CustomVariables') || in_array('nb_visits', $dataTable->getColumns())) { |
| |
| return; |
| } |
|
|
| |
| $ecommerceViews = \Piwik\Plugins\CustomVariables\API::getInstance()->getCustomVariablesValuesFromNameId($idSite, $period, $date, $idSubtable, $segment, $_leavePriceViewedColumn = true); |
|
|
| |
| |
| |
| foreach ($ecommerceViews->getRows() as $rowView) { |
| |
| $rowFound = $dataTable->getRowFromLabel($rowView->getColumn('label')); |
| $price = $rowFound |
| ? $rowFound->getColumn(Metrics::INDEX_ECOMMERCE_ITEM_PRICE) |
| : false; |
| if (empty($price)) { |
| |
| if ($rowView->getColumn(Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED)) { |
| $rowView->renameColumn(Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED, self::AVG_PRICE_VIEWED); |
| } |
| } |
| $rowView->deleteColumn(Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED); |
| } |
|
|
| $ecommerceViews->filter('ReplaceColumnNames'); |
|
|
| $dataTable->addDataTable($ecommerceViews); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getItemsSku($idSite, string $period, string $date, $abandonedCarts = false, $segment = false) |
| { |
| $dataTable = $this->getItems('Goals_ItemsSku', $idSite, $period, $date, $abandonedCarts, $segment); |
| $dataTable->filter('AddSegmentByLabel', ['productSku']); |
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getItemsName($idSite, string $period, string $date, $abandonedCarts = false, $segment = false) |
| { |
| $dataTable = $this->getItems('Goals_ItemsName', $idSite, $period, $date, $abandonedCarts, $segment); |
| $dataTable->filter('AddSegmentByLabel', ['productName']); |
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getItemsCategory($idSite, string $period, string $date, $abandonedCarts = false, $segment = false) |
| { |
| $dataTable = $this->getItems('Goals_ItemsCategory', $idSite, $period, $date, $abandonedCarts, $segment); |
| $dataTable->filter('AddSegmentByLabel', ['productCategory']); |
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected static function convertSpecialGoalIds($idGoal) |
| { |
| if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { |
| return GoalManager::IDGOAL_ORDER; |
| } elseif ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) { |
| return GoalManager::IDGOAL_CART; |
| } else { |
| return $idGoal; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function get($idSite, string $period, string $date, $segment = false, $idGoal = false, $columns = [], $showAllGoalSpecificMetrics = false, $compare = false) |
| { |
| Piwik::checkUserHasViewAccess($idSite); |
|
|
| |
| $table = null; |
|
|
| $segments = array( |
| '' => false, |
| '_new_visit' => VisitFrequencyAPI::NEW_VISITOR_SEGMENT, |
| '_returning_visit' => VisitFrequencyAPI::RETURNING_VISITOR_SEGMENT, |
| ); |
|
|
| foreach ($segments as $appendToMetricName => $predefinedSegment) { |
| $startingArchiveDependent = \Piwik\Plugin\Archiver::$ARCHIVE_DEPENDENT; |
| try { |
| if (!empty($predefinedSegment)) { |
| |
| |
| |
| |
| |
| |
| \Piwik\Plugin\Archiver::$ARCHIVE_DEPENDENT = false; |
| } |
| $segmentToUse = $this->appendSegment($segment, $predefinedSegment); |
|
|
| |
| $tableSegmented = Request::processRequest('Goals.getMetrics', array( |
| 'segment' => $segmentToUse, |
| 'idSite' => $idSite, |
| 'period' => $period, |
| 'date' => $date, |
| 'idGoal' => $idGoal, |
| 'columns' => $columns, |
| 'showAllGoalSpecificMetrics' => $showAllGoalSpecificMetrics, |
| 'format_metrics' => !empty($compare) ? 0 : Common::getRequestVar('format_metrics', 'bc'), |
| ), $default = []); |
| } finally { |
| \Piwik\Plugin\Archiver::$ARCHIVE_DEPENDENT = $startingArchiveDependent; |
| } |
| $tableSegmented->filter( |
| 'Piwik\Plugins\Goals\DataTable\Filter\AppendNameToColumnNames', |
| array($appendToMetricName) |
| ); |
|
|
| if (!isset($table)) { |
| $table = $tableSegmented; |
| } else { |
| $merger = new MergeDataTables(); |
| $merger->mergeDataTables($table, $tableSegmented); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| $formatMetricsRequest = \Piwik\Request::fromRequest()->getStringParameter('format_metrics', 'bc'); |
| if (!empty($compare) && $formatMetricsRequest !== '0') { |
| $getMetricsReport = ReportsProvider::factory('Goals', 'getMetrics'); |
| $table->queueFilter(function (DataTable $t) use ($getMetricsReport) { |
| $t->setMetadata(Metrics\Formatter::PROCESSED_METRICS_FORMATTED_FLAG, false); |
|
|
| $formatter = new Metrics\Formatter(); |
| $formatter->formatMetrics($t, $getMetricsReport, $metricsToFormat = null, $formatAll = true); |
| }); |
| } |
|
|
| return $table; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getMetrics($idSite, string $period, string $date, $segment = false, $idGoal = false, $columns = [], $showAllGoalSpecificMetrics = false) |
| { |
| Piwik::checkUserHasViewAccess($idSite); |
| $archive = Archive::build($idSite, $period, $date, $segment); |
|
|
| $showAllGoalSpecificMetrics = $showAllGoalSpecificMetrics && $idGoal === false; |
|
|
| |
| $idGoal = self::convertSpecialGoalIds($idGoal); |
| $isEcommerceGoal = $idGoal === GoalManager::IDGOAL_ORDER || $idGoal === GoalManager::IDGOAL_CART; |
|
|
| $allMetrics = Goals::getGoalColumns($idGoal); |
|
|
| if ($showAllGoalSpecificMetrics) { |
| foreach ($this->getGoals($idSite) as $aGoal) { |
| foreach (Goals::getGoalColumns($aGoal['idgoal']) as $goalColumn) { |
| $allMetrics[] = Goals::makeGoalColumn($aGoal['idgoal'], $goalColumn); |
| } |
| } |
| $allMetrics[] = 'nb_visits'; |
| } |
|
|
| $columnsToShow = Piwik::getArrayFromApiParameter($columns); |
| $requestedColumns = $columnsToShow; |
|
|
| $shouldAddAverageOrderRevenue = (in_array('avg_order_revenue', $requestedColumns) || empty($requestedColumns)) && $isEcommerceGoal; |
|
|
| if ($shouldAddAverageOrderRevenue && !empty($requestedColumns)) { |
| $avgOrder = new AverageOrderRevenue(); |
| $metricsToAdd = $avgOrder->getDependentMetrics(); |
|
|
| $requestedColumns = array_unique(array_merge($requestedColumns, $metricsToAdd)); |
| } |
|
|
| if ($showAllGoalSpecificMetrics && !empty($requestedColumns)) { |
| foreach ($requestedColumns as $requestedColumn) { |
| if (strpos($requestedColumn, '_conversion_rate') !== false) { |
| $columnIdGoal = Goals::getGoalIdFromGoalColumn($requestedColumn); |
| if ($columnIdGoal) { |
| $goalConversionRate = new GoalConversionRate($idSite, $columnIdGoal); |
| $metricsToAdd = $goalConversionRate->getDependentMetrics(); |
| $requestedColumns = array_unique(array_merge($requestedColumns, $metricsToAdd)); |
| } |
| } |
| } |
| } |
|
|
| |
| $report = ReportsProvider::factory('Goals', 'getMetrics'); |
| $columnsToGet = $report->getMetricsRequiredForReport($allMetrics, $requestedColumns); |
|
|
| $inDbMetricNames = array_map(function ($name) use ($idGoal) { |
| $name = str_replace('goal_', '', $name); |
| return $name == 'nb_visits' ? $name : Archiver::getRecordName($name, $idGoal); |
| }, $columnsToGet); |
| $dataTable = $archive->getDataTableFromNumeric($inDbMetricNames); |
|
|
| if (count($columnsToGet) > 0) { |
| $newNameMapping = array_combine($inDbMetricNames, $columnsToGet); |
| } else { |
| $newNameMapping = array(); |
| } |
| $dataTable->filter('ReplaceColumnNames', array($newNameMapping)); |
|
|
| |
| |
| |
| if ($shouldAddAverageOrderRevenue) { |
| $dataTable->filter(function (DataTable $table) { |
| $extraProcessedMetrics = $table->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME); |
| if (empty($extraProcessedMetrics)) { |
| $extraProcessedMetrics = array(); |
| } |
| $extraProcessedMetrics[] = new AverageOrderRevenue(); |
| $table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $extraProcessedMetrics); |
| }); |
| } |
| if ($showAllGoalSpecificMetrics) { |
| $dataTable->filter(function (DataTable $table) use ($idSite, &$allMetrics, $requestedColumns) { |
| $extraProcessedMetrics = $table->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME); |
| if (empty($extraProcessedMetrics)) { |
| $extraProcessedMetrics = array(); |
| } |
| foreach ($this->getGoals($idSite) as $aGoal) { |
| $metric = new GoalConversionRate($idSite, $aGoal['idgoal']); |
| if (!empty($requestedColumns) && !in_array($metric->getName(), $requestedColumns)) { |
| continue; |
| } |
| $extraProcessedMetrics[] = $metric; |
| $allMetrics[] = $metric->getName(); |
| } |
| $table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $extraProcessedMetrics); |
| }); |
| } |
|
|
| |
| if (empty($columnsToShow)) { |
| $columnsToShow = $allMetrics; |
| $columnsToShow[] = 'conversion_rate'; |
| if ($isEcommerceGoal) { |
| $columnsToShow[] = 'avg_order_revenue'; |
| } |
| } |
|
|
| $dataTable->queueFilter('ColumnDelete', array($columnsToRemove = array(), $columnsToShow)); |
|
|
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| protected function appendSegment($segment, $segmentToAppend) |
| { |
| return Segment::combine($segment, SegmentExpression::AND_DELIMITER, $segmentToAppend); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| protected function getNumeric($idSite, string $period, string $date, $segment, $toFetch) |
| { |
| Piwik::checkUserHasViewAccess($idSite); |
| $archive = Archive::build($idSite, $period, $date, $segment); |
| $dataTable = $archive->getDataTableFromNumeric($toFetch); |
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public function getConversions($idSite, string $period, string $date, $segment = false, $idGoal = false) |
| { |
| return $this->getNumeric($idSite, $period, $date, $segment, Archiver::getRecordName('nb_conversions', $idGoal)); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public function getNbVisitsConverted($idSite, string $period, string $date, $segment = false, $idGoal = false) |
| { |
| return $this->getNumeric($idSite, $period, $date, $segment, Archiver::getRecordName('nb_visits_converted', $idGoal)); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public function getConversionRate($idSite, string $period, string $date, $segment = false, $idGoal = false) |
| { |
| $table = $this->get($idSite, $period, $date, $segment, $idGoal, 'conversion_rate'); |
| $table->filter(function (DataTable $dataTable) { |
| $dataTable->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, [new ConversionRate()]); |
| }); |
| return $table; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public function getRevenue($idSite, string $period, string $date, $segment = false, $idGoal = false) |
| { |
| return $this->getNumeric($idSite, $period, $date, $segment, Archiver::getRecordName('revenue', $idGoal)); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function getGoalSpecificDataTable(string $recordName, $idSite, string $period, string $date, $segment, $idGoal) |
| { |
| Piwik::checkUserHasViewAccess($idSite); |
|
|
| $archive = Archive::build($idSite, $period, $date, $segment); |
|
|
| |
| $realGoalId = !$idGoal ? false : self::convertSpecialGoalIds($idGoal); |
|
|
| |
| $dataTable = $archive->getDataTable(Archiver::getRecordName($recordName, $realGoalId), $idSubtable = null); |
| $dataTable->queueFilter('ReplaceColumnNames'); |
|
|
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getDaysToConversion($idSite, string $period, string $date, $segment = false, $idGoal = false) |
| { |
| $dataTable = $this->getGoalSpecificDataTable( |
| Archiver::DAYS_UNTIL_CONV_RECORD_NAME, |
| $idSite, |
| $period, |
| $date, |
| $segment, |
| $idGoal |
| ); |
|
|
| $dataTable->queueFilter('Sort', array('label', 'asc', true, false)); |
| $dataTable->queueFilter( |
| 'BeautifyRangeLabels', |
| array(Piwik::translate('Intl_OneDay'), Piwik::translate('Intl_NDays')) |
| ); |
|
|
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getVisitsUntilConversion($idSite, string $period, string $date, $segment = false, $idGoal = false) |
| { |
| $dataTable = $this->getGoalSpecificDataTable( |
| Archiver::VISITS_UNTIL_RECORD_NAME, |
| $idSite, |
| $period, |
| $date, |
| $segment, |
| $idGoal |
| ); |
|
|
| $dataTable->queueFilter('Sort', array('label', 'asc', true, false)); |
| $dataTable->queueFilter( |
| 'BeautifyRangeLabels', |
| array(Piwik::translate('General_OneVisit'), Piwik::translate('General_NVisits')) |
| ); |
|
|
| return $dataTable; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function enrichItemsTableWithViewMetrics($dataTable, string $recordName, $idSite, string $period, string $date, $segment) |
| { |
| if (!Manager::getInstance()->isPluginActivated('CustomVariables')) { |
| return; |
| } |
|
|
| |
| $customVariables = \Piwik\Plugins\CustomVariables\API::getInstance()->getCustomVariables( |
| $idSite, |
| $period, |
| $date, |
| $segment, |
| $expanded = false, |
| $_leavePiwikCoreVariables = true |
| ); |
| $mapping = array( |
| 'Goals_ItemsSku' => '_pks', |
| 'Goals_ItemsName' => '_pkn', |
| 'Goals_ItemsCategory' => '_pkc', |
| ); |
| $customVarNameToLookFor = $mapping[$recordName]; |
|
|
| |
| if ($customVariables instanceof DataTable\Map) { |
| $customVariableDatatables = $customVariables->getDataTables(); |
| |
| $dataTables = $dataTable->getDataTables(); |
| foreach ($customVariableDatatables as $key => $customVariableTableForDate) { |
| |
| $dataTableForDate = $dataTables[$key] ?? new DataTable(); |
|
|
| |
| |
| if ( |
| $customVariableTableForDate instanceof DataTable |
| && $customVariableTableForDate->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX) |
| ) { |
| $dateRewrite = $customVariableTableForDate->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart()->toString(); |
| $row = $customVariableTableForDate->getRowFromLabel($customVarNameToLookFor); |
| if ($row) { |
| $idSubtable = $row->getIdSubDataTable(); |
| $this->enrichItemsDataTableWithItemsViewMetrics($dataTableForDate, $idSite, $period, $dateRewrite, $segment, $idSubtable); |
| } |
| $dataTable->addTable($dataTableForDate, $key); |
| } |
| } |
| } elseif ($customVariables instanceof DataTable) { |
| $row = $customVariables->getRowFromLabel($customVarNameToLookFor); |
| if ($row) { |
| $idSubtable = $row->getIdSubDataTable(); |
| |
| $this->enrichItemsDataTableWithItemsViewMetrics($dataTable, $idSite, $period, $date, $segment, $idSubtable); |
| } |
| } |
| } |
|
|
| |
| |
| |
| private function getCacheId($idSite): string |
| { |
| return CacheId::pluginAware('Goals.getGoals.' . $idSite); |
| } |
|
|
| private function getGoalsInfoStaticCache(): \Matomo\Cache\Transient |
| { |
| return PiwikCache::getTransientCache(); |
| } |
| } |
|
|