'General_AverageOrderValue', 'nb_conversions' => 'Goals_ColumnConversions', 'conversion_rate' => 'General_ColumnConversionRate', 'revenue' => 'General_TotalRevenue', 'items' => 'General_PurchasedProducts', ); /** * @var Translator */ private $translator; private $goals; private function formatConversionRate($conversionRate, $columnName = 'conversion_rate') { if ($conversionRate instanceof DataTable) { if ($conversionRate->getRowsCount() == 0) { $conversionRate = 0; } else { $conversionRate = $conversionRate->getFirstRow()->getColumn($columnName); } } if (!is_numeric($conversionRate)) { $conversionRate = sprintf('%.' . self::CONVERSION_RATE_PRECISION . 'f%%', $conversionRate); } return $conversionRate; } public function __construct(Translator $translator) { parent::__construct(); $this->translator = $translator; $this->idSite = Common::getRequestVar('idSite', null, 'int'); $this->goals = API::getInstance()->getGoals($this->idSite); } public function manage() { Piwik::checkUserHasAdminAccess($this->idSite); $view = new View('@Goals/manageGoals'); $this->setGeneralVariablesView($view); $this->setEditGoalsViewVariables($view); $this->setGoalOptions($view); return $view->render(); } public function goalConversionsOverview() { $view = new View('@Goals/conversionOverview'); $idGoal = Common::getRequestVar('idGoal', null, 'string'); $view->topDimensions = $this->getTopDimensions($idGoal); $goalMetrics = Request::processRequest('Goals.get', array('idGoal' => $idGoal)); // conversion rate for new and returning visitors $view->conversion_rate_returning = $this->formatConversionRate($goalMetrics, 'conversion_rate_returning_visit'); $view->conversion_rate_new = $this->formatConversionRate($goalMetrics, 'conversion_rate_new_visit'); $view->idGoal = $idGoal; return $view->render(); } public function getLastNbConversionsGraph() { $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getConversions'); return $this->renderView($view); } public function getLastConversionRateGraph() { $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getConversionRate'); return $this->renderView($view); } public function getLastRevenueGraph() { $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getRevenue'); return $this->renderView($view); } public function addNewGoal() { $view = new View('@Goals/addNewGoal'); $this->setGeneralVariablesView($view); $this->setGoalOptions($view); $view->onlyShowAddNewGoal = true; return $view->render(); } public function editGoals() { $view = new View('@Goals/editGoals'); $this->setGeneralVariablesView($view); $this->setEditGoalsViewVariables($view); $this->setGoalOptions($view); return $view->render(); } public function hasConversions() { $this->checkSitePermission(); $idGoal = Common::getRequestVar('idGoal', '', 'string'); $idSite = Common::getRequestVar('idSite', null, 'int'); $period = Common::getRequestVar('period', null, 'string'); $date = Common::getRequestVar('date', null, 'string'); Piwik::checkUserHasViewAccess($idSite); $conversions = new Conversions(); Json::sendHeaderJSON(); $numConversions = $conversions->getConversionForGoal($idGoal, $idSite, $period, $date); return json_encode($numConversions > 0); } public function getEvolutionGraph(array $columns = array(), $idGoal = false, array $defaultColumns = array()) { if (empty($columns)) { $columns = Common::getRequestVar('columns', false); if (false !== $columns) { $columns = Piwik::getArrayFromApiParameter($columns); } } if (false !== $columns) { $columns = !is_array($columns) ? array($columns) : $columns; } if (empty($idGoal)) { $idGoal = Common::getRequestVar('idGoal', false, 'string'); } $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.get'); $view->requestConfig->request_parameters_to_modify['idGoal'] = $idGoal; $nameToLabel = $this->goalColumnNameToLabel; if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { $nameToLabel['nb_conversions'] = 'General_EcommerceOrders'; } elseif ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) { $nameToLabel['nb_conversions'] = $this->translator->translate('General_VisitsWith', $this->translator->translate('Goals_AbandonedCart')); $nameToLabel['conversion_rate'] = $nameToLabel['nb_conversions']; $nameToLabel['revenue'] = $this->translator->translate('Goals_LeftInCart', $this->translator->translate('General_ColumnRevenue')); $nameToLabel['items'] = $this->translator->translate('Goals_LeftInCart', $this->translator->translate('Goals_Products')); } $selectableColumns = array('nb_conversions', 'conversion_rate', 'revenue'); if ($this->site->isEcommerceEnabled()) { $selectableColumns[] = 'items'; $selectableColumns[] = 'avg_order_revenue'; } foreach (array_merge($columns ? $columns : array(), $selectableColumns) as $columnName) { $columnTranslation = ''; // find the right translation for this column, eg. find 'revenue' if column is Goal_1_revenue foreach ($nameToLabel as $metric => $metricTranslation) { if (strpos($columnName, $metric) !== false) { $columnTranslation = $this->translator->translate($metricTranslation); break; } } if (!empty($idGoal) && isset($this->goals[$idGoal])) { $goalName = $this->goals[$idGoal]['name']; $columnTranslation = "$columnTranslation (" . $this->translator->translate('Goals_GoalX', "$goalName") . ")"; } $view->config->translations[$columnName] = $columnTranslation; } if (!empty($columns)) { $view->config->columns_to_display = $columns; } elseif (empty($view->config->columns_to_display) && !empty($defaultColumns)) { $view->config->columns_to_display = $defaultColumns; } $view->config->selectable_columns = $selectableColumns; $langString = $idGoal ? 'Goals_SingleGoalOverviewDocumentation' : 'Goals_GoalsOverviewDocumentation'; $view->config->documentation = $this->translator->translate($langString, '
'); return $this->renderView($view); } protected function getTopDimensions($idGoal) { $columnNbConversions = 'goal_' . $idGoal . '_nb_conversions'; $columnConversionRate = 'goal_' . $idGoal . '_conversion_rate'; $topDimensionsToLoad = array(); if (\Piwik\Plugin\Manager::getInstance()->isPluginActivated('UserCountry')) { $topDimensionsToLoad += array( 'country' => 'UserCountry.getCountry', ); } $keywordNotDefinedString = ''; if (\Piwik\Plugin\Manager::getInstance()->isPluginActivated('Referrers')) { $keywordNotDefinedString = APIReferrers::getKeywordNotDefinedString(); $topDimensionsToLoad += array( 'keyword' => 'Referrers.getKeywords', 'website' => 'Referrers.getWebsites', ); } $topDimensions = array(); foreach ($topDimensionsToLoad as $dimensionName => $apiMethod) { $request = new Request("method=$apiMethod &format=original &filter_update_columns_when_show_all_goals=1 &idGoal=" . AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE . " &filter_sort_order=desc &filter_sort_column=$columnNbConversions" . // select a couple more in case some are not valid (ie. conversions==0 or they are "Keyword not defined") "&filter_limit=" . (self::COUNT_TOP_ROWS_TO_DISPLAY + 2)); $datatable = $request->process(); $topDimension = array(); $count = 0; foreach ($datatable->getRows() as $row) { $conversions = $row->getColumn($columnNbConversions); if ($conversions > 0 && $count < self::COUNT_TOP_ROWS_TO_DISPLAY // Don't put the "Keyword not defined" in the best segment since it's irritating && !($dimensionName == 'keyword' && $row->getColumn('label') == $keywordNotDefinedString) ) { $topDimension[] = array( 'name' => $row->getColumn('label'), 'nb_conversions' => $conversions, 'conversion_rate' => $this->formatConversionRate($row->getColumn($columnConversionRate)), 'metadata' => $row->getMetadata(), ); $count++; } } $topDimensions[$dimensionName] = $topDimension; } return $topDimensions; } protected function getMetricsForGoal($idGoal) { $request = new Request("method=Goals.get&format=original&idGoal=$idGoal"); $datatable = $request->process(); $dataRow = $datatable->getFirstRow(); $nbConversions = $dataRow->getColumn('nb_conversions'); $nbVisitsConverted = $dataRow->getColumn('nb_visits_converted'); // Backward compatibility before 1.3, this value was not processed if (empty($nbVisitsConverted)) { $nbVisitsConverted = $nbConversions; } $revenue = $dataRow->getColumn('revenue'); $return = array( 'id' => $idGoal, 'nb_conversions' => (int)$nbConversions, 'nb_visits_converted' => (int)$nbVisitsConverted, 'conversion_rate' => $this->formatConversionRate($dataRow->getColumn('conversion_rate')), 'revenue' => $revenue ? $revenue : 0, 'urlSparklineConversions' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_conversions'), 'idGoal' => $idGoal)), 'urlSparklineConversionRate' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('conversion_rate'), 'idGoal' => $idGoal)), 'urlSparklineRevenue' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('revenue'), 'idGoal' => $idGoal)), ); if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { $items = $dataRow->getColumn('items'); $aov = $dataRow->getColumn('avg_order_revenue'); $return = array_merge($return, array( 'revenue_subtotal' => $dataRow->getColumn('revenue_subtotal'), 'revenue_tax' => $dataRow->getColumn('revenue_tax'), 'revenue_shipping' => $dataRow->getColumn('revenue_shipping'), 'revenue_discount' => $dataRow->getColumn('revenue_discount'), 'items' => $items ? $items : 0, 'avg_order_revenue' => $aov ? $aov : 0, 'urlSparklinePurchasedProducts' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('items'), 'idGoal' => $idGoal)), 'urlSparklineAverageOrderValue' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_order_revenue'), 'idGoal' => $idGoal)), )); } return $return; } private function setEditGoalsViewVariables($view) { $goals = $this->goals; $view->goals = $goals; $idGoal = Common::getRequestVar('idGoal', 0, 'int'); $view->idGoal = 0; if ($idGoal && array_key_exists($idGoal, $goals)) { $view->idGoal = $idGoal; } // unsanitize goal names and other text data (not done in API so as not to break // any other code/cause security issues) foreach ($goals as &$goal) { $goal['name'] = Common::unsanitizeInputValue($goal['name']); if (isset($goal['pattern'])) { $goal['pattern'] = Common::unsanitizeInputValue($goal['pattern']); } } $view->goalsJSON = json_encode($goals); $view->ecommerceEnabled = $this->site->isEcommerceEnabled(); } private function setGoalOptions(View $view) { $view->userCanEditGoals = Piwik::isUserHasAdminAccess($this->idSite); $view->goalTriggerTypeOptions = array( 'visitors' => Piwik::translate('Goals_WhenVisitors'), 'manually' => Piwik::translate('Goals_Manually') ); $view->goalMatchAttributeOptions = array( array('key' => 'url', 'value' => Piwik::translate('Goals_VisitUrl')), array('key' => 'title', 'value' => Piwik::translate('Goals_VisitPageTitle')), array('key' => 'event', 'value' => Piwik::translate('Goals_SendEvent')), array('key' => 'file', 'value' => Piwik::translate('Goals_Download')), array('key' => 'external_website', 'value' => Piwik::translate('Goals_ClickOutlink')), ); $view->allowMultipleOptions = array( array('key' => '0', 'value' => Piwik::translate('Goals_DefaultGoalConvertedOncePerVisit')), array('key' => '1', 'value' => Piwik::translate('Goals_AllowGoalConvertedMoreThanOncePerVisit')) ); $view->eventTypeOptions = array( array('key' => 'event_category', 'value' => Piwik::translate('Events_EventCategory')), array('key' => 'event_action', 'value' => Piwik::translate('Events_EventAction')), array('key' => 'event_name', 'value' => Piwik::translate('Events_EventName')) ); $view->patternTypeOptions = array( array('key' => 'contains', 'value' => Piwik::translate('Goals_Contains', '')), array('key' => 'exact', 'value' => Piwik::translate('Goals_IsExactly', '')), array('key' => 'regex', 'value' => Piwik::translate('Goals_MatchesExpression', '')) ); } /** * @deprecated used to be a widgetized URL. There to not break widget URLs */ public function widgetGoalReport() { $idGoal = Common::getRequestVar('idGoal', '', 'string'); if ($idGoal === Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { $_GET['containerId'] = 'EcommerceOverview'; } elseif (!empty($idGoal)) { $_GET['containerId'] = 'Goal_' . (int) $idGoal; } else { return ''; } return FrontController::getInstance()->fetchDispatch('CoreHome', 'renderWidgetContainer'); } /** * @deprecated used to be a widgetized URL. There to not break widget URLs */ public function widgetGoalsOverview() { $_GET['containerId'] = 'GoalsOverview'; return FrontController::getInstance()->fetchDispatch('CoreHome', 'renderWidgetContainer'); } }