Newer
Older
Benaka Moorthi
a validé
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
* @category Piwik_Plugins
* @package CoreVisualizations
Benaka Moorthi
a validé
*/
Benaka Moorthi
a validé
namespace Piwik\Plugins\CoreVisualizations\Visualizations;
use Piwik\Common;
use Piwik\Config;
use Piwik\DataTable;
Benaka Moorthi
a validé
use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal;
use Piwik\MetricsFormatter;
use Piwik\Piwik;
use Piwik\Plugins\Goals\API as APIGoals;
use Piwik\Site;
use Piwik\View;
use Piwik\ViewDataTable\Visualization;
use Piwik\Visualization\Config as VizConfig;
use Piwik\Visualization\Request;
Benaka Moorthi
a validé
require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php';
require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php';
Benaka Moorthi
a validé
/**
* DataTable visualization that shows DataTable data in an HTML table.
*/
Benaka Moorthi
a validé
class HtmlTable extends Visualization
Benaka Moorthi
a validé
{
Benaka Moorthi
a validé
const ID = 'table';
const TEMPLATE_FILE = "@CoreVisualizations/_dataTableViz_htmlTable.twig";
/**
Benaka Moorthi
a validé
* If this property is set to true, subtables will be shown as embedded in the original table.
* If false, subtables will be shown as whole tables between rows.
Benaka Moorthi
a validé
* Default value: false
*/
Benaka Moorthi
a validé
const SHOW_EMBEDDED_SUBTABLE = 'show_embedded_subtable';
/**
* Controls whether the entire DataTable should be rendered (including subtables) or just one
* specific table in the tree.
* Default value: false
*/
const SHOW_EXPANDED = 'show_expanded';
/**
* When showing an expanded datatable, this property controls whether rows with subtables are
* replaced with their subtables, or if they are shown alongside their subtables.
* Default value: false
*/
const REPLACE_ROW_WITH_SUBTABLE = 'replace_row_with_subtable';
/**
* Controls whether any DataTable Row Action icons are shown. If true, no icons are shown.
* @see also self::DISABLE_ROW_EVOLUTION
* Default value: false
*/
const DISABLE_ROW_ACTIONS = 'disable_row_actions';
/**
* Controls whether the row evolution DataTable Row Action icon is shown or not.
* @see also self::DISABLE_ROW_ACTIONS
* Default value: false
*/
const DISABLE_ROW_EVOLUTION = 'disable_row_evolution';
/**
* If true, the 'label', 'nb_visits', 'nb_uniq_visitors' (if present), 'nb_actions',
* 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate' and 'conversion_rate' (if
* goals view is not allowed) are displayed.
* Default value: false
*/
const SHOW_EXTRA_COLUMNS = 'show_extra_columns';
/**
* If true, conversions for each existing goal will be displayed for the visits in
* each row.
* Default value: false
*/
const SHOW_GOALS_COLUMNS = 'show_goals_columns';
/**
* If true, subtables will not be loaded when rows are clicked, but only if the
* 'show_goals_columns' property is also true.
* @see also self::SHOW_GOALS_COLUMNS
* Default value: false
*/
const DISABLE_SUBTABLE_IN_GOALS_VIEW = 'disable_subtable_when_show_goals';
Benaka Moorthi
a validé
/**
* Controls whether the summary row is displayed on every page of the datatable view or not.
* If false, the summary row will be treated as the last row of the dataset and will only visible
* when viewing the last rows.
* Default value: false
Benaka Moorthi
a validé
*/
const KEEP_SUMMARY_ROW = 'keep_summary_row';
/**
* If true, the summary row will be colored differently than all other DataTable rows.
Benaka Moorthi
a validé
* @see also self::KEEP_SUMMARY_ROW
* Default value: false
Benaka Moorthi
a validé
*/
const HIGHLIGHT_SUMMARY_ROW = 'highlight_summary_row';
static public $clientSideParameters = array(
'search_recursive',
Benaka Moorthi
a validé
'filter_limit',
'filter_offset',
Benaka Moorthi
a validé
'filter_sort_column',
'filter_sort_order',
Benaka Moorthi
a validé
);
static public $clientSideProperties = array(
Benaka Moorthi
a validé
'show_extra_columns',
'show_goals_columns',
'disable_row_evolution',
'disable_row_actions',
'enable_sort',
'keep_summary_row',
'subtable_controller_action',
Benaka Moorthi
a validé
);
Benaka Moorthi
a validé
public static $overridableProperties = array(
'show_expanded',
'disable_row_actions',
'disable_row_evolution',
'show_extra_columns',
'show_goals_columns',
'disable_subtable_when_show_goals',
'keep_summary_row',
'highlight_summary_row',
);
public function configureVisualization(VizConfig $properties)
{
if (Common::getRequestVar('idSubtable', false)
&& $properties->visualization_properties->show_embedded_subtable
) {
}
if ($properties->visualization_properties->show_extra_columns) {
$properties->show_exclude_low_population = true;
$properties->datatable_css_class = 'dataTableVizAllColumns';
Benaka Moorthi
a validé
}
if ($properties->visualization_properties->show_goals_columns) {
$properties->datatable_css_class = 'dataTableVizGoals';
$properties->show_exclude_low_population = true;
$properties->show_goals = true;
$properties->translations += array(
'nb_conversions' => Piwik::translate('Goals_ColumnConversions'),
'conversion_rate' => Piwik::translate('General_ColumnConversionRate'),
'revenue' => Piwik::translate('General_ColumnRevenue'),
'revenue_per_visit' => Piwik::translate('General_ColumnValuePerVisit'),
);
$properties->metrics_documentation['nb_visits'] = Piwik::translate('Goals_ColumnVisits');
if (Common::getRequestVar('documentationForGoalsPage', 0, 'int') == 1) { // TODO: should not use query parameter
$properties->documentation = Piwik::translate('Goals_ConversionByTypeReportDocumentation',
array('<br />', '<br />', '<a href="http://piwik.org/docs/tracking-goals-web-analytics/" target="_blank">', '</a>'));
}
if (!$properties->visualization_properties->disable_subtable_when_show_goals) {
$properties->subtable_controller_action = null;
}
$this->setShowGoalsColumnsProperties();
Benaka Moorthi
a validé
}
}
public static function getDefaultPropertyValues()
{
$defaults = array(
'enable_sort' => true,
'datatable_js_type' => 'DataTable',
'filter_limit' => Config::getInstance()->General['datatable_default_limit'],
'visualization_properties' => array(
'table' => array(
'disable_row_evolution' => false,
'disable_row_actions' => false,
'show_extra_columns' => false,
'show_goals_columns' => false,
'disable_subtable_when_show_goals' => false,
'keep_summary_row' => false,
'highlight_summary_row' => false,
'show_expanded' => false,
'show_embedded_subtable' => false
),
);
if (Common::getRequestVar('enable_filter_excludelowpop', false) == '1') {
$defaults['filter_excludelowpop'] = 'nb_visits';
$defaults['filter_excludelowpop_value'] = null;
}
return $defaults;
}
Benaka Moorthi
a validé
/**
* @param DataTable|DataTable\Map $dataTable
* @param \Piwik\Visualization\Config $properties
* @param \Piwik\Visualization\Request $request
*/
public function beforeGenericFiltersAreAppliedToLoadedDataTable($dataTable, VizConfig $properties, Request $request)
Benaka Moorthi
a validé
{
if ($properties->visualization_properties->show_extra_columns) {
$dataTable->filter(function ($dataTable) use ($properties) {
$columnsToDisplay = array('label', 'nb_visits');
Benaka Moorthi
a validé
if (in_array('nb_uniq_visitors', $dataTable->getColumns())) {
$columnsToDisplay[] = 'nb_uniq_visitors';
}
Benaka Moorthi
a validé
$columnsToDisplay = array_merge(
$columnsToDisplay, array('nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate')
);
Benaka Moorthi
a validé
// only display conversion rate for the plugins that do not provide "per goal" metrics
// otherwise, conversion rate is meaningless as a whole (since we don't process 'cross goals' conversions)
if (!$properties->show_goals) {
$columnsToDisplay[] = 'conversion_rate';
}
Benaka Moorthi
a validé
$properties->columns_to_display = $columnsToDisplay;
});
Benaka Moorthi
a validé
$prettifyTime = array('\Piwik\MetricsFormatter', 'getPrettyTimeFromSeconds');
Benaka Moorthi
a validé
$dataTable->filter('ColumnCallbackReplace', array('avg_time_on_site', $prettifyTime));
}
Benaka Moorthi
a validé
}
/**
* @param DataTable|DataTable\Map $dataTable
* @param \Piwik\Visualization\Config $properties
* @param \Piwik\Visualization\Request $request
*/
public function afterAllFilteresAreApplied($dataTable, VizConfig $properties, Request $request)
Benaka Moorthi
a validé
{
if ($properties->visualization_properties->show_extra_columns) {
$dataTable->filter('AddColumnsProcessedMetrics');
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
private function setShowGoalsColumnsProperties()
{
$view = $this->viewDataTable;
Benaka Moorthi
a validé
// set view properties based on goal requested
$idSite = Common::getRequestVar('idSite', null, 'int');
$idGoal = Common::getRequestVar('idGoal', AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW, 'string');
if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
$this->setPropertiesForEcommerceView($view);
} else if ($idGoal == AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE) {
$this->setPropertiesForGoals($view, $idSite, 'all');
} else if ($idGoal == AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW) {
$this->setPropertiesForGoalsOverview($view, $idSite);
} else {
$this->setPropertiesForGoals($view, $idSite, array($idGoal));
}
// add goals columns
$view->filters[] = array('AddColumnsProcessedMetricsGoal', array($ignore = true, $idGoal), $priority = true);
Benaka Moorthi
a validé
// prettify columns
$setRatePercent = function ($rate, $thang = false) {
return $rate == 0 ? "0%" : $rate;
};
Benaka Moorthi
a validé
foreach ($view->columns_to_display as $columnName) {
if (strpos($columnName, 'conversion_rate') !== false) {
$view->filters[] = array('ColumnCallbackReplace', array($columnName, $setRatePercent));
}
}
$formatPercent = function ($value) use ($idSite) {
return MetricsFormatter::getPrettyMoney(sprintf("%.1f", $value), $idSite);
Benaka Moorthi
a validé
};
foreach ($view->columns_to_display as $columnName) {
if ($this->isRevenueColumn($columnName)) {
$view->filters[] = array('ColumnCallbackReplace', array($columnName, $formatPercent));
}
}
// this ensures that the value is set to zero for all rows where the value was not set (no conversion)
$identityFunction = function ($value) {
return $value;
};
Benaka Moorthi
a validé
foreach ($view->columns_to_display as $columnName) {
if (!$this->isRevenueColumn($columnName)) {
$view->filters[] = array('ColumnCallbackReplace', array($columnName, $identityFunction));
}
}
}
private function setPropertiesForEcommerceView($view)
{
$view->filter_sort_column = 'goal_ecommerceOrder_revenue';
$view->filter_sort_order = 'desc';
$view->columns_to_display = array(
'label', 'nb_visits', 'goal_ecommerceOrder_nb_conversions', 'goal_ecommerceOrder_revenue',
'goal_ecommerceOrder_conversion_rate', 'goal_ecommerceOrder_avg_order_revenue', 'goal_ecommerceOrder_items',
'goal_ecommerceOrder_revenue_per_visit'
);
$view->translations += array(
'goal_ecommerceOrder_conversion_rate' => Piwik::translate('Goals_ConversionRate', Piwik::translate('Goals_EcommerceOrder')),
'goal_ecommerceOrder_nb_conversions' => Piwik::translate('General_EcommerceOrders'),
'goal_ecommerceOrder_revenue' => Piwik::translate('General_TotalRevenue'),
'goal_ecommerceOrder_revenue_per_visit' => Piwik::translate('General_ColumnValuePerVisit'),
'goal_ecommerceOrder_avg_order_revenue' => Piwik::translate('General_AverageOrderValue'),
'goal_ecommerceOrder_items' => Piwik::translate('General_PurchasedProducts')
Benaka Moorthi
a validé
);
$goalName = Piwik::translate('General_EcommerceOrders');
Benaka Moorthi
a validé
$view->metrics_documentation += array(
'goal_ecommerceOrder_conversion_rate' => Piwik::translate('Goals_ColumnConversionRateDocumentation', $goalName),
'goal_ecommerceOrder_nb_conversions' => Piwik::translate('Goals_ColumnConversionsDocumentation', $goalName),
'goal_ecommerceOrder_revenue' => Piwik::translate('Goals_ColumnRevenueDocumentation', $goalName),
'goal_ecommerceOrder_revenue_per_visit' => Piwik::translate('Goals_ColumnAverageOrderRevenueDocumentation', $goalName),
'goal_ecommerceOrder_avg_order_revenue' => Piwik::translate('Goals_ColumnAverageOrderRevenueDocumentation', $goalName),
'goal_ecommerceOrder_items' => Piwik::translate('Goals_ColumnPurchasedProductsDocumentation', $goalName),
'revenue_per_visit' => Piwik::translate('Goals_ColumnRevenuePerVisitDocumentation', $goalName)
Benaka Moorthi
a validé
);
}
private function setPropertiesForGoalsOverview($view, $idSite)
{
$allGoals = $this->getGoals($idSite);
// set view properties
$view->columns_to_display = array('label', 'nb_visits');
foreach ($allGoals as $goal) {
$column = "goal_{$goal['idgoal']}_conversion_rate";
$view->columns_to_display[] = $column;
$view->translations[$column] = Piwik::translate('Goals_ConversionRate', $goal['name']);
Benaka Moorthi
a validé
$view->metrics_documentation[$column]
= Piwik::translate('Goals_ColumnConversionRateDocumentation', $goal['quoted_name'] ? : $goal['name']);
Benaka Moorthi
a validé
}
$view->columns_to_display[] = 'revenue_per_visit';
$view->metrics_documentation['revenue_per_visit'] =
Piwik::translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik::translate('Goals_EcommerceAndGoalsMenu'));
Benaka Moorthi
a validé
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
}
private function setPropertiesForGoals($view, $idSite, $idGoals)
{
$allGoals = $this->getGoals($idSite);
if ($idGoals == 'all') {
$idGoals = array_keys($allGoals);
} else {
// only sort by a goal's conversions if not showing all goals (for FULL_REPORT)
$view->filter_sort_column = 'goal_' . reset($idGoals) . '_nb_conversions';
$view->filter_sort_order = 'desc';
}
$view->columns_to_display = array('label', 'nb_visits');
$goalColumnTemplates = array(
'goal_%s_nb_conversions',
'goal_%s_conversion_rate',
'goal_%s_revenue',
'goal_%s_revenue_per_visit',
);
// set columns to display (columns of same type but different goals will be next to each other,
// ie, goal_0_nb_conversions, goal_1_nb_conversions, etc.)
foreach ($goalColumnTemplates as $idx => $columnTemplate) {
foreach ($idGoals as $idGoal) {
$column = sprintf($columnTemplate, $idGoal);
$view->columns_to_display[] = $column;
}
}
// set translations & metric docs for goal specific metrics
foreach ($idGoals as $idGoal) {
$goalName = $allGoals[$idGoal]['name'];
$quotedGoalName = $allGoals[$idGoal]['quoted_name'] ? : $goalName;
Benaka Moorthi
a validé
$view->translations += array(
'goal_' . $idGoal . '_nb_conversions' => Piwik::translate('Goals_Conversions', $goalName),
'goal_' . $idGoal . '_conversion_rate' => Piwik::translate('Goals_ConversionRate', $goalName),
Piwik::translate('%s ' . Piwik::translate('General_ColumnRevenue'), $goalName),
Benaka Moorthi
a validé
'goal_' . $idGoal . '_revenue_per_visit' =>
Piwik::translate('%s ' . Piwik::translate('General_ColumnValuePerVisit'), $goalName),
Benaka Moorthi
a validé
);
$view->metrics_documentation += array(
'goal_' . $idGoal . '_nb_conversions' => Piwik::translate('Goals_ColumnConversionsDocumentation', $quotedGoalName),
'goal_' . $idGoal . '_conversion_rate' => Piwik::translate('Goals_ColumnConversionRateDocumentation', $quotedGoalName),
'goal_' . $idGoal . '_revenue' => Piwik::translate('Goals_ColumnRevenueDocumentation', $quotedGoalName),
Benaka Moorthi
a validé
'goal_' . $idGoal . '_revenue_per_visit' =>
Piwik::translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik::translate('Goals_EcommerceAndGoalsMenu')),
Benaka Moorthi
a validé
);
}
$view->columns_to_display[] = 'revenue_per_visit';
}
private function getGoals($idSite)
{
// get all goals to display info for
$allGoals = array();
Benaka Moorthi
a validé
// add the ecommerce goal if ecommerce is enabled for the site
Benaka Moorthi
a validé
if (Site::isEcommerceEnabledFor($idSite)) {
$ecommerceGoal = array(
'idgoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER,
'name' => Piwik::translate('Goals_EcommerceOrder'),
Benaka Moorthi
a validé
'quoted_name' => false
);
$allGoals[$ecommerceGoal['idgoal']] = $ecommerceGoal;
}
Benaka Moorthi
a validé
// add the site's goals (and escape all goal names)
$siteGoals = APIGoals::getInstance()->getGoals($idSite);
Benaka Moorthi
a validé
foreach ($siteGoals as &$goal) {
Benaka Moorthi
a validé
$goal['name'] = Common::sanitizeInputValue($goal['name']);
Benaka Moorthi
a validé
$goal['quoted_name'] = '"' . $goal['name'] . '"';
$allGoals[$goal['idgoal']] = $goal;
}
return $allGoals;
}
private function isRevenueColumn($name)
{
return strpos($name, '_revenue') !== false || $name == 'revenue_per_visit';
}